From 328965986406c9aa09fbcf9c06bda6f8fb4f44fc Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 10 May 2023 18:47:03 +0530 Subject: [PATCH 001/113] ezrSquared Rewrite - Part 1 --- .gitignore | 6 +- Changelog.txt | 23 +- Classes/Errors.cs | 85 - Classes/General.cs | 206 - Classes/Helpers.cs | 123 - Classes/Nodes.cs | 268 -- Classes/Values.cs | 2767 ------------- Constants.cs | 64 - Libraries/io/IO.cs | 1518 ------- Libraries/io/io.csproj | 18 - Libraries/std/STD.cs | 186 - Libraries/std/std.csproj | 19 - README.md | 5 +- Tests/fullTest.ezr2 | 205 - {Offline Site => docs/offline}/config.yml | 2 +- .../offline}/jekyll_offline.rb | 0 .../offline}/lib_rellinks.rb | 0 {Offline Site => docs/offline}/template.rhtml | 0 ezr.cs | 3590 ----------------- ezrShell.cs | 82 - ezrSquared.csproj | 19 - ezrSquared.sln | 28 +- .../tic_tac_toe_demo.ezr2 | 0 .../turing_machine_demo.ezr2 | 0 src/AssemblyInfo.cs | 11 + src/AutoGeneratedAssemblyInfo.cs | 19 + src/Directory.Build.props | 14 + src/EzrErrors.cs | 114 + src/EzrGeneral.cs | 230 ++ src/EzrLexer.cs | 591 +++ src/EzrShell.cs | 59 + src/EzrSquared.csproj | 24 + {Graphics => src}/Icon.ico | Bin {Installer => src/installer}/environment.iss | 0 .../installer}/ezrSquared 32-bit.iss | 16 +- .../installer}/ezrSquared 64-bit.iss | 16 +- tests/full_test.ezr2 | 1 + .../snake.ezr2 => tests/graphics_test_01.ezr2 | 0 .../graphics_test_02.ezr2 | 0 .../library_test.ezr2 | 0 40 files changed, 1094 insertions(+), 9215 deletions(-) delete mode 100644 Classes/Errors.cs delete mode 100644 Classes/General.cs delete mode 100644 Classes/Helpers.cs delete mode 100644 Classes/Nodes.cs delete mode 100644 Classes/Values.cs delete mode 100644 Constants.cs delete mode 100644 Libraries/io/IO.cs delete mode 100644 Libraries/io/io.csproj delete mode 100644 Libraries/std/STD.cs delete mode 100644 Libraries/std/std.csproj delete mode 100644 Tests/fullTest.ezr2 rename {Offline Site => docs/offline}/config.yml (61%) rename {Offline Site => docs/offline}/jekyll_offline.rb (100%) rename {Offline Site => docs/offline}/lib_rellinks.rb (100%) rename {Offline Site => docs/offline}/template.rhtml (100%) delete mode 100644 ezr.cs delete mode 100644 ezrShell.cs delete mode 100644 ezrSquared.csproj rename Tests/tic-tac-toe_demo.ezr2 => samples/tic_tac_toe_demo.ezr2 (100%) rename Tests/turingMachine.ezr2 => samples/turing_machine_demo.ezr2 (100%) create mode 100644 src/AssemblyInfo.cs create mode 100644 src/AutoGeneratedAssemblyInfo.cs create mode 100644 src/Directory.Build.props create mode 100644 src/EzrErrors.cs create mode 100644 src/EzrGeneral.cs create mode 100644 src/EzrLexer.cs create mode 100644 src/EzrShell.cs create mode 100644 src/EzrSquared.csproj rename {Graphics => src}/Icon.ico (100%) rename {Installer => src/installer}/environment.iss (100%) rename {Installer => src/installer}/ezrSquared 32-bit.iss (81%) rename {Installer => src/installer}/ezrSquared 64-bit.iss (81%) create mode 100644 tests/full_test.ezr2 rename Tests/snake.ezr2 => tests/graphics_test_01.ezr2 (100%) rename Tests/gameTest.ezr2 => tests/graphics_test_02.ezr2 (100%) rename Tests/consoleTest.ezr2 => tests/library_test.ezr2 (100%) diff --git a/.gitignore b/.gitignore index 917dfe7..87b3f24 100644 --- a/.gitignore +++ b/.gitignore @@ -364,6 +364,6 @@ FodyWeavers.xsd # -------------------------------------------------- -Graphics/Visualization.png -Offline\ Site/ezrSquared\ Offline/ -*.zip \ No newline at end of file +graphics/ +docs/offline/_site/ +docs/offline/ezrSquared.Offline.Documentation.zip \ No newline at end of file diff --git a/Changelog.txt b/Changelog.txt index d8e7fba..70b58ee 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,23 +1,4 @@ CHANGELOG - What's new? -* prerelease-1.5.1.3.0 - [03-05-23] - * Added new functions `get_window_size`, `set_window_size`, `get_window_position` and `set_window_position` - - to `Console` class in the IO library - * Function `set_buffer_size` in `Console` class in the IO library now uses the `SetBufferSize` C# function - -* prerelease-1.5.1.2.0 - [01-04-23] - * Added new functions `get_buffer_size` and `set_buffer_size` to `Console` class in the IO library - * Unsupported functions in `Console` class in the IO library will now show new error if called - -* prerelease-1.5.1.1.0 - [27-03-23] - * `Console.set_cursor_position` in the IO library now accepts two seperate integers - -* prerelease-1.5.1.0.1 - [25-03-23] - * Fixed bug in special function `equals` - -* prerelease-1.5.1.0.0 - [23-03-23] - * "all" keyword and ',' symbol now interchangeable in normal and QuickSyntax `include` expressions - -* prerelease-1.5.0.0.0 - [21-03-23] - * More major changes to module/library system and `include` expression - * Context name of value-derived types now the name of the derived type \ No newline at end of file +* ezr² Rewrite - Part 1 [10-05-23] + * Completed rewriting the Lexer and it's supporting components \ No newline at end of file diff --git a/Classes/Errors.cs b/Classes/Errors.cs deleted file mode 100644 index 225d76e..0000000 --- a/Classes/Errors.cs +++ /dev/null @@ -1,85 +0,0 @@ -using ezrSquared.General; -using static ezrSquared.Constants.constants; -using System; - -namespace ezrSquared.Errors -{ - public abstract class error - { - internal string name; - internal string details; - internal position startPos; - internal position endPos; - - public error(string name, string details, position startPos, position endPos) - { - this.name = name; - this.details = details; - this.startPos = startPos; - this.endPos = endPos; - } - - public virtual string asString() { return $"(error) {name}: {details} -> File '{startPos.file}', line {startPos.line + 1}\n{stringWithUnderline(startPos.text, startPos, endPos)}"; } - - internal string stringWithUnderline(string text, position startPos, position endPos) - { - int start = Math.Max(text[0..((startPos.index <= text.Length) ? startPos.index : text.Length)].LastIndexOf('\n'), 0); - int end = text.IndexOf('\n', start + 1); - if (end == -1) end = text.Length; - - string result = text[start..end] + '\n'; - for (int i = 0; i < startPos.column; i++) - result += ' '; - for (int i = 0; i < endPos.column - startPos.column; i++) - result += '~'; - return result.Replace('\t', ' '); - } - } - - public class unknownCharacterError : error - { - public unknownCharacterError(string details, position startPos, position endPos) : base("Unknown character", details, startPos, endPos) { } - } - - public class invalidGrammarError : error - { - public invalidGrammarError(string details, position startPos, position endPos) : base("Invalid grammar", details, startPos, endPos) { } - } - - public class overflowError : error - { - public overflowError(string details, position startPos, position endPos) : base("Overflow", details, startPos, endPos) { } - } - - public class runtimeError : error - { - private context context; - public runtimeError(position startPos, position endPos, string tag, string details, context context) : base(tag, details, startPos, endPos) { this.context = context; } - - public override string asString() { return $"{generateTraceback()}(runtime error) : {details} -> tag '{name}'\n\n{stringWithUnderline(startPos.text, startPos, endPos)}"; } - - internal string generateTraceback() - { - string result = ""; - position? pos = startPos; - context? context = this.context; - - while (context != null) - { - result = $"\t File '{pos.file}', line {pos.line + 1} - In '{context.name}'\n{result}"; - pos = context.parentEntryPos; - context = context.parent; - } - - return $"Traceback - most recent call last:\n{result}"; - } - } - - public class runtimeRunError : runtimeError - { - private string runError; - public runtimeRunError(position startPos, position endPos, string details, string runError, context context) : base(startPos, endPos, RT_RUN, details, context) { this.runError = runError; } - - public override string asString() { return $"{generateTraceback()}(runtime error) : {details} -> tag '{name}'\n\n{stringWithUnderline(startPos.text, startPos, endPos)}\n\n{runError}"; } - } -} \ No newline at end of file diff --git a/Classes/General.cs b/Classes/General.cs deleted file mode 100644 index dab554d..0000000 --- a/Classes/General.cs +++ /dev/null @@ -1,206 +0,0 @@ -using ezrSquared.Values; -using System.Collections.Generic; - -namespace ezrSquared.General -{ - public enum TOKENTYPE : int - { - INT, - FLOAT, - STRING, - CHARLIST, - ID, - KEY, - QEY, - PLUS, - MINUS, - MUL, - DIV, - MOD, - POW, - BITAND, - BITOR, - BITXOR, - BITNOT, - BITLSHIFT, - BITRSHIFT, - COLON, - ASSIGNPLUS, - ASSIGNMINUS, - ASSIGNMUL, - ASSIGNDIV, - ASSIGNMOD, - ASSIGNPOW, - ASSIGNBITAND, - ASSIGNBITOR, - ASSIGNBITXOR, - ASSIGNBITLSHIFT, - ASSIGNBITRSHIFT, - LPAREN, - RPAREN, - LSQUARE, - RSQUARE, - LCURLY, - RCURLY, - ISEQUAL, - NOTEQUAL, - LESSTHAN, - GREATERTHAN, - LESSTHANOREQUAL, - GREATERTHANOREQUAL, - COMMA, - PERIOD, - ARROW, - NEWLINE, - ENDOFFILE - } - - public class position - { - public int index; - public int line; - public int column; - public string file; - public string text; - private int prevLineColumn = 0; - - public position(int index, int line, int column, string file, string text) - { - this.index = index; - this.line = line; - this.column = column; - this.file = file; - this.text = text; - } - - public position advance(char? currentChar = null) - { - index++; - column++; - - if (currentChar == '\n') - { - line++; - prevLineColumn = column; - column = 0; - } - - return this; - } - - public position reverse(char? currentChar, int count = 1) - { - index--; - column--; - - if (currentChar == '\n') - { - line--; - column = prevLineColumn; - } - - return this; - } - - public position copy() { return new position(index, line, column, file, text); } - } - - public class token - { - public TOKENTYPE type; - public object? value; - public position startPos; - public position endPos; - - public token(TOKENTYPE type, position startPos, position? endPos = null) - { - this.type = type; - this.value = null; - - this.startPos = startPos.copy(); - if (endPos != null) - this.endPos = endPos.copy(); - else - { - this.endPos = startPos.copy(); - this.endPos.advance(); - } - } - - public token(TOKENTYPE type, object value, position startPos, position? endPos = null) - { - this.type = type; - this.value = value; - - this.startPos = startPos.copy(); - if (endPos != null) - this.endPos = endPos.copy(); - else - { - this.endPos = startPos.copy(); - this.endPos.advance(); - } - } - - public bool matchString(TOKENTYPE type, string value) - { - if (this.type == (TOKENTYPE.INT | TOKENTYPE.FLOAT) || this.value == null) return false; - - return this.type == type && (string)this.value == value; - } - } - - public class context - { - public string name; - public context? parent; - public position? parentEntryPos; - public symbolTable? symbolTable; - public bool locked; - - public context(string name, context? parent = null, position? parentEntryPos = null, bool locked = false) - { - this.name = name; - this.parent = parent; - this.parentEntryPos = parentEntryPos; - this.locked = locked; - this.symbolTable = null; - } - } - - public class symbolTable - { - public symbolTable? parent; - - private Dictionary symbols; - - public symbolTable(symbolTable? parent = null) - { - this.symbols = new Dictionary(); - this.parent = parent; - } - - public item? get(string name) - { - if (symbols.TryGetValue(name, out item? value)) - return value; - else if (parent != null) - return parent.get(name); - return null; - } - - public void set(string name, item value) - { - if (symbols.ContainsKey(name)) - symbols[name] = value; - else - symbols.Add(name, value); - } - - public void remove(string name) - { - if (symbols.ContainsKey(name)) - symbols.Remove(name); - } - } -} diff --git a/Classes/Helpers.cs b/Classes/Helpers.cs deleted file mode 100644 index f830e8e..0000000 --- a/Classes/Helpers.cs +++ /dev/null @@ -1,123 +0,0 @@ -using ezrSquared.Errors; -using ezrSquared.Nodes; -using ezrSquared.Values; - -namespace ezrSquared.Helpers -{ - public class parseResult - { - public error? error; - public node? node; - public int advanceCount; - public int reverseCount; - - public parseResult() - { - this.error = null; - this.node = null; - this.advanceCount = 0; - this.reverseCount = 0; - } - - public void registerAdvance() { advanceCount++; } - - public node register(parseResult result) - { - advanceCount += result.advanceCount; - if (result.error != null) - error = result.error; - return result.node; - } - - public node? tryRegister(parseResult result) - { - if (result.error != null) - { - reverseCount = result.advanceCount; - return null; - } - - return register(result); - } - - public parseResult success(node node) - { - this.node = node; - return this; - } - - public parseResult failure(error error) - { - if (this.error == null || advanceCount == 0) - this.error = error; - return this; - } - } - - public class runtimeResult - { - public item? value; - public error? error; - public item? functionReturnValue; - public bool loopShouldSkip; - public bool loopShouldStop; - - public runtimeResult() { reset(); } - - public void reset() - { - value = null; - error = null; - functionReturnValue = null; - loopShouldSkip = false; - loopShouldStop = false; - } - - public item? register(runtimeResult result) - { - if (result.error != null) - error = result.error; - functionReturnValue = result.functionReturnValue; - loopShouldSkip = result.loopShouldSkip; - loopShouldStop = result.loopShouldStop; - return result.value; - } - - public runtimeResult success(item value) - { - reset(); - this.value = value; - return this; - } - - public runtimeResult returnSuccess(item value) - { - reset(); - functionReturnValue = value; - return this; - } - - public runtimeResult skipSuccess() - { - reset(); - loopShouldSkip = true; - return this; - } - - public runtimeResult stopSuccess() - { - reset(); - loopShouldStop = true; - return this; - } - - public runtimeResult failure(error error) - { - reset(); - this.error = error; - return this; - } - - public bool shouldReturn() { return (error != null || functionReturnValue != null || loopShouldSkip || loopShouldStop); } - } -} \ No newline at end of file diff --git a/Classes/Nodes.cs b/Classes/Nodes.cs deleted file mode 100644 index 575d167..0000000 --- a/Classes/Nodes.cs +++ /dev/null @@ -1,268 +0,0 @@ -using ezrSquared.General; - -namespace ezrSquared.Nodes -{ - public abstract class node - { - public position startPos; - public position endPos; - - public node(position startPos, position endPos) - { - this.startPos = startPos; - this.endPos = endPos; - } - } - - public abstract class valueNode : node - { - public token valueToken; - - public valueNode(token valueToken, position startPos, position endPos) : base(startPos, endPos) - { this.valueToken = valueToken; } - } - - public abstract class arraylikeNode : node - { - public node[] elementNodes; - - public arraylikeNode(node[] elementNodes, position startPos, position endPos) : base(startPos, endPos) - { this.elementNodes = elementNodes; } - } - - public abstract class containerNode : node - { - public token? nameToken; - public token[] argNameTokens; - public node bodyNode; - public bool shouldReturnNull; - - public containerNode(token? nameToken, token[] argNameTokens, node bodyNode, bool shouldReturnNull, position startPos, position endPos) : base(startPos, endPos) - { - this.nameToken = nameToken; - this.argNameTokens = argNameTokens; - this.bodyNode = bodyNode; - this.shouldReturnNull = shouldReturnNull; - } - } - - public abstract class variableAssignmentNode : node - { - public token? operatorToken; - public node valueNode; - public bool isGlobal; - - public variableAssignmentNode(token? operatorToken, node valueNode, bool isGlobal, position startPos, position endPos) : base(startPos, endPos) - { - this.operatorToken = operatorToken; - this.valueNode = valueNode; - this.isGlobal = isGlobal; - } - } - - public class numberNode : valueNode - { - public numberNode(token valueToken, position startPos, position endPos) : base(valueToken, startPos, endPos) { } - } - - public class stringNode : valueNode - { - public stringNode(token valueToken, position startPos, position endPos) : base(valueToken, startPos, endPos) { } - } - - public class charListNode : valueNode - { - public charListNode(token valueToken, position startPos, position endPos) : base(valueToken, startPos, endPos) { } - } - - public class arrayNode : arraylikeNode - { - public arrayNode(node[] elements, position startPos, position endPos) : base(elements, startPos, endPos) { } - } - - public class listNode : arraylikeNode - { - public listNode(node[] elements, position startPos, position endPos) : base(elements, startPos, endPos) { } - } - - public class dictionaryNode : node - { - public node[][] nodePairs; - - public dictionaryNode(node[][] nodePairs, position startPos, position endPos) : base(startPos, endPos) - { this.nodePairs = nodePairs; } - } - - public class variableAccessNode : valueNode - { - public bool isGlobal; - public variableAccessNode(token valueToken, bool isGlobal, position startPos, position endPos) : base(valueToken, startPos, endPos) - { this.isGlobal = isGlobal; } - } - - public class simpleVariableAssignNode : variableAssignmentNode - { - public token nameToken; - public simpleVariableAssignNode(token nameToken, token? operatorToken, node valueNode, bool isGlobal, position startPos, position endPos) : base(operatorToken, valueNode, isGlobal, startPos, endPos) { this.nameToken = nameToken; } - } - - public class objectVariableAssignNode : variableAssignmentNode - { - public node accessNode; - public token varName; - - public objectVariableAssignNode(node accessNode, token varName, token? operatorToken, node valueNode, position startPos, position endPos) : base(operatorToken, valueNode, false, startPos, endPos) { this.accessNode = accessNode; this.varName = varName; } - } - - public class binaryOperationNode : node - { - public node leftNode; - public node rightNode; - public token operatorToken; - - public binaryOperationNode(node leftNode, node rightNode, token operatorToken, position startPos, position endPos) : base(startPos, endPos) - { - this.leftNode = leftNode; - this.rightNode = rightNode; - this.operatorToken = operatorToken; - } - } - - public class unaryOperationNode : node - { - public node operatedNode; - public token operatorToken; - - public unaryOperationNode(node operatedNode, token operatorToken, position startPos, position endPos) : base(startPos, endPos) - { - this.operatedNode = operatedNode; - this.operatorToken = operatorToken; - } - } - - public class ifNode : node - { - public node[][] cases; - public node? elseCase; - public bool shouldReturnNull; - - public ifNode(node[][] cases, node? elseCase, bool shouldReturnNull, position startPos, position endPos) : base(startPos, endPos) - { - this.cases = cases; - this.elseCase = elseCase; - this.shouldReturnNull = shouldReturnNull; - } - } - - public class countNode : node - { - public token? variableNameToken; - public node? startValueNode; - public node endValueNode; - public node? stepValueNode; - public node bodyNode; - public bool shouldReturnNull; - - public countNode(token? variableNameToken, node? startValueNode, node endValueNode, node? stepValueNode, node bodyNode, bool shouldReturnNull, position startPos, position endPos) : base(startPos, endPos) - { - this.variableNameToken = variableNameToken; - this.startValueNode = startValueNode; - this.endValueNode = endValueNode; - this.stepValueNode = stepValueNode; - this.bodyNode = bodyNode; - this.shouldReturnNull = shouldReturnNull; - } - } - - public class whileNode : node - { - public node conditionNode; - public node bodyNode; - public bool shouldReturnNull; - - public whileNode(node conditionNode, node bodyNode, bool shouldReturnNull, position startPos, position endPos) : base(startPos, endPos) - { - this.conditionNode = conditionNode; - this.bodyNode = bodyNode; - this.shouldReturnNull = shouldReturnNull; - } - } - - public class tryNode : node - { - public node bodyNode; - public object?[][] catches; - public bool shouldReturnNull; - - public tryNode(node bodyNode, object?[][] catches, bool shouldReturnNull, position startPos, position endPos) : base(startPos, endPos) - { - this.bodyNode = bodyNode; - this.catches = catches; - this.shouldReturnNull = shouldReturnNull; - } - } - - public class functionDefinitionNode : containerNode - { - public functionDefinitionNode(token? nameToken, token[] argNameTokens, node bodyNode, bool shouldReturnNull, position startPos, position endPos) : base(nameToken, argNameTokens, bodyNode, shouldReturnNull, startPos, endPos) { } - } - - public class specialDefinitionNode : containerNode - { - public specialDefinitionNode(token nameToken, node bodyNode, bool shouldReturnNull, position startPos, position endPos) : base(nameToken, new token[0], bodyNode, shouldReturnNull, startPos, endPos) { } - } - - public class objectDefinitionNode : containerNode - { - public token? inheritanceToken; - - public objectDefinitionNode(token nameToken, token? inheritFrom, token[] argNameTokens, node bodyNode, position startPos, position endPos) : base(nameToken, argNameTokens, bodyNode, true, startPos, endPos) - { this.inheritanceToken = inheritFrom; } - } - - public class callNode : node - { - public node nodeToCall; - public node[] argNodes; - - public callNode(node nodeToCall, node[] argNodes, position startPos, position endPos) : base(startPos, endPos) - { - this.nodeToCall = nodeToCall; - this.argNodes = argNodes; - } - } - - public class includeNode : node - { - public node fileNode; - public node? classNode; - public token? nicknameToken; - public bool dumpAll; - - public includeNode(node fileNode, node? classNode, bool dumpAll, token? nicknameToken, position startPos, position endPos) : base(startPos, endPos) - { - this.fileNode = fileNode; - this.classNode = classNode; - this.dumpAll = dumpAll; - this.nicknameToken = nicknameToken; - } - } - - public class returnNode : node - { - public node? nodeToReturn; - - public returnNode(node? nodeToReturn, position startPos, position endPos) : base(startPos, endPos) - { this.nodeToReturn = nodeToReturn; } - } - - public class skipNode : node - { - public skipNode(position startPos, position endPos) : base(startPos, endPos) { } - } - - public class stopNode : node - { - public stopNode(position startPos, position endPos) : base(startPos, endPos) { } - } -} \ No newline at end of file diff --git a/Classes/Values.cs b/Classes/Values.cs deleted file mode 100644 index cce3b63..0000000 --- a/Classes/Values.cs +++ /dev/null @@ -1,2767 +0,0 @@ -using ezrSquared.Errors; -using ezrSquared.General; -using ezrSquared.Nodes; -using ezrSquared.Helpers; -using static ezrSquared.Constants.constants; -using static ezrSquared.Main.ezr; -using System.Runtime.InteropServices; -using System.Collections.Generic; -using System.Reflection; -using System.Linq; -using System.IO; -using System; - -namespace ezrSquared.Values -{ - public static class Extras - { - [DllImport("libc")] - public static extern int system(string exec); - } - - public class ItemDictionary : LinkedList> - { - public int Count => _values.Length; - - private LinkedList>[] _values; - private error? firstError; - private int capacity; - private int raise; - - public ItemDictionary() - { - raise = 4; - _values = new LinkedList>[16]; - } - - public void Add(item key, item val, out error? error) - { - var hash = GetKeyHashCode(key, out error); - if (error != null) return; - - if (_values[hash] == null) - _values[hash] = new LinkedList>(); - - var keyPresent = _values[hash].Any(p => CheckEqual(p, key)); - if (firstError != null) - { - error = firstError; - firstError = null; - return; - } - - var newValue = new KeyValuePair(key, val); - - if (keyPresent) - { - _values[hash] = new LinkedList>(); - _values[hash].AddLast(newValue); - } - else - { - _values[hash].AddLast(newValue); - - capacity++; - if (Count <= capacity) - ResizeCollection(); - } - } - - private bool CheckEqual(KeyValuePair pair, item key) - { - bool isEqual = pair.Key.ItemEquals(key, out error? error); - if (error != null && firstError == null) - firstError = error; - - return isEqual; - } - - private void ResizeCollection() - { - raise++; - LinkedList>[] newArray = new LinkedList>[(int)MathF.Pow(2, raise)]; - Array.Copy(_values, newArray, _values.Length); - - _values = newArray; - } - - public void Remove(item key, out error? error) - { - var hash = GetKeyHashCode(key, out error); - if (error != null) return; - - var keyPresent = _values[hash].Any(p => CheckEqual(p, key)); - if (firstError != null) - { - error = firstError; - firstError = null; - return; - } - - if (keyPresent) - _values[hash] = new LinkedList>(); - } - - public bool ContainsKey(item key, out error? error) - { - var hash = GetKeyHashCode(key, out error); - if (error != null) return false; - - bool containsKey = _values[hash] == null ? false : _values[hash].Any(p => CheckEqual(p, key)); - if (firstError != null) - { - error = firstError; - firstError = null; - return false; - } - - return containsKey; - } - - public item? GetValue(item key, out error? error) - { - var hash = GetKeyHashCode(key, out error); - if (error != null) return null; - - item? value = _values[hash] == null ? null : _values[hash].First(m => CheckEqual(m, key)).Value; - if (firstError != null) - { - error = firstError; - firstError = null; - return null; - } - - return value; - } - - public IEnumerator> GetEnumerator() - { - return (from collections in _values - where collections != null - from item in collections - select item).GetEnumerator(); - } - - public KeyValuePair[] GetArray() - { - return (from collections in _values - where collections != null - from item in collections - select item).ToArray(); - } - - public int GetKeyHashCode(item key, out error? error) - { - error = null; - - var hash = key.GetItemHashCode(out error); - if (error != null) return 0; - - return (Math.Abs(hash)) % _values.Length; - } - } - - public abstract class item - { - public position? startPos; - public position? endPos; - public context? context; - public virtual bool UPDATEONACCESS => false; - - public item() { } - - public item setPosition(position? startPos, position? endPos) - { - this.startPos = startPos; - this.endPos = endPos; - return this; - } - - public virtual item setContext(context? context) - { - this.context = context; - return this; - } - - public virtual item? compareEqual(item other, out error? error) - { - error = null; - return new boolean(ItemEquals(other, out error)).setContext(context); - } - - public virtual item? compareNotEqual(item other, out error? error) - { - error = null; - return new boolean(!ItemEquals(other, out error)).setContext(context); - } - - public virtual item? compareAnd(item other, out error? error) - { - error = null; - - bool boolValue = isTrue(out error); - if (error != null) return null; - - bool otherBoolValue = other.isTrue(out error); - if (error != null) return null; - - return new boolean(boolValue && otherBoolValue); - } - - public virtual item? compareOr(item other, out error? error) - { - error = null; - - bool boolValue = isTrue(out error); - if (error != null) return null; - - bool otherBoolValue = other.isTrue(out error); - if (error != null) return null; - - return new boolean(boolValue || otherBoolValue); - } - - public virtual item? checkIn(item other, out error? error) - { - error = null; - if (other is list) - return new boolean(((list)other).hasElement(this, out error)).setContext(context); - else if (other is array) - return new boolean(((array)other).hasElement(this, out error)).setContext(context); - - error = illegalOperation(); - return null; - } - public virtual bool isTrue(out error? error) { error = null; return false; } - - public virtual item? bitwiseOrdTo(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? bitwiseXOrdTo(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? bitwiseAndedTo(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? bitwiseLeftShiftedTo(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? bitwiseRightShiftedTo(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? bitwiseNotted(out error? error) - { - error = illegalOperation(); - return null; - } - - public virtual item? addedTo(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? subbedBy(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? multedBy(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? divedBy(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? modedBy(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? powedBy(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? compareLessThan(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? compareGreaterThan(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? compareLessThanOrEqual(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? compareGreaterThanOrEqual(item other, out error? error) - { - error = illegalOperation(other); - return null; - } - - public virtual item? invert(out error? error) - { - error = illegalOperation(); - return null; - } - - public virtual runtimeResult execute(item[] args) { return new runtimeResult().failure(new runtimeError(startPos, endPos, RT_ILLEGALOP, "\"execute\" method called on unsupported object", context)); } - public virtual runtimeResult get(node node) { return new runtimeResult().failure(new runtimeError(node.startPos, node.endPos, RT_ILLEGALOP, "\"get\" method called on unsupported object", context)); } - public virtual runtimeResult set(string name, item variable) { return new runtimeResult().failure(new runtimeError(startPos, endPos, RT_ILLEGALOP, "\"set\" method called on unsupported object", context)); } - - public virtual item copy() { throw new Exception($"No copy method defined for \"{GetType().Name}\"!"); } - - public error illegalOperation(item? other = null) - { - if (other != null) - return new runtimeError(this.startPos, other.endPos, RT_ILLEGALOP, $"Illegal operation for types \"{this.GetType().Name}\" and \"{other.GetType().Name}\"", this.context); - return new runtimeError(this.startPos, this.endPos, RT_ILLEGALOP, $"Illegal operation for type \"{this.GetType().Name}\"", this.context); - } - - public override string ToString() { throw new Exception($"No ToString method defined for \"{GetType().Name}\"!"); } - public virtual bool ItemEquals(item obj, out error? error) { throw new Exception($"No Equals method defined for \"{GetType().Name}\"!"); } - public virtual int GetItemHashCode(out error? error) { throw new Exception($"No GetHashCode method defined for \"{GetType().Name}\"!"); } - } - - public abstract class value : item - { - public dynamic storedValue; - public context? internalContext; - private interpreter interpreter; - public override bool UPDATEONACCESS => true; - - public value(dynamic storedValue) - { - this.storedValue = storedValue; - interpreter = new interpreter(); - } - - public context generateContext() - { - context newContext = new context(GetType().Name, context, startPos, false); - newContext.symbolTable = new symbolTable(newContext.parent.symbolTable); - return newContext; - } - - public override runtimeResult execute(item[] args) - { - internalContext = generateContext(); - return new runtimeResult().success(this); - } - - public override runtimeResult get(node node) - { - runtimeResult result = new runtimeResult(); - if (internalContext != null) - { - item value = result.register(interpreter.visit(node, internalContext)); - if (result.shouldReturn()) return result; - return result.success(value); - } - - return base.get(node); - } - - public override string ToString() { return storedValue.ToString(); } - public override bool ItemEquals(item obj, out error? error) { error = null; if (GetType() == obj.GetType()) return storedValue == ((value)obj).storedValue; return false; } - public override int GetItemHashCode(out error? error) { error = null; return storedValue.GetHashCode(); } - } - - public class boolean : value - { - public boolean(bool value) : base(value) { } - - public override item? invert(out error? error) - { - error = null; - return new boolean(!storedValue).setContext(context); - } - - public override runtimeResult execute(item[] args) - { - base.execute(args); - - internalContext.symbolTable.set("as_string", new predefined_function("boolean_as_string", asString, new string[0])); - internalContext.symbolTable.set("as_character_list", new predefined_function("boolean_as_character_list", asCharList, new string[0])); - internalContext.symbolTable.set("as_integer", new predefined_function("boolean_as_integer", asInteger, new string[0])); - return new runtimeResult().success(this); - } - - private runtimeResult asString(context context, position[] positions) { return new runtimeResult().success(new @string(ToString())); } - private runtimeResult asCharList(context context, position[] positions) { return new runtimeResult().success(new character_list(ToString())); } - private runtimeResult asInteger(context context, position[] positions) { return new runtimeResult().success(new integer(storedValue ? 1 : 0)); } - - public override bool isTrue(out error? error) { error = null; return storedValue; } - public override item copy() { return new boolean(storedValue).setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return base.ToString().ToLower(); } - } - - public class nothing : value - { - public nothing() : base(null) { } - - public override runtimeResult execute(item[] args) - { - base.execute(args); - - internalContext.symbolTable.set("as_string", new predefined_function("nothing_as_string", asString, new string[0])); - internalContext.symbolTable.set("as_character_list", new predefined_function("nothing_as_character_list", asCharList, new string[0])); - internalContext.symbolTable.set("as_integer", new predefined_function("nothing_as_integer", asInteger, new string[0])); - internalContext.symbolTable.set("as_boolean", new predefined_function("nothing_as_boolean", asBoolean, new string[0])); - return new runtimeResult().success(this); - } - - private runtimeResult asString(context context, position[] positions) { return new runtimeResult().success(new @string(ToString())); } - private runtimeResult asCharList(context context, position[] positions) { return new runtimeResult().success(new character_list(ToString())); } - private runtimeResult asInteger(context context, position[] positions) { return new runtimeResult().success(new integer(0)); } - private runtimeResult asBoolean(context context, position[] positions) { return new runtimeResult().success(new boolean(false)); } - - public override item copy() { return new nothing().setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return "nothing"; } - public override int GetItemHashCode(out error? error) { error = null; return 0; } - } - - public class integer : value - { - public integer(int value) : base(value) { } - - public override item? bitwiseOrdTo(item other, out error? error) - { - error = null; - if (other is integer) - return new integer(storedValue | ((integer)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? bitwiseXOrdTo(item other, out error? error) - { - error = null; - if (other is integer) - return new integer(storedValue ^ ((integer)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? bitwiseAndedTo(item other, out error? error) - { - error = null; - if (other is integer) - return new integer(storedValue & ((integer)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? bitwiseLeftShiftedTo(item other, out error? error) - { - error = null; - if (other is integer) - return new integer(storedValue << ((integer)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? bitwiseRightShiftedTo(item other, out error? error) - { - error = null; - if (other is integer) - return new integer(storedValue >> ((integer)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? bitwiseNotted(out error? error) - { - error = null; - return new integer(~storedValue).setContext(context); - } - - public override item? addedTo(item other, out error? error) - { - error = null; - if (other is integer) - return new integer(storedValue + ((integer)other).storedValue).setContext(context); - else if (other is @float) - return new @float(storedValue + ((@float)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? subbedBy(item other, out error? error) - { - error = null; - if (other is integer) - return new integer(storedValue - ((integer)other).storedValue).setContext(context); - else if (other is @float) - return new @float(storedValue - ((@float)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? multedBy(item other, out error? error) - { - error = null; - if (other is integer) - return new integer(storedValue * ((integer)other).storedValue).setContext(context); - else if (other is @float) - return new @float(storedValue * ((@float)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? divedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue == 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Division by zero", context); - return null; - } - - if (other is @float) - return new @float(storedValue / otherValue.storedValue).setContext(context); - return new integer(storedValue / otherValue.storedValue).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? modedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue == 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Modulo by zero", context); - return null; - } - - if (other is @float) - return new @float(storedValue % otherValue.storedValue).setContext(context); - return new integer(storedValue % otherValue.storedValue).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? powedBy(item other, out error? error) - { - error = null; - if (other is integer) - return new integer((int)MathF.Pow(storedValue, ((integer)other).storedValue)).setContext(context); - else if (other is @float) - return new @float(MathF.Pow(storedValue, ((@float)other).storedValue)).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? compareLessThan(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new boolean(storedValue < ((value)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? compareGreaterThan(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new boolean(storedValue > ((value)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? compareLessThanOrEqual(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new boolean(storedValue <= ((value)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? compareGreaterThanOrEqual(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new boolean(storedValue >= ((value)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? invert(out error? error) - { - error = null; - return new integer((storedValue == 0) ? 1 : 0).setContext(context); - } - - public override runtimeResult execute(item[] args) - { - base.execute(args); - - internalContext.symbolTable.set("abs", new predefined_function("integer_abs", abs, new string[0])); - internalContext.symbolTable.set("as_string", new predefined_function("integer_as_string", asString, new string[0])); - internalContext.symbolTable.set("as_character_list", new predefined_function("integer_as_character_list", asCharList, new string[0])); - internalContext.symbolTable.set("as_float", new predefined_function("integer_as_float", asFloat, new string[0])); - internalContext.symbolTable.set("as_boolean", new predefined_function("integer_as_boolean", asBoolean, new string[0])); - return new runtimeResult().success(this); - } - - - private runtimeResult abs(context context, position[] positions) { return new runtimeResult().success(new integer(int.Abs(storedValue))); } - private runtimeResult asString(context context, position[] positions) { return new runtimeResult().success(new @string(ToString())); } - private runtimeResult asCharList(context context, position[] positions) { return new runtimeResult().success(new character_list(ToString())); } - private runtimeResult asFloat(context context, position[] positions) { return new runtimeResult().success(new @float(storedValue)); } - private runtimeResult asBoolean(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - bool boolValue = isTrue(out error? error); - if (error != null) return result.failure(error); - return result.success(new boolean(boolValue)); - } - - public override bool isTrue(out error? error) { error = null; return storedValue != 0; } - public override item copy() { return new integer(storedValue).setPosition(startPos, endPos).setContext(context); } - } - - public class @float : value - { - public @float(float value) : base(value) { } - public @float(int value) : base((float)value) { } - - public override item? addedTo(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new @float(storedValue + ((value)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? subbedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new @float(storedValue - ((value)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? multedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new @float(storedValue * ((value)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? divedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value other_ = (value)other; - if (other_.storedValue == 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Division by zero", context); - return null; - } - - return new @float(storedValue / other_.storedValue).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? modedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value other_ = (value)other; - if (other_.storedValue == 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Modulo by zero", context); - return null; - } - - return new @float(storedValue % other_.storedValue).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? powedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new @float(MathF.Pow(storedValue, ((value)other).storedValue)).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? compareLessThan(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new boolean(storedValue < ((value)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? compareGreaterThan(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new boolean(storedValue > ((value)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? compareLessThanOrEqual(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new boolean(storedValue <= ((value)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? compareGreaterThanOrEqual(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - return new boolean(storedValue >= ((value)other).storedValue).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? invert(out error? error) - { - error = null; - return new @float((storedValue == 0f) ? 1f : 0f).setContext(context); - } - - public override runtimeResult execute(item[] args) - { - base.execute(args); - - internalContext.symbolTable.set("abs", new predefined_function("float_abs", abs, new string[0])); - internalContext.symbolTable.set("as_string", new predefined_function("float_as_string", asString, new string[0])); - internalContext.symbolTable.set("as_character_list", new predefined_function("float_as_character_list", asCharList, new string[0])); - internalContext.symbolTable.set("as_integer", new predefined_function("float_as_integer", asInteger, new string[0])); - internalContext.symbolTable.set("as_boolean", new predefined_function("float_as_boolean", asBoolean, new string[0])); - internalContext.symbolTable.set("round_to", new predefined_function("float_round_to", roundTo, new string[1] { "digit" })); - return new runtimeResult().success(this); - } - - private runtimeResult abs(context context, position[] positions) { return new runtimeResult().success(new @float(float.Abs(storedValue))); } - private runtimeResult asString(context context, position[] positions) { return new runtimeResult().success(new @string(ToString())); } - private runtimeResult asCharList(context context, position[] positions) { return new runtimeResult().success(new character_list(ToString())); } - private runtimeResult asInteger(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (storedValue < int.MinValue || storedValue > int.MaxValue) - return result.failure(new runtimeError(startPos, endPos, RT_OVERFLOW, "Value either too large or too small to be converted to an integer", context)); - return result.success(new integer(storedValue)); - } - private runtimeResult asBoolean(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - bool boolValue = isTrue(out error? error); - if (error != null) return result.failure(error); - return result.success(new boolean(boolValue)); - } - - private runtimeResult roundTo(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item digit = context.symbolTable.get("digit"); - if (digit is not integer) - return result.failure(new runtimeError(startPos, endPos, RT_TYPE, "Digit must be an integer", context)); - - return new runtimeResult().success(new @float(MathF.Round(storedValue, ((integer)digit).storedValue))); - } - - public override bool isTrue(out error? error) { error = null; return storedValue != 0f; } - public override item copy() { return new @float(storedValue).setPosition(startPos, endPos).setContext(context); } - } - - public class @string : value - { - public @string(string value) : base(value) { } - public @string(char value) : base(value.ToString()) { } - - public override item? addedTo(item other, out error? error) - { - error = null; - if (other is @string) - return new @string(storedValue + ((@string)other).storedValue).setContext(context); - else if (other is character_list) - return new @string(storedValue + string.Join("", ((character_list)other).storedValue)).setContext(context); - - error = illegalOperation(other); - return null; - } - - public override item? multedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - string result = ""; - for (int i = 0; i < ((value)other).storedValue; i++) - result += storedValue; - return new @string(result).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? divedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue == 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Division by zero", context); - return null; - } - else if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "String division by negative value", context); - return null; - } - - string result = storedValue.Substring(0, storedValue.Length / otherValue.storedValue); - return new @string(result).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? compareLessThanOrEqual(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be negative value", context); - return null; - } - else if (otherValue.storedValue >= storedValue.Length) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be greater than or equal to length of string", context); - return null; - } - - return new @string(storedValue[(int)otherValue.storedValue]).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? checkIn(item other, out error? error) - { - error = null; - if (other is @string) - return new boolean(((@string)other).storedValue.Contains(storedValue)).setContext(context); - else if (other is character_list) - return new boolean(string.Join("", ((character_list)other).storedValue).Contains(storedValue)).setContext(context); - return base.checkIn(other, out error); - } - - public override runtimeResult execute(item[] args) - { - base.execute(args); - - internalContext.symbolTable.set("length", new integer(storedValue.ToString().Length)); - internalContext.symbolTable.set("slice", new predefined_function("string_slice", stringSlice, new string[2] { "start", "end" })); - internalContext.symbolTable.set("insert", new predefined_function("string_insert", stringInsert, new string[2] { "index", "substring" })); - internalContext.symbolTable.set("replace", new predefined_function("string_replace", stringReplace, new string[2] { "old", "new" })); - internalContext.symbolTable.set("split", new predefined_function("string_split", stringSplit, new string[1] { "substring" })); - internalContext.symbolTable.set("join", new predefined_function("string_join", stringJoin, new string[1] { "array" })); - internalContext.symbolTable.set("as_integer", new predefined_function("string_as_integer", asInteger, new string[0] { })); - internalContext.symbolTable.set("as_float", new predefined_function("string_as_float", asFloat, new string[0] { })); - internalContext.symbolTable.set("try_as_integer", new predefined_function("string_try_as_integer", tryAsInteger, new string[0] { })); - internalContext.symbolTable.set("try_as_float", new predefined_function("string_try_as_float", tryAsFloat, new string[0] { })); - internalContext.symbolTable.set("as_boolean", new predefined_function("string_as_boolean", asBoolean, new string[0] { })); - internalContext.symbolTable.set("try_as_boolean", new predefined_function("string_try_as_boolean", tryAsBoolean, new string[0] { })); - internalContext.symbolTable.set("as_boolean_value", new predefined_function("string_as_boolean_value", asBooleanValue, new string[0] { })); - internalContext.symbolTable.set("as_character_list", new predefined_function("string_character_list", asCharList, new string[0] { })); - internalContext.symbolTable.set("is_null_or_empty", new predefined_function("string_is_null_or_empty", isNullOrEmpty, new string[0] { })); - internalContext.symbolTable.set("is_null_or_spaces", new predefined_function("string_is_null_or_spaces", isNullOrSpaces, new string[0] { })); - - return new runtimeResult().success(this); - } - - private runtimeResult stringSlice(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item start = context.symbolTable.get("start"); - item end = context.symbolTable.get("end"); - - if (start is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Start must be an integer", context)); - else if (end is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "End must be an integer", context)); - - int startAsInt = ((integer)start).storedValue; - int endAsInt = ((integer)end).storedValue; - - if (startAsInt < 0) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Start cannot be less than zero", context)); - else if (endAsInt > storedValue.ToString().Length) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "End cannot be greater than length of string", context)); - else if (startAsInt > endAsInt) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Start cannot be greater than end", context)); - - return result.success(new @string(storedValue.ToString().Substring(startAsInt, endAsInt))); - } - - private runtimeResult stringInsert(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item start = context.symbolTable.get("index"); - item substring = context.symbolTable.get("substring"); - - if (start is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Index must be an integer", context)); - else if (substring is not @string && substring is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Substring must be a string or character_list", context)); - - string subString = (substring is @string) ? ((@string)substring).storedValue : string.Join("", ((character_list)substring).storedValue); - int startAsInt = ((integer)start).storedValue; - - if (startAsInt < 0) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Index cannot be less than zero", context)); - else if (startAsInt > storedValue.ToString().Length) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Index cannot be greater than length of string", context)); - - return result.success(new @string(storedValue.ToString().Insert(startAsInt, subString))); - } - - private runtimeResult stringReplace(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item old = context.symbolTable.get("old"); - item new_ = context.symbolTable.get("new"); - - if (old is not @string && old is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Old must be a string or character_list", context)); - if (new_ is not @string && new_ is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "New must be a string or character_list", context)); - string oldString = (old is @string) ? ((@string)old).storedValue : string.Join("", ((character_list)old).storedValue); - string newString = (new_ is @string) ? ((@string)new_).storedValue : string.Join("", ((character_list)new_).storedValue); - - return result.success(new @string(storedValue.ToString().Replace(oldString, newString))); - } - - private runtimeResult stringSplit(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item substring = context.symbolTable.get("substring"); - - if (substring is not @string && substring is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Substring must be a string or character_list", context)); - - string subString = (substring is @string) ? ((@string)substring).storedValue : string.Join("", ((character_list)substring).storedValue); - string[] split = storedValue.ToString().Split(subString); - - item[] elements = new item[split.Length]; - for (int i = 0; i < split.Length; i++) - elements[i] = new @string(split[i]).setPosition(positions[0], positions[1]).setContext(context); - return result.success(new array(elements)); - } - - private runtimeResult stringJoin(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item array = context.symbolTable.get("array"); - - item[] items; - if (array is array) - items = (item[])((array)array).storedValue; - else if (array is list) - items = ((List)((list)array).storedValue).ToArray(); - else - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Array must be an array or list", context)); - - string[] arrayAsString = new string[items.Length]; - for (int i = 0; i < items.Length; i++) - { - if (items[i] is @string || items[i] is character_list) - arrayAsString[i] = (items[i] is @string) ? ((@string)items[i]).storedValue : string.Join("", ((character_list)items[i]).storedValue); - else - arrayAsString[i] = items[i].ToString(); - } - - return result.success(new @string(string.Join(storedValue.ToString(), arrayAsString))); - } - - private runtimeResult asInteger(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (int.TryParse(storedValue.ToString(), out int integer)) - return result.success(new integer(integer)); - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Could not convert string to integer", context)); - } - - private runtimeResult asFloat(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (float.TryParse(storedValue.ToString(), out float float_)) - return result.success(new @float(float_)); - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Could not convert string to float", context)); - } - - private runtimeResult tryAsInteger(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (int.TryParse(storedValue.ToString(), out int integer)) - return result.success(new integer(integer)); - return result.success(new nothing()); - } - - private runtimeResult tryAsFloat(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (float.TryParse(storedValue.ToString(), out float float_)) - return result.success(new @float(float_)); - return result.success(new nothing()); - } - - private runtimeResult asBoolean(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (bool.TryParse(storedValue.ToString(), out bool bool_)) - return result.success(new boolean(bool_)); - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Could not convert string to boolean", context)); - } - - private runtimeResult tryAsBoolean(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (bool.TryParse(storedValue.ToString(), out bool bool_)) - return result.success(new boolean(bool_)); - return result.success(new nothing()); - } - - private runtimeResult asCharList(context context, position[] positions) { return new runtimeResult().success(new character_list(storedValue)); } - private runtimeResult asBooleanValue(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - bool boolValue = isTrue(out error? error); - if (error != null) return result.failure(error); - return result.success(new boolean(boolValue)); - } - - private runtimeResult isNullOrEmpty(context context, position[] positions) { return new runtimeResult().success(new boolean(string.IsNullOrEmpty(storedValue))); } - private runtimeResult isNullOrSpaces(context context, position[] positions) { return new runtimeResult().success(new boolean(string.IsNullOrWhiteSpace(storedValue))); } - - public override bool isTrue(out error? error) { error = null; return storedValue.Length > 0; } - public override item copy() { return new @string(storedValue).setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $"\"{storedValue}\""; } - public string ToPureString() { return storedValue; } - } - - public class character_list : value - { - public character_list(string value) : base(value.ToCharArray().ToList()) { } - public character_list(List value) : base(value) { } - - public override item? addedTo(item other, out error? error) - { - error = null; - if (other is @string) - { - ((List)storedValue).AddRange(((@string)other).storedValue.ToString().ToCharArray()); - return new nothing().setContext(context); - } - else if (other is character_list) - { - ((List)storedValue).AddRange(((character_list)other).storedValue); - return new nothing().setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? subbedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be negative value", context); - return null; - } - else if (otherValue.storedValue >= storedValue.Count) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be greater than or equal to length of character_list", context); - return null; - } - - string removed = storedValue[(int)otherValue.storedValue].ToString(); - storedValue.RemoveAt((int)otherValue.storedValue); - return new @string(removed).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? multedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "CharacterList multiplication by negative value", context); - return null; - } - - char[] multedValues = new char[storedValue.Count * otherValue.storedValue]; - - for (int i = 0; i < otherValue.storedValue; i++) - storedValue.CopyTo(multedValues, storedValue.Count * i); - return new character_list(multedValues.ToList()).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? divedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue == 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Division by zero", context); - return null; - } - else if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "CharacterList division by negative value", context); - return null; - } - - char[] divedValues = new char[storedValue.Count / otherValue.storedValue]; - for (int i = 0; i < divedValues.Length; i++) - divedValues[i] = storedValue[i]; - - return new character_list(divedValues.ToList()).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? compareLessThanOrEqual(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be negative value", context); - return null; - } - else if (otherValue.storedValue >= storedValue.Count) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be greater than or equal to length of character_list", context); - return null; - } - - return new @string(storedValue[(int)otherValue.storedValue].ToString()).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? checkIn(item other, out error? error) - { - error = null; - if (other is @string) - return new boolean(((@string)other).storedValue.Contains(storedValue)).setContext(context); - else if (other is character_list) - return new boolean(string.Join("", ((character_list)other).storedValue).Contains(string.Join("", storedValue))).setContext(context); - return base.checkIn(other, out error); - } - - public override runtimeResult execute(item[] args) - { - base.execute(args); - - internalContext.symbolTable.set("length", new integer(((List)storedValue).Count)); - internalContext.symbolTable.set("slice", new predefined_function("character_list_slice", charListSlice, new string[2] { "start", "end" })); - internalContext.symbolTable.set("insert", new predefined_function("character_list_insert", charListInsert, new string[2] { "index", "value" })); - internalContext.symbolTable.set("set", new predefined_function("character_list_set", charListSet, new string[2] { "index", "value" })); - internalContext.symbolTable.set("remove", new predefined_function("character_list_remove", charListRemove, new string[1] { "value" })); - internalContext.symbolTable.set("as_integer", new predefined_function("character_list_as_integer", asInteger, new string[0] { })); - internalContext.symbolTable.set("as_float", new predefined_function("character_list_as_float", asFloat, new string[0] { })); - internalContext.symbolTable.set("try_as_integer", new predefined_function("character_list_try_as_integer", tryAsInteger, new string[0] { })); - internalContext.symbolTable.set("try_as_float", new predefined_function("character_list_try_as_float", tryAsFloat, new string[0] { })); - internalContext.symbolTable.set("as_boolean", new predefined_function("character_list_as_boolean", asBoolean, new string[0] { })); - internalContext.symbolTable.set("try_as_boolean", new predefined_function("character_list_try_as_boolean", tryAsBoolean, new string[0] { })); - internalContext.symbolTable.set("as_boolean_value", new predefined_function("character_list_as_boolean_value", asBooleanValue, new string[0] { })); - internalContext.symbolTable.set("as_string", new predefined_function("character_list_as_string", asString, new string[0] { })); - internalContext.symbolTable.set("is_null_or_empty", new predefined_function("character_list_is_null_or_empty", isNullOrEmpty, new string[0] { })); - internalContext.symbolTable.set("is_null_or_spaces", new predefined_function("character_list_is_null_or_spaces", isNullOrSpaces, new string[0] { })); - return new runtimeResult().success(this); - } - - private runtimeResult charListSlice(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item start = context.symbolTable.get("start"); - item end = context.symbolTable.get("end"); - - if (start is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Start must be an integer", context)); - else if (end is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "End must be an integer", context)); - - int startAsInt = ((integer)start).storedValue; - int endAsInt = ((integer)end).storedValue + 1; - - if (startAsInt < 0) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Start cannot be less than zero", context)); - else if (endAsInt > ((List)storedValue).Count) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "End cannot be greater than length of character_list", context)); - else if (startAsInt >= endAsInt - 1) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Start cannot be greater than or equal to end", context)); - - return result.success(new character_list(((List)storedValue).GetRange(startAsInt, endAsInt - startAsInt))); - } - - private runtimeResult charListInsert(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item index = context.symbolTable.get("index"); - item value = context.symbolTable.get("value"); - - if (index is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Index must be an integer", context)); - - int indexAsInt = ((integer)index).storedValue; - - if (indexAsInt < 0) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Index cannot be less than zero", context)); - else if (indexAsInt > ((List)storedValue).Count) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Index cannot be greater than length of character_list", context)); - - if (value is not @string && value is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Value must be a string or character_list", context)); - - char[] value_ = (value is @string) ? ((@string)value).storedValue.ToCharArray() : ((character_list)value).storedValue.ToArray(); - ((List)storedValue).InsertRange(indexAsInt, value_); - return result.success(new nothing()); - } - - private runtimeResult charListSet(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item index = context.symbolTable.get("index"); - item value = context.symbolTable.get("value"); - - if (index is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Index must be an integer", context)); - - int indexAsInt = ((integer)index).storedValue; - - if (indexAsInt < 0) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Index cannot be less than zero", context)); - else if (indexAsInt >= ((List)storedValue).Count) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Index cannot be greater than length of character_list", context)); - - if (value is not @string && value is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Value must be a string or character_list", context)); - - string value_ = (value is @string) ? ((@string)value).storedValue : string.Join("", ((character_list)value).storedValue); - if (value_.Length > 1 || value_.Length < 1) - return result.failure(new runtimeError(positions[0], positions[1], RT_LEN, "Value must be of length 1", context)); - - ((List)storedValue)[indexAsInt] = value_[0]; - return result.success(new nothing()); - } - - private runtimeResult charListRemove(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item value = context.symbolTable.get("value"); - - if (value is not @string && value is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Value must be a string or character_list", context)); - - string value_ = (value is @string) ? ((@string)value).storedValue : string.Join("", ((character_list)value).storedValue); - char[] chars = string.Join("", storedValue).Replace(value_, string.Empty).ToCharArray(); - storedValue.Clear(); - storedValue.AddRange(chars); - return result.success(new nothing()); - } - - private runtimeResult asInteger(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (int.TryParse(string.Join("", storedValue), out int integer)) - return result.success(new integer(integer)); - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Could not convert string to integer", context)); - } - - private runtimeResult asFloat(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (float.TryParse(string.Join("", storedValue), out float float_)) - return result.success(new @float(float_)); - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Could not convert string to float", context)); - } - - private runtimeResult tryAsInteger(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (int.TryParse(string.Join("", storedValue), out int integer)) - return result.success(new integer(integer)); - return result.success(new nothing()); - } - - private runtimeResult tryAsFloat(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (float.TryParse(string.Join("", storedValue), out float float_)) - return result.success(new @float(float_)); - return result.success(new nothing()); - } - - private runtimeResult asBoolean(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (bool.TryParse(string.Join("", storedValue), out bool bool_)) - return result.success(new boolean(bool_)); - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Could not convert string to boolean", context)); - } - - private runtimeResult tryAsBoolean(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (bool.TryParse(string.Join("", storedValue), out bool bool_)) - return result.success(new boolean(bool_)); - return result.success(new nothing()); - } - - private runtimeResult asString(context context, position[] positions) { return new runtimeResult().success(new @string(string.Join("", storedValue))); } - private runtimeResult asBooleanValue(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - bool boolValue = isTrue(out error? error); - if (error != null) return result.failure(error); - return result.success(new boolean(boolValue)); - } - - private runtimeResult isNullOrEmpty(context context, position[] positions) { return new runtimeResult().success(new boolean(string.IsNullOrEmpty(string.Join("", storedValue)))); } - private runtimeResult isNullOrSpaces(context context, position[] positions) { return new runtimeResult().success(new boolean(string.IsNullOrWhiteSpace(string.Join("", storedValue)))); } - - public override bool isTrue(out error? error) { error = null; return storedValue.Count > 0; } - public override item copy() { return new character_list(storedValue).setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $"'{string.Join("", storedValue)}'"; } - public string ToPureString() { return string.Join("", storedValue); } - public override bool ItemEquals(item obj, out error? error) { error = null; if (GetType() == obj.GetType()) return ToPureString() == ((character_list)obj).ToPureString(); return false; } - public override int GetItemHashCode(out error? error) { error = null; return ToPureString().GetHashCode(); } - } - - public class array : value - { - public array(item[] elements) : base(elements) { } - - public bool hasElement(item other, out error? error) - { - error = null; - for (int i = 0; i < storedValue.Length; i++) - { - if (storedValue[i].ItemEquals(other, out error)) return true; - if (error != null) return false; - } - return false; - } - - public override item? multedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Array multiplication by negative value", context); - return null; - } - - item[] multedValues = new item[storedValue.Length * (int)otherValue.storedValue]; - - for (int i = 0; i < (int)otherValue.storedValue; i++) - storedValue.CopyTo(multedValues, storedValue.Length * i); - return new array(multedValues).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? divedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue == 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Division by zero", context); - return null; - } - else if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Array division by negative value", context); - return null; - } - - item[] divedValues = new item[storedValue.Length / (int)otherValue.storedValue]; - for (int i = 0; i < divedValues.Length; i++) - divedValues[i] = storedValue[i]; - - return new array(divedValues).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? compareLessThanOrEqual(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be negative value", context); - return null; - } - else if (otherValue.storedValue >= storedValue.Length) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be greater than or equal to length of array", context); - return null; - } - - return storedValue[(int)otherValue.storedValue].setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override runtimeResult execute(item[] args) - { - base.execute(args); - - internalContext.symbolTable.set("length", new integer(((item[])storedValue).Length)); - internalContext.symbolTable.set("slice", new predefined_function("array_slice", arraySlice, new string[2] { "start", "end" })); - internalContext.symbolTable.set("as_boolean", new predefined_function("array_as_boolean", asBoolean, new string[0] { })); - internalContext.symbolTable.set("as_string", new predefined_function("array_as_string", asString, new string[0] { })); - internalContext.symbolTable.set("as_character_list", new predefined_function("array_as_character_list", asCharList, new string[0] { })); - return new runtimeResult().success(this); - } - - private runtimeResult arraySlice(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item start = context.symbolTable.get("start"); - item end = context.symbolTable.get("end"); - - if (start is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Start must be an integer", context)); - else if (end is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "End must be an integer", context)); - - int startAsInt = ((integer)start).storedValue; - int endAsInt = ((integer)end).storedValue + 1; - - if (startAsInt < 0) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Start cannot be less than zero", context)); - else if (endAsInt > ((item[])storedValue).Length) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "End cannot be greater than length of array", context)); - else if (startAsInt > endAsInt) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Start cannot be greater than end", context)); - - return result.success(new array(((item[])storedValue)[startAsInt..endAsInt])); - } - - private runtimeResult asBoolean(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - bool boolValue = isTrue(out error? error); - if (error != null) return result.failure(error); - return result.success(new boolean(boolValue)); - } - - private runtimeResult asString(context context, position[] positions) { return new runtimeResult().success(new @string(ToString())); } - private runtimeResult asCharList(context context, position[] positions) { return new runtimeResult().success(new character_list(ToString())); } - - public override bool isTrue(out error? error) { error = null; return storedValue.Length > 0; } - public override item copy() { return new array(storedValue).setPosition(startPos, endPos).setContext(context); } - - public override string ToString() - { - string[] elementStrings = new string[storedValue.Length]; - for (int i = 0; i < storedValue.Length; i++) - elementStrings[i] = storedValue[i].ToString(); - return $"({string.Join(", ", elementStrings)})"; - } - - public override int GetItemHashCode(out error? error) - { - error = null; - int hashCode = 0; - for (int i = 0; i < storedValue.Length; i++) - { - hashCode = (((hashCode << 5) + hashCode) ^ storedValue[i].GetItemHashCode(out error)); - if (error != null) return 0; - } - - return hashCode; - } - - public override bool ItemEquals(item obj, out error? error) - { - error = null; - if (obj is array) - { - int hash = GetItemHashCode(out error); - if (error != null) return false; - - int otherHash = ((array)obj).GetItemHashCode(out error); - if (error != null) return false; - - return hash == otherHash; - } - return false; - } - } - - public class list : value - { - public list(item[] elements) : base(elements.ToList()) { } - public list(List elements) : base(elements) { } - - public bool hasElement(item other, out error? error) - { - error = null; - for (int i = 0; i < storedValue.Count; i++) - { - if (storedValue[i].ItemEquals(other, out error)) return true; - if (error != null) return false; - } - return false; - } - - public override item? addedTo(item other, out error? error) - { - error = null; - if (other is list) - { - list otherAsArrayLike = (list)other; - storedValue.AddRange(otherAsArrayLike.storedValue); - return new nothing().setContext(context); - } - - storedValue.Add(other); - return new nothing().setContext(context); - } - - public override item? subbedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be negative value", context); - return null; - } - else if (otherValue.storedValue >= storedValue.Count) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be greater than or equal to length of list", context); - return null; - } - - item removedValue = storedValue[(int)otherValue.storedValue]; - storedValue.RemoveAt((int)otherValue.storedValue); - return removedValue.setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? multedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "List multiplication by negative value", context); - return null; - } - - item[] multedValues = new item[storedValue.Count * (int)otherValue.storedValue]; - - for (int i = 0; i < (int)otherValue.storedValue; i++) - storedValue.CopyTo(multedValues, storedValue.Count * i); - return new list(multedValues).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? divedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue == 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Division by zero", context); - return null; - } - else if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "List division by negative value", context); - return null; - } - - item[] divedValues = new item[storedValue.Count / (int)otherValue.storedValue]; - for (int i = 0; i < divedValues.Length; i++) - divedValues[i] = storedValue[i]; - - return new list(divedValues).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? compareLessThanOrEqual(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be negative value", context); - return null; - } - else if (otherValue.storedValue >= storedValue.Count) - { - error = new runtimeError(other.startPos, other.endPos, RT_INDEX, "Index cannot be greater than or equal to length of list", context); - return null; - } - - return storedValue[(int)otherValue.storedValue].setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override runtimeResult execute(item[] args) - { - base.execute(args); - - internalContext.symbolTable.set("length", new integer(((List)storedValue).Count)); - internalContext.symbolTable.set("slice", new predefined_function("list_slice", listSlice, new string[2] { "start", "end" })); - internalContext.symbolTable.set("insert", new predefined_function("list_insert", listInsert, new string[2] { "index", "value" })); - internalContext.symbolTable.set("set", new predefined_function("list_set", listSet, new string[2] { "index", "value" })); - internalContext.symbolTable.set("remove", new predefined_function("list_remove", listRemove, new string[1] { "value" })); - internalContext.symbolTable.set("as_boolean", new predefined_function("list_as_boolean", asBoolean, new string[0] { })); - internalContext.symbolTable.set("as_string", new predefined_function("list_as_string", asString, new string[0] { })); - internalContext.symbolTable.set("as_character_list", new predefined_function("list_as_character_list", asCharList, new string[0] { })); - return new runtimeResult().success(this); - } - - private runtimeResult listSlice(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item start = context.symbolTable.get("start"); - item end = context.symbolTable.get("end"); - - if (start is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Start must be an integer", context)); - else if (end is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "End must be an integer", context)); - - int startAsInt = ((integer)start).storedValue; - int endAsInt = ((integer)end).storedValue + 1; - - if (startAsInt < 0) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Start cannot be less than zero", context)); - else if (endAsInt > ((List)storedValue).Count) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "End cannot be greater than length of list", context)); - else if (startAsInt >= endAsInt - 1) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Start cannot be greater than or equal to end", context)); - - return result.success(new list(((List)storedValue).GetRange(startAsInt, endAsInt - startAsInt))); - } - - private runtimeResult listInsert(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item index = context.symbolTable.get("index"); - item value = context.symbolTable.get("value"); - - if (index is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Index must be an integer", context)); - - int indexAsInt = ((integer)index).storedValue; - - if (indexAsInt < 0) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Index cannot be less than zero", context)); - else if (indexAsInt > ((List)storedValue).Count) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Index cannot be greater than length of list", context)); - - ((List)storedValue).Insert(indexAsInt, value); - return result.success(new nothing()); - } - - private runtimeResult listSet(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item index = context.symbolTable.get("index"); - item value = context.symbolTable.get("value"); - - if (index is not integer) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Index must be an integer", context)); - - int indexAsInt = ((integer)index).storedValue; - - if (indexAsInt < 0) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Index cannot be less than zero", context)); - else if (indexAsInt >= ((List)storedValue).Count) - return result.failure(new runtimeError(positions[0], positions[1], RT_INDEX, "Index cannot be greater than length of list", context)); - - ((List)storedValue)[indexAsInt] = value; - return result.success(new nothing()); - } - - private runtimeResult listRemove(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item value = context.symbolTable.get("value"); - - if (!((List)storedValue).Contains(value)) - return result.failure(new runtimeError(positions[0], positions[1], RT_KEY, "List does not contain value", context)); - - ((List)storedValue).Remove(value); - return result.success(new nothing()); - } - - private runtimeResult asBoolean(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - bool boolValue = isTrue(out error? error); - if (error != null) return result.failure(error); - return result.success(new boolean(boolValue)); - } - - private runtimeResult asString(context context, position[] positions) { return new runtimeResult().success(new @string(ToString())); } - private runtimeResult asCharList(context context, position[] positions) { return new runtimeResult().success(new character_list(ToString())); } - - public override bool isTrue(out error? error) { error = null; return storedValue.Count > 0; } - public override item copy() { return new list(storedValue).setPosition(startPos, endPos).setContext(context); } - - public override string ToString() - { - string[] elementStrings = new string[storedValue.Count]; - for (int i = 0; i < storedValue.Count; i++) - elementStrings[i] = storedValue[i].ToString(); - return $"[{string.Join(", ", elementStrings)}]"; - } - public override int GetItemHashCode(out error? error) - { - error = null; - int hashCode = 0; - for (int i = 0; i < storedValue.Count; i++) - { - hashCode = (((hashCode << 5) + hashCode) ^ storedValue[i].GetItemHashCode(out error)); - if (error != null) return 0; - } - - return hashCode; - } - public override bool ItemEquals(item obj, out error? error) - { - error = null; - if (obj is list) - { - int hash = GetItemHashCode(out error); - if (error != null) return false; - - int otherHash = ((list)obj).GetItemHashCode(out error); - if (error != null) return false; - - return hash == otherHash; - } - return false; - } - } - - public class dictionary : value - { - public dictionary(ItemDictionary dictionary) : base(dictionary) { } - - public override item? addedTo(item other, out error? error) - { - error = null; - if (other is dictionary) - { - KeyValuePair[] otherValue = ((dictionary)other).storedValue.GetArray(); - for (int i = 0; i < otherValue.Length; i++) - { - storedValue.Add(otherValue[i].Key, otherValue[i].Value, out error); - if (error != null) return null; - } - - return new nothing().setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? subbedBy(item other, out error? error) - { - error = null; - - bool containsKey = storedValue.ContainsKey(other, out error); - if (error != null) return null; - - if (containsKey) - { - storedValue.Remove(other, out error); - return new nothing().setContext(context); - } - - error = new runtimeError(other.startPos, other.endPos, RT_KEY, "Key does not correspond to any value in dictionary", context); - return null; - } - - public override item? divedBy(item other, out error? error) - { - error = null; - if (other is integer || other is @float) - { - value otherValue = (value)other; - if (otherValue.storedValue == 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Division by zero", context); - return null; - } - else if (otherValue.storedValue < 0) - { - error = new runtimeError(other.startPos, other.endPos, RT_MATH, "Dictionary division by negative value", context); - return null; - } - - KeyValuePair[] pairs = ((ItemDictionary)storedValue).GetArray(); - ItemDictionary newDict = new ItemDictionary(); - - for (int i = 0; i < pairs.Length / (int)otherValue.storedValue; i++) - { - newDict.Add(pairs[i].Key, pairs[i].Value, out error); - if (error != null) return null; - } - - return new dictionary(newDict).setContext(context); - } - - error = illegalOperation(other); - return null; - } - - public override item? compareLessThanOrEqual(item other, out error? error) - { - error = null; - - item? value = storedValue.GetValue(other, out error); - if (error != null) return null; - - if (value != null) - return value.setContext(context); - else - { - error = new runtimeError(other.startPos, other.endPos, RT_KEY, "Key does not correspond to any value in dictionary", context); - return null; - } - } - public override runtimeResult execute(item[] args) - { - base.execute(args); - - KeyValuePair[] pairs = storedValue.GetArray(); - item[] keys = new item[pairs.Length]; - item[] values = new item[pairs.Length]; - item[] keyValuePairs = new item[pairs.Length]; - - for (int i = 0; i < pairs.Length; i++) - { - keys[i] = pairs[i].Key; - values[i] = pairs[i].Value; - keyValuePairs[i] = new array(new item[2] { pairs[i].Key, pairs[i].Value }).setPosition(startPos, endPos).setContext(context); - } - - internalContext.symbolTable.set("length", new integer(pairs.Length)); - internalContext.symbolTable.set("keys", new array(keys)); - internalContext.symbolTable.set("values", new array(values)); - internalContext.symbolTable.set("pairs", new array(keyValuePairs)); - internalContext.symbolTable.set("as_boolean", new predefined_function("dictionary_as_boolean", asBoolean, new string[0] { })); - internalContext.symbolTable.set("as_string", new predefined_function("dictionary_as_string", asString, new string[0] { })); - internalContext.symbolTable.set("as_character_list", new predefined_function("dictionary_as_character_list", asCharList, new string[0] { })); - return new runtimeResult().success(this); - } - - private runtimeResult asBoolean(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - bool boolValue = isTrue(out error? error); - if (error != null) return result.failure(error); - return result.success(new boolean(boolValue)); - } - - private runtimeResult asString(context context, position[] positions) { return new runtimeResult().success(new @string(ToString())); } - private runtimeResult asCharList(context context, position[] positions) { return new runtimeResult().success(new character_list(ToString())); } - - public override bool isTrue(out error? error) { error = null; return storedValue.Count > 0; } - public override item copy() { return new dictionary(storedValue).setPosition(startPos, endPos).setContext(context); } - - public override string ToString() - { - KeyValuePair[] values = storedValue.GetArray(); - string[] elementStrings = new string[values.Length]; - - for (int i = 0; i < values.Length; i++) - elementStrings[i] = $"{values[i].Key} : {values[i].Value}"; - return '{' + string.Join(", ", elementStrings) + '}'; - } - - public override int GetItemHashCode(out error? error) - { - error = null; - int hashCode = 0; - KeyValuePair[] pairs = storedValue.GetArray(); - for (int i = 0; i < pairs.Length; i++) - { - int keyHash = pairs[i].Key.GetItemHashCode(out error); - if (error != null) return 0; - - int valueHash = pairs[i].Value.GetItemHashCode(out error); - if (error != null) return 0; - - int hash1 = ((keyHash << 5) + keyHash) ^ valueHash; - hashCode = ((hashCode << 5) + hashCode) ^ hash1; - } - return hashCode; - } - public override bool ItemEquals(item obj, out error? error) - { - error = null; - if (obj is dictionary) - { - int hash = GetItemHashCode(out error); - if (error != null) return false; - - int otherHash = ((dictionary)obj).GetItemHashCode(out error); - if (error != null) return false; - - return hash == otherHash; - } - return false; - } - } - - public abstract class baseFunction : item - { - public string name; - public baseFunction(string name) : base() - { this.name = name; } - - public context generateContext() - { - context newContext = new context(name, context, startPos, false); - newContext.symbolTable = new symbolTable(newContext.parent.symbolTable); - return newContext; - } - - public runtimeResult checkArgs(string[] argNames, item[] args) - { - runtimeResult result = new runtimeResult(); - if (args.Length > argNames.Length) - return result.failure(new runtimeError(startPos, endPos, RT_ARGS, $"{args.Length - argNames.Length} too many arguments passed into \"{name}\"", context)); - else if (args.Length < argNames.Length) - return result.failure(new runtimeError(startPos, endPos, RT_ARGS, $"{argNames.Length - args.Length} too few arguments passed into \"{name}\"", context)); - - return result.success(new nothing()); - } - - public void populateArgs(string[] argNames, item[] args, context context) - { - for (int i = 0; i < args.Length; i++) - { - string argName = argNames[i]; - item argValue = args[i]; - - argValue.setContext(context); - context.symbolTable.set(argName, argValue); - } - } - - public runtimeResult checkAndPopulateArgs(string[] argNames, item[] args, context context) - { - runtimeResult result = new runtimeResult(); - item returnValue = result.register(checkArgs(argNames, args)); - if (result.shouldReturn()) return result; - populateArgs(argNames, args, context); - return result.success(returnValue); - } - - public override bool isTrue(out error? error) { error = null; return true; } - - public override int GetItemHashCode(out error? error) { error = null; return ToString().GetHashCode(); } - } - - public class predefined_function : baseFunction - { - private string[] argNames; - private Func function; - - public predefined_function(string name, Func function, string[] argNames) : base(name) - { - this.function = function; - this.argNames = argNames; - } - - public override runtimeResult execute(item[] args) - { - runtimeResult result = new runtimeResult(); - context newContext = generateContext(); - - result.register(checkAndPopulateArgs(argNames, args, newContext)); - if (result.shouldReturn()) return result; - - item returnValue = result.register(function.Invoke(newContext, new position[2] { startPos, endPos })); - if (result.shouldReturn()) return result; - - return result.success(returnValue); - } - - public override item copy() { return new predefined_function(name, function, argNames).setPosition(startPos, endPos).setContext(context); } - - public override bool ItemEquals(item obj, out error? error) { error = null; if (obj is predefined_function) return ToString() == obj.ToString(); return false; } - public override string ToString() { return $">"; } - } - - public class builtin_function : baseFunction - { - private string[] argNames; - public builtin_function(string name, string[] argNames) : base(name) - { this.argNames = argNames; } - - public override runtimeResult execute(item[] args) - { - runtimeResult result = new runtimeResult(); - context newContext = generateContext(); - - string methodName = $"_{name}"; - MethodInfo? info = GetType().GetMethod(methodName, (BindingFlags.NonPublic | BindingFlags.Instance)); - if (info != null) - { - result.register(checkAndPopulateArgs(argNames, args, newContext)); - if (result.shouldReturn()) return result; - - item returnValue = result.register((runtimeResult)info.Invoke(this, new object[] { newContext })); - if (result.shouldReturn()) return result; - return result.success(returnValue.setPosition(startPos, endPos).setContext(newContext)); - } - throw new Exception($"No {methodName} method defined!"); - } - - private runtimeResult _show(context context) - { - item value = context.symbolTable.get("message"); - if (value is @string) - Console.WriteLine(((@string)value).ToPureString()); - else if (value is character_list) - Console.WriteLine(((character_list)value).ToPureString()); - else - Console.WriteLine(value.ToString()); - - return new runtimeResult().success(new nothing()); - } - - private runtimeResult _simple_show(context context) - { - item value = context.symbolTable.get("message"); - if (value is @string) - Console.Write(((@string)value).ToPureString()); - else if (value is character_list) - Console.Write(((character_list)value).ToPureString()); - else - Console.Write(value.ToString()); - - return new runtimeResult().success(new nothing()); - } - - private runtimeResult _show_error(context context) - { - runtimeResult result = new runtimeResult(); - - item tag = context.symbolTable.get("tag"); - item message = context.symbolTable.get("message"); - - if (tag is not @string && tag is not character_list) - return result.failure(new runtimeError(startPos, endPos, RT_TYPE, "Tag must be a string or character_list", context)); - if (message is not @string && message is not character_list) - return result.failure(new runtimeError(startPos, endPos, RT_TYPE, "Message must be a string or character_list", context)); - - string msg = (message is @string) ? ((@string)message).ToPureString() : ((character_list)message).ToPureString(); - string tg = (tag is @string) ? ((@string)tag).ToPureString() : ((character_list)tag).ToPureString(); - - return new runtimeResult().failure(new runtimeError(startPos, endPos, tg, msg, context)); - } - - private runtimeResult _get(context context) - { - item message = context.symbolTable.get("message"); - if (message is not nothing) - { - if (message is @string) - Console.Write(((@string)message).ToPureString()); - else if (message is character_list) - Console.Write(((character_list)message).ToPureString()); - else - Console.Write(message.ToString()); - } - - string? input = Console.ReadLine(); - return new runtimeResult().success(new @string(input == null ? "" : input)); - } - - private runtimeResult _clear(context context) - { - if (OperatingSystem.IsLinux()) - Extras.system("clear"); - else - Console.Clear(); - - return new runtimeResult().success(new nothing()); - } - - private runtimeResult _hash(context context) - { - runtimeResult result = new runtimeResult(); - - int hash = context.symbolTable.get("value").GetItemHashCode(out error? error); - if (error != null) return result.failure(error); - - return result.success(new integer(hash)); - } - - private runtimeResult _type_of(context context) - { - item value = context.symbolTable.get("value"); - - string type; - if (value is @object) - type = ((@object)value).name; - else - type = value.GetType().Name; - - return new runtimeResult().success(new @string(type)); - } - - private runtimeResult _run(context context) - { - runtimeResult result = new runtimeResult(); - item file = context.symbolTable.get("file"); - if (file is not @string && file is not character_list) - return result.failure(new runtimeError(startPos, endPos, RT_TYPE, "File must be a string or character_list", context)); - - string path = (file is @string) ? ((@string)file).storedValue : string.Join("", ((character_list)file).storedValue); - if (!File.Exists(path)) - return result.failure(new runtimeError(startPos, endPos, RT_IO, $"Script \"{path}\" does not exist", context)); - - string script; - try - { - script = string.Join('\n', File.ReadAllLines(path)); - } - catch (IOException exception) - { - return result.failure(new runtimeError(startPos, endPos, RT_IO, $"Failed to load script \"{path}\"\n{exception.Message}", context)); - } - - context runtimeContext = new context("
", globalPredefinedContext, new position(0, 0, 0, "
", ""), false); - runtimeContext.symbolTable = new symbolTable(globalPredefinedContext.symbolTable); - - error? error = easyRun(Path.GetFileName(path), script, runtimeContext, out item? _); - if (error != null) - return result.failure(new runtimeRunError(startPos, endPos, $"Failed to execute script \"{path}\"", error.asString(), context)); - return result.success(new nothing()); - } - - public override item copy() { return new builtin_function(name, argNames).setPosition(startPos, endPos).setContext(context); } - - public override bool ItemEquals(item obj, out error? error) { error = null; if (obj is builtin_function) return ToString() == obj.ToString(); return false; } - public override string ToString() { return $">"; } - } - - public class function : baseFunction - { - private node bodyNode; - private string[] argNames; - private bool shouldReturnNull; - private interpreter interpreter; - - public function(string? name, node bodyNode, string[] argNames, bool shouldReturnNull) : base((name != null) ? name : "") - { - this.bodyNode = bodyNode; - this.argNames = argNames; - this.shouldReturnNull = shouldReturnNull; - this.interpreter = new interpreter(); - } - - public override runtimeResult? execute(item[] args) - { - runtimeResult result = new runtimeResult(); - context newContext = generateContext(); - - result.register(checkAndPopulateArgs(argNames, args, newContext)); - if (result.shouldReturn()) return result; - - item? value = result.register(interpreter.visit(bodyNode, newContext)); - if (result.shouldReturn() && result.functionReturnValue == null) return result; - - if (!shouldReturnNull && value != null) - return result.success(value); - else if (result.functionReturnValue != null) - return result.success(result.functionReturnValue); - return result.success(new nothing()); - } - - public override item copy() { return new function(name, bodyNode, argNames, shouldReturnNull).setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; if (obj is function) return ToString() == obj.ToString(); return false; } - } - - public class special : baseFunction - { - private node bodyNode; - private string[] argNames; - private bool shouldReturnNull; - private interpreter interpreter; - - public special(string name, node bodyNode, string[] argNames, bool shouldReturnNull) : base(name) - { - this.bodyNode = bodyNode; - this.argNames = argNames; - this.shouldReturnNull = shouldReturnNull; - this.interpreter = new interpreter(); - } - - public override runtimeResult? execute(item[] args) - { - runtimeResult result = new runtimeResult(); - context newContext = generateContext(); - - result.register(checkAndPopulateArgs(argNames, args, newContext)); - if (result.shouldReturn()) return result; - - item? value = result.register(interpreter.visit(bodyNode, newContext)); - if (result.shouldReturn() && result.functionReturnValue == null) return result; - - if (!shouldReturnNull && value != null) - return result.success(value); - else if (result.functionReturnValue != null) - return result.success(result.functionReturnValue); - return result.success(new nothing()); - } - - public override item copy() { return new special(name, bodyNode, argNames, shouldReturnNull).setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; if (obj is special) return ToString() == obj.ToString(); return false; } - } - - public class @class : baseFunction - { - public string[] argNames { get; private set; } - private node bodyNode; - private @class? parent; - - public @class(string name, @class? inherit, node bodyNode, string[] argNames) : base(name) - { - this.bodyNode = bodyNode; - this.argNames = argNames; - this.parent = inherit; - } - - public override runtimeResult execute(item[] args) - { - runtimeResult result = new runtimeResult(); - context internalContext = generateContext(); - - result.register(checkAndPopulateArgs(argNames, args, internalContext)); - if (result.shouldReturn()) return result; - - if (parent != null) - { - item[] parentArgs = new item[parent.argNames.Length]; - for (int i = 0; i < parentArgs.Length; i++) - parentArgs[i] = args[Array.IndexOf(argNames, parent.argNames[i])]; - - item parentObject = result.register(parent.execute(parentArgs)); - if (result.shouldReturn()) return result; - - internalContext.symbolTable.set("parent", parentObject); - } - - @object object_ = (@object)new @object(name, internalContext).setPosition(startPos, endPos).setContext(context); - result.register(object_.initialize(bodyNode)); - if (result.shouldReturn()) return result; - - return result.success(object_); - } - - public override item copy() { return new @class(name, parent, bodyNode, argNames).setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; if (obj is @class) return ToString() == obj.ToString(); return false; } - } - - public class @object : baseFunction - { - public context internalContext { get; private set; } - private interpreter interpreter; - - public @object(string name, context internalContext) : base(name) - { - this.internalContext = internalContext; - this.interpreter = new interpreter(); - } - - public runtimeResult initialize(node body) - { - runtimeResult result = new runtimeResult(); - internalContext.symbolTable.set("this", this); - - result.register(interpreter.visit(body, internalContext)); - if (result.shouldReturn()) return result; - - return result.success(new nothing()); - } - - public override item setContext(context? context) - { - base.setContext(context); - internalContext.parent = context; - internalContext.symbolTable.parent = context.symbolTable; - return this; - } - - private item? getOutput(item func, item[] args, out error? error) - { - error = null; - - runtimeResult result = new runtimeResult(); - item output = result.register(func.execute(args)); - if (result.shouldReturn() && result.error == null) return new nothing().setContext(context); - - if (result.error != null) - { - error = result.error; - return null; - } - return output; - } - - public override item? compareEqual(item other, out error? error) - { - item? func = internalContext.symbolTable.get("compare_equal"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.compareEqual(other, out error); - } - - public override item? compareNotEqual(item other, out error? error) - { - item? func = internalContext.symbolTable.get("compare_not_equal"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.compareNotEqual(other, out error); - } - - public override item? compareAnd(item other, out error? error) - { - item? func = internalContext.symbolTable.get("compare_and"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.compareAnd(other, out error); - } - - public override item? compareOr(item other, out error? error) - { - item? func = internalContext.symbolTable.get("compare_or"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.compareOr(other, out error); - } - - public override item? checkIn(item other, out error? error) - { - item? func = internalContext.symbolTable.get("check_in"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.checkIn(other, out error); - } - - public override item? bitwiseOrdTo(item other, out error? error) - { - item? func = internalContext.symbolTable.get("bitwise_or"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.bitwiseOrdTo(other, out error); - } - - public override item? bitwiseXOrdTo(item other, out error? error) - { - item? func = internalContext.symbolTable.get("bitwise_xor"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.bitwiseXOrdTo(other, out error); - } - - public override item? bitwiseAndedTo(item other, out error? error) - { - item? func = internalContext.symbolTable.get("bitwise_and"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.bitwiseAndedTo(other, out error); - } - - public override item? bitwiseLeftShiftedTo(item other, out error? error) - { - item? func = internalContext.symbolTable.get("bitwise_left_shift"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.bitwiseLeftShiftedTo(other, out error); - } - - public override item? bitwiseRightShiftedTo(item other, out error? error) - { - item? func = internalContext.symbolTable.get("bitwise_right_shift"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.bitwiseRightShiftedTo(other, out error); - } - - public override item? bitwiseNotted(out error? error) - { - item? func = internalContext.symbolTable.get("bitwise_not"); - if (func != null && func is special) - return getOutput(func, new item[0], out error); - - return base.bitwiseNotted(out error); - } - - public override item? addedTo(item other, out error? error) - { - item? func = internalContext.symbolTable.get("addition"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.addedTo(other, out error); - } - - public override item? subbedBy(item other, out error? error) - { - item? func = internalContext.symbolTable.get("subtraction"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.subbedBy(other, out error); - } - - public override item? multedBy(item other, out error? error) - { - item? func = internalContext.symbolTable.get("multiplication"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.multedBy(other, out error); - } - - public override item? divedBy(item other, out error? error) - { - item? func = internalContext.symbolTable.get("division"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.divedBy(other, out error); - } - - public override item? modedBy(item other, out error? error) - { - item? func = internalContext.symbolTable.get("modulo"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.modedBy(other, out error); - } - - public override item? powedBy(item other, out error? error) - { - item? func = internalContext.symbolTable.get("power"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.powedBy(other, out error); - } - - public override item? compareLessThan(item other, out error? error) - { - item? func = internalContext.symbolTable.get("compare_less_than"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.compareLessThan(other, out error); - } - - public override item? compareGreaterThan(item other, out error? error) - { - item? func = internalContext.symbolTable.get("compare_greater_than"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.compareGreaterThan(other, out error); - } - - public override item? compareLessThanOrEqual(item other, out error? error) - { - item? func = internalContext.symbolTable.get("compare_less_than_or_equal"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.compareLessThanOrEqual(other, out error); - } - - public override item? compareGreaterThanOrEqual(item other, out error? error) - { - item? func = internalContext.symbolTable.get("compare_greater_than_or_equal"); - if (func != null && func is special) - return getOutput(func, new item[] { other }, out error); - - return base.compareGreaterThanOrEqual(other, out error); - } - - public override item? invert(out error? error) - { - item? func = internalContext.symbolTable.get("invert"); - if (func != null && func is special) - return getOutput(func, new item[0], out error); - - return base.invert(out error); - } - - public override bool isTrue(out error? error) - { - item? func = internalContext.symbolTable.get("is_true"); - if (func != null && func is special) - { - item? output = getOutput(func, new item[0], out error); - if (error != null) return false; - return output.isTrue(out error); - } - - return base.isTrue(out error); - } - - public override int GetItemHashCode(out error? error) - { - error = null; - item? func = internalContext.symbolTable.get("hash"); - if (func != null && func is special) - { - item? output = getOutput(func, new item[0], out error); - if (error != null) return 0; - - if (output is not integer) - { - error = new runtimeError(startPos, endPos, RT_TYPE, "Return type of special function \"hash\" must be an integer", context); - return 0; - } - - return ((integer)output).storedValue; - } - - return base.GetItemHashCode(out error); - } - - public override runtimeResult get(node node) - { - runtimeResult result = new runtimeResult(); - - item value = result.register(interpreter.visit(node, internalContext)); - if (result.shouldReturn()) return result; - return result.success(value); - } - - public override runtimeResult set(string name, item variable) - { - internalContext.symbolTable.set(name, variable.copy()); - return new runtimeResult().success(variable); - } - - public override item copy() { return new @object(name, internalContext).setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) - { - error = null; - - item? func = internalContext.symbolTable.get("equals"); - if (func != null && func is special) - { - item? output = getOutput(func, new item[1] { obj }, out error); - if (error != null) return false; - return output.isTrue(out error); - } - else if (obj is @object) - { - int hash = GetItemHashCode(out error); - if (error != null) return false; - - int otherHash = ((@object)obj).GetItemHashCode(out error); - if (error != null) return false; - - return hash == otherHash; - } - return false; - } - } -} \ No newline at end of file diff --git a/Constants.cs b/Constants.cs deleted file mode 100644 index f4e20ad..0000000 --- a/Constants.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Collections.Generic; - -namespace ezrSquared.Constants -{ - public static class constants - { - public const string VERSION = "prerelease-1.5.1.3.0"; - public const string VERSION_DATE = "03.05.2023"; - - public static readonly string[] KEYWORDS = { "item", "and", "or", "invert", "if", "else", "do", "count", "from", "as", "to", "step", "while", "function", "special", "with", "end", "return", "skip", "stop", "try", "error", "in", "object", "global", "include", "all" }; - public static readonly string[] QEYWORDS = { "f", "l", "e", "c", "t", "n", "w", "fd", "sd", "od", "i", "s", "d", "g", "v" }; - - public const string LETTERS_UNDERSCORE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"; - public const string ALPHANUM_UNDERSCORE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; - public const string DIGITS = "0123456789"; - public const string DIGITS_PERIOD = "0123456789."; - - public static readonly Dictionary SPECIALS = new Dictionary() - { - { "compare_equal", new string[1] { "other" } }, - { "compare_not_equal", new string[1] { "other" } }, - { "compare_less_than", new string[1] { "other" } }, - { "compare_greater_than", new string[1] { "other" } }, - { "compare_less_than_or_equal", new string[1] { "other" } }, - { "compare_greater_than_or_equal", new string[1] { "other" } }, - { "compare_and", new string[1] { "other" } }, - { "compare_or", new string[1] { "other" } }, - - { "bitwise_or", new string[1] { "other" } }, - { "bitwise_xor", new string[1] { "other" } }, - { "bitwise_and", new string[1] { "other" } }, - { "bitwise_left_shift", new string[1] { "other" } }, - { "bitwise_right_shift", new string[1] { "other" } }, - { "bitwise_not", new string[0] }, - - { "addition", new string[1] { "other" } }, - { "subtraction", new string[1] { "other" } }, - { "multiplication", new string[1] { "other" } }, - { "division", new string[1] { "other" } }, - { "modulo", new string[1] { "other" } }, - { "power", new string[1] { "other" } }, - - { "invert", new string[0] }, - { "check_in", new string[1] { "other" } }, - - { "equals", new string[1] { "other" } }, - { "is_true", new string[0] }, - { "hash", new string[0] }, - }; - - public const string RT_DEFAULT = "any"; - public const string RT_OVERFLOW = "overflow-error"; - public const string RT_ILLEGALOP = "operation-error"; - public const string RT_UNDEFINED = "undefined-error"; - public const string RT_KEY = "key-error"; - public const string RT_INDEX = "index-error"; - public const string RT_ARGS = "arguments-error"; - public const string RT_TYPE = "type-error"; - public const string RT_MATH = "math-error"; - public const string RT_LEN = "length-error"; - public const string RT_RUN = "run-error"; - public const string RT_IO = "io-error"; - } -} \ No newline at end of file diff --git a/Libraries/io/IO.cs b/Libraries/io/IO.cs deleted file mode 100644 index c0325fe..0000000 --- a/Libraries/io/IO.cs +++ /dev/null @@ -1,1518 +0,0 @@ -using ezrSquared.Values; -using ezrSquared.Helpers; -using ezrSquared.Errors; -using ezrSquared.General; -using static ezrSquared.Constants.constants; -using System.Collections.Generic; -using System.IO; -using System; - -namespace ezrSquared.Libraries.IO -{ - public class console : baseFunction - { - public override bool UPDATEONACCESS => true; - - private Dictionary stringToKeyLookup = new Dictionary() - { - { "Backspace", ConsoleKey.Backspace }, - { "Tab", ConsoleKey.Tab }, - { "Clear", ConsoleKey.Clear }, - { "Enter", ConsoleKey.Enter }, - { "Pause", ConsoleKey.Pause }, - { "Escape", ConsoleKey.Escape }, - { "Spacebar", ConsoleKey.Spacebar }, - { "PageUp", ConsoleKey.PageUp }, - { "PageDown", ConsoleKey.PageDown }, - { "End", ConsoleKey.End }, - { "Home", ConsoleKey.Home }, - { "LeftArrow", ConsoleKey.LeftArrow }, - { "UpArrow", ConsoleKey.UpArrow }, - { "RightArrow", ConsoleKey.RightArrow }, - { "DownArrow", ConsoleKey.DownArrow }, - { "Select", ConsoleKey.Select }, - { "Print", ConsoleKey.Print }, - { "Execute", ConsoleKey.Execute }, - { "PrintScreen", ConsoleKey.PrintScreen }, - { "Insert", ConsoleKey.Insert }, - { "Delete", ConsoleKey.Delete }, - { "Help", ConsoleKey.Help }, - { "D0", ConsoleKey.D0 }, - { "D1", ConsoleKey.D1 }, - { "D2", ConsoleKey.D2 }, - { "D3", ConsoleKey.D3 }, - { "D4", ConsoleKey.D4 }, - { "D5", ConsoleKey.D5 }, - { "D6", ConsoleKey.D6 }, - { "D7", ConsoleKey.D7 }, - { "D8", ConsoleKey.D8 }, - { "D9", ConsoleKey.D9 }, - { "A", ConsoleKey.A }, - { "B", ConsoleKey.B }, - { "C", ConsoleKey.C }, - { "D", ConsoleKey.D }, - { "E", ConsoleKey.E }, - { "F", ConsoleKey.F }, - { "G", ConsoleKey.G }, - { "H", ConsoleKey.H }, - { "I", ConsoleKey.I }, - { "J", ConsoleKey.J }, - { "K", ConsoleKey.K }, - { "L", ConsoleKey.L }, - { "M", ConsoleKey.M }, - { "N", ConsoleKey.N }, - { "O", ConsoleKey.O }, - { "P", ConsoleKey.P }, - { "Q", ConsoleKey.Q }, - { "R", ConsoleKey.R }, - { "S", ConsoleKey.S }, - { "T", ConsoleKey.T }, - { "U", ConsoleKey.U }, - { "V", ConsoleKey.V }, - { "W", ConsoleKey.W }, - { "X", ConsoleKey.X }, - { "Y", ConsoleKey.Y }, - { "Z", ConsoleKey.Z }, - { "LeftWindows", ConsoleKey.LeftWindows }, - { "RightWindows", ConsoleKey.RightWindows }, - { "Applications", ConsoleKey.Applications }, - { "Sleep", ConsoleKey.Sleep }, - { "NumPad0", ConsoleKey.NumPad0 }, - { "NumPad1", ConsoleKey.NumPad1 }, - { "NumPad2", ConsoleKey.NumPad2 }, - { "NumPad3", ConsoleKey.NumPad3 }, - { "NumPad4", ConsoleKey.NumPad4 }, - { "NumPad5", ConsoleKey.NumPad5 }, - { "NumPad6", ConsoleKey.NumPad6 }, - { "NumPad7", ConsoleKey.NumPad7 }, - { "NumPad8", ConsoleKey.NumPad8 }, - { "NumPad9", ConsoleKey.NumPad9 }, - { "Multiply", ConsoleKey.Multiply }, - { "Add", ConsoleKey.Add }, - { "Separator", ConsoleKey.Separator }, - { "Subtract", ConsoleKey.Subtract }, - { "Decimal", ConsoleKey.Decimal }, - { "Divide", ConsoleKey.Divide }, - { "F1", ConsoleKey.F1 }, - { "F2", ConsoleKey.F2 }, - { "F3", ConsoleKey.F3 }, - { "F4", ConsoleKey.F4 }, - { "F5", ConsoleKey.F5 }, - { "F6", ConsoleKey.F6 }, - { "F7", ConsoleKey.F7 }, - { "F8", ConsoleKey.F8 }, - { "F9", ConsoleKey.F9 }, - { "F10", ConsoleKey.F10 }, - { "F11", ConsoleKey.F11 }, - { "F12", ConsoleKey.F12 }, - { "F13", ConsoleKey.F13 }, - { "F14", ConsoleKey.F14 }, - { "F15", ConsoleKey.F15 }, - { "F16", ConsoleKey.F16 }, - { "F17", ConsoleKey.F17 }, - { "F18", ConsoleKey.F18 }, - { "F19", ConsoleKey.F19 }, - { "F20", ConsoleKey.F20 }, - { "F21", ConsoleKey.F21 }, - { "F22", ConsoleKey.F22 }, - { "F23", ConsoleKey.F23 }, - { "F24", ConsoleKey.F24 }, - { "BrowserBack", ConsoleKey.BrowserBack }, - { "BrowserForward", ConsoleKey.BrowserForward }, - { "BrowserRefresh", ConsoleKey.BrowserRefresh }, - { "BrowserStop", ConsoleKey.BrowserStop }, - { "BrowserSearch", ConsoleKey.BrowserSearch }, - { "BrowserFavorites", ConsoleKey.BrowserFavorites }, - { "BrowserHome", ConsoleKey.BrowserHome }, - { "VolumeMute", ConsoleKey.VolumeMute }, - { "VolumeDown", ConsoleKey.VolumeDown }, - { "VolumeUp", ConsoleKey.VolumeUp }, - { "MediaNext", ConsoleKey.MediaNext }, - { "MediaPrevious", ConsoleKey.MediaPrevious }, - { "MediaStop", ConsoleKey.MediaStop }, - { "MediaPlay", ConsoleKey.MediaPlay }, - { "LaunchMail", ConsoleKey.LaunchMail }, - { "LaunchMediaSelect", ConsoleKey.LaunchMediaSelect }, - { "LaunchApp1", ConsoleKey.LaunchApp1 }, - { "LaunchApp2", ConsoleKey.LaunchApp2 }, - { "Oem1", ConsoleKey.Oem1 }, - { "OemPlus", ConsoleKey.OemPlus }, - { "OemComma", ConsoleKey.OemComma }, - { "OemMinus", ConsoleKey.OemMinus }, - { "OemPeriod", ConsoleKey.OemPeriod }, - { "Oem2", ConsoleKey.Oem2 }, - { "Oem3", ConsoleKey.Oem3 }, - { "Oem4", ConsoleKey.Oem4 }, - { "Oem5", ConsoleKey.Oem5 }, - { "Oem6", ConsoleKey.Oem6 }, - { "Oem7", ConsoleKey.Oem7 }, - { "Oem8", ConsoleKey.Oem8 }, - { "Oem102", ConsoleKey.Oem102 }, - { "Process", ConsoleKey.Process }, - { "Packet", ConsoleKey.Packet }, - { "Attention", ConsoleKey.Attention }, - { "CrSel", ConsoleKey.CrSel }, - { "ExSel", ConsoleKey.ExSel }, - { "EraseEndOfFile", ConsoleKey.EraseEndOfFile }, - { "Play", ConsoleKey.Play }, - { "Zoom", ConsoleKey.Zoom }, - { "NoName", ConsoleKey.NoName }, - { "Pa1", ConsoleKey.Pa1 }, - { "OemClear", ConsoleKey.OemClear } - }; - private Dictionary keyToStringLookup = new Dictionary() - { - { ConsoleKey.Backspace , "Backspace" }, - { ConsoleKey.Tab , "Tab" }, - { ConsoleKey.Clear , "Clear" }, - { ConsoleKey.Enter , "Enter" }, - { ConsoleKey.Pause , "Pause" }, - { ConsoleKey.Escape , "Escape" }, - { ConsoleKey.Spacebar , "Spacebar" }, - { ConsoleKey.PageUp , "PageUp" }, - { ConsoleKey.PageDown , "PageDown" }, - { ConsoleKey.End , "End" }, - { ConsoleKey.Home , "Home" }, - { ConsoleKey.LeftArrow , "LeftArrow" }, - { ConsoleKey.UpArrow , "UpArrow" }, - { ConsoleKey.RightArrow , "RightArrow" }, - { ConsoleKey.DownArrow , "DownArrow" }, - { ConsoleKey.Select , "Select" }, - { ConsoleKey.Print , "Print" }, - { ConsoleKey.Execute , "Execute" }, - { ConsoleKey.PrintScreen , "PrintScreen" }, - { ConsoleKey.Insert , "Insert" }, - { ConsoleKey.Delete , "Delete" }, - { ConsoleKey.Help , "Help" }, - { ConsoleKey.D0 , "D0" }, - { ConsoleKey.D1 , "D1" }, - { ConsoleKey.D2 , "D2" }, - { ConsoleKey.D3 , "D3" }, - { ConsoleKey.D4 , "D4" }, - { ConsoleKey.D5 , "D5" }, - { ConsoleKey.D6 , "D6" }, - { ConsoleKey.D7 , "D7" }, - { ConsoleKey.D8 , "D8" }, - { ConsoleKey.D9 , "D9" }, - { ConsoleKey.A , "A" }, - { ConsoleKey.B , "B" }, - { ConsoleKey.C , "C" }, - { ConsoleKey.D , "D" }, - { ConsoleKey.E , "E" }, - { ConsoleKey.F , "F" }, - { ConsoleKey.G , "G" }, - { ConsoleKey.H , "H" }, - { ConsoleKey.I , "I" }, - { ConsoleKey.J , "J" }, - { ConsoleKey.K , "K" }, - { ConsoleKey.L , "L" }, - { ConsoleKey.M , "M" }, - { ConsoleKey.N , "N" }, - { ConsoleKey.O , "O" }, - { ConsoleKey.P , "P" }, - { ConsoleKey.Q , "Q" }, - { ConsoleKey.R , "R" }, - { ConsoleKey.S , "S" }, - { ConsoleKey.T , "T" }, - { ConsoleKey.U , "U" }, - { ConsoleKey.V , "V" }, - { ConsoleKey.W , "W" }, - { ConsoleKey.X , "X" }, - { ConsoleKey.Y , "Y" }, - { ConsoleKey.Z , "Z" }, - { ConsoleKey.LeftWindows , "LeftWindows" }, - { ConsoleKey.RightWindows , "RightWindows" }, - { ConsoleKey.Applications , "Applications" }, - { ConsoleKey.Sleep , "Sleep" }, - { ConsoleKey.NumPad0 , "NumPad0" }, - { ConsoleKey.NumPad1 , "NumPad1" }, - { ConsoleKey.NumPad2 , "NumPad2" }, - { ConsoleKey.NumPad3 , "NumPad3" }, - { ConsoleKey.NumPad4 , "NumPad4" }, - { ConsoleKey.NumPad5 , "NumPad5" }, - { ConsoleKey.NumPad6 , "NumPad6" }, - { ConsoleKey.NumPad7 , "NumPad7" }, - { ConsoleKey.NumPad8 , "NumPad8" }, - { ConsoleKey.NumPad9 , "NumPad9" }, - { ConsoleKey.Multiply , "Multiply" }, - { ConsoleKey.Add , "Add" }, - { ConsoleKey.Separator , "Separator" }, - { ConsoleKey.Subtract , "Subtract" }, - { ConsoleKey.Decimal , "Decimal" }, - { ConsoleKey.Divide , "Divide" }, - { ConsoleKey.F1 , "F1" }, - { ConsoleKey.F2 , "F2" }, - { ConsoleKey.F3 , "F3" }, - { ConsoleKey.F4 , "F4" }, - { ConsoleKey.F5 , "F5" }, - { ConsoleKey.F6 , "F6" }, - { ConsoleKey.F7 , "F7" }, - { ConsoleKey.F8 , "F8" }, - { ConsoleKey.F9 , "F9" }, - { ConsoleKey.F10 , "F10" }, - { ConsoleKey.F11 , "F11" }, - { ConsoleKey.F12 , "F12" }, - { ConsoleKey.F13 , "F13" }, - { ConsoleKey.F14 , "F14" }, - { ConsoleKey.F15 , "F15" }, - { ConsoleKey.F16 , "F16" }, - { ConsoleKey.F17 , "F17" }, - { ConsoleKey.F18 , "F18" }, - { ConsoleKey.F19 , "F19" }, - { ConsoleKey.F20 , "F20" }, - { ConsoleKey.F21 , "F21" }, - { ConsoleKey.F22 , "F22" }, - { ConsoleKey.F23 , "F23" }, - { ConsoleKey.F24 , "F24" }, - { ConsoleKey.BrowserBack , "BrowserBack" }, - { ConsoleKey.BrowserForward , "BrowserForward" }, - { ConsoleKey.BrowserRefresh , "BrowserRefresh" }, - { ConsoleKey.BrowserStop , "BrowserStop" }, - { ConsoleKey.BrowserSearch , "BrowserSearch" }, - { ConsoleKey.BrowserFavorites , "BrowserFavorites" }, - { ConsoleKey.BrowserHome , "BrowserHome" }, - { ConsoleKey.VolumeMute , "VolumeMute" }, - { ConsoleKey.VolumeDown , "VolumeDown" }, - { ConsoleKey.VolumeUp , "VolumeUp" }, - { ConsoleKey.MediaNext , "MediaNext" }, - { ConsoleKey.MediaPrevious , "MediaPrevious" }, - { ConsoleKey.MediaStop , "MediaStop" }, - { ConsoleKey.MediaPlay , "MediaPlay" }, - { ConsoleKey.LaunchMail , "LaunchMail" }, - { ConsoleKey.LaunchMediaSelect , "LaunchMediaSelect" }, - { ConsoleKey.LaunchApp1 , "LaunchApp1" }, - { ConsoleKey.LaunchApp2 , "LaunchApp2" }, - { ConsoleKey.Oem1 , "Oem1" }, - { ConsoleKey.OemPlus , "OemPlus" }, - { ConsoleKey.OemComma , "OemComma" }, - { ConsoleKey.OemMinus , "OemMinus" }, - { ConsoleKey.OemPeriod , "OemPeriod" }, - { ConsoleKey.Oem2 , "Oem2" }, - { ConsoleKey.Oem3 , "Oem3" }, - { ConsoleKey.Oem4 , "Oem4" }, - { ConsoleKey.Oem5 , "Oem5" }, - { ConsoleKey.Oem6 , "Oem6" }, - { ConsoleKey.Oem7 , "Oem7" }, - { ConsoleKey.Oem8 , "Oem8" }, - { ConsoleKey.Oem102 , "Oem102" }, - { ConsoleKey.Process , "Process" }, - { ConsoleKey.Packet , "Packet" }, - { ConsoleKey.Attention , "Attention" }, - { ConsoleKey.CrSel , "CrSel" }, - { ConsoleKey.ExSel , "ExSel" }, - { ConsoleKey.EraseEndOfFile , "EraseEndOfFile" }, - { ConsoleKey.Play , "Play" }, - { ConsoleKey.Zoom , "Zoom" }, - { ConsoleKey.NoName , "NoName" }, - { ConsoleKey.Pa1 , "Pa1" }, - { ConsoleKey.OemClear , "OemClear" } - }; - - private Dictionary stringToConsoleColorLookup = new Dictionary() - { - { "black", ConsoleColor.Black }, - { "dark blue", ConsoleColor.DarkBlue }, - { "dark green", ConsoleColor.DarkGreen }, - { "dark cyan", ConsoleColor.DarkCyan }, - { "dark red", ConsoleColor.DarkRed }, - { "dark magenta", ConsoleColor.DarkMagenta }, - { "dark yellow", ConsoleColor.DarkYellow }, - { "gray", ConsoleColor.Gray }, - { "dark gray", ConsoleColor.DarkGray }, - { "blue", ConsoleColor.Blue }, - { "green", ConsoleColor.Green }, - { "cyan", ConsoleColor.Cyan }, - { "red", ConsoleColor.Red }, - { "magenta", ConsoleColor.Magenta }, - { "yellow", ConsoleColor.Yellow }, - { "white", ConsoleColor.White } - }; - private Dictionary consoleColorToStringLookup = new Dictionary() - { - { ConsoleColor.Black, "black" }, - { ConsoleColor.DarkBlue, "dark blue" }, - { ConsoleColor.DarkGreen, "dark green" }, - { ConsoleColor.DarkCyan, "dark cyan" }, - { ConsoleColor.DarkRed, "dark red" }, - { ConsoleColor.DarkMagenta, "dark magenta" }, - { ConsoleColor.DarkYellow, "dark yellow" }, - { ConsoleColor.Gray, "gray" }, - { ConsoleColor.DarkGray, "dark gray" }, - { ConsoleColor.Blue, "blue" }, - { ConsoleColor.Green, "green" }, - { ConsoleColor.Cyan, "cyan" }, - { ConsoleColor.Red, "red" }, - { ConsoleColor.Magenta, "magenta" }, - { ConsoleColor.Yellow, "yellow" }, - { ConsoleColor.White, "white" } - }; - - public console() : base(">") { } - - public override runtimeResult execute(item[] args) - { - context internalContext = base.generateContext(); - internalContext.symbolTable.set("is_key_pressed", new predefined_function("console_is_key_pressed", keyPressed, new string[4] { "key", "shift_pressed", "control_pressed", "alt_pressed" })); - internalContext.symbolTable.set("current_key_pressed", new predefined_function("console_current_key_pressed", anyKeyPressed, new string[0])); - - if (OperatingSystem.IsWindows()) - { - internalContext.symbolTable.set("is_numberlocked", new predefined_function("console_is_numberlocked", numberLocked, new string[0])); - internalContext.symbolTable.set("is_capslocked", new predefined_function("console_is_capslocked", capsLocked, new string[0])); - - internalContext.symbolTable.set("get_cursor_size", new predefined_function("console_get_cursor_size", getCursorSize, new string[0])); - internalContext.symbolTable.set("set_cursor_size", new predefined_function("console_set_cursor_size", setCursorSize, new string[1] { "size" })); - internalContext.symbolTable.set("get_cursor_visibility", new predefined_function("console_get_cursor_visibility", getCursorVisibility, new string[0])); - internalContext.symbolTable.set("set_cursor_visibility", new predefined_function("console_set_cursor_visibility", setCursorVisibility, new string[1] { "visibility" })); - internalContext.symbolTable.set("set_buffer_size", new predefined_function("console_set_buffer_size", setBufferSize, new string[2] { "x_size", "y_size" })); - internalContext.symbolTable.set("set_window_position", new predefined_function("console_set_window_position", setWindowPosition, new string[2] { "x_position", "y_position" })); - internalContext.symbolTable.set("set_window_size", new predefined_function("console_set_window_size", setWindowSize, new string[2] { "x_size", "y_size" })); - } - else - { - internalContext.symbolTable.set("is_numberlocked", new predefined_function("console_is_numberlocked", platformNotSupported, new string[0])); - internalContext.symbolTable.set("is_capslocked", new predefined_function("console_is_capslocked", platformNotSupported, new string[0])); - - internalContext.symbolTable.set("get_cursor_size", new predefined_function("console_get_cursor_size", platformNotSupported, new string[0])); - internalContext.symbolTable.set("set_cursor_size", new predefined_function("console_set_cursor_size", platformNotSupported, new string[1] { "size" })); - internalContext.symbolTable.set("get_cursor_visibility", new predefined_function("console_get_cursor_visibility", platformNotSupported, new string[0])); - internalContext.symbolTable.set("set_cursor_visibility", new predefined_function("console_set_cursor_visibility", platformNotSupported, new string[1] { "visibility" })); - internalContext.symbolTable.set("set_buffer_size", new predefined_function("console_set_buffer_size", platformNotSupported, new string[2] { "x_size", "y_size" })); - internalContext.symbolTable.set("set_window_position", new predefined_function("console_set_window_position", platformNotSupported, new string[2] { "x_position", "y_position" })); - internalContext.symbolTable.set("set_window_size", new predefined_function("console_set_window_size", platformNotSupported, new string[2] { "x_size", "y_size" })); - } - - internalContext.symbolTable.set("get_background", new predefined_function("console_get_background", getConsoleBackground, new string[0])); - internalContext.symbolTable.set("set_background", new predefined_function("console_set_background", setConsoleBackground, new string[1] { "color" })); - internalContext.symbolTable.set("get_foreground", new predefined_function("console_get_foreground", getConsoleForeground, new string[0])); - internalContext.symbolTable.set("set_foreground", new predefined_function("console_set_foreground", setConsoleForeground, new string[1] { "color" })); - internalContext.symbolTable.set("reset_colors", new predefined_function("console_reset_colors", consoleResetColors, new string[0])); - internalContext.symbolTable.set("get_cursor_position", new predefined_function("console_get_cursor_position", getCursorPosition, new string[0])); - internalContext.symbolTable.set("set_cursor_position", new predefined_function("console_set_cursor_position", setCursorPosition, new string[2] { "x_position", "y_position" })); - internalContext.symbolTable.set("get_buffer_size", new predefined_function("console_get_buffer_size", getBufferSize, new string[0])); - internalContext.symbolTable.set("get_window_position", new predefined_function("console_get_window_position", getWindowPosition, new string[0])); - internalContext.symbolTable.set("get_window_size", new predefined_function("console_get_window_size", getWindowSize, new string[0])); - internalContext.symbolTable.set("exit", new predefined_function("console_exit", stopApplication, new string[0])); - - return new runtimeResult().success(new @object(name, internalContext).setPosition(startPos, endPos).setContext(context)); - } - - private runtimeResult platformNotSupported(context context, position[] positions) - { - return new runtimeResult().failure(new runtimeError(positions[0], positions[1], RT_IO, $"Function not supported on current platform", context)); - } - - private runtimeResult getCursorVisibility(context context, position[] positions) - { - return new runtimeResult().success(new boolean(Console.CursorVisible)); - } - - private runtimeResult setCursorVisibility(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item visibility = context.symbolTable.get("visibility"); - if (visibility is not boolean) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Visibility must be a boolean", context)); - - Console.CursorVisible = ((value)visibility).storedValue; - return result.success(new nothing()); - } - - private runtimeResult getCursorSize(context context, position[] positions) - { - return new runtimeResult().success(new integer(Console.CursorSize)); - } - - private runtimeResult setCursorSize(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item size = context.symbolTable.get("size"); - if (size is not integer && size is not @float) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Size must be an integer or float", context)); - - int sizeValue = (int)((value)size).storedValue; - if (sizeValue < 1 || sizeValue > 100) - return result.failure(new runtimeError(positions[0], positions[1], RT_OVERFLOW, "Size must be in range 1-100", context)); - - Console.CursorSize = sizeValue; - return result.success(new nothing()); - } - - private runtimeResult getWindowSize(context context, position[] positions) - { - int width = Console.WindowWidth; - int height = Console.WindowHeight; - - return new runtimeResult().success(new array(new item[2] { new integer(width).setPosition(positions[0], positions[1]).setContext(context), new integer(height).setPosition(positions[0], positions[1]).setContext(context) })); - } - - private runtimeResult setWindowSize(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item xsize = context.symbolTable.get("x_size"); - if (xsize is not integer && xsize is not @float) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "X_size must be an integer or float", context)); - - item ysize = context.symbolTable.get("y_size"); - if (ysize is not integer && ysize is not @float) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Y_size must be an integer or float", context)); - - (int width, int height) = ((int)((value)xsize).storedValue, (int)((value)ysize).storedValue); - - int maxWindowHeight2 = height + Console.WindowTop; - if (width < 1 || width > Console.LargestWindowWidth) - return result.failure(new runtimeError(positions[0], positions[1], RT_OVERFLOW, $"X size must be in range 1-{Console.LargestWindowWidth}", context)); - if (height < 1 || height > Console.LargestWindowHeight || maxWindowHeight2 >= Int16.MaxValue) - return result.failure(new runtimeError(positions[0], positions[1], RT_OVERFLOW, $"Y size must be in range 1-{Console.LargestWindowHeight}", context)); - - Console.SetWindowSize(width, height); - return result.success(new nothing()); - } - - private runtimeResult getWindowPosition(context context, position[] positions) - { - int left = Console.WindowLeft; - int top = Console.WindowTop; - - return new runtimeResult().success(new array(new item[2] { new integer(left).setPosition(positions[0], positions[1]).setContext(context), new integer(top).setPosition(positions[0], positions[1]).setContext(context) })); - } - - private runtimeResult setWindowPosition(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item xposition = context.symbolTable.get("x_position"); - if (xposition is not integer && xposition is not @float) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "X_position must be an integer or float", context)); - - item yposition = context.symbolTable.get("y_position"); - if (yposition is not integer && yposition is not @float) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Y_position must be an integer or float", context)); - - (int left, int top) = ((int)((value)xposition).storedValue, (int)((value)yposition).storedValue); - - if (left < 0 || left + Console.WindowWidth > Console.BufferWidth) - return result.failure(new runtimeError(positions[0], positions[1], RT_OVERFLOW, $"X position must be in range 0-{Console.BufferWidth - Console.WindowWidth}", context)); - if (top < 0 || top + Console.WindowHeight > Console.BufferHeight) - return result.failure(new runtimeError(positions[0], positions[1], RT_OVERFLOW, $"Y position must be in range 0-{Console.BufferHeight - Console.WindowHeight}", context)); - - Console.SetWindowPosition(left, top); - return result.success(new nothing()); - } - - private runtimeResult getBufferSize(context context, position[] positions) - { - int width = Console.BufferWidth; - int height = Console.BufferHeight; - - return new runtimeResult().success(new array(new item[2] { new integer(width).setPosition(positions[0], positions[1]).setContext(context), new integer(height).setPosition(positions[0], positions[1]).setContext(context) })); - } - - private runtimeResult setBufferSize(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item xsize = context.symbolTable.get("x_size"); - if (xsize is not integer && xsize is not @float) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "X_size must be an integer or float", context)); - - item ysize = context.symbolTable.get("y_size"); - if (ysize is not integer && ysize is not @float) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Y_size must be an integer or float", context)); - - (int width, int height) = ((int)((value)xsize).storedValue, (int)((value)ysize).storedValue); - - int minWidth = Console.WindowLeft + Console.WindowWidth; - int minHeight = Console.WindowTop + Console.WindowHeight; - if (width < minWidth || width >= Int16.MaxValue) - return result.failure(new runtimeError(positions[0], positions[1], RT_OVERFLOW, $"X size must be in range {minWidth}-{Int16.MaxValue - 1}", context)); - if (height < minHeight || height >= Int16.MaxValue) - return result.failure(new runtimeError(positions[0], positions[1], RT_OVERFLOW, $"Y size must be in range {minHeight}-{Int16.MaxValue - 1}", context)); - - Console.SetBufferSize(width, height); - return result.success(new nothing()); - } - - private runtimeResult getCursorPosition(context context, position[] positions) - { - (int left, int top) = Console.GetCursorPosition(); - - return new runtimeResult().success(new array(new item[2] { new integer(left).setPosition(positions[0], positions[1]).setContext(context), new integer(top).setPosition(positions[0], positions[1]).setContext(context) })); - } - - private runtimeResult setCursorPosition(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item xpos = context.symbolTable.get("x_position"); - if (xpos is not integer && xpos is not @float) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "X_position must be an integer or float", context)); - - item ypos = context.symbolTable.get("y_position"); - if (ypos is not integer && ypos is not @float) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Y_position must be an integer or float", context)); - - (int left, int top) = ((int)((value)xpos).storedValue, (int)((value)ypos).storedValue); - if (left < 0 || left >= Console.BufferWidth) - return result.failure(new runtimeError(positions[0], positions[1], RT_OVERFLOW, $"X position must be in range 0-{Console.BufferWidth - 1}", context)); - if (top < 0 || top >= Console.BufferHeight) - return result.failure(new runtimeError(positions[0], positions[1], RT_OVERFLOW, $"Y position must be in range 0-{Console.BufferHeight - 1}", context)); - - Console.SetCursorPosition(left, top); - return result.success(new nothing()); - } - - private runtimeResult consoleResetColors(context context, position[] positions) - { - Console.ResetColor(); - return new runtimeResult().success(new nothing()); - } - - private runtimeResult stopApplication(context context, position[] positions) - { - Environment.Exit(0); - return new runtimeResult().success(new nothing()); - } - - private runtimeResult getConsoleBackground(context context, position[] positions) - { - return new runtimeResult().success(new @string(consoleColorToStringLookup[Console.BackgroundColor])); - } - - private runtimeResult setConsoleBackground(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item color = context.symbolTable.get("color"); - if (color is not @string && color is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Color must be a string or character_list", context)); - - string colorName = (color is @string) ? ((@string)color).storedValue.ToString() : string.Join("", ((character_list)color).storedValue); - if (!stringToConsoleColorLookup.ContainsKey(colorName)) - return result.failure(new runtimeError(positions[0], positions[1], RT_KEY, "Unknown color", context)); - - Console.BackgroundColor = stringToConsoleColorLookup[colorName]; - return result.success(new nothing()); - } - - private runtimeResult getConsoleForeground(context context, position[] positions) - { - return new runtimeResult().success(new @string(consoleColorToStringLookup[Console.ForegroundColor])); - } - - private runtimeResult setConsoleForeground(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item color = context.symbolTable.get("color"); - if (color is not @string && color is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Color must be a string or character_list", context)); - - string colorName = (color is @string) ? ((@string)color).storedValue.ToString() : string.Join("", ((character_list)color).storedValue); - if (!stringToConsoleColorLookup.ContainsKey(colorName)) - return result.failure(new runtimeError(positions[0], positions[1], RT_KEY, "Unknown color", context)); - - Console.ForegroundColor = stringToConsoleColorLookup[colorName]; - return result.success(new nothing()); - } - - private runtimeResult keyPressed(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item key = context.symbolTable.get("key"); - if (key is not @string && key is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Key must be a string or character_list", context)); - - item shift = context.symbolTable.get("shift_pressed"); - if (shift is not boolean) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Shift_pressed must be a boolean", context)); - - item control = context.symbolTable.get("control_pressed"); - if (control is not boolean) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Control_pressed must be a boolean", context)); - - item alt = context.symbolTable.get("alt_pressed"); - if (alt is not boolean) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Alt_pressed must be a boolean", context)); - - string keyCode = (key is @string) ? ((@string)key).storedValue.ToString() : string.Join("", ((character_list)key).storedValue); - if (!stringToKeyLookup.ContainsKey(keyCode)) - return result.failure(new runtimeError(positions[0], positions[1], RT_KEY, "Unknown key", context)); - - if (!Console.KeyAvailable) return result.success(new nothing()); - - ConsoleKeyInfo keyPress = Console.ReadKey(true); - bool shiftPress = (((value)shift).storedValue) ? (keyPress.Modifiers & ConsoleModifiers.Shift) != 0 : true; - bool controlPress = (((value)control).storedValue) ? (keyPress.Modifiers & ConsoleModifiers.Control) != 0 : true; - bool altPress = (((value)alt).storedValue) ? (keyPress.Modifiers & ConsoleModifiers.Alt) != 0 : true; - return result.success(new boolean(keyPress.Key == stringToKeyLookup[keyCode] && shiftPress && controlPress && altPress)); - } - - private runtimeResult anyKeyPressed(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - if (!Console.KeyAvailable) - return result.success(new nothing()); - - ConsoleKeyInfo keyPress = Console.ReadKey(true); - - return result.success(new array(new item[2] { - new @string(keyToStringLookup[keyPress.Key]).setPosition(positions[0], positions[1]).setContext(context), - new array(new item[3] { - new boolean((keyPress.Modifiers & ConsoleModifiers.Shift) != 0).setPosition(positions[0], positions[1]).setContext(context), - new boolean((keyPress.Modifiers & ConsoleModifiers.Control) != 0).setPosition(positions[0], positions[1]).setContext(context), - new boolean((keyPress.Modifiers & ConsoleModifiers.Alt) != 0).setPosition(positions[0], positions[1]).setContext(context) - }).setPosition(positions[0], positions[1]).setContext(context) - })); - } - - private runtimeResult numberLocked(context context, position[] positions) - { - return new runtimeResult().success(new boolean(Console.NumberLock)); - } - - private runtimeResult capsLocked(context context, position[] positions) - { - return new runtimeResult().success(new boolean(Console.CapsLock)); - } - - public override item copy() { return new console().setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; return obj is console; } - } - - public class @file : baseFunction - { - public override bool UPDATEONACCESS => true; - - public @file() : base(">") { } - - public override runtimeResult execute(item[] args) - { - context internalContext = base.generateContext(); - internalContext.symbolTable.set("exists", new predefined_function("file_exists", fileExists, new string[1] { "filepath" })); - internalContext.symbolTable.set("create", new predefined_function("file_create", createFile, new string[1] { "filepath" })); - internalContext.symbolTable.set("delete", new predefined_function("file_delete", deleteFile, new string[1] { "filepath" })); - internalContext.symbolTable.set("read", new predefined_function("file_read", readFile, new string[1] { "filepath" })); - internalContext.symbolTable.set("write", new predefined_function("file_write", writeFile, new string[3] { "contents", "filepath", "mode" })); - internalContext.symbolTable.set("copy", new predefined_function("file_copy", copyFile, new string[2] { "from_path", "to_path" })); - internalContext.symbolTable.set("move", new predefined_function("file_move", moveFile, new string[2] { "from_path", "to_path" })); - - return new runtimeResult().success(new @object(name, internalContext).setPosition(startPos, endPos).setContext(context)); - } - - private runtimeResult fileExists(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("filepath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Filepath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - return result.success(new boolean(File.Exists(filepath))); - } - - private runtimeResult createFile(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("filepath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Filepath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - - try - { - File.Create(filepath).Close(); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to create file \"{filepath}\"\n{exception.Message}", context)); - } - - return result.success(new nothing()); - } - - private runtimeResult deleteFile(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("filepath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Filepath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - if (!File.Exists(filepath)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"File \"{filepath}\" does not exist", context)); - - try - { - File.Delete(filepath); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to delete file \"{filepath}\"\n{exception.Message}", context)); - } - - return result.success(new nothing()); - } - - private runtimeResult readFile(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("filepath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Filepath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - if (!File.Exists(filepath)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"File \"{filepath}\" does not exist", context)); - - string[] contents; - try - { - contents = File.ReadAllLines(filepath); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to load file \"{filepath}\"\n{exception.Message}", context)); - } - - item[] contentsAsString = new item[contents.Length]; - for (int i = 0; i < contentsAsString.Length; i++) - contentsAsString[i] = new @string(contents[i]).setPosition(positions[0], positions[1]).setContext(context); - return result.success(new array(contentsAsString)); - } - - private runtimeResult writeFile(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item content = context.symbolTable.get("contents"); - if (content is not @string && content is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Contents must be a string or character_list", context)); - item path = context.symbolTable.get("filepath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Filepath must be a string or character_list", context)); - item mode = context.symbolTable.get("mode"); - if (mode is not @string && mode is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Mode must be a string or character_list", context)); - - string content_ = (content is @string) ? ((@string)content).storedValue.ToString() : string.Join("", ((character_list)content).storedValue); - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - string mode_ = ((mode is @string) ? ((@string)mode).storedValue.ToString() : string.Join("", ((character_list)mode).storedValue)).ToLower(); - - if (mode_ == "write") - { - try - { - File.WriteAllText(filepath, content_); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to write to file \"{filepath}\"\n{exception.Message}", context)); - } - } - else if (mode_ == "append") - { - try - { - File.AppendAllText(filepath, content_); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to append to file \"{filepath}\"\n{exception.Message}", context)); - } - } - else - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Mode must be string/character_list literal \"write\" or \"append\"", context)); - - return result.success(new nothing()); - } - - private runtimeResult copyFile(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item from = context.symbolTable.get("from_path"); - if (from is not @string && from is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "From_path must be a string or character_list", context)); - item to = context.symbolTable.get("to_path"); - if (to is not @string && to is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "To_path must be a string or character_list", context)); - - string from_ = (from is @string) ? ((@string)from).storedValue.ToString() : string.Join("", ((character_list)from).storedValue); - string to_ = (to is @string) ? ((@string)to).storedValue.ToString() : string.Join("", ((character_list)to).storedValue); - - if (!File.Exists(from_)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"File \"{from_}\" does not exist", context)); - - try - { - File.Copy(from_, to_); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to copy contents of file \"{from_}\" to \"{to_}\"\n{exception.Message}", context)); - } - - return result.success(new nothing()); - } - - private runtimeResult moveFile(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item from = context.symbolTable.get("from_path"); - if (from is not @string && from is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "From_path must be a string or character_list", context)); - item to = context.symbolTable.get("to_path"); - if (to is not @string && to is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "To_path must be a string or character_list", context)); - - string from_ = (from is @string) ? ((@string)from).storedValue.ToString() : string.Join("", ((character_list)from).storedValue); - string to_ = (to is @string) ? ((@string)to).storedValue.ToString() : string.Join("", ((character_list)to).storedValue); - - if (!File.Exists(from_)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"File \"{from_}\" does not exist", context)); - - try - { - File.Move(from_, to_); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to move file \"{from_}\" to \"{to_}\"\n{exception.Message}", context)); - } - - return result.success(new nothing()); - } - - public override item copy() { return new @file().setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; return obj is @file; } - } - - public class folder : baseFunction - { - public override bool UPDATEONACCESS => true; - - public folder() : base(">") { } - - public override runtimeResult execute(item[] args) - { - context internalContext = base.generateContext(); - internalContext.symbolTable.set("exists", new predefined_function("folder_exists", folderExists, new string[1] { "folderpath" })); - internalContext.symbolTable.set("create", new predefined_function("folder_create", createFolder, new string[1] { "folderpath" })); - internalContext.symbolTable.set("delete", new predefined_function("folder_delete", deleteFolder, new string[1] { "folderpath" })); - internalContext.symbolTable.set("subfolders_in", new predefined_function("folder_subfolders_in", subFolders, new string[1] { "folderpath" })); - internalContext.symbolTable.set("files_in", new predefined_function("folder_files_in", filesInFolder, new string[1] { "folderpath" })); - internalContext.symbolTable.set("files_and_subfolders_in", new predefined_function("folder_files_and_subfolders_in", filesAndSubFolders, new string[1] { "folderpath" })); - internalContext.symbolTable.set("parent_of", new predefined_function("folder_parent_of", folderParent, new string[1] { "folderpath" })); - internalContext.symbolTable.set("root_of", new predefined_function("folder_root_of", folderRoot, new string[1] { "folderpath" })); - internalContext.symbolTable.set("current", new predefined_function("folder_current", currentFolder, new string[0])); - internalContext.symbolTable.set("set_current", new predefined_function("folder_set_current", setCurrentFolder, new string[1] { "folderpath" })); - internalContext.symbolTable.set("move", new predefined_function("folder_move", moveFolder, new string[2] { "from_path", "to_path" })); - - return new runtimeResult().success(new @object(name, internalContext).setPosition(startPos, endPos).setContext(context)); - } - - private runtimeResult folderExists(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("folderpath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Folderpath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - return result.success(new boolean(Directory.Exists(filepath))); - } - - private runtimeResult createFolder(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("folderpath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Folderpath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - - try - { - Directory.CreateDirectory(filepath); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to create folder \"{filepath}\"\n{exception.Message}", context)); - } - - return result.success(new nothing()); - } - - private runtimeResult deleteFolder(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("folderpath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Folderpath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - if (!Directory.Exists(filepath)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Folder \"{filepath}\" does not exist", context)); - - try - { - Directory.Delete(filepath); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to delete folder \"{filepath}\"\n{exception.Message}", context)); - } - - return result.success(new nothing()); - } - - private runtimeResult subFolders(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("folderpath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Folderpath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - if (!Directory.Exists(filepath)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Folder \"{filepath}\" does not exist", context)); - - string[] subDirectories; - try - { - subDirectories = Directory.GetDirectories(filepath); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to access subfolders in folder \"{filepath}\"\n{exception.Message}", context)); - } - - item[] subDirectoriesAsString = new item[subDirectories.Length]; - for (int i = 0; i < subDirectories.Length; i++) - subDirectoriesAsString[i] = new @string(subDirectories[i]).setPosition(positions[0], positions[1]).setContext(context); - return result.success(new array(subDirectoriesAsString)); - } - - private runtimeResult filesInFolder(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("folderpath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Folderpath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - if (!Directory.Exists(filepath)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Folder \"{filepath}\" does not exist", context)); - - string[] subFiles; - try - { - subFiles = Directory.GetFiles(filepath); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to access files in folder \"{filepath}\"\n{exception.Message}", context)); - } - - item[] subFilesAsString = new item[subFiles.Length]; - for (int i = 0; i < subFiles.Length; i++) - subFilesAsString[i] = new @string(subFiles[i]).setPosition(positions[0], positions[1]).setContext(context); - return result.success(new array(subFilesAsString)); - } - - private runtimeResult filesAndSubFolders(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("folderpath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Folderpath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - if (!Directory.Exists(filepath)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Folder \"{filepath}\" does not exist", context)); - - string[] subFilesAndDirectories; - try - { - subFilesAndDirectories = Directory.GetFileSystemEntries(filepath); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to access subfolders and files in folder \"{filepath}\"\n{exception.Message}", context)); - } - - item[] subFilesAndDirectoriesAsString = new item[subFilesAndDirectories.Length]; - for (int i = 0; i < subFilesAndDirectories.Length; i++) - subFilesAndDirectoriesAsString[i] = new @string(subFilesAndDirectories[i]).setPosition(positions[0], positions[1]).setContext(context); - return result.success(new array(subFilesAndDirectoriesAsString)); - } - - private runtimeResult folderParent(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("folderpath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Folderpath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - if (!Directory.Exists(filepath)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Folder \"{filepath}\" does not exist", context)); - - DirectoryInfo? parentInfo; - try - { - parentInfo = Directory.GetParent(filepath); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to access parent of folder \"{filepath}\"\n{exception.Message}", context)); - } - - return result.success((parentInfo != null) ? new @string(parentInfo.Name) : new nothing()); - } - - private runtimeResult folderRoot(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("folderpath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Folderpath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - if (!Directory.Exists(filepath)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Folder \"{filepath}\" does not exist", context)); - - string root; - try - { - root = Directory.GetDirectoryRoot(filepath); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to access root of folder \"{filepath}\"\n{exception.Message}", context)); - } - - return result.success(new @string(root)); - } - - private runtimeResult moveFolder(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item from = context.symbolTable.get("from_path"); - if (from is not @string && from is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "From_path must be a string or character_list", context)); - item to = context.symbolTable.get("to_path"); - if (to is not @string && to is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "To_path must be a string or character_list", context)); - - string from_ = (from is @string) ? ((@string)from).storedValue.ToString() : string.Join("", ((character_list)from).storedValue); - string to_ = (to is @string) ? ((@string)to).storedValue.ToString() : string.Join("", ((character_list)to).storedValue); - - if (!Directory.Exists(from_)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Folder \"{from_}\" does not exist", context)); - - try - { - Directory.Move(from_, to_); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to move folder \"{from_}\" to \"{to_}\"\n{exception.Message}", context)); - } - - return result.success(new nothing()); - } - - private runtimeResult currentFolder(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - string filepath; - try - { - filepath = Directory.GetCurrentDirectory(); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to access current working directory\n{exception.Message}", context)); - } - - return result.success(new @string(filepath)); - } - - private runtimeResult setCurrentFolder(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("folderpath"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Folderpath must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - if (!Directory.Exists(filepath)) - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Folder \"{filepath}\" does not exist", context)); - - try - { - Directory.SetCurrentDirectory(filepath); - } - catch (IOException exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Failed to set current working directory to \"{filepath}\"\n{exception.Message}", context)); - } - - return result.success(new nothing()); - } - - public override item copy() { return new folder().setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; return obj is folder; } - } - - public class path : baseFunction - { - public override bool UPDATEONACCESS => true; - - public path() : base(">") { } - - public override runtimeResult execute(item[] args) - { - context internalContext = base.generateContext(); - - internalContext.symbolTable.set("directory_separator", new @string(Path.DirectorySeparatorChar.ToString())); - internalContext.symbolTable.set("alternate_directory_separator", new @string(Path.AltDirectorySeparatorChar.ToString())); - internalContext.symbolTable.set("invalid_filename_characters", new @string(string.Join("", Path.GetInvalidFileNameChars()))); - internalContext.symbolTable.set("invalid_path_characters", new @string(string.Join("", Path.GetInvalidPathChars()))); - internalContext.symbolTable.set("exists", new predefined_function("path_exists", pathExists, new string[1] { "path" })); - internalContext.symbolTable.set("join", new predefined_function("path_join", joinPaths, new string[1] { "paths" })); - internalContext.symbolTable.set("combine", new predefined_function("path_combine", combinePaths, new string[2] { "path_1", "path_2" })); - internalContext.symbolTable.set("has_extension", new predefined_function("path_has_extension", pathHasExtension, new string[1] { "path" })); - internalContext.symbolTable.set("get_extension", new predefined_function("path_get_extension", pathExtension, new string[1] { "path" })); - internalContext.symbolTable.set("set_extension", new predefined_function("path_set_extension", setPathExtension, new string[2] { "path", "extension" })); - internalContext.symbolTable.set("get_folder", new predefined_function("path_get_folder", folderNameOfPath, new string[1] { "path" })); - internalContext.symbolTable.set("get_file", new predefined_function("path_get_file", fileNameOfPath, new string[1] { "path" })); - internalContext.symbolTable.set("get_file_without_extension", new predefined_function("path_get_file_without_extension", fileNameOfPathWithoutExtension, new string[1] { "path" })); - internalContext.symbolTable.set("get_whole", new predefined_function("path_get_whole", fullPath, new string[1] { "path" })); - internalContext.symbolTable.set("get_root", new predefined_function("path_get_root", pathRoot, new string[1] { "path" })); - internalContext.symbolTable.set("create_temp_file", new predefined_function("path_create_temp_file", createTempFilePath, new string[0])); - internalContext.symbolTable.set("temp", new predefined_function("path_temp", tempPath, new string[0])); - internalContext.symbolTable.set("relative_path", new predefined_function("path_relative_path", relativePath, new string[2] { "relative_to", "path" })); - internalContext.symbolTable.set("ends_in_folder_seperator", new predefined_function("path_ends_in_folder_seperator", pathEndsInFolderSeperator, new string[1] { "path" })); - internalContext.symbolTable.set("remove_last_folder_seperator", new predefined_function("path_remove_last_folder_seperator", removeLastFolderSeperatorOfPath, new string[1] { "path" })); - - return new runtimeResult().success(new @object(name, internalContext).setPosition(startPos, endPos).setContext(context)); - } - - private runtimeResult pathExists(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - return result.success(new boolean(Path.Exists(filepath))); - } - - private runtimeResult joinPaths(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item paths = context.symbolTable.get("paths"); - if (paths is not list && paths is not array) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Paths must be a list or array", context)); - - item[] paths_ = (paths is list) ? ((list)paths).storedValue.ToArray() : ((array)paths).storedValue; - string[] filepaths = new string[paths_.Length]; - for (int i = 0; i < paths_.Length; i++) - { - if (paths_[i] is not @string && paths_[i] is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "All elements of paths must be strings or character_lists", context)); - filepaths[i] = (paths_[i] is @string) ? ((@string)paths_[i]).storedValue : string.Join("", ((character_list)paths_[i]).storedValue); - } - - return result.success(new @string(Path.Join(filepaths))); - } - - private runtimeResult combinePaths(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path1 = context.symbolTable.get("path_1"); - if (path1 is not @string && path1 is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path_1 must be a string or character_list", context)); - item path2 = context.symbolTable.get("path_2"); - if (path2 is not @string && path2 is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path_2 must be a string or character_list", context)); - - string filepath1 = (path1 is @string) ? ((@string)path1).storedValue.ToString() : string.Join("", ((character_list)path1).storedValue); - string filepath2 = (path2 is @string) ? ((@string)path2).storedValue.ToString() : string.Join("", ((character_list)path2).storedValue); - return result.success(new @string(Path.Combine(filepath1, filepath2))); - } - - private runtimeResult pathHasExtension(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - return result.success(new boolean(Path.HasExtension(filepath))); - } - - private runtimeResult pathExtension(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - - string? extension = Path.GetExtension(filepath); - return result.success((extension != null) ? new @string(extension) : new nothing()); - } - - private runtimeResult setPathExtension(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - item extension = context.symbolTable.get("extension"); - if (extension is not @string && extension is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Extension must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - string extension_ = (extension is @string) ? ((@string)extension).storedValue.ToString() : string.Join("", ((character_list)extension).storedValue); - - string? newPath = Path.ChangeExtension(filepath, extension_); - return result.success((newPath != null) ? new @string(newPath) : new nothing()); - } - - private runtimeResult folderNameOfPath(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - - string? folder; - try - { - folder = Path.GetDirectoryName(filepath); - } - catch (Exception exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Could not access directory name of path \"{filepath}\"\n\n{exception.Message}", context)); - } - - return result.success((folder != null) ? new @string(folder) : new nothing()); - } - - private runtimeResult fileNameOfPath(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - - string? filename; - try - { - filename = Path.GetFileName(filepath); - } - catch (Exception exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Could not access file name of path \"{filepath}\"\n\n{exception.Message}", context)); - } - - return result.success((filename != null) ? new @string(filename) : new nothing()); - } - - private runtimeResult fileNameOfPathWithoutExtension(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - - string? filename; - try - { - filename = Path.GetFileNameWithoutExtension(filepath); - } - catch (Exception exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Could not access file name of path \"{filepath}\"\n\n{exception.Message}", context)); - } - - return result.success((filename != null) ? new @string(filename) : new nothing()); - } - - private runtimeResult fullPath(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - - string filepath_; - try - { - filepath_ = Path.GetFullPath(filepath); - } - catch (Exception exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Could not access full path of path \"{filepath}\"\n\n{exception.Message}", context)); - } - - return result.success(new @string(filepath_)); - } - - private runtimeResult pathRoot(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - - string? filepath_; - try - { - filepath_ = Path.GetPathRoot(filepath); - } - catch (Exception exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Could not access root of path \"{filepath}\"\n\n{exception.Message}", context)); - } - - return result.success((filepath_ != null) ? new @string(filepath_) : new nothing()); - } - - private runtimeResult createTempFilePath(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - string filepath; - try - { - filepath = Path.GetTempFileName(); - } - catch (Exception exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Could not create new temporary file\n\n{exception.Message}", context)); - } - - return result.success(new @string(filepath)); - } - - private runtimeResult tempPath(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - string filepath; - try - { - filepath = Path.GetTempPath(); - } - catch (Exception exception) - { - return result.failure(new runtimeError(positions[0], positions[1], RT_IO, $"Could not access Temp path\n\n{exception.Message}", context)); - } - - return result.success(new @string(filepath)); - } - - private runtimeResult relativePath(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item relativeTo = context.symbolTable.get("relative_to"); - if (relativeTo is not @string && relativeTo is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Relative_to must be a string or character_list", context)); - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - - string relativeTo_ = (relativeTo is @string) ? ((@string)relativeTo).storedValue.ToString() : string.Join("", ((character_list)relativeTo).storedValue); - string path_ = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - - return result.success(new @string(Path.GetRelativePath(relativeTo_, path_))); - } - - private runtimeResult pathEndsInFolderSeperator(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - return result.success(new boolean(Path.EndsInDirectorySeparator(filepath))); - } - - private runtimeResult removeLastFolderSeperatorOfPath(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item path = context.symbolTable.get("path"); - if (path is not @string && path is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Path must be a string or character_list", context)); - - string filepath = (path is @string) ? ((@string)path).storedValue.ToString() : string.Join("", ((character_list)path).storedValue); - return result.success(new @string(Path.TrimEndingDirectorySeparator(filepath))); - } - - public override item copy() { return new path().setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; return obj is path; } - } -} \ No newline at end of file diff --git a/Libraries/io/io.csproj b/Libraries/io/io.csproj deleted file mode 100644 index a607f3e..0000000 --- a/Libraries/io/io.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - net7.0 - win-x64 - disable - enable - - - - false - false - - - - - - diff --git a/Libraries/std/STD.cs b/Libraries/std/STD.cs deleted file mode 100644 index 3924491..0000000 --- a/Libraries/std/STD.cs +++ /dev/null @@ -1,186 +0,0 @@ -using ezrSquared.Values; -using ezrSquared.Helpers; -using ezrSquared.Errors; -using ezrSquared.General; -using static ezrSquared.Constants.constants; -using System; - -namespace ezrSquared.Libraries.STD -{ - public class integer_class : baseFunction - { - public override bool UPDATEONACCESS => true; - - public integer_class() : base(">") { } - - public override runtimeResult execute(item[] args) - { - context internalContext = base.generateContext(); - internalContext.symbolTable.set("maximum", new integer(int.MaxValue)); - internalContext.symbolTable.set("minimum", new integer(int.MinValue)); - - return new runtimeResult().success(new @object(name, internalContext).setPosition(startPos, endPos).setContext(context)); - } - - public override item copy() { return new integer_class().setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; return obj is integer_class; } - } - - public class float_class : baseFunction - { - public override bool UPDATEONACCESS => true; - - public float_class() : base(">") { } - - public override runtimeResult execute(item[] args) - { - context internalContext = base.generateContext(); - internalContext.symbolTable.set("maximum", new @float(float.MaxValue)); - internalContext.symbolTable.set("minimum", new @float(float.MinValue)); - internalContext.symbolTable.set("epsilon", new @float(float.Epsilon)); - internalContext.symbolTable.set("nan", new @float(float.NaN)); - internalContext.symbolTable.set("infinity", new @float(float.PositiveInfinity)); - internalContext.symbolTable.set("negative_infinity", new @float(float.NegativeInfinity)); - internalContext.symbolTable.set("negative_zero", new @float(float.NegativeZero)); - internalContext.symbolTable.set("pi", new @float(MathF.PI)); - internalContext.symbolTable.set("tau", new @float(MathF.Tau)); - internalContext.symbolTable.set("e", new @float(MathF.E)); - - - return new runtimeResult().success(new @object(name, internalContext).setPosition(startPos, endPos).setContext(context)); - } - - public override item copy() { return new float_class().setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; return obj is float_class; } - } - - public class string_class : baseFunction - { - public override bool UPDATEONACCESS => true; - - public string_class() : base(">") { } - - public override runtimeResult execute(item[] args) - { - context internalContext = base.generateContext(); - internalContext.symbolTable.set("empty", new @string(string.Empty)); - internalContext.symbolTable.set("concatenate", new predefined_function("string_class_concatenate", concatenate, new string[1] { "values" })); - - return new runtimeResult().success(new @object(name, internalContext).setPosition(startPos, endPos).setContext(context)); - } - - private runtimeResult concatenate(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item values = context.symbolTable.get("values"); - if (values is not list && values is not array) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Values must be a list or array", context)); - - item[] values_ = (values is list) ? ((list)values).storedValue.ToArray() : ((array)values).storedValue; - string[] strings = new string[values_.Length]; - for (int i = 0; i < strings.Length; i++) - { - if (values_[i] is not @string && values_[i] is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "All items in values must be a string or character_list", context)); - strings[i] = (values_[i] is @string) ? ((@string)values_[i]).storedValue : string.Join("", ((character_list)values_[i]).storedValue); - } - - return result.success(new @string(string.Concat(strings))); - } - - public override item copy() { return new string_class().setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; return obj is string_class; } - } - - public class character_list_class : baseFunction - { - public override bool UPDATEONACCESS => true; - - public character_list_class() : base(">") { } - - public override runtimeResult execute(item[] args) - { - context internalContext = base.generateContext(); - internalContext.symbolTable.set("empty", new character_list(string.Empty)); - internalContext.symbolTable.set("concatenate", new predefined_function("character_list_class_concatenate", concatenate, new string[1] { "values" })); - - return new runtimeResult().success(new @object(name, internalContext).setPosition(startPos, endPos).setContext(context)); - } - - private runtimeResult concatenate(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - - item values = context.symbolTable.get("values"); - if (values is not list && values is not array) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Values must be a list or array", context)); - - item[] values_ = (values is list) ? ((list)values).storedValue.ToArray() : ((array)values).storedValue; - string[] strings = new string[values_.Length]; - for (int i = 0; i < strings.Length; i++) - { - if (values_[i] is not @string && values_[i] is not character_list) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "All items in values must be a string or character_list", context)); - strings[i] = (values_[i] is @string) ? ((@string)values_[i]).storedValue : string.Join("", ((character_list)values_[i]).storedValue); - } - - return result.success(new character_list(string.Concat(strings))); - } - - public override item copy() { return new character_list_class().setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; return obj is character_list_class; } - } - - public class random : baseFunction - { - public override bool UPDATEONACCESS => true; - - private Random random_; - public random() : base(">") - { random_ = new Random(); } - - public override runtimeResult execute(item[] args) - { - context internalContext = base.generateContext(); - internalContext.symbolTable.set("get", new predefined_function("random_get", randomNumber, new string[0])); - internalContext.symbolTable.set("get_limited", new predefined_function("random_get_limited", randomNumberLimited, new string[2] { "minimum", "maximum" })); - internalContext.symbolTable.set("get_float", new predefined_function("random_get_float", randomNumberFloat, new string[0])); - - return new runtimeResult().success(new @object(name, internalContext).setPosition(startPos, endPos).setContext(context)); - } - - private runtimeResult randomNumber(context context, position[] positions) { return new runtimeResult().success(new integer(random_.Next())); } - - private runtimeResult randomNumberLimited(context context, position[] positions) - { - runtimeResult result = new runtimeResult(); - item minimum = context.symbolTable.get("minimum"); - item maximum = context.symbolTable.get("maximum"); - - if (minimum is not integer && minimum is not @float) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Minimum must be an integer or float", context)); - if (maximum is not integer && maximum is not @float) - return result.failure(new runtimeError(positions[0], positions[1], RT_TYPE, "Maximum must be an integer or float", context)); - - int min = (minimum is integer) ? ((integer)minimum).storedValue : (int)((@float)minimum).storedValue; - int max = (maximum is integer) ? ((integer)maximum).storedValue : (int)((@float)maximum).storedValue; - return result.success(new integer(random_.Next(min, max))); - } - - private runtimeResult randomNumberFloat(context context, position[] positions) { return new runtimeResult().success(new @float(random_.NextSingle())); } - - public override item copy() { return new random().setPosition(startPos, endPos).setContext(context); } - - public override string ToString() { return $""; } - public override bool ItemEquals(item obj, out error? error) { error = null; return obj is random; } - } -} diff --git a/Libraries/std/std.csproj b/Libraries/std/std.csproj deleted file mode 100644 index f4d0368..0000000 --- a/Libraries/std/std.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - net7.0 - win-x64 - disable - enable - - - - false - false - - - - - - - diff --git a/README.md b/README.md index 3d32bd7..c05fd93 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ # The `ezr²` Programming Language **ezr², or ezrSquared when you can't use the `²` symbol - is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#!** -All information and documentation about ezr² has been moved to ***https://uralstech.github.io/ezrSquared***! +More information and documentation about ezr² is available at ***https://uralstech.github.io/ezrSquared***! + +## What's the 'ezrSquared-re' branch? +ezrSquared is being rewritten from the ground up! Expect more features, better performance and better code documentation! ## Contributing ezr² is an open source project and welcomes contributions from anyone who wants to improve it. diff --git a/Tests/fullTest.ezr2 b/Tests/fullTest.ezr2 deleted file mode 100644 index 0595853..0000000 --- a/Tests/fullTest.ezr2 +++ /dev/null @@ -1,205 +0,0 @@ -@ "in" -show("----item test----") -item a: 2 -show(a) -item a: 3 -show(a) -show("----and/or test----") -show(a and 6) -show(a and 0) -show(a or 6) -show(a or 0) -show("----invert test----") -show(invert a) -show(invert true) -show(invert 0) -show(invert 65) -show("----if test----") -if a do -show("sds") -else do -show("sd") -end -if invert a do -show("sds") -else do -show("sd") -end -if invert a do -show("sds") -else if invert 1 do -show("sd") -else do -show("dssdf") -end -show("----count test----") -count from 0 to 10 as i do -show("sd") -end -count from 0 to 10 step 2 as i do -show("sd_") -end -count from 0 to 10 as i do -if i = 5 do -skip -end -show("sd" + i.as_string()) -end -count from 0 to 10 as i do -if i = 5 do -stop -end -show("sd2" + i.as_string()) -end -show("----while test----") -while a do -show(a) -item a: a - 1 -end -item a: 30 -while a do -item a: a - 1 -if a = 20 do -skip -end -show(a) -end -item a: 30 -while a do -item a: a - 1 -if a = 20 do -stop -end -show(a) -end -show("----func test----") -function name with args do -show(args) -end -function nameno do -show("noargs") -end -function retu do -return 2 -end -show(name("fdgffdf")) -show(nameno()) -show(retu()) -show("----try test----") -try do -1/0 -end -try do -1/0 -error do -show("errrrr") -end -try do -1/0 -error "math-error" do -show("errrrr") -error do -show("sdfsdf") -end -try do -1/0 -error "MAH" do -show("errrrr") -error do -show("sdfsdf") -end -@ show("----include/as test----") -@ include "time.py" -@ show(time.time()) -@ show(time.localTime(time.time())) -@ show(time.localTime(time.time()).readableTime()) -@ include "time.py" as t -@ show(t.time()) -@ show(t.localTime(t.time())) -@ show(t.localTime(t.time()).readableTime()) -show("----global test----") -function ChangeA with NewA do -show("a: " + a.as_string()) -function localChangeA with localNewA do -function local2ChangeA with local2NewA do -global item a: local2NewA -end -local2ChangeA(localNewA) -show("a: " + a.as_string()) -end -localChangeA(NewA) -end -ChangeA(123124) -show("----in test----") -show("sd" in (1,2,3)) -show("sd" in (1,"sd",3)) -show("sd" in [1,2,3]) -show("sd" in [1,"sd",3]) -show("----array test----") -show((1)) -show((1,)) -show((1,2,3)) -show((1,2,3)<=1) -show((1,2,3)*6) -show(((1,2,3)*6)/2) -show("----list test----") -show([1]) -show([1,2,3]) -show([1,2,3]<=1) -item a: [12,5,3] -show(a) -a + 2 -show(a) -a + [3,[3,4],4] -show(a) -show(a<=5<=1) -a - 5 -show(a) -show(a*2) -show(a/2) -show(a=a) -show(a!a) -show(a=[1,2,3]) -show(a![1,2,3]) -show("----dict test----") -show({1:2}) -show({1:2, 3:4, 5:6}) -show({1:2, 3:4, 5:6}<=1) -show({1:2, 3:4, 5:6}<=5) -item a: {1:2, 3:4, 5:6} -show(a) -a + {2:6} -show(a) -a + {1:8, 8:[1,2,3,(1,2,3)]} -show(a) -show(a<=8<=1) -show(a<=8<=3) -a - 8 -show(a) -show(a/2) -show(a=a) -show(a!a) -show(a={1:2, 3:4, 5:6}) -show(a!{1:2, 3:4, 5:6}) -show("----obj test----") -object obj do -item a: 4 -function name with args do -show("obj") -show(args) -end -end -object objtoo with args do -item a: args -function name do -show("obj") -show(args) -end -end -show(obj()) -show(obj().a) -show(obj().name("fsd")) -show(objtoo("dsfsfdfdsfsd")) -show(objtoo("dsfsfdfdsfsd").a) -show(objtoo("dsfsfdfdsfsd").name()) -show("----test complete----") \ No newline at end of file diff --git a/Offline Site/config.yml b/docs/offline/config.yml similarity index 61% rename from Offline Site/config.yml rename to docs/offline/config.yml index 7fec40c..a15dfdf 100644 --- a/Offline Site/config.yml +++ b/docs/offline/config.yml @@ -1,3 +1,3 @@ absolute_base: https://uralstech.github.io/ezrSquared/ source_dir: D:/Code/csharp/ezrSquared/docs/_site/ -out_dir: D:/Code/csharp/ezrSquared/Offline Site/ezrSquared Offline/ \ No newline at end of file +out_dir: D:/Code/csharp/ezrSquared/docs/offline/_site/ \ No newline at end of file diff --git a/Offline Site/jekyll_offline.rb b/docs/offline/jekyll_offline.rb similarity index 100% rename from Offline Site/jekyll_offline.rb rename to docs/offline/jekyll_offline.rb diff --git a/Offline Site/lib_rellinks.rb b/docs/offline/lib_rellinks.rb similarity index 100% rename from Offline Site/lib_rellinks.rb rename to docs/offline/lib_rellinks.rb diff --git a/Offline Site/template.rhtml b/docs/offline/template.rhtml similarity index 100% rename from Offline Site/template.rhtml rename to docs/offline/template.rhtml diff --git a/ezr.cs b/ezr.cs deleted file mode 100644 index bb4310f..0000000 --- a/ezr.cs +++ /dev/null @@ -1,3590 +0,0 @@ -using ezrSquared.General; -using ezrSquared.Errors; -using ezrSquared.Nodes; -using ezrSquared.Values; -using ezrSquared.Helpers; -using static ezrSquared.Constants.constants; -using System.Collections.Generic; -using System.Reflection; -using System.Linq; -using System.IO; -using System; - -namespace ezrSquared.Main -{ - public class ezr - { - public class lexer - { - private string file; - private string input; - private position pos; - private char? currentChar; - - public lexer(string file, string input) - { - this.file = file; - this.input = input; - - pos = new position(-1, 0, -1, this.file, this.input); - currentChar = null; - advance(); - } - - private void advance() - { - pos.advance(currentChar); - currentChar = (pos.index < input.Length) ? input[pos.index] : null; - } - - private void reverse(int count = 1) - { - pos.reverse(currentChar, count); - currentChar = (pos.index < input.Length) ? input[pos.index] : null; - } - - public token[] compileTokens(out error? error) - { - token[] emptyTokenArray = new token[0]; - List tokens = new List(); - error = null; - - while (currentChar != null) - { - if (" \t".Contains(currentChar.ToString())) - advance(); - else if (currentChar == '@') - skipComment(); - else if (currentChar == '\'') - { - tokens.Add(compileString((char)currentChar, TOKENTYPE.CHARLIST, out error)); - if (error != null) return emptyTokenArray; - } - else if (currentChar == '"') - { - tokens.Add(compileString((char)currentChar, TOKENTYPE.STRING, out error)); - if (error != null) return emptyTokenArray; - } - else if (currentChar == ':') - tokens.Add(compileColon()); - else if (currentChar == '<') - tokens.Add(compileLessThan()); - else if (currentChar == '>') - tokens.Add(compileGreaterThan()); - else if (currentChar == '-') - tokens.Add(compileMinus()); - else if (LETTERS_UNDERSCORE.Contains((char)currentChar)) - tokens.Add(compileIdentifier()); - else if (DIGITS.Contains((char)currentChar)) - { - token? token = compileNumber(out error); - if (error != null) return emptyTokenArray; - tokens.Add(token); - } - else if (";\n".Contains(currentChar.ToString())) - { - tokens.Add(new token(TOKENTYPE.NEWLINE, pos)); - advance(); - } - else if (currentChar == '+') - { - tokens.Add(new token(TOKENTYPE.PLUS, pos)); - advance(); - } - else if (currentChar == '*') - { - tokens.Add(new token(TOKENTYPE.MUL, pos)); - advance(); - } - else if (currentChar == '/') - { - tokens.Add(new token(TOKENTYPE.DIV, pos)); - advance(); - } - else if (currentChar == '%') - { - tokens.Add(new token(TOKENTYPE.MOD, pos)); - advance(); - } - else if (currentChar == '^') - { - tokens.Add(new token(TOKENTYPE.POW, pos)); - advance(); - } - else if (currentChar == '=') - { - tokens.Add(new token(TOKENTYPE.ISEQUAL, pos)); - advance(); - } - else if (currentChar == '!') - { - tokens.Add(new token(TOKENTYPE.NOTEQUAL, pos)); - advance(); - } - else if (currentChar == ',') - { - tokens.Add(new token(TOKENTYPE.COMMA, pos)); - advance(); - } - else if (currentChar == '.') - { - tokens.Add(new token(TOKENTYPE.PERIOD, pos)); - advance(); - } - else if (currentChar == '(') - { - tokens.Add(new token(TOKENTYPE.LPAREN, pos)); - advance(); - } - else if (currentChar == ')') - { - tokens.Add(new token(TOKENTYPE.RPAREN, pos)); - advance(); - } - else if (currentChar == '[') - { - tokens.Add(new token(TOKENTYPE.LSQUARE, pos)); - advance(); - } - else if (currentChar == ']') - { - tokens.Add(new token(TOKENTYPE.RSQUARE, pos)); - advance(); - } - else if (currentChar == '{') - { - tokens.Add(new token(TOKENTYPE.LCURLY, pos)); - advance(); - } - else if (currentChar == '}') - { - tokens.Add(new token(TOKENTYPE.RCURLY, pos)); - advance(); - } - else if (currentChar == '&') - { - tokens.Add(new token(TOKENTYPE.BITAND, pos)); - advance(); - } - else if (currentChar == '|') - { - tokens.Add(new token(TOKENTYPE.BITOR, pos)); - advance(); - } - else if (currentChar == '\\') - { - tokens.Add(new token(TOKENTYPE.BITXOR, pos)); - advance(); - } - else if (currentChar == '~') - { - tokens.Add(new token(TOKENTYPE.BITNOT, pos)); - advance(); - } - else - { - position startPos = pos.copy(); - char char_ = (char)currentChar; - advance(); - - error = new unknownCharacterError($"'{char_}'", startPos, pos); - return emptyTokenArray; - } - } - - tokens.Add(new token(TOKENTYPE.ENDOFFILE, pos)); - return tokens.ToArray(); - } - - private void skipComment() - { - advance(); - while (currentChar != '\n' && currentChar != null) - advance(); - } - - private token compileColon() - { - position startPos = pos.copy(); - advance(); - - if (currentChar == '+') - { - advance(); - return new token(TOKENTYPE.ASSIGNPLUS, startPos, pos); - } - else if (currentChar == '-') - { - advance(); - return new token(TOKENTYPE.ASSIGNMINUS, startPos, pos); - } - else if (currentChar == '*') - { - advance(); - return new token(TOKENTYPE.ASSIGNMUL, startPos, pos); - } - else if (currentChar == '/') - { - advance(); - return new token(TOKENTYPE.ASSIGNDIV, startPos, pos); - } - else if (currentChar == '%') - { - advance(); - return new token(TOKENTYPE.ASSIGNMOD, startPos, pos); - } - else if (currentChar == '^') - { - advance(); - return new token(TOKENTYPE.ASSIGNPOW, startPos, pos); - } - else if (currentChar == '&') - { - advance(); - return new token(TOKENTYPE.ASSIGNBITAND, startPos, pos); - } - else if (currentChar == '|') - { - advance(); - return new token(TOKENTYPE.ASSIGNBITOR, startPos, pos); - } - else if (currentChar == '\\') - { - advance(); - return new token(TOKENTYPE.ASSIGNBITXOR, startPos, pos); - } - else if (currentChar == '<') - { - advance(); - return new token(TOKENTYPE.ASSIGNBITLSHIFT, startPos, pos); - } - else if (currentChar == '>') - { - advance(); - return new token(TOKENTYPE.ASSIGNBITRSHIFT, startPos, pos); - } - - return new token(TOKENTYPE.COLON, startPos, pos); - } - - private token compileLessThan() - { - position startPos = pos.copy(); - advance(); - - if (currentChar == '=') - { - advance(); - return new token(TOKENTYPE.LESSTHANOREQUAL, startPos, pos); - } - else if (currentChar == '<') - { - advance(); - return new token(TOKENTYPE.BITLSHIFT, startPos, pos); - } - - return new token(TOKENTYPE.LESSTHAN, startPos, pos); - } - - private token compileGreaterThan() - { - position startPos = pos.copy(); - advance(); - - if (currentChar == '=') - { - advance(); - return new token(TOKENTYPE.GREATERTHANOREQUAL, startPos, pos); - } - else if (currentChar == '>') - { - advance(); - return new token(TOKENTYPE.BITRSHIFT, startPos, pos); - } - - return new token(TOKENTYPE.GREATERTHAN, startPos, pos); - } - - private token compileMinus() - { - position startPos = pos.copy(); - advance(); - - if (currentChar == '>') - { - advance(); - return new token(TOKENTYPE.ARROW, startPos, pos); - } - - return new token(TOKENTYPE.MINUS, startPos, pos); - } - - private token compileString(char stringChar, TOKENTYPE targetToken, out error? error) - { - error = null; - string stringToReturn = ""; - position startPos = pos.copy(); - bool escapeChar = false; - advance(); - - Dictionary escapeChars = new Dictionary() - { - { 'n', '\n' }, - { 't', '\t' }, - { 'r', '\r' } - }; - - while (currentChar != null && (currentChar != stringChar || escapeChar)) - { - if (escapeChar) - { - if (escapeChars.TryGetValue((char)currentChar, out char escaped)) - stringToReturn += escaped; - else - stringToReturn += currentChar; - - escapeChar = false; - } - else - { - if (currentChar == '\\') - escapeChar = true; - else - stringToReturn += currentChar; - } - - advance(); - } - - position prevPosition = pos.copy(); - if (currentChar == null || currentChar != stringChar) - error = new invalidGrammarError($"Expected '{stringChar}'", prevPosition, pos); - - advance(); - return new token(targetToken, stringToReturn, startPos, pos); - } - - private token compileIdentifier() - { - string idString = ""; - position startPos = pos.copy(); - - while (currentChar != null && ALPHANUM_UNDERSCORE.Contains((char)currentChar)) - { - idString += currentChar; - advance(); - } - - TOKENTYPE tokenType = KEYWORDS.Contains(idString) ? TOKENTYPE.KEY : (QEYWORDS.Contains(idString) ? TOKENTYPE.QEY : TOKENTYPE.ID); - return new token(tokenType, idString, startPos, pos); - } - - private token? compileNumber(out error? error) - { - error = null; - string numberString = ""; - position startPos = pos.copy(); - int periodCount = 0; - - while (currentChar != null && DIGITS_PERIOD.Contains((char)currentChar)) - { - bool wasCharPeriod = false; - if (currentChar == '.') - { - if (periodCount == 1) - break; - - wasCharPeriod = true; - periodCount++; - } - - numberString += currentChar; - advance(); - - if (wasCharPeriod && (currentChar == null || !DIGITS.Contains((char)currentChar))) - { - numberString = numberString.Remove(numberString.Length - 1); - reverse(); - - periodCount--; - break; - } - } - - if (periodCount == 0 && int.TryParse(numberString, out int int_)) - return new token(TOKENTYPE.INT, int_, startPos, pos); - return new token(TOKENTYPE.FLOAT, float.Parse(numberString), startPos, pos); - } - } - - public class parser - { - private token[] tokens; - private token currentToken; - private int index; - - private bool usingQSyntax = false; - - public parser(token[] tokens) - { - this.tokens = tokens; - this.index = -1; - - advance(); - } - - private void advance() - { - index++; - updateCurrentToken(); - } - - private void reverse(int amount = 1) - { - index -= amount; - updateCurrentToken(); - } - - private void updateCurrentToken() - { - if (index >= 0 && index < tokens.Length) - currentToken = tokens[index]; - } - - public parseResult parse() - { - parseResult result = statements(); - if (result.error == null && currentToken.type != TOKENTYPE.ENDOFFILE) - return result.failure(new invalidGrammarError("Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', 'global', 'item', 'return', 'skip', 'stop', '!', '(', '[', '{', '+', '-' or '~'", currentToken.startPos, currentToken.endPos)); - return result; - } - - private bool isAssignmentTokenType(TOKENTYPE type) { return type == TOKENTYPE.ASSIGNPLUS || type == TOKENTYPE.ASSIGNMINUS || type == TOKENTYPE.ASSIGNMUL || type == TOKENTYPE.ASSIGNDIV || type == TOKENTYPE.ASSIGNMOD || type == TOKENTYPE.ASSIGNPOW || type == TOKENTYPE.ASSIGNBITAND || type == TOKENTYPE.ASSIGNBITOR || type == TOKENTYPE.ASSIGNBITXOR || type == TOKENTYPE.ASSIGNBITLSHIFT || type == TOKENTYPE.ASSIGNBITRSHIFT; } - - private int skipNewlines(parseResult result) - { - int newlineCount = 0; - while (currentToken.type == TOKENTYPE.NEWLINE) - { - result.registerAdvance(); - advance(); - - newlineCount++; - } - - return newlineCount; - } - - private parseResult statements() - { - parseResult result = new parseResult(); - List statements = new List(); - position startPos = currentToken.startPos.copy(); - skipNewlines(result); - - node statement = result.register(this.statement()); - if (result.error != null) - return result; - statements.Add(statement); - - bool moreStatements = true; - while (true) - { - int newlineCount = skipNewlines(result); - if (newlineCount == 0 || - currentToken.matchString(TOKENTYPE.KEY, "end") || - currentToken.matchString(TOKENTYPE.KEY, "else") || - currentToken.matchString(TOKENTYPE.KEY, "error") || - (usingQSyntax && (currentToken.matchString(TOKENTYPE.QEY, "f") || - currentToken.matchString(TOKENTYPE.QEY, "l") || - currentToken.matchString(TOKENTYPE.QEY, "e") || - currentToken.matchString(TOKENTYPE.QEY, "s"))) || - currentToken.type == TOKENTYPE.ENDOFFILE) - moreStatements = false; - - if (!moreStatements) break; - - statement = result.register(this.statement()); - if (result.error != null) - return result; - statements.Add(statement); - } - - return result.success(new arrayNode(statements.ToArray(), startPos, currentToken.endPos.copy())); - } - - private parseResult statement() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (currentToken.matchString(TOKENTYPE.KEY, "return")) - { - result.registerAdvance(); - advance(); - - node? expression_ = result.tryRegister(this.expression()); - if (expression_ == null) - { - reverse(result.reverseCount); - return result.success(new returnNode(expression_, startPos, currentToken.startPos.copy())); - } - else - return result.success(new returnNode(expression_, startPos, currentToken.endPos.copy())); - } - else if (currentToken.matchString(TOKENTYPE.KEY, "skip")) - { - result.registerAdvance(); - advance(); - - return result.success(new skipNode(startPos, currentToken.startPos.copy())); - } - else if (currentToken.matchString(TOKENTYPE.KEY, "stop")) - { - result.registerAdvance(); - advance(); - - return result.success(new stopNode(startPos, currentToken.startPos.copy())); - } - - node expression = result.register(this.expression()); - if (result.error != null) - return result.failure(new invalidGrammarError("Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', 'global', 'item', 'return', 'skip', 'stop', '!', '(', '[', '{', '+', '-' or '~'", currentToken.startPos, currentToken.endPos)); - return result.success(expression); - } - - private parseResult expression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - bool isGlobal = false; - if (currentToken.type == TOKENTYPE.NOTEQUAL) - { - bool wasUsingQSyntax = usingQSyntax; - usingQSyntax = true; - - result.registerAdvance(); - advance(); - - if (currentToken.matchString(TOKENTYPE.QEY, "g") || currentToken.matchString(TOKENTYPE.QEY, "d")) - { - if (currentToken.matchString(TOKENTYPE.QEY, "g")) - { - isGlobal = true; - result.registerAdvance(); - advance(); - } - - if (currentToken.matchString(TOKENTYPE.QEY, "d")) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - token varName = currentToken; - result.registerAdvance(); - advance(); - - node accessNode = new variableAccessNode(varName, isGlobal, varName.startPos.copy(), varName.endPos.copy()); - bool isSimple = true; - if (currentToken.type == TOKENTYPE.PERIOD) - { - isSimple = false; - - while (currentToken.type == TOKENTYPE.PERIOD) - { - token operatorToken_ = currentToken; - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - token right = currentToken; - result.registerAdvance(); - advance(); - - accessNode = new binaryOperationNode(accessNode, new variableAccessNode(right, false, right.startPos.copy(), right.endPos.copy()), operatorToken_, accessNode.startPos.copy(), right.endPos.copy()); - } - } - - token? operatorToken = null; - if (isAssignmentTokenType(currentToken.type)) - { - operatorToken = currentToken; - result.registerAdvance(); - advance(); - } - - node expression = result.register(this.expression()); - if (result.error != null) return result; - - if (!wasUsingQSyntax) - usingQSyntax = false; - - if (isSimple) - return result.success(new simpleVariableAssignNode(varName, operatorToken, expression, isGlobal, startPos, currentToken.endPos.copy())); - else if (isGlobal) - return result.failure(new invalidGrammarError("Variable assignment in objects cannot be globalized", startPos, currentToken.endPos)); - else - return result.success(new objectVariableAssignNode(accessNode, varName, operatorToken, expression, startPos, currentToken.endPos.copy())); - } - else if (isGlobal) - { - isGlobal = false; - reverse(result.advanceCount); - } - } - else - reverse(result.advanceCount); - - if (!wasUsingQSyntax) - usingQSyntax = false; - } - - if (currentToken.matchString(TOKENTYPE.KEY, "global")) - { - isGlobal = true; - result.registerAdvance(); - advance(); - } - - if (currentToken.matchString(TOKENTYPE.KEY, "item")) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - token varName = currentToken; - result.registerAdvance(); - advance(); - - node accessNode = new variableAccessNode(varName, isGlobal, varName.startPos.copy(), varName.endPos.copy()); - bool isSimple = true; - if (currentToken.type == TOKENTYPE.PERIOD) - { - isSimple = false; - - while (currentToken.type == TOKENTYPE.PERIOD) - { - token operatorToken_ = currentToken; - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - token right = currentToken; - result.registerAdvance(); - advance(); - - accessNode = new binaryOperationNode(accessNode, new variableAccessNode(right, false, right.startPos.copy(), right.endPos.copy()), operatorToken_, accessNode.startPos.copy(), right.endPos.copy()); - varName = right; - } - } - - if (currentToken.type != TOKENTYPE.COLON && !isAssignmentTokenType(currentToken.type)) - return result.failure(new invalidGrammarError("Expected ':', ':+', ':-', ':*', ':/', ':%', ':^', ':&', ':|', ':\\', ':<' or ':>'", currentToken.startPos, currentToken.endPos)); - token operatorToken = currentToken; - result.registerAdvance(); - advance(); - - node expression = result.register(this.expression()); - if (result.error != null) return result; - - if (isSimple) - return result.success(new simpleVariableAssignNode(varName, operatorToken, expression, isGlobal, startPos, currentToken.endPos.copy())); - else if (isGlobal) - return result.failure(new invalidGrammarError("Variable assignment in objects cannot be globalized", startPos, currentToken.endPos)); - else - return result.success(new objectVariableAssignNode(accessNode, varName, operatorToken, expression, startPos, currentToken.endPos.copy())); - } - else if (isGlobal) - reverse(result.advanceCount); - - node node = result.register(binaryOperation(compExpression, new TypeValuePair[] { new TypeValuePair(TOKENTYPE.KEY, "and"), new TypeValuePair(TOKENTYPE.KEY, "or" ) })); - if (result.error != null) - return result.failure(new invalidGrammarError("Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', 'global', 'item', '!', '(', '[', '{', '+', '-' or '~'", currentToken.startPos, currentToken.endPos)); - return result.success(node); - } - - private parseResult compExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (currentToken.type == TOKENTYPE.NOTEQUAL) - { - bool wasUsingQSyntax = usingQSyntax; - usingQSyntax = true; - result.registerAdvance(); - advance(); - - if (currentToken.matchString(TOKENTYPE.QEY, "v")) - { - token operatorToken = currentToken; - operatorToken.type = TOKENTYPE.KEY; - result.registerAdvance(); - advance(); - - node node_ = result.register(compExpression()); - if (result.error != null) return result; - - if (!wasUsingQSyntax) - usingQSyntax = false; - return result.success(new unaryOperationNode(node_, operatorToken, startPos, currentToken.endPos.copy())); - } - else - reverse(result.advanceCount); - - if (!wasUsingQSyntax) - usingQSyntax = false; - } - - if (currentToken.matchString(TOKENTYPE.KEY, "invert")) - { - token operatorToken = currentToken; - result.registerAdvance(); - advance(); - - node node_ = result.register(compExpression()); - if (result.error != null) return result; - - return result.success(new unaryOperationNode(node_, operatorToken, startPos, currentToken.endPos.copy())); - } - - node node = result.register(binaryOperation(bitOrExpression, new TypeValuePair[] { new TypeValuePair(TOKENTYPE.ISEQUAL), new TypeValuePair(TOKENTYPE.NOTEQUAL), new TypeValuePair(TOKENTYPE.LESSTHAN), new TypeValuePair(TOKENTYPE.GREATERTHAN), new TypeValuePair(TOKENTYPE.LESSTHANOREQUAL), new TypeValuePair(TOKENTYPE.GREATERTHANOREQUAL) })); - if (result.error != null) - return result.failure(new invalidGrammarError("Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', '!', '(', '[', '{', '+', '-' or '~'", currentToken.startPos, currentToken.endPos)); - return result.success(node); - } - - private parseResult bitOrExpression() { return binaryOperation(bitXOrExpression, new TypeValuePair[] { new TypeValuePair(TOKENTYPE.BITOR) }); } - - private parseResult bitXOrExpression() { return binaryOperation(bitAndExpression, new TypeValuePair[] { new TypeValuePair(TOKENTYPE.BITXOR) }); } - - private parseResult bitAndExpression() { return binaryOperation(bitShiftExpression, new TypeValuePair[] { new TypeValuePair(TOKENTYPE.BITAND) }); } - - private parseResult bitShiftExpression() { return binaryOperation(arithExpression, new TypeValuePair[] { new TypeValuePair(TOKENTYPE.BITLSHIFT), new TypeValuePair(TOKENTYPE.BITRSHIFT) }); } - - private parseResult arithExpression() { return binaryOperation(term, new TypeValuePair[] { new TypeValuePair(TOKENTYPE.PLUS), new TypeValuePair(TOKENTYPE.MINUS) }); } - - private parseResult term() { return binaryOperation(factor, new TypeValuePair[] { new TypeValuePair(TOKENTYPE.MUL), new TypeValuePair(TOKENTYPE.DIV), new TypeValuePair(TOKENTYPE.MOD) }); } - - private parseResult factor() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - token token = currentToken; - - if (token.type == TOKENTYPE.PLUS || token.type == TOKENTYPE.MINUS || token.type == TOKENTYPE.BITNOT) - { - result.registerAdvance(); - advance(); - - node node = result.register(factor()); - if (result.error != null) return result; - - return result.success(new unaryOperationNode(node, token, startPos, currentToken.endPos.copy())); - } - - return power(); - } - - private parseResult power() { return binaryOperation(inExpression, new TypeValuePair[] { new TypeValuePair(TOKENTYPE.POW) }); } - - private parseResult inExpression() { return binaryOperation(objectCall, new TypeValuePair[] { new TypeValuePair(TOKENTYPE.KEY, "in") }); } - - private parseResult objectCall() { return binaryOperation(call, new TypeValuePair[] { new TypeValuePair(TOKENTYPE.PERIOD) }, objectCall); } - - private parseResult call() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - node node = result.register(atom()); - if (result.error != null) return result; - - if (currentToken.type == TOKENTYPE.LPAREN) - { - result.registerAdvance(); - advance(); - - List argNodes = new List(); - if (currentToken.type == TOKENTYPE.RPAREN) - { - result.registerAdvance(); - advance(); - } - else - { - argNodes.Add(result.register(expression())); - if (result.error != null) - return result.failure(new invalidGrammarError("Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', 'global', 'item', '!', '(', '[', '{', '+', '-', '~' or ')'", currentToken.startPos, currentToken.endPos)); - - while (currentToken.type == TOKENTYPE.COMMA) - { - result.registerAdvance(); - advance(); - - argNodes.Add(result.register(expression())); - if (result.error != null) return result; - } - - if (currentToken.type != TOKENTYPE.RPAREN) return result.failure(new invalidGrammarError("Expected ',' or ')'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - } - - return result.success(new callNode(node, argNodes.ToArray(), startPos, currentToken.startPos.copy())); - } - - return result.success(node); - } - - private parseResult atom() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - token token = currentToken; - - if (token.type == TOKENTYPE.NOTEQUAL) - { - bool wasUsingQSyntax = usingQSyntax; - usingQSyntax = true; - node quickSyntaxAtom = result.register(this.quickSyntaxAtom()); - if (!wasUsingQSyntax) - usingQSyntax = false; - - if (result.error != null) return result; - return result.success(quickSyntaxAtom); - } - else if (token.type == TOKENTYPE.INT || token.type == TOKENTYPE.FLOAT) - { - result.registerAdvance(); - advance(); - - return result.success(new numberNode(token, startPos, currentToken.startPos.copy())); - } - else if (token.type == TOKENTYPE.STRING) - { - result.registerAdvance(); - advance(); - - return result.success(new stringNode(token, startPos, currentToken.startPos.copy())); - } - else if (token.type == TOKENTYPE.CHARLIST) - { - result.registerAdvance(); - advance(); - - return result.success(new charListNode(token, startPos, currentToken.startPos.copy())); - } - else if (token.type == TOKENTYPE.ID || currentToken.type == TOKENTYPE.QEY) - { - result.registerAdvance(); - advance(); - - return result.success(new variableAccessNode(token, false, startPos, currentToken.startPos.copy())); - } - else if (token.type == TOKENTYPE.LPAREN) - { - result.registerAdvance(); - advance(); - - node? expression = result.tryRegister(this.expression()); - if (expression == null || currentToken.type == TOKENTYPE.COMMA) - { - reverse(result.advanceCount); - - node arrayExpression = result.register(this.arrayExpression()); - if (result.error != null) return result; - - return result.success(arrayExpression); - } - - if (currentToken.type == TOKENTYPE.RPAREN) - { - result.registerAdvance(); - advance(); - - expression.startPos = startPos; - expression.endPos = currentToken.startPos.copy(); - return result.success(expression); - } - - return result.failure(new invalidGrammarError("Expected ',' or ')'", currentToken.startPos, currentToken.endPos)); - } - else if (token.type == TOKENTYPE.LSQUARE) - { - node listExpression = result.register(this.listExpression()); - if (result.error != null) return result; - return result.success(listExpression); - } - else if (token.type == TOKENTYPE.LCURLY) - { - node dictionaryExpression = result.register(this.dictionaryExpression()); - if (result.error != null) return result; - return result.success(dictionaryExpression); - } - else if (token.matchString(TOKENTYPE.KEY, "global")) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected 'item' or [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - token varName = currentToken; - result.registerAdvance(); - advance(); - - return result.success(new variableAccessNode(varName, true, startPos, currentToken.startPos.copy())); - } - else if (token.matchString(TOKENTYPE.KEY, "if")) - { - node ifExpression = result.register(this.ifExpression()); - if (result.error != null) return result; - return result.success(ifExpression); - } - else if (token.matchString(TOKENTYPE.KEY, "count")) - { - node countExpression = result.register(this.countExpression()); - if (result.error != null) return result; - return result.success(countExpression); - } - else if (token.matchString(TOKENTYPE.KEY, "while")) - { - node whileExpression = result.register(this.whileExpression()); - if (result.error != null) return result; - return result.success(whileExpression); - } - else if (token.matchString(TOKENTYPE.KEY, "try")) - { - node tryExpression = result.register(this.tryExpression()); - if (result.error != null) return result; - return result.success(tryExpression); - } - else if (token.matchString(TOKENTYPE.KEY, "function")) - { - node functionExpression = result.register(this.functionExpression()); - if (result.error != null) return result; - return result.success(functionExpression); - } - else if (token.matchString(TOKENTYPE.KEY, "special")) - { - node specialExpression = result.register(this.specialExpression()); - if (result.error != null) return result; - return result.success(specialExpression); - } - else if (token.matchString(TOKENTYPE.KEY, "object")) - { - node objectExpression = result.register(this.objectExpression()); - if (result.error != null) return result; - return result.success(objectExpression); - } - else if (token.matchString(TOKENTYPE.KEY, "include")) - { - node includeExpression = result.register(this.includeExpression()); - if (result.error != null) return result; - return result.success(includeExpression); - } - - return result.failure(new invalidGrammarError("Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', '!', '(', '[' or '{'", currentToken.startPos, currentToken.endPos)); - } - - private parseResult arrayExpression() - { - parseResult result = new parseResult(); - node[] elementNodes = new node[0]; - position startPos = currentToken.startPos.copy(); - - if (currentToken.type != TOKENTYPE.LPAREN) - return result.failure(new invalidGrammarError("Expected '('", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - if (currentToken.type == TOKENTYPE.RPAREN) - { - result.registerAdvance(); - advance(); - } - else - { - skipNewlines(result); - node firstElement = result.register(expression()); - if (result.error != null) - return result.failure(new invalidGrammarError("Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', 'global', 'item', '!', '(', '[', '{', '+', '-', '~' or ')'", currentToken.startPos, currentToken.endPos)); - - List nodeList = new List { firstElement }; - bool moreElements = true; - skipNewlines(result); - while (currentToken.type == TOKENTYPE.COMMA) - { - result.registerAdvance(); - advance(); - - skipNewlines(result); - node? node = result.tryRegister(expression()); - if (node == null) - { - reverse(result.reverseCount); - moreElements = false; - break; - } - nodeList.Add(node); - } - skipNewlines(result); - - if (currentToken.type != TOKENTYPE.RPAREN) - { - if (moreElements) - return result.failure(new invalidGrammarError("Expected ',' or ')'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', 'global', 'item', '!', '(', '[', '{', '+', '-', '~', or ')'", currentToken.startPos, currentToken.endPos)); - } - - elementNodes = nodeList.ToArray(); - result.registerAdvance(); - advance(); - } - - return result.success(new arrayNode(elementNodes, startPos, currentToken.startPos.copy())); - } - - private parseResult listExpression() - { - parseResult result = new parseResult(); - node[] elementNodes = new node[0]; - position startPos = currentToken.startPos.copy(); - - if (currentToken.type != TOKENTYPE.LSQUARE) - return result.failure(new invalidGrammarError("Expected '['", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - if (currentToken.type == TOKENTYPE.RSQUARE) - { - result.registerAdvance(); - advance(); - } - else - { - skipNewlines(result); - node element = result.register(expression()); - if (result.error != null) - return result.failure(new invalidGrammarError("Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', 'global', 'item', '!', '(', '[', '{', '+', '-', '~' or ']'", currentToken.startPos, currentToken.endPos)); - - List nodeList = new List { element }; - skipNewlines(result); - while (currentToken.type == TOKENTYPE.COMMA) - { - result.registerAdvance(); - advance(); - skipNewlines(result); - - element = result.register(expression()); - if (result.error != null) return result; - nodeList.Add(element); - } - skipNewlines(result); - - if (currentToken.type != TOKENTYPE.RSQUARE) - return result.failure(new invalidGrammarError("Expected ',' or ']'", currentToken.startPos, currentToken.endPos)); - - elementNodes = nodeList.ToArray(); - result.registerAdvance(); - advance(); - } - - return result.success(new listNode(elementNodes, startPos, currentToken.startPos.copy())); - } - - private parseResult dictionaryExpression() - { - - parseResult result = new parseResult(); - node[][] nodePairs = new node[0][]; - position startPos = currentToken.startPos.copy(); - - if (currentToken.type != TOKENTYPE.LCURLY) - return result.failure(new invalidGrammarError("Expected '{'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - if (currentToken.type == TOKENTYPE.RCURLY) - { - result.registerAdvance(); - advance(); - } - else - { - skipNewlines(result); - - node key = result.register(expression()); - if (result.error != null) return result; - - if (currentToken.type != TOKENTYPE.COLON) - return result.failure(new invalidGrammarError("Expected ':'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node value = result.register(expression()); - if (result.error != null) return result; - - List pairs = new List { new node[2] { key, value } }; - skipNewlines(result); - - while (currentToken.type == TOKENTYPE.COMMA) - { - result.registerAdvance(); - advance(); - - skipNewlines(result); - key = result.register(expression()); - if (result.error != null) return result; - - skipNewlines(result); - if (currentToken.type != TOKENTYPE.COLON) - return result.failure(new invalidGrammarError("Expected ':'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - skipNewlines(result); - value = result.register(expression()); - if (result.error != null) return result; - pairs.Add(new node[2] { key, value }); - } - - skipNewlines(result); - if (currentToken.type != TOKENTYPE.RCURLY) - return result.failure(new invalidGrammarError("Expected ',' or '}'", currentToken.startPos, currentToken.endPos)); - - nodePairs = pairs.ToArray(); - result.registerAdvance(); - advance(); - } - - return result.success(new dictionaryNode(nodePairs, startPos, currentToken.startPos.copy())); - } - - private parseResult ifExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - List cases = new List(); - node? elseCase = null; - - if (!currentToken.matchString(TOKENTYPE.KEY, "if")) - return result.failure(new invalidGrammarError("Expected 'if'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node condition = result.register(this.expression()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.KEY, "do")) - return result.failure(new invalidGrammarError("Expected 'do'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - result.registerAdvance(); - advance(); - - bodyNode = result.register(this.statements()); - if (result.error != null) return result; - cases.Add(new node[2] { condition, bodyNode }); - - if (currentToken.matchString(TOKENTYPE.KEY, "end")) - { - result.registerAdvance(); - advance(); - } - else - { - if (!currentToken.matchString(TOKENTYPE.KEY, "else")) - return result.failure(new invalidGrammarError("Expected 'else' or 'end'", currentToken.startPos, currentToken.endPos)); - - while (currentToken.matchString(TOKENTYPE.KEY, "else")) - { - result.registerAdvance(); - advance(); - - bool isElseIf = false; - if (currentToken.matchString(TOKENTYPE.KEY, "if")) - { - result.registerAdvance(); - advance(); - - condition = result.register(this.expression()); - if (result.error != null) return result; - isElseIf = true; - } - - if (!currentToken.matchString(TOKENTYPE.KEY, "do")) - { - if (isElseIf) - return result.failure(new invalidGrammarError("Expected 'do'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected 'if' or 'do'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node bodyNode_ = result.register(this.statements()); - if (result.error != null) return result; - if (!isElseIf) - { - elseCase = bodyNode_; - break; - } - else - { - bodyNode = bodyNode_; - cases.Add(new node[2] { condition, bodyNode }); - } - } - - if (!currentToken.matchString(TOKENTYPE.KEY, "end")) - { - if (elseCase == null) - return result.failure(new invalidGrammarError("Expected 'else' or 'end'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected 'end'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - } - - return result.success(new ifNode(cases.ToArray(), elseCase, true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(statement()); - if (result.error != null) return result; - cases.Add(new node[2] { condition, bodyNode }); - - while (currentToken.matchString(TOKENTYPE.KEY, "else")) - { - result.registerAdvance(); - advance(); - - bool isElseIf = false; - if (currentToken.matchString(TOKENTYPE.KEY, "if")) - { - result.registerAdvance(); - advance(); - - condition = result.register(this.expression()); - if (result.error != null) return result; - isElseIf = true; - } - - if (!currentToken.matchString(TOKENTYPE.KEY, "do")) - { - if (isElseIf) - return result.failure(new invalidGrammarError("Expected 'do'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected 'if' or 'do'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node body = result.register(statement()); - if (result.error != null) return result; - if (!isElseIf) - { - elseCase = body; - break; - } - else - { - bodyNode = body; - cases.Add(new node[2] { condition, bodyNode }); - } - } - - return result.success(new ifNode(cases.ToArray(), elseCase, false, startPos, currentToken.endPos.copy())); - } - - private parseResult countExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.KEY, "count")) - return result.failure(new invalidGrammarError("Expected 'count'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node? start = null; - if (currentToken.matchString(TOKENTYPE.KEY, "from")) - { - result.registerAdvance(); - advance(); - - start = result.register(expression()); - if (result.error != null) return result; - } - - if (!currentToken.matchString(TOKENTYPE.KEY, "to")) - { - if (start != null) - return result.failure(new invalidGrammarError("Expected 'to'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected 'from' or 'to'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node end = result.register(expression()); - if (result.error != null) return result; - - node? step = null; - if (currentToken.matchString(TOKENTYPE.KEY, "step")) - { - result.registerAdvance(); - advance(); - - step = result.register(expression()); - if (result.error != null) return result; - } - - token? variableName = null; - if (currentToken.matchString(TOKENTYPE.KEY, "as")) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - variableName = currentToken; - result.registerAdvance(); - advance(); - } - - if (!currentToken.matchString(TOKENTYPE.KEY, "do")) - { - if (step == null && variableName == null) - return result.failure(new invalidGrammarError("Expected 'step', 'as' or 'do'", currentToken.startPos, currentToken.endPos)); - else if (variableName == null) - return result.failure(new invalidGrammarError("Expected 'as' or 'do'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected 'do'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - result.registerAdvance(); - advance(); - - bodyNode = result.register(statements()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.KEY, "end")) - return result.failure(new invalidGrammarError("Expected 'end'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new countNode(variableName, start, end, step, bodyNode, true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(statement()); - if (result.error != null) return result; - - return result.success(new countNode(variableName, start, end, step, bodyNode, false, startPos, currentToken.endPos.copy())); - } - - private parseResult whileExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.KEY, "while")) - return result.failure(new invalidGrammarError("Expected 'while'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node condition = result.register(this.expression()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.KEY, "do")) - return result.failure(new invalidGrammarError("Expected 'do'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - result.registerAdvance(); - advance(); - - bodyNode = result.register(statements()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.KEY, "end")) - return result.failure(new invalidGrammarError("Expected 'end'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new whileNode(condition, bodyNode, true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(statement()); - if (result.error != null) return result; - - return result.success(new whileNode(condition, bodyNode, false, startPos, currentToken.endPos.copy())); - } - - private parseResult tryExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - List catches = new List(); - - if (!currentToken.matchString(TOKENTYPE.KEY, "try")) - return result.failure(new invalidGrammarError("Expected 'try'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - if (!currentToken.matchString(TOKENTYPE.KEY, "do")) - return result.failure(new invalidGrammarError("Expected 'do'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - result.registerAdvance(); - advance(); - - bodyNode = result.register(statements()); - if (result.error != null) return result; - - int emptyCatches_ = 0; - int emptyCatchIndex_ = -1; - - while (currentToken.matchString(TOKENTYPE.KEY, "error")) - { - result.registerAdvance(); - advance(); - - node? error = result.tryRegister(this.expression()); - if (error == null) - reverse(result.reverseCount); - - token? varName = null; - if (currentToken.matchString(TOKENTYPE.KEY, "as")) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - - varName = currentToken; - result.registerAdvance(); - advance(); - } - - if (!currentToken.matchString(TOKENTYPE.KEY, "do")) - { - if (error == null && varName == null) - return result.failure(new invalidGrammarError("Expected Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', 'global', 'item', '!', '(', '[', '{', '+', '-', '~', 'as' or 'do'", currentToken.startPos, currentToken.endPos)); - else if (varName == null) - return result.failure(new invalidGrammarError("Expected 'as' or 'do'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected 'do'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node body = result.register(statements()); - if (result.error != null) return result; - - if (error == null) - { - emptyCatches_++; - emptyCatchIndex_ = catches.Count; - } - - catches.Add(new object?[3] { error, varName, body }); - } - - if (emptyCatches_ > 0) - { - if (emptyCatches_ > 1) - return result.failure(new invalidGrammarError("There cannot be more than one empty 'error' statements", startPos, currentToken.endPos)); - if (emptyCatchIndex_ != catches.Count - 1) - return result.failure(new invalidGrammarError("Empty 'error' statements should always be declared last", startPos, currentToken.endPos)); - } - - if (!currentToken.matchString(TOKENTYPE.KEY, "end")) - return result.failure(new invalidGrammarError("Expected 'end'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new tryNode(bodyNode, catches.ToArray(), true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(statement()); - if (result.error != null) return result; - - int emptyCatches = 0; - int emptyCatchIndex = -1; - - while (currentToken.matchString(TOKENTYPE.KEY, "error")) - { - result.registerAdvance(); - advance(); - - node? error = result.tryRegister(this.expression()); - if (error == null) - reverse(result.reverseCount); - - token? varName = null; - if (currentToken.matchString(TOKENTYPE.KEY, "as")) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - - varName = currentToken; - result.registerAdvance(); - advance(); - } - - if (!currentToken.matchString(TOKENTYPE.KEY, "do")) - { - if (error == null && varName == null) - return result.failure(new invalidGrammarError("Expected Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', 'global', 'item', '!', '(', '[', '{', '+', '-', '~', 'as' or 'do'", currentToken.startPos, currentToken.endPos)); - else if (varName == null) - return result.failure(new invalidGrammarError("Expected 'as' or 'do'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected 'do'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node expression = result.register(statement()); - if (result.error != null) return result; - - if (error == null) - { - emptyCatches++; - emptyCatchIndex = catches.Count; - } - - catches.Add(new object?[3] { error, varName, expression }); - } - - if (emptyCatches > 0) - { - if (emptyCatches > 1) - return result.failure(new invalidGrammarError("There cannot be more than one empty 'error' statements", startPos, currentToken.endPos)); - if (emptyCatchIndex != catches.Count - 1) - return result.failure(new invalidGrammarError("Empty 'error' statements should always be declared last", startPos, currentToken.endPos)); - } - - return result.success(new tryNode(bodyNode, catches.ToArray(), false, startPos, currentToken.endPos.copy())); - } - - private parseResult functionExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.KEY, "function")) - return result.failure(new invalidGrammarError("Expected 'function'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - token? varName = null; - if (currentToken.type == TOKENTYPE.ID || currentToken.type == TOKENTYPE.QEY) - { - varName = currentToken; - result.registerAdvance(); - advance(); - } - - List argNames = new List(); - if (currentToken.matchString(TOKENTYPE.KEY, "with")) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - argNames.Add(currentToken); - result.registerAdvance(); - advance(); - - while (currentToken.type == TOKENTYPE.COMMA) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - argNames.Add(currentToken); - result.registerAdvance(); - advance(); - } - } - - if (!currentToken.matchString(TOKENTYPE.KEY, "do")) - { - if (argNames.Count == 0 && varName == null) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER], 'with' or 'do'", currentToken.startPos, currentToken.endPos)); - else if (argNames.Count == 0) - return result.failure(new invalidGrammarError("Expected 'with' or 'do'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected 'do'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - bodyNode = result.register(statements()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.KEY, "end")) - return result.failure(new invalidGrammarError("Expected 'end'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new functionDefinitionNode(varName, argNames.ToArray(), bodyNode, true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(expression()); - if (result.error != null) return result; - return result.success(new functionDefinitionNode(varName, argNames.ToArray(), bodyNode, false, startPos, currentToken.endPos.copy())); - } - - private parseResult specialExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.KEY, "special")) - return result.failure(new invalidGrammarError("Expected 'special'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - token varName = currentToken; - result.registerAdvance(); - advance(); - - if (!currentToken.matchString(TOKENTYPE.KEY, "do")) - return result.failure(new invalidGrammarError("Expected 'do'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - bodyNode = result.register(statements()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.KEY, "end")) - return result.failure(new invalidGrammarError("Expected 'end'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new specialDefinitionNode(varName, bodyNode, true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(expression()); - if (result.error != null) return result; - - return result.success(new specialDefinitionNode(varName, bodyNode, false, startPos, currentToken.endPos.copy())); - } - - private parseResult objectExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.KEY, "object")) - return result.failure(new invalidGrammarError("Expected 'object'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - token? inheritFrom = null; - if (currentToken.type == TOKENTYPE.ID || currentToken.type == TOKENTYPE.QEY) - { - inheritFrom = currentToken; - result.registerAdvance(); - advance(); - } - - token varName; - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - { - if (inheritFrom == null) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - else - { - varName = inheritFrom; - inheritFrom = null; - } - } - else - { - varName = currentToken; - result.registerAdvance(); - advance(); - } - - List argNames = new List(); - if (currentToken.matchString(TOKENTYPE.KEY, "with")) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - argNames.Add(currentToken); - result.registerAdvance(); - advance(); - - while (currentToken.type == TOKENTYPE.COMMA) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - argNames.Add(currentToken); - result.registerAdvance(); - advance(); - } - } - - if (!currentToken.matchString(TOKENTYPE.KEY, "do")) - { - if (inheritFrom == null && argNames.Count == 0) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER], 'with' or 'do'", currentToken.startPos, currentToken.endPos)); - if (argNames.Count == 0) - return result.failure(new invalidGrammarError("Expected 'with' or 'do'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected ',' or 'do'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - bodyNode = result.register(statements()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.KEY, "end")) - return result.failure(new invalidGrammarError("Expected 'end'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new objectDefinitionNode(varName, inheritFrom, argNames.ToArray(), bodyNode, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(expression()); - if (result.error != null) return result; - return result.success(new objectDefinitionNode(varName, inheritFrom, argNames.ToArray(), bodyNode, startPos, currentToken.endPos.copy())); - } - - private parseResult includeExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.KEY, "include")) - return result.failure(new invalidGrammarError("Expected 'include'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node? class_ = null; - node file = null; - bool dump = false; - - if (!currentToken.matchString(TOKENTYPE.KEY, "all") && currentToken.type != TOKENTYPE.COMMA ) - { - file = result.register(expression()); - if (result.error != null) return result; - } - else - { - dump = true; - result.registerAdvance(); - advance(); - } - - if (currentToken.matchString(TOKENTYPE.KEY, "from")) - { - result.registerAdvance(); - advance(); - - class_ = file; - file = result.register(expression()); - if (result.error != null) return result; - } - else if (file == null) - return result.failure(new invalidGrammarError("Expected 'from'", currentToken.startPos, currentToken.endPos)); - - token? nickname = null; - if (currentToken.matchString(TOKENTYPE.KEY, "as")) - { - result.registerAdvance(); - advance(); - - if (dump) - return result.failure(new invalidGrammarError("Cannot assign nickname when including all objects from script into active context.", currentToken.startPos, currentToken.endPos)); - - if (currentToken.type == TOKENTYPE.ID || currentToken.type == TOKENTYPE.QEY) - { - nickname = currentToken; - nickname.type = TOKENTYPE.ID; - } - else - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - } - - return result.success(new includeNode(file, class_, dump, nickname, startPos, currentToken.startPos.copy())); - } - - private parseResult quickSyntaxAtom() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (currentToken.type != TOKENTYPE.NOTEQUAL) - return result.failure(new invalidGrammarError("Expected '!'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - token token = currentToken; - if (token.matchString(TOKENTYPE.QEY, "g")) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected 'd' or [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - token varName = currentToken; - result.registerAdvance(); - advance(); - - return result.success(new variableAccessNode(varName, true, startPos, currentToken.startPos.copy())); - } - else if (token.matchString(TOKENTYPE.QEY, "f")) - { - node ifExpression = result.register(quickIfExpression()); - if (result.error != null) return result; - return result.success(ifExpression); - } - else if (token.matchString(TOKENTYPE.QEY, "c")) - { - node countExpression = result.register(quickCountExpression()); - if (result.error != null) return result; - return result.success(countExpression); - } - else if (token.matchString(TOKENTYPE.QEY, "w")) - { - node whileExpression = result.register(quickWhileExpression()); - if (result.error != null) return result; - return result.success(whileExpression); - } - else if (token.matchString(TOKENTYPE.QEY, "t")) - { - node tryExpression = result.register(quickTryExpression()); - if (result.error != null) return result; - return result.success(tryExpression); - } - else if (token.matchString(TOKENTYPE.QEY, "fd")) - { - node functionExpression = result.register(quickFunctionExpression()); - if (result.error != null) return result; - return result.success(functionExpression); - } - else if (token.matchString(TOKENTYPE.QEY, "sd")) - { - node specialExpression = result.register(quickSpecialExpression()); - if (result.error != null) return result; - return result.success(specialExpression); - } - else if (token.matchString(TOKENTYPE.QEY, "od")) - { - node objectExpression = result.register(quickObjectExpression()); - if (result.error != null) return result; - return result.success(objectExpression); - } - else if (token.matchString(TOKENTYPE.QEY, "i")) - { - node includeExpression = result.register(quickIncludeExpression()); - if (result.error != null) return result; - return result.success(includeExpression); - } - - return result.failure(new invalidGrammarError("Expected 'g', 'd', 'v', 'f', 'c', 'w', 't', 'fd', 'sd', 'od' or 'i'", currentToken.startPos, currentToken.endPos)); - } - - private parseResult quickIfExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - List cases = new List(); - node? elseCase = null; - - if (!currentToken.matchString(TOKENTYPE.QEY, "f")) - return result.failure(new invalidGrammarError("Expected 'f'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node condition = result.register(this.expression()); - if (result.error != null) return result; - - if (currentToken.type != TOKENTYPE.COLON) - return result.failure(new invalidGrammarError("Expected ':'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - result.registerAdvance(); - advance(); - - bodyNode = result.register(this.statements()); - if (result.error != null) return result; - cases.Add(new node[2] { condition, bodyNode }); - - if (currentToken.matchString(TOKENTYPE.QEY, "s")) - { - result.registerAdvance(); - advance(); - } - else - { - if (!currentToken.matchString(TOKENTYPE.QEY, "l") && !currentToken.matchString(TOKENTYPE.QEY, "e")) - return result.failure(new invalidGrammarError("Expected 'l', 'e' or 's'", currentToken.startPos, currentToken.endPos)); - - while (currentToken.matchString(TOKENTYPE.QEY, "l")) - { - result.registerAdvance(); - advance(); - - condition = result.register(this.expression()); - if (result.error != null) return result; - - if (currentToken.type != TOKENTYPE.COLON) - return result.failure(new invalidGrammarError("Expected ':'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - bodyNode = result.register(this.statements()); - if (result.error != null) return result; - cases.Add(new node[2] { condition, bodyNode }); - } - - if (currentToken.matchString(TOKENTYPE.QEY, "e")) - { - result.registerAdvance(); - advance(); - - elseCase = result.register(this.statements()); - if (result.error != null) return result; - } - - if (!currentToken.matchString(TOKENTYPE.QEY, "s")) - { - if (elseCase == null) - return result.failure(new invalidGrammarError("Expected 'e' or 's'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected 's'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - } - - return result.success(new ifNode(cases.ToArray(), elseCase, true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(statement()); - if (result.error != null) return result; - cases.Add(new node[2] { condition, bodyNode }); - - while (currentToken.matchString(TOKENTYPE.QEY, "l")) - { - result.registerAdvance(); - advance(); - - condition = result.register(this.expression()); - if (result.error != null) return result; - - if (currentToken.type != TOKENTYPE.COLON) - return result.failure(new invalidGrammarError("Expected ':'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - bodyNode = result.register(this.statement()); - if (result.error != null) return result; - cases.Add(new node[2] { condition, bodyNode }); - } - - if (currentToken.matchString(TOKENTYPE.QEY, "e")) - { - result.registerAdvance(); - advance(); - - elseCase = result.register(this.statement()); - if (result.error != null) return result; - } - - return result.success(new ifNode(cases.ToArray(), elseCase, false, startPos, currentToken.endPos.copy())); - } - - private parseResult quickCountExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.QEY, "c")) - return result.failure(new invalidGrammarError("Expected 'c'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node startOrEnd = result.register(expression()); - if (result.error != null) return result; - - node? start = null; - node end; - - if (currentToken.type == TOKENTYPE.ARROW) - { - result.registerAdvance(); - advance(); - - end = result.register(expression()); - if (result.error != null) return result; - start = startOrEnd; - } - else - end = startOrEnd; - - node? step = null; - if (currentToken.matchString(TOKENTYPE.QEY, "t")) - { - result.registerAdvance(); - advance(); - - step = result.register(expression()); - if (result.error != null) return result; - } - - token? variableName = null; - if (currentToken.matchString(TOKENTYPE.QEY, "n")) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - variableName = currentToken; - result.registerAdvance(); - advance(); - } - - if (currentToken.type != TOKENTYPE.COLON) - { - if (start == null && step == null && variableName == null) - return result.failure(new invalidGrammarError("Expected '->', 't', 'n' or ':'", currentToken.startPos, currentToken.endPos)); - if (step == null && variableName == null) - return result.failure(new invalidGrammarError("Expected 't', 'n' or ':'", currentToken.startPos, currentToken.endPos)); - else if (variableName == null) - return result.failure(new invalidGrammarError("Expected 'n' or ':'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected ':'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - result.registerAdvance(); - advance(); - - bodyNode = result.register(statements()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.QEY, "s")) - return result.failure(new invalidGrammarError("Expected 's'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new countNode(variableName, start, end, step, bodyNode, true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(statement()); - if (result.error != null) return result; - - return result.success(new countNode(variableName, start, end, step, bodyNode, false, startPos, currentToken.endPos.copy())); - } - - private parseResult quickWhileExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.QEY, "w")) - return result.failure(new invalidGrammarError("Expected 'w'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node condition = result.register(this.expression()); - if (result.error != null) return result; - - if (currentToken.type != TOKENTYPE.COLON) - return result.failure(new invalidGrammarError("Expected ':'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - result.registerAdvance(); - advance(); - - bodyNode = result.register(statements()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.QEY, "s")) - return result.failure(new invalidGrammarError("Expected 's'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new whileNode(condition, bodyNode, true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(statement()); - if (result.error != null) return result; - - return result.success(new whileNode(condition, bodyNode, false, startPos, currentToken.endPos.copy())); - } - - private parseResult quickTryExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - List catches = new List(); - - if (!currentToken.matchString(TOKENTYPE.QEY, "t")) - return result.failure(new invalidGrammarError("Expected 't'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - result.registerAdvance(); - advance(); - - bodyNode = result.register(statements()); - if (result.error != null) return result; - - int emptyCatches_ = 0; - int emptyCatchIndex_ = -1; - while (currentToken.matchString(TOKENTYPE.QEY, "e")) - { - result.registerAdvance(); - advance(); - - node? error = result.tryRegister(this.expression()); - if (error == null) - reverse(result.reverseCount); - - token? varName = null; - if (currentToken.type == TOKENTYPE.ARROW) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - - varName = currentToken; - result.registerAdvance(); - advance(); - } - - if (currentToken.type != TOKENTYPE.COLON) - { - if (error == null && varName == null) - return result.failure(new invalidGrammarError("Expected Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', 'global', 'item', '!', '(', '[', '{', '+', '-', '~', '->' or ':'", currentToken.startPos, currentToken.endPos)); - else if (varName == null) - return result.failure(new invalidGrammarError("Expected '->' or ':'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected ':'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node body = result.register(statements()); - if (result.error != null) return result; - - if (error == null) - { - emptyCatches_++; - emptyCatchIndex_ = catches.Count; - } - - catches.Add(new object?[3] { error, varName, body }); - } - - if (emptyCatches_ > 0) - { - if (emptyCatches_ > 1) - return result.failure(new invalidGrammarError("There cannot be more than one empty 'error' statements", startPos, currentToken.endPos)); - if (emptyCatchIndex_ != catches.Count - 1) - return result.failure(new invalidGrammarError("Empty 'error' statements should always be declared last", startPos, currentToken.endPos)); - } - - if (!currentToken.matchString(TOKENTYPE.QEY, "s")) - return result.failure(new invalidGrammarError("Expected 's'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new tryNode(bodyNode, catches.ToArray(), true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(statement()); - if (result.error != null) return result; - - int emptyCatches = 0; - int emptyCatchIndex = -1; - while (currentToken.matchString(TOKENTYPE.QEY, "e")) - { - result.registerAdvance(); - advance(); - - node? error = result.tryRegister(this.expression()); - if (error == null) - reverse(result.reverseCount); - - token? varName = null; - if (currentToken.type == TOKENTYPE.ARROW) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - - varName = currentToken; - result.registerAdvance(); - advance(); - } - - if (currentToken.type != TOKENTYPE.COLON) - { - if (error == null && varName == null) - return result.failure(new invalidGrammarError("Expected Expected [INT], [FLOAT], [STRING], [CHARACTER-LIST], [IDENTIFIER], 'if', 'count', 'while', 'try', 'function', 'special', 'object', 'include', 'invert', 'global', 'item', '!', '(', '[', '{', '+', '-', '~', '->' or ':'", currentToken.startPos, currentToken.endPos)); - else if (varName == null) - return result.failure(new invalidGrammarError("Expected '->' or ':'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected ':'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node expression = result.register(statement()); - if (result.error != null) return result; - - if (error == null) - { - emptyCatches++; - emptyCatchIndex = catches.Count; - } - - catches.Add(new object?[3] { error, varName, expression }); - } - - if (emptyCatches > 0) - { - if (emptyCatches > 1) - return result.failure(new invalidGrammarError("There cannot be more than one empty 'error' statements", startPos, currentToken.endPos)); - if (emptyCatchIndex != catches.Count - 1) - return result.failure(new invalidGrammarError("Empty 'error' statements should always be declared last", startPos, currentToken.endPos)); - } - - return result.success(new tryNode(bodyNode, catches.ToArray(), false, startPos, currentToken.endPos.copy())); - } - - private parseResult quickFunctionExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.QEY, "fd")) - return result.failure(new invalidGrammarError("Expected 'fd'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - token? varName = null; - if (currentToken.type == TOKENTYPE.ID || currentToken.type == TOKENTYPE.QEY) - { - varName = currentToken; - result.registerAdvance(); - advance(); - } - - List argNames = new List(); - if (currentToken.matchString(TOKENTYPE.QEY, "n")) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - argNames.Add(currentToken); - result.registerAdvance(); - advance(); - - while (currentToken.type == TOKENTYPE.COMMA) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - argNames.Add(currentToken); - result.registerAdvance(); - advance(); - } - } - - if (currentToken.type != TOKENTYPE.COLON) - { - if (argNames.Count == 0 && varName == null) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER], 'n' or ':'", currentToken.startPos, currentToken.endPos)); - else if (argNames.Count == 0) - return result.failure(new invalidGrammarError("Expected 'n' or ':'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected ':'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - bodyNode = result.register(statements()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.QEY, "s")) - return result.failure(new invalidGrammarError("Expected 's'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new functionDefinitionNode(varName, argNames.ToArray(), bodyNode, true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(expression()); - if (result.error != null) return result; - return result.success(new functionDefinitionNode(varName, argNames.ToArray(), bodyNode, false, startPos, currentToken.endPos.copy())); - } - - private parseResult quickSpecialExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.QEY, "sd")) - return result.failure(new invalidGrammarError("Expected 'sd'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - token varName = currentToken; - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.COLON) - return result.failure(new invalidGrammarError("Expected ':'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - bodyNode = result.register(statements()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.QEY, "s")) - return result.failure(new invalidGrammarError("Expected 's'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new specialDefinitionNode(varName, bodyNode, true, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(expression()); - if (result.error != null) return result; - - return result.success(new specialDefinitionNode(varName, bodyNode, false, startPos, currentToken.endPos.copy())); - } - - private parseResult quickObjectExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.QEY, "od")) - return result.failure(new invalidGrammarError("Expected 'od'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - token? inheritFrom = null; - if (currentToken.type == TOKENTYPE.ID || currentToken.type == TOKENTYPE.QEY) - { - inheritFrom = currentToken; - result.registerAdvance(); - advance(); - } - - token varName; - bool varNameIsQEY = false; - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - { - if (inheritFrom == null) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - else - { - varName = inheritFrom; - inheritFrom = null; - } - } - else - { - varNameIsQEY = currentToken.matchString(TOKENTYPE.QEY, "n"); - - varName = currentToken; - result.registerAdvance(); - advance(); - } - - List argNames = new List(); - bool matchedN = currentToken.matchString(TOKENTYPE.QEY, "n"); - if (matchedN || varNameIsQEY) - { - if (matchedN) - { - result.registerAdvance(); - advance(); - } - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - { - if (currentToken.type != TOKENTYPE.COLON && !matchedN) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER], 'n' or ':'", currentToken.startPos, currentToken.endPos)); - else if (matchedN) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - } - else if (currentToken.type != TOKENTYPE.COLON) - { - if (varNameIsQEY && !matchedN) - { - varName = inheritFrom; - inheritFrom = null; - } - - argNames.Add(currentToken); - result.registerAdvance(); - advance(); - - while (currentToken.type == TOKENTYPE.COMMA) - { - result.registerAdvance(); - advance(); - - if (currentToken.type != TOKENTYPE.ID && currentToken.type != TOKENTYPE.QEY) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - argNames.Add(currentToken); - result.registerAdvance(); - advance(); - } - } - } - - if (currentToken.type != TOKENTYPE.COLON) - { - if (inheritFrom == null && argNames.Count == 0) - return result.failure(new invalidGrammarError("Expected [IDENTIFIER], 'n' or ':'", currentToken.startPos, currentToken.endPos)); - if (argNames.Count == 0) - return result.failure(new invalidGrammarError("Expected 'n' or ':'", currentToken.startPos, currentToken.endPos)); - return result.failure(new invalidGrammarError("Expected ',' or ':'", currentToken.startPos, currentToken.endPos)); - } - result.registerAdvance(); - advance(); - - node bodyNode; - if (currentToken.type == TOKENTYPE.NEWLINE) - { - bodyNode = result.register(statements()); - if (result.error != null) return result; - - if (!currentToken.matchString(TOKENTYPE.QEY, "s")) - return result.failure(new invalidGrammarError("Expected 's'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - return result.success(new objectDefinitionNode(varName, inheritFrom, argNames.ToArray(), bodyNode, startPos, currentToken.startPos.copy())); - } - - bodyNode = result.register(expression()); - if (result.error != null) return result; - return result.success(new objectDefinitionNode(varName, inheritFrom, argNames.ToArray(), bodyNode, startPos, currentToken.endPos.copy())); - } - - private parseResult quickIncludeExpression() - { - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - if (!currentToken.matchString(TOKENTYPE.QEY, "i")) - return result.failure(new invalidGrammarError("Expected 'i'", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - - node? class_ = null; - node file = null; - bool dump = false; - - if (currentToken.type != TOKENTYPE.COMMA && !currentToken.matchString(TOKENTYPE.KEY, "all")) - { - file = result.register(expression()); - if (result.error != null) return result; - } - else - { - dump = true; - result.registerAdvance(); - advance(); - } - - if (currentToken.matchString(TOKENTYPE.QEY, "f")) - { - result.registerAdvance(); - advance(); - - class_ = file; - file = result.register(expression()); - if (result.error != null) return result; - } - else if (file == null) - return result.failure(new invalidGrammarError("Expected 'f'", currentToken.startPos, currentToken.endPos)); - - token? nickname = null; - if (currentToken.matchString(TOKENTYPE.QEY, "n")) - { - result.registerAdvance(); - advance(); - - if (dump) - return result.failure(new invalidGrammarError("Cannot assign nickname when including all objects from script into active context.", currentToken.startPos, currentToken.endPos)); - - if (currentToken.type == TOKENTYPE.ID || currentToken.type == TOKENTYPE.QEY) - { - nickname = currentToken; - nickname.type = TOKENTYPE.ID; - } - else - return result.failure(new invalidGrammarError("Expected [IDENTIFIER]", currentToken.startPos, currentToken.endPos)); - result.registerAdvance(); - advance(); - } - - return result.success(new includeNode(file, class_, dump, nickname, startPos, currentToken.startPos.copy())); - } - - private struct TypeValuePair - { - public TOKENTYPE type; - public object? value; - - public TypeValuePair(TOKENTYPE type) - { - this.type = type; - this.value = null; - } - - public TypeValuePair(TOKENTYPE type, string? value) - { - this.type = type; - this.value = value; - } - } - - private parseResult binaryOperation(Func funcA, TypeValuePair[] operations, Func? funcB = null) - { - if (funcB == null) funcB = funcA; - - parseResult result = new parseResult(); - position startPos = currentToken.startPos.copy(); - - node left = result.register(funcA.Invoke()); - if (result.error != null) return result; - - while (true) - { - bool changed = false; - for (int i = 0; i < operations.Length; i++) - { - if (operations[i].type == currentToken.type && ((operations[i].value != null && currentToken.value.ToString() == operations[i].value.ToString()) || (operations[i].value == null))) - { - token operatorToken = currentToken; - if (operatorToken.type == TOKENTYPE.QEY) - operatorToken.type = TOKENTYPE.KEY; - - result.registerAdvance(); - advance(); - - node right = result.register(funcB.Invoke()); - if (result.error != null) return result; - - left = new binaryOperationNode(left, right, operatorToken, startPos, currentToken.endPos.copy()); - changed = true; - } - } - - if (!changed) - break; - } - - return result.success(left); - } - } - - public class interpreter - { - public interpreter() { } - - public runtimeResult visit(node node, context context) - { - string nodeName = node.GetType().Name; - string methodName = $"visit_{nodeName}"; - MethodInfo? info = GetType().GetMethod(methodName, (BindingFlags.NonPublic | BindingFlags.Instance)); - if (info != null) - { - object result = info.Invoke(this, new object[] { node, context }); - return (runtimeResult)result; - } - - throw new Exception($"No {methodName} method defined!"); - } - - private runtimeResult visit_numberNode(numberNode node, context context) - { - if (node.valueToken.type == TOKENTYPE.INT) - return new runtimeResult().success(new integer((int)node.valueToken.value).setPosition(node.startPos, node.endPos).setContext(context)); - return new runtimeResult().success(new @float((float)node.valueToken.value).setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_stringNode(stringNode node, context context) - { - return new runtimeResult().success(new @string(node.valueToken.value.ToString()).setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_charListNode(charListNode node, context context) - { - return new runtimeResult().success(new character_list(node.valueToken.value.ToString()).setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_arrayNode(arrayNode node, context context) - { - runtimeResult result = new runtimeResult(); - item[] elements = new item[node.elementNodes.Length]; - - for (int i = 0; i < elements.Length; i++) - { - elements[i] = result.register(visit(node.elementNodes[i], context)); - if (result.shouldReturn()) return result; - } - - return result.success(new array(elements).setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_listNode(listNode node, context context) - { - runtimeResult result = new runtimeResult(); - item[] elements = new item[node.elementNodes.Length]; - - for (int i = 0; i < elements.Length; i++) - { - elements[i] = result.register(visit(node.elementNodes[i], context)); - if (result.shouldReturn()) return result; - } - - return result.success(new list(elements).setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_dictionaryNode(dictionaryNode node, context context) - { - runtimeResult result = new runtimeResult(); - ItemDictionary dictionary_ = new ItemDictionary(); - - for (int i = 0; i < node.nodePairs.Length; i++) - { - item key = result.register(visit(node.nodePairs[i][0], context)); - if (result.shouldReturn()) return result; - - item value = result.register(visit(node.nodePairs[i][1], context)); - if (result.shouldReturn()) return result; - - dictionary_.Add(key, value, out error? error); - if (error != null) return result.failure(error); - } - - return result.success(new dictionary(dictionary_).setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_variableAccessNode(variableAccessNode node, context context) - { - runtimeResult result = new runtimeResult(); - string varName = node.valueToken.value.ToString(); - - item? variable; - if (node.isGlobal) - { - variable = globalPredefinedContext.symbolTable.get(varName); - - if (variable == null) - { - context parentContext = context; - while (parentContext.parent != null && !parentContext.parent.locked) - parentContext = parentContext.parent; - variable = parentContext.symbolTable.get(varName); - } - } - else - variable = context.symbolTable.get(varName); - - if (variable == null) - return result.failure(new runtimeError(node.valueToken.startPos, node.valueToken.endPos, RT_UNDEFINED, $"\"{varName}\" is not defined", context)); - return result.success(variable.copy().setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_simpleVariableAssignNode(simpleVariableAssignNode node, context context) - { - runtimeResult result = new runtimeResult(); - string varName = node.nameToken.value.ToString(); - - item variable = result.register(visit(node.valueNode, context)); - if (result.shouldReturn()) return result; - - if (node.operatorToken != null && node.operatorToken.type != TOKENTYPE.COLON) - { - item? oldVariableValue = context.symbolTable.get(varName); - if (oldVariableValue == null) - return result.failure(new runtimeError(node.nameToken.startPos, node.nameToken.endPos, RT_UNDEFINED, $"\"{varName}\" is not defined", context)); - - error? err = null; - item? newVariable = null; - if (node.operatorToken.type == TOKENTYPE.ASSIGNPLUS) - newVariable = oldVariableValue.addedTo(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNMINUS) - newVariable = oldVariableValue.subbedBy(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNMUL) - newVariable = oldVariableValue.multedBy(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNDIV) - newVariable = oldVariableValue.divedBy(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNMOD) - newVariable = oldVariableValue.modedBy(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNPOW) - newVariable = oldVariableValue.powedBy(variable, out err); - - else if (node.operatorToken.type == TOKENTYPE.ASSIGNBITAND) - newVariable = oldVariableValue.bitwiseAndedTo(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNBITOR) - newVariable = oldVariableValue.bitwiseOrdTo(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNBITXOR) - newVariable = oldVariableValue.bitwiseXOrdTo(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNBITLSHIFT) - newVariable = oldVariableValue.bitwiseLeftShiftedTo(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNBITRSHIFT) - newVariable = oldVariableValue.bitwiseRightShiftedTo(variable, out err); - - if (err != null) return result.failure(err); - variable = newVariable; - } - - if (node.isGlobal) - { - context parentContext = context; - while (parentContext.parent != null && !parentContext.parent.locked) - parentContext = parentContext.parent; - parentContext.symbolTable.set(varName, variable); - } - else - context.symbolTable.set(varName, variable); - return result.success(variable); - } - - private runtimeResult visit_objectVariableAssignNode(objectVariableAssignNode node, context context) - { - runtimeResult result = new runtimeResult(); - string varName = node.varName.value.ToString(); - - item variable = result.register(visit(node.valueNode, context)); - if (result.shouldReturn()) return result; - - binaryOperationNode binOpNode = (binaryOperationNode)node.accessNode; - item object_ = result.register(visit(binOpNode.leftNode, context)); - if (result.shouldReturn()) return result; - - if (object_.UPDATEONACCESS) - object_ = result.register(object_.execute(new item[0])); - if (result.shouldReturn()) return result; - - if (node.operatorToken != null && node.operatorToken.type != TOKENTYPE.COLON) - { - item? oldVariableValue = result.register(object_.get(binOpNode.rightNode)); - if (result.shouldReturn()) return result; - - error? err = null; - item? newVariable = null; - if (node.operatorToken.type == TOKENTYPE.ASSIGNPLUS) - newVariable = oldVariableValue.addedTo(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNMINUS) - newVariable = oldVariableValue.subbedBy(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNMUL) - newVariable = oldVariableValue.multedBy(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNDIV) - newVariable = oldVariableValue.divedBy(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNMOD) - newVariable = oldVariableValue.modedBy(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNPOW) - newVariable = oldVariableValue.powedBy(variable, out err); - - else if (node.operatorToken.type == TOKENTYPE.ASSIGNBITAND) - newVariable = oldVariableValue.bitwiseAndedTo(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNBITOR) - newVariable = oldVariableValue.bitwiseOrdTo(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNBITXOR) - newVariable = oldVariableValue.bitwiseXOrdTo(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNBITLSHIFT) - newVariable = oldVariableValue.bitwiseLeftShiftedTo(variable, out err); - else if (node.operatorToken.type == TOKENTYPE.ASSIGNBITRSHIFT) - newVariable = oldVariableValue.bitwiseRightShiftedTo(variable, out err); - - if (err != null) return result.failure(err); - variable = newVariable; - } - - result.register(object_.set(varName, variable)); - if (result.shouldReturn()) return result; - return result.success(variable); - } - - private runtimeResult visit_binaryOperationNode(binaryOperationNode node, context context) - { - runtimeResult result = new runtimeResult(); - item left = result.register(visit(node.leftNode, context)); - if (result.shouldReturn()) return result; - - if (node.operatorToken.type == TOKENTYPE.PERIOD) - { - left = left.copy().setPosition(node.startPos, node.endPos); - if (left.UPDATEONACCESS) - left = result.register(left.execute(new item[0])); - if (result.shouldReturn()) return result; - - item returnValue = result.register(left.get(node.rightNode)); - if (result.shouldReturn()) return result; - - return result.success(returnValue.copy().setPosition(node.startPos, node.endPos).setContext(context)); - } - - item right = result.register(visit(node.rightNode, context)); - if (result.shouldReturn()) return result; - - error? err = null; - item? res = null; - if (node.operatorToken.type == TOKENTYPE.BITOR) - res = left.bitwiseOrdTo(right, out err); - else if (node.operatorToken.type == TOKENTYPE.BITXOR) - res = left.bitwiseXOrdTo(right, out err); - else if (node.operatorToken.type == TOKENTYPE.BITAND) - res = left.bitwiseAndedTo(right, out err); - else if (node.operatorToken.type == TOKENTYPE.BITLSHIFT) - res = left.bitwiseLeftShiftedTo(right, out err); - else if (node.operatorToken.type == TOKENTYPE.BITRSHIFT) - res = left.bitwiseRightShiftedTo(right, out err); - - else if (node.operatorToken.type == TOKENTYPE.PLUS) - res = left.addedTo(right, out err); - else if (node.operatorToken.type == TOKENTYPE.MINUS) - res = left.subbedBy(right, out err); - else if (node.operatorToken.type == TOKENTYPE.MUL) - res = left.multedBy(right, out err); - else if (node.operatorToken.type == TOKENTYPE.DIV) - res = left.divedBy(right, out err); - else if (node.operatorToken.type == TOKENTYPE.MOD) - res = left.modedBy(right, out err); - else if (node.operatorToken.type == TOKENTYPE.POW) - res = left.powedBy(right, out err); - - else if (node.operatorToken.type == TOKENTYPE.ISEQUAL) - res = left.compareEqual(right, out err); - else if (node.operatorToken.type == TOKENTYPE.NOTEQUAL) - res = left.compareNotEqual(right, out err); - else if (node.operatorToken.type == TOKENTYPE.LESSTHAN) - res = left.compareLessThan(right, out err); - else if (node.operatorToken.type == TOKENTYPE.GREATERTHAN) - res = left.compareGreaterThan(right, out err); - else if (node.operatorToken.type == TOKENTYPE.LESSTHANOREQUAL) - res = left.compareLessThanOrEqual(right, out err); - else if (node.operatorToken.type == TOKENTYPE.GREATERTHANOREQUAL) - res = left.compareGreaterThanOrEqual(right, out err); - else if (node.operatorToken.matchString(TOKENTYPE.KEY, "and")) - res = left.compareAnd(right, out err); - else if (node.operatorToken.matchString(TOKENTYPE.KEY, "or")) - res = left.compareOr(right, out err); - - else if (node.operatorToken.matchString(TOKENTYPE.KEY, "in")) - res = left.checkIn(right, out err); - - if (err != null) return result.failure(err); - return result.success(res.setPosition(node.startPos, node.endPos)); - } - - private runtimeResult visit_unaryOperationNode(unaryOperationNode node, context context) - { - runtimeResult result = new runtimeResult(); - item variable = result.register(visit(node.operatedNode, context)); - if (result.shouldReturn()) return result; - - error? err = null; - item? res = null; - if (node.operatorToken.type == TOKENTYPE.BITNOT) - res = variable.bitwiseNotted(out err); - - else if (node.operatorToken.type == TOKENTYPE.MINUS) - res = variable.multedBy(new integer(-1), out err); - else if (node.operatorToken.type == TOKENTYPE.PLUS) - res = variable.multedBy(new integer(1), out err); - - else if (node.operatorToken.matchString(TOKENTYPE.KEY, "invert") || node.operatorToken.matchString(TOKENTYPE.KEY, "v")) - res = variable.invert(out err); - - if (err != null) return result.failure(err); - return result.success(res.setPosition(node.startPos, node.endPos)); - } - - private runtimeResult visit_ifNode(ifNode node, context context) - { - runtimeResult result = new runtimeResult(); - - for (int i = 0; i < node.cases.Length; i++) - { - item condition = result.register(visit(node.cases[i][0], context)); - if (result.shouldReturn()) return result; - - bool boolValue = condition.isTrue(out error? error); - if (error != null) return result.failure(error); - - if (boolValue) - { - item value = result.register(visit(node.cases[i][1], context)); - if (result.shouldReturn()) return result; - - return result.success(node.shouldReturnNull ? new nothing().setPosition(node.startPos, node.endPos).setContext(context) : value); - } - } - - if (node.elseCase != null) - { - item value = result.register(visit(node.elseCase, context)); - if (result.shouldReturn()) return result; - - return result.success(node.shouldReturnNull ? new nothing().setPosition(node.startPos, node.endPos).setContext(context) : value); - } - - return result.success(new nothing().setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_countNode(countNode node, context context) - { - runtimeResult result = new runtimeResult(); - List elements = new List(); - dynamic i = 0; - dynamic length = 0; - dynamic step_ = 1; - - if (node.startValueNode != null) - { - item start = result.register(visit(node.startValueNode, context)); - if (result.shouldReturn()) return result; - - if (start is not integer && start is not @float) - return result.failure(new runtimeError(start.startPos, start.endPos, RT_TYPE, "Count loop start must be an integer or float", context)); - - if (start is integer) - i = ((integer)start).storedValue; - else - i = ((@float)start).storedValue; - } - - item end = result.register(visit(node.endValueNode, context)); - if (result.shouldReturn()) return result; - - if (end is not integer && end is not @float) - return result.failure(new runtimeError(end.startPos, end.endPos, RT_TYPE, "Count loop end must be an integer or float", context)); - - if (end is integer) - length = ((integer)end).storedValue; - else - length = ((@float)end).storedValue; - - if (node.stepValueNode != null) - { - item step = result.register(visit(node.stepValueNode, context)); - if (result.shouldReturn()) return result; - - if (step is not integer && step is not @float) - return result.failure(new runtimeError(step.startPos, step.endPos, RT_TYPE, "Count loop step must be an integer or float", context)); - - if (step is integer) - step_ = ((integer)step).storedValue; - else - step_ = ((@float)step).storedValue; - } - - string? varName = null; - if (node.variableNameToken != null) - varName = node.variableNameToken.value.ToString(); - - for (var j = i; j < length; j += step_) - { - if (varName != null) - { - if (step_ is float) - context.symbolTable.set(varName, new @float(j)); - else if (step_ is int) - context.symbolTable.set(varName, new integer((int)j)); - } - - item body = result.register(visit(node.bodyNode, context)); - if (result.shouldReturn() && !result.loopShouldSkip && !result.loopShouldStop) return result; - - if (result.loopShouldSkip) continue; - if (result.loopShouldStop) break; - - elements.Add(body); - } - - return result.success(node.shouldReturnNull ? new nothing().setPosition(node.startPos, node.endPos).setContext(context) : new array(elements.ToArray()).setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_whileNode(whileNode node, context context) - { - runtimeResult result = new runtimeResult(); - List elements = new List(); - - while (true) - { - item condition = result.register(visit(node.conditionNode, context)); - if (result.shouldReturn()) return result; - - bool boolValue = condition.isTrue(out error? error); - if (error != null) return result.failure(error); - if (!boolValue) break; - - item body = result.register(visit(node.bodyNode, context)); - if (result.shouldReturn() && !result.loopShouldSkip && !result.loopShouldStop) return result; - - if (result.loopShouldSkip) continue; - if (result.loopShouldStop) break; - - elements.Add(body); - } - - return result.success(node.shouldReturnNull ? new nothing().setPosition(node.startPos, node.endPos).setContext(context) : new array(elements.ToArray()).setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_tryNode(tryNode node, context context) - { - runtimeResult result = new runtimeResult(); - - item value = result.register(visit(node.bodyNode, context)); - if (result.shouldReturn() && result.error == null) return result; - - if (result.error != null) - { - string tag = result.error.name; - value = new nothing(); - result.reset(); - - if (node.catches.Length > 0) - { - for (int i = 0; i < node.catches.Length; i++) - { - if (node.catches[i][0] == null) - { - if (node.catches[i][1] != null) - context.symbolTable.set(((token)node.catches[i][1]).value.ToString(), new @string(tag).setPosition(node.startPos, node.endPos).setContext(context)); - - value = result.register(visit((node)node.catches[i][2], context)); - if (result.shouldReturn()) return result; - break; - } - else - { - node errorNode = (node)node.catches[i][0]; - item errorTag = result.register(visit(errorNode, context)); - if (result.shouldReturn()) return result; - - if (errorTag is not @string && errorTag is not character_list) - return result.failure(new runtimeError(errorNode.startPos, errorNode.endPos, RT_TYPE, $"Error tag must be a string or character_list", context)); - string catchTag = (errorTag is @string) ? ((@string)errorTag).storedValue : string.Join("", ((character_list)errorTag).storedValue); - - if (catchTag == tag || catchTag == RT_DEFAULT) - { - if (node.catches[i][1] != null) - context.symbolTable.set(((token)node.catches[i][1]).value.ToString(), new @string(tag).setPosition(node.startPos, node.endPos).setContext(context)); - - value = result.register(visit((node)node.catches[i][2], context)); - if (result.shouldReturn()) return result; - break; - } - } - } - } - } - - return result.success(node.shouldReturnNull ? new nothing().setPosition(node.startPos, node.endPos).setContext(context) : value.setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_skipNode(skipNode node, context context) - { - return new runtimeResult().skipSuccess(); - } - - private runtimeResult visit_stopNode(stopNode node, context context) - { - return new runtimeResult().stopSuccess(); - } - - private runtimeResult visit_functionDefinitionNode(functionDefinitionNode node, context context) - { - runtimeResult result = new runtimeResult(); - - string? name = (node.nameToken != null) ? node.nameToken.value.ToString() : null; - string[] argNames = new string[node.argNameTokens.Length]; - for (int i = 0; i < node.argNameTokens.Length; i++) - argNames[i] = node.argNameTokens[i].value.ToString(); - - item function = new function(name, node.bodyNode, argNames, node.shouldReturnNull).setPosition(node.startPos, node.endPos).setContext(context); - if (name != null) - context.symbolTable.set(name, function); - return result.success(function); - } - - private runtimeResult visit_specialDefinitionNode(specialDefinitionNode node, context context) - { - runtimeResult result = new runtimeResult(); - - string name = node.nameToken.value.ToString(); - if (!SPECIALS.Keys.Contains(name)) - return result.failure(new runtimeError(node.nameToken.startPos, node.nameToken.endPos, RT_UNDEFINED, $"Special function \"{name}\" is not defined", context)); - - item special = new special(name, node.bodyNode, SPECIALS[name], node.shouldReturnNull).setPosition(node.startPos, node.endPos).setContext(context); - context.symbolTable.set(name, special); - - return result.success(special); - } - - private runtimeResult visit_objectDefinitionNode(objectDefinitionNode node, context context) - { - runtimeResult result = new runtimeResult(); - - string name = node.nameToken.value.ToString(); - string[] argNames = new string[node.argNameTokens.Length]; - for (int i = 0; i < node.argNameTokens.Length; i++) - argNames[i] = node.argNameTokens[i].value.ToString(); - - @class? inheritFrom = null; - if (node.inheritanceToken != null) - { - item? parent = context.symbolTable.get(node.inheritanceToken.value.ToString()); - - if (parent == null) - return result.failure(new runtimeError(node.inheritanceToken.startPos, node.inheritanceToken.endPos, RT_UNDEFINED, $"\"{node.inheritanceToken.value}\" is not defined", context)); - else if (parent is not @class) - return result.failure(new runtimeError(node.inheritanceToken.startPos, node.inheritanceToken.endPos, RT_TYPE, "Parent must be a class", context)); - inheritFrom = (@class)parent; - - for (int i = 0; i < inheritFrom.argNames.Length; i++) - { - if (!argNames.Contains(inheritFrom.argNames[i])) - return result.failure(new runtimeError(node.startPos, node.endPos, RT_UNDEFINED, $"Parent argument \"{inheritFrom.argNames[i]}\" is not defined", context)); - } - } - - item @object = new @class(name, inheritFrom, node.bodyNode, argNames).setPosition(node.startPos, node.endPos).setContext(context); - context.symbolTable.set(name, @object); - return result.success(@object); - } - - private runtimeResult visit_callNode(callNode node, context context) - { - runtimeResult result = new runtimeResult(); - List args = new List(); - - item valueToCall = result.register(visit(node.nodeToCall, context)); - if (result.shouldReturn()) return result; - - valueToCall = valueToCall.copy().setPosition(node.startPos, node.endPos); - for (int i = 0; i < node.argNodes.Length; i++) - { - args.Add(result.register(visit(node.argNodes[i], context))); - if (result.shouldReturn()) return result; - } - - item returnValue = result.register(valueToCall.execute(args.ToArray())); - if (result.shouldReturn()) return result; - - return result.success(returnValue.copy().setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_returnNode(returnNode node, context context) - { - runtimeResult result = new runtimeResult(); - - item value = new nothing(); - if (node.nodeToReturn != null) - { - value = result.register(visit(node.nodeToReturn, context)); - if (result.shouldReturn()) return result; - } - - return result.returnSuccess(value.setPosition(node.startPos, node.endPos).setContext(context)); - } - - private runtimeResult visit_includeNode(includeNode node, context context) - { - runtimeResult result = new runtimeResult(); - - item file = result.register(visit(node.fileNode, context)); - if (result.shouldReturn()) return result; - - if (file is not @string && file is not character_list) - return result.failure(new runtimeError(node.fileNode.startPos, node.fileNode.endPos, RT_TYPE, $"Filepath must be a string or character_list", context)); - string filepath = (file is @string) ? ((@string)file).storedValue : string.Join("", ((character_list)file).storedValue); - - string class_ = string.Empty; - if (node.classNode != null) - { - item classItem = result.register(visit(node.classNode, context)); - if (result.shouldReturn()) return result; - - if (classItem is not @string && classItem is not character_list) - return result.failure(new runtimeError(node.classNode.startPos, node.classNode.endPos, RT_TYPE, $"Class name must be a string or character_list", context)); - class_ = (classItem is @string) ? ((@string)classItem).storedValue : string.Join("", ((character_list)classItem).storedValue); - } - - string[] localLibPaths = new string[LOCALLIBPATHS.Count]; - for (int i = 0; i < LOCALLIBPATHS.Count; i++) - localLibPaths[i] = Path.Join(LOCALLIBPATHS[i], filepath); - - if (!Path.HasExtension(filepath)) - { - string dllLibPath = Path.Join(STATICLIBPATH, $"{filepath}.dll"); - string ezr2LibPath = Path.Join(STATICLIBPATH, $"{filepath}.ezr2"); - - string dllPath = $"{filepath}.dll"; - string ezr2Path = $"{filepath}.ezr2"; - - if (Path.Exists(dllLibPath)) - filepath = dllLibPath; - else if (Path.Exists(ezr2LibPath)) - filepath = ezr2LibPath; - else if (Path.Exists(dllPath)) - filepath = dllPath; - else if (Path.Exists(ezr2Path)) - filepath = ezr2Path; - else - { - for (int i = 0; i < localLibPaths.Length; i++) - { - string dllLocalPath = $"{localLibPaths[i]}.dll"; - string ezr2LocalPath = $"{localLibPaths[i]}.ezr2"; - - if (Path.Exists(dllLocalPath)) - { - filepath = dllLocalPath; - break; - } - else if (Path.Exists(ezr2LocalPath)) - { - filepath = ezr2LocalPath; - break; - } - } - } - } - else - { - for (int i = 0; i < localLibPaths.Length; i++) - { - if (File.Exists(localLibPaths[i])) - { - filepath = localLibPaths[i]; - break; - } - } - } - - if (!File.Exists(filepath)) - return result.failure(new runtimeError(node.startPos, node.endPos, RT_IO, $"Script \"{file}\" was not found", context)); - - string name; - string nickname_ = string.Empty; - if (node.nicknameToken != null) - { - nickname_ = node.nicknameToken.value.ToString(); - name = nickname_; - } - else - { - string? filenameWithoutExtension = Path.GetFileNameWithoutExtension(filepath); - name = (filenameWithoutExtension != null) ? filenameWithoutExtension : filepath; - } - - string formattedFileName = LETTERS_UNDERSCORE.Contains(name[0]) ? name[0].ToString() : "_"; - for (int i = 1; i < name.Length; i++) - { - if (!ALPHANUM_UNDERSCORE.Contains(name[i])) - formattedFileName += '_'; - else - formattedFileName += name[i]; - } - - string? extension = Path.GetExtension(filepath); - - item value; - if (extension == ".dll") - { - Assembly DLL; - try - { - DLL = Assembly.LoadFile(filepath); - } - catch (Exception exception) - { - return result.failure(new runtimeError(node.startPos, node.endPos, RT_IO, $"Failed to load script \"{file}\"\n{exception.Message}", context)); - } - - try - { - Type[] foundTypes = DLL.GetExportedTypes(); - - if (foundTypes.Length < 1) - return result.failure(new runtimeError(node.startPos, node.endPos, RT_IO, $"Could not find any classes in script \"{file}\"", context)); - else if (foundTypes.Length == 1) - { - if (typeof(item).IsAssignableFrom(foundTypes[0]) && !foundTypes[0].IsAbstract && (string.IsNullOrEmpty(class_) || foundTypes[0].Name == class_)) - { - dynamic? val; - try - { - val = Activator.CreateInstance(foundTypes[0]); - } - catch - { - return result.failure(new runtimeError(node.startPos, node.endPos, RT_IO, $"Could not find suitable classes in script \"{file}\"", context)); - } - - value = result.register(val.setPosition(node.startPos, node.endPos).setContext(context).execute(new item[0])); - if (result.shouldReturn()) return result; - - if (node.dumpAll) - context.symbolTable.set(foundTypes[0].Name, value); - else if (string.IsNullOrEmpty(class_)) - { - context newContext = new context(formattedFileName, context, node.startPos, false); - newContext.symbolTable = new symbolTable(newContext.parent.symbolTable); - - newContext.symbolTable.set(foundTypes[0].Name, value); - context.symbolTable.set(formattedFileName, new @object(formattedFileName, newContext).setPosition(node.startPos, node.endPos).setContext(context)); - } - else - context.symbolTable.set((!string.IsNullOrEmpty(nickname_)) ? nickname_ : foundTypes[0].Name, value); - } - else if (!string.IsNullOrEmpty(class_)) - return result.failure(new runtimeError(node.startPos, node.endPos, RT_IO, $"Could not find suitable class \"{class_}\" in script \"{file}\"", context)); - else - return result.failure(new runtimeError(node.startPos, node.endPos, RT_IO, $"Could not find suitable classes in script \"{file}\"", context)); - } - else - { - context? newContext = null; - if (!node.dumpAll) - { - newContext = new context(formattedFileName, context, node.startPos, false); - newContext.symbolTable = new symbolTable(newContext.parent.symbolTable); - } - - int foundClasses = 0; - for (int i = 0; i < foundTypes.Length; i++) - { - if (typeof(item).IsAssignableFrom(foundTypes[i]) && !foundTypes[i].IsAbstract && (string.IsNullOrEmpty(class_) || foundTypes[i].Name == class_)) - { - dynamic? val; - try - { - val = Activator.CreateInstance(foundTypes[i]); - } - catch - { - continue; - } - - value = result.register(val.setPosition(node.startPos, node.endPos).setContext(context).execute(new item[0])); - if (result.shouldReturn()) return result; - - foundClasses++; - - if (node.dumpAll) - context.symbolTable.set(foundTypes[i].Name, value); - else if (string.IsNullOrEmpty(class_)) - newContext.symbolTable.set(foundTypes[i].Name, value); - else - { - context.symbolTable.set((!string.IsNullOrEmpty(nickname_)) ? nickname_ : foundTypes[i].Name, value); - return result.success(new nothing().setPosition(node.startPos, node.endPos).setContext(context)); - } - } - } - - if (foundClasses == 0 && !string.IsNullOrEmpty(class_)) - return result.failure(new runtimeError(node.startPos, node.endPos, RT_IO, $"Could not find class \"{class_}\" in script \"{file}\"", context)); - else if (foundClasses == 0) - return result.failure(new runtimeError(node.startPos, node.endPos, RT_IO, $"Could not find suitable classes in script \"{file}\"", context)); - - if (!node.dumpAll) - context.symbolTable.set(formattedFileName, new @object(formattedFileName, newContext).setPosition(node.startPos, node.endPos).setContext(context)); - } - } - catch (Exception exception) - { - return result.failure(new runtimeRunError(node.startPos, node.endPos, $"Failed to execute script \"{file}\"", exception.Message, context)); - } - } - else - { - string script; - try - { - script = string.Join('\n', File.ReadAllLines(filepath)); - } - catch (Exception exception) - { - return result.failure(new runtimeError(node.startPos, node.endPos, RT_IO, $"Failed to load script \"{file}\"\n{exception.Message}", context)); - } - - token[] tokens = new lexer(filepath, script).compileTokens(out error? error); - if (error != null) - return result.failure(new runtimeRunError(node.startPos, node.endPos, $"Failed to execute script \"{file}\"", error.asString(), context)); - - parseResult parseResult = new parser(tokens).parse(); - if (parseResult.error != null) - return result.failure(new runtimeRunError(node.startPos, node.endPos, $"Failed to execute script \"{file}\"", parseResult.error.asString(), context)); - - value = result.register(new @class(formattedFileName, null, parseResult.node, new string[0]).setPosition(node.startPos, node.endPos).setContext(context).execute(new item[0])); - if (result.shouldReturn()) return result; - - context.symbolTable.set(formattedFileName, value); - } - - return result.success(new nothing().setPosition(node.startPos, node.endPos).setContext(context)); - } - } - - private static context _globalPredefinedContext = new context("", null, null, true); - public static context globalPredefinedContext - { - get - { - if (_globalPredefinedContext.symbolTable == null) - { - symbolTable predefinedSymbolTable = new symbolTable(); - predefinedSymbolTable.set("nothing", new nothing()); - predefinedSymbolTable.set("true", new boolean(true)); - predefinedSymbolTable.set("false", new boolean(false)); - - predefinedSymbolTable.set("version__", new @string(VERSION)); - - predefinedSymbolTable.set("err_any", new @string(RT_DEFAULT)); - predefinedSymbolTable.set("err_illegalop", new @string(RT_ILLEGALOP)); - predefinedSymbolTable.set("err_undefined", new @string(RT_UNDEFINED)); - predefinedSymbolTable.set("err_key", new @string(RT_KEY)); - predefinedSymbolTable.set("err_index", new @string(RT_INDEX)); - predefinedSymbolTable.set("err_args", new @string(RT_ARGS)); - predefinedSymbolTable.set("err_type", new @string(RT_TYPE)); - predefinedSymbolTable.set("err_math", new @string(RT_MATH)); - predefinedSymbolTable.set("err_run", new @string(RT_RUN)); - predefinedSymbolTable.set("err_io", new @string(RT_IO)); - predefinedSymbolTable.set("err_overflow", new @string(RT_OVERFLOW)); - predefinedSymbolTable.set("err_length", new @string(RT_LEN)); - - predefinedSymbolTable.set("show", new builtin_function("show", new string[1] { "message" })); - predefinedSymbolTable.set("simple_show", new builtin_function("simple_show", new string[1] { "message" })); - predefinedSymbolTable.set("show_error", new builtin_function("show_error", new string[2] { "tag", "message" })); - predefinedSymbolTable.set("get", new builtin_function("get", new string[1] { "message" })); - predefinedSymbolTable.set("clear", new builtin_function("clear", new string[0])); - predefinedSymbolTable.set("hash", new builtin_function("hash", new string[1] { "value" })); - predefinedSymbolTable.set("type_of", new builtin_function("type_of", new string[1] { "value" })); - predefinedSymbolTable.set("run", new builtin_function("run", new string[1] { "file" })); - - _globalPredefinedContext.symbolTable = predefinedSymbolTable; - } - - return _globalPredefinedContext; - } - } - - public static string STATICLIBPATH = Path.Join(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Libraries"); - public static List LOCALLIBPATHS = new List(); - - public static error? easyRun(string file, string input, context runtimeContext, out item? result) - { - result = null; - string fullFilePath = Path.GetDirectoryName(Path.GetFullPath(file)); - if (fullFilePath != Directory.GetCurrentDirectory()) - LOCALLIBPATHS.Add(fullFilePath); - - return simpleRun(file, input, runtimeContext, out result); - } - - public static error? simpleRun(string file, string input, context runtimeContext, out item? result) - { - result = null; - - lexer lexer = new lexer(file, input); - token[] tokens = lexer.compileTokens(out error? error); - if (error != null) return error; - - parser parser = new parser(tokens); - parseResult abstractSyntaxTree = parser.parse(); - if (abstractSyntaxTree.error != null) return abstractSyntaxTree.error; - - interpreter interpreter = new interpreter(); - runtimeResult result_ = interpreter.visit(abstractSyntaxTree.node, runtimeContext); - if (result_.error != null) return result_.error; - - result = result_.value; - return null; - } - } -} \ No newline at end of file diff --git a/ezrShell.cs b/ezrShell.cs deleted file mode 100644 index a407bd1..0000000 --- a/ezrShell.cs +++ /dev/null @@ -1,82 +0,0 @@ -using ezrSquared.Main; -using ezrSquared.Errors; -using ezrSquared.Values; -using ezrSquared.General; -using static ezrSquared.Constants.constants; -using System; - -namespace ezrSquared.Shell -{ - public class ezrShell - { - public static void Main(string[] args) - { - string filepath = string.Empty; - if (args.Length > 0) - filepath = args[0].Replace("\\", "\\\\"); - - Console.WriteLine($"ezr² biShell version- ({VERSION}) release- [{VERSION_DATE}]"); - - bool isScript = false; - string script = string.Empty; - int scriptLine = 1; - - context runtimeContext = new context("
", ezr.globalPredefinedContext, new position(0, 0, 0, "
", ""), false); - runtimeContext.symbolTable = new symbolTable(ezr.globalPredefinedContext.symbolTable); - - while (true) - { - if (string.IsNullOrEmpty(filepath)) - { - if (isScript) - Console.Write($"({scriptLine}) > "); - else - Console.Write($"> "); - - string? input = Console.ReadLine(); - if (string.IsNullOrWhiteSpace(input)) continue; - - if (input == "switch mode") - { - isScript = !isScript; - scriptLine = 1; - script = ""; - continue; - } - else if (input == "run code") - isScript = false; - else if (input == "quit shell") - break; - else - script += input; - - if (isScript) - { - script += '\n'; - scriptLine++; - continue; - } - } - else - { - script = $"run(\"{filepath}\")"; - filepath = string.Empty; - } - - if (!string.IsNullOrEmpty(script)) - { - error? error = ezr.easyRun("", script, runtimeContext, out item? result); - if (error != null) Console.WriteLine(error.asString()); - else if (result != null) - { - item[] results = ((array)result).storedValue; - if (results.Length == 1) Console.WriteLine(results[0].ToString()); - else Console.WriteLine(result.ToString()); - } - } - - script = ""; - } - } - } -} \ No newline at end of file diff --git a/ezrSquared.csproj b/ezrSquared.csproj deleted file mode 100644 index 5657608..0000000 --- a/ezrSquared.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - Exe - win-x64 - True - - net7.0 - ezrSquared - ezrSquared.Shell.ezrShell - disable - enable - - Graphics\Icon.ico - - - - - - diff --git a/ezrSquared.sln b/ezrSquared.sln index 4f3c019..abe7886 100644 --- a/ezrSquared.sln +++ b/ezrSquared.sln @@ -3,17 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.4.33122.133 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ezrSquared", "ezrSquared.csproj", "{BA3608FA-BD80-4826-A75B-A8F9E3662147}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "io", "Libraries\io\io.csproj", "{1193FFE9-DAC9-45FA-B7F4-0B757FE272EE}" - ProjectSection(ProjectDependencies) = postProject - {BA3608FA-BD80-4826-A75B-A8F9E3662147} = {BA3608FA-BD80-4826-A75B-A8F9E3662147} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "std", "Libraries\std\std.csproj", "{C8EA702B-6553-4540-9541-7C9A5B731BAA}" - ProjectSection(ProjectDependencies) = postProject - {BA3608FA-BD80-4826-A75B-A8F9E3662147} = {BA3608FA-BD80-4826-A75B-A8F9E3662147} - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EzrSquared", "src\EzrSquared.csproj", "{C2192D60-CF75-4781-B016-116E6709A76C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,18 +11,10 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BA3608FA-BD80-4826-A75B-A8F9E3662147}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BA3608FA-BD80-4826-A75B-A8F9E3662147}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BA3608FA-BD80-4826-A75B-A8F9E3662147}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BA3608FA-BD80-4826-A75B-A8F9E3662147}.Release|Any CPU.Build.0 = Release|Any CPU - {1193FFE9-DAC9-45FA-B7F4-0B757FE272EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1193FFE9-DAC9-45FA-B7F4-0B757FE272EE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1193FFE9-DAC9-45FA-B7F4-0B757FE272EE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1193FFE9-DAC9-45FA-B7F4-0B757FE272EE}.Release|Any CPU.Build.0 = Release|Any CPU - {C8EA702B-6553-4540-9541-7C9A5B731BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C8EA702B-6553-4540-9541-7C9A5B731BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C8EA702B-6553-4540-9541-7C9A5B731BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C8EA702B-6553-4540-9541-7C9A5B731BAA}.Release|Any CPU.Build.0 = Release|Any CPU + {C2192D60-CF75-4781-B016-116E6709A76C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2192D60-CF75-4781-B016-116E6709A76C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2192D60-CF75-4781-B016-116E6709A76C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2192D60-CF75-4781-B016-116E6709A76C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Tests/tic-tac-toe_demo.ezr2 b/samples/tic_tac_toe_demo.ezr2 similarity index 100% rename from Tests/tic-tac-toe_demo.ezr2 rename to samples/tic_tac_toe_demo.ezr2 diff --git a/Tests/turingMachine.ezr2 b/samples/turing_machine_demo.ezr2 similarity index 100% rename from Tests/turingMachine.ezr2 rename to samples/turing_machine_demo.ezr2 diff --git a/src/AssemblyInfo.cs b/src/AssemblyInfo.cs new file mode 100644 index 0000000..26a4256 --- /dev/null +++ b/src/AssemblyInfo.cs @@ -0,0 +1,11 @@ +using System.Reflection; + +[assembly: AssemblyCompany("Uralstech")] +[assembly: AssemblyCopyright("Copyright 2022 - 2023 URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED.")] +[assembly: AssemblyProduct("ezrSquared")] + +[assembly: AssemblyVersion("0.1.0")] +[assembly: AssemblyFileVersion("0.1.0")] +[assembly: AssemblyInformationalVersion("0.1.0")] +[assembly: AssemblyTitle("ezrSquared")] +[assembly: AssemblyDescription("ezrSquared")] \ No newline at end of file diff --git a/src/AutoGeneratedAssemblyInfo.cs b/src/AutoGeneratedAssemblyInfo.cs new file mode 100644 index 0000000..c36e89c --- /dev/null +++ b/src/AutoGeneratedAssemblyInfo.cs @@ -0,0 +1,19 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Runtime.Versioning.TargetPlatformAttribute("Windows10.0.22621.0")] +[assembly: System.Runtime.Versioning.SupportedOSPlatformAttribute("Windows7.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000..bbc4966 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,14 @@ + + + true + false + false + false + false + false + false + false + false + D:\Code\csharp\ezrSquared\obj\ezrSquared\ + + \ No newline at end of file diff --git a/src/EzrErrors.cs b/src/EzrErrors.cs new file mode 100644 index 0000000..3d5429d --- /dev/null +++ b/src/EzrErrors.cs @@ -0,0 +1,114 @@ +using System; +using System.Text; + +namespace EzrSquared.EzrErrors +{ + using EzrGeneral; + + /// + /// The base of all other, more specific, error classes. Only for inheritance! + /// + public abstract class Error + { + /// + /// The name of the . + /// + internal readonly string _name; + + /// + /// The reason why the occured. + /// + internal readonly string _details; + + /// + /// The starting of the . + /// + internal readonly Position _startPosition; + + /// + /// The ending of the . + /// + internal readonly Position _endPosition; + + /// + /// Creates a new object. + /// + /// The name of the . + /// The reason why the occured. + /// The starting of the . + /// The ending of the . + public Error(string name, string details, Position startPosition, Position endPosition) + { + _name = name; + _details = details; + _startPosition = startPosition; + _endPosition = endPosition; + } + + /// + /// Creates the formatted text representation of the . + /// + /// The formatted text. + public override string ToString() + { + return $"(error) {_name}: {_details} -> File \"{_startPosition.File}\", line {_startPosition.Line}\n{StringWithUnderline()}"; + } + + /// + /// Creates formatted text which contains the text between and , underlined with tilde symbols. + /// + /// The formatted text. + internal string StringWithUnderline() + { + string text = _startPosition.Script; + int start = Math.Max(text[0..((_startPosition.Index <= text.Length) ? _startPosition.Index : text.Length)].LastIndexOf('\n'), 0); + int end = text.IndexOf('\n', start + 1); + if (end == -1) + end = text.Length; + + return new StringBuilder(text[start..end]).Append('\n').Append(' ', _startPosition.Index).Append('~', _endPosition.Index - _startPosition.Index).Replace("\t", string.Empty).ToString(); + } + } + + /// + /// The returned when an unknown character is identified in the script. + /// + internal class UnknownCharacterError : Error + { + /// + /// Creates a new object. + /// + /// The reason why the occured. + /// The starting of the . + /// The ending of the . + public UnknownCharacterError(string details, Position startPosition, Position endPosition) : base("Unknown character", details, startPosition, endPosition) { } + } + + /// + /// The returned when an invalid hexadecimal value is identified in the script. + /// + internal class InvalidHexValueError : Error + { + /// + /// Creates a new object. + /// + /// The reason why the occured. + /// The starting of the . + /// The ending of the . + public InvalidHexValueError(string details, Position startPosition, Position endPosition) : base("Invalid hexadecimal value", details, startPosition, endPosition) { } + } + + /// + /// The returned when invalid code syntax is identified in the script. + /// + internal class InvalidGrammarError : Error + { + /// + /// Creates a new object. + /// + /// The reason why the occured. + /// The starting of the . + /// The ending of the . + public InvalidGrammarError(string details, Position startPosition, Position endPosition) : base("Invalid grammar", details, startPosition, endPosition) { } + } +} \ No newline at end of file diff --git a/src/EzrGeneral.cs b/src/EzrGeneral.cs new file mode 100644 index 0000000..3e4aa81 --- /dev/null +++ b/src/EzrGeneral.cs @@ -0,0 +1,230 @@ +namespace EzrSquared.EzrGeneral +{ + /// + /// The representation of a position in the script. + /// + public class Position + { + /// + /// The index of the in the script. + /// + public int Index; + + /// + /// The line number of the in the script. + /// + public int Line; + + /// + /// The file name/path of the script. + /// + public readonly string File; + + /// + /// The script as text. + /// + public readonly string Script; + + /// + /// Creates a new object. + /// + /// The index of the in the script. + /// The line number of the in the script. + /// The file name/path of the script. + /// The script as text. + public Position(int index, int line, string file, string script) + { + Index = index; + Line = line; + File = file; + Script = script; + } + + /// + /// Advances the and increments by 1. If is a new-line character, is also incremented by 1. + /// + /// The character associated with the before advancing. + public void Advance(char currentChar = '\0') + { + Index++; + + if (currentChar == '\n') + Line++; + } + + /// + /// Creates a copy of the object. + /// + /// The copy. + public Position Copy() + { + return new Position(Index, Line, File, Script); + } + } + + /// + /// The identifying type of a . + /// + public enum TokenType : int + { + // Values + Integer, + FloatingPoint, + String, + Character, + CharacterList, + Identifier, + + // Keywords + KeywordAnd, + KeywordOr, + KeywordInvert, + KeywordIn, + KeywordGlobal, + KeywordItem, + KeywordIf, + KeywordElse, + KeywordCount, + KeywordFrom, + KeywordTo, + KeywordStep, + KeywordAs, + KeywordWhile, + KeywordSkip, + KeywordStop, + KeywordFunction, + KeywordSpecial, + KeywordObject, + KeywordWith, + KeywordReturn, + KeywordTry, + KeywordError, + KeywordDo, + KeywordEnd, + KeywordInclude, + KeywordAll, + + // Qeywords + QeywordF, + QeywordL, + QeywordE, + QeywordC, + QeywordT, + QeywordN, + QeywordW, + QeywordFD, + QeywordSD, + QeywordOD, + QeywordI, + QeywordS, + QeywordD, + QeywordG, + QeywordV, + + // One-character types + Plus, + HyphenMinus, + Asterisk, + Slash, + PercentSign, + Caret, + Ampersand, + VerticalBar, + Backslash, + Tilde, + Colon, + LeftParenthesis, + RightParenthesis, + LeftSquareBracket, + RightSquareBracket, + LeftCurlyBracket, + RightCurlyBracket, + EqualSign, + ExclamationMark, + LessThanSign, + GreaterThanSign, + Comma, + Period, + + // Two-character types + BitwiseLeftShift, + BitwiseRightShift, + AssignmentAddition, + AssignmentSubtraction, + AssignmentMultiplication, + AssignmentDivision, + AssignmentModulo, + AssignmentPower, + AssignmentBitwiseAnd, + AssignmentBitwiseOr, + AssignmentBitwiseXOr, + AssignmentBitwiseLeftShift, + AssignmentBitwiseRightShift, + LessThanOrEqual, + GreaterThanOrEqual, + Arrow, + + // Special + NewLine, + EndOfFile + } + + /// + /// The smallest component in the script, grouped together in Nodes (TODO) to from structures of code (math expressions, variable assignment, if statements, etc). + /// + public class Token + { + /// + /// The identifying of the . + /// + public readonly TokenType Type; + + /// + /// The value of the ; may be empty. + /// + public readonly string Value; + + /// + /// The starting of the in the script. + /// + public readonly Position StartPosition; + + /// + /// The ending of the in the script. + /// + public readonly Position EndPosition; + + /// + /// Creates a new object. + /// + /// The identifying of the . + /// The value of the ; may be empty. + /// The starting of the in the script. + /// The ending of the in the script. If not given, copies and advances it. + public Token(TokenType type, string value, Position startPosition, Position? endPosition = null) + { + Type = type; + Value = value; + + StartPosition = startPosition; + if (endPosition != null) + EndPosition = endPosition; + else + { + EndPosition = startPosition.Copy(); + EndPosition.Advance(); + } + } + + /// + /// Compares and with the given and . + /// + /// The value to compare to . + /// The value to compare to . + /// if both and match and respectively; otherwise . + public bool CheckToken(TokenType type, string value) + { + return Type == type && Value == value; + } + } +} \ No newline at end of file diff --git a/src/EzrLexer.cs b/src/EzrLexer.cs new file mode 100644 index 0000000..3a5584f --- /dev/null +++ b/src/EzrLexer.cs @@ -0,0 +1,591 @@ +using System; +using System.Text; +using System.Collections.Generic; + +namespace EzrSquared.EzrLexer +{ + using EzrGeneral; + using EzrErrors; + + /// + /// The ezrSquared Lexer or Tokenizer. The job of the Lexer is to convert the user input (code) into objects to be given as the input to the Parser (TODO). + /// + public class Lexer + { + /// + /// The file name/path of the script. + /// + private readonly string _file; + + /// + /// The script as text. + /// + private readonly string _script; + + /// + /// The of the current lexing iteration in the script. + /// + private Position _position; + + /// + /// The character in the of the current lexing iteration in the script. + /// + private char _currentChar; + + /// + /// The value for checking if the has reached the end of the script. + /// + private bool _reachedEndFlag; + + /// + /// Creates a new object. + /// + /// The file name/path of the script. + /// The script as text. + public Lexer(string file, string script) + { + _file = file; + _script = script; + _position = new Position(-1, 1, _file, _script); + _currentChar = char.MinValue; + Advance(); + } + + /// + /// Advances the current in the script. + /// + private void Advance() + { + _position.Advance(_currentChar); + if (_position.Index < _script.Length) + _currentChar = _script[_position.Index]; + else + { + _currentChar = '\0'; + _reachedEndFlag = true; + } + } + + /// + /// Peeks one character in front of the current in the script. + /// + /// The character in front of the current ; if the next character is the end of the script. + private char Peek() + { + int peekIndex = _position.Index + 1; + if (peekIndex < _script.Length) + return _script[peekIndex]; + else + return '\0'; + } + + /// + /// Creates a of objects from the given script. + /// + /// The created of objects. + /// Any that occured in the lexing; if none occured. + /// if the lexing succeeded without any errors; otherwise . + public bool Tokenize(out List tokens, out Error? error) + { + tokens = new List(); + error = null; + + while (!_reachedEndFlag) + { + switch (_currentChar) + { + case '\t': + case ' ': + Advance(); + break; + case ';': + case '\n': + Advance(); + tokens.Add(new Token(TokenType.NewLine, string.Empty, _position.Copy())); + break; + case '@': + Advance(); + while (!_reachedEndFlag && _currentChar != '\n') + Advance(); + break; + case '"': + tokens.Add(CompileStringLike(_currentChar, TokenType.String, out error)); + if (error != null) + return false; + break; + case '`': + tokens.Add(CompileStringLike(_currentChar, TokenType.Character, out error)); + if (error != null) + return false; + break; + case '\'': + tokens.Add(CompileStringLike(_currentChar, TokenType.CharacterList, out error)); + if (error != null) + return false; + break; + case ':': + tokens.Add(CompileColon()); + break; + case '<': + Position lessThanTokenStartPosition = _position.Copy(); + Advance(); + + if (_currentChar == '=') + { + Advance(); + tokens.Add(new Token(TokenType.LessThanOrEqual, string.Empty, lessThanTokenStartPosition, _position.Copy())); + } + else if (_currentChar == '<') + { + Advance(); + tokens.Add(new Token(TokenType.BitwiseLeftShift, string.Empty, lessThanTokenStartPosition, _position.Copy())); + } + else + tokens.Add(new Token(TokenType.LessThanSign, string.Empty, lessThanTokenStartPosition, _position.Copy())); + break; + case '>': + Position greaterThanTokenStartPosition = _position.Copy(); + Advance(); + + if (_currentChar == '=') + { + Advance(); + tokens.Add(new Token(TokenType.GreaterThanOrEqual, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + } + else if (_currentChar == '>') + { + Advance(); + tokens.Add(new Token(TokenType.BitwiseRightShift, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + } + else + tokens.Add(new Token(TokenType.GreaterThanSign, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + break; + case '-': + Position minusTokenStartPosition = _position.Copy(); + Advance(); + + if (_currentChar == '>') + { + Advance(); + tokens.Add(new Token(TokenType.Arrow, string.Empty, minusTokenStartPosition, _position.Copy())); + } + else + tokens.Add(new Token(TokenType.HyphenMinus, string.Empty, minusTokenStartPosition, _position.Copy())); + break; + case '+': + Advance(); + tokens.Add(new Token(TokenType.Plus, string.Empty, _position.Copy())); + break; + case '*': + Advance(); + tokens.Add(new Token(TokenType.Asterisk, string.Empty, _position.Copy())); + break; + case '/': + Advance(); + tokens.Add(new Token(TokenType.Slash, string.Empty, _position.Copy())); + break; + case '%': + Advance(); + tokens.Add(new Token(TokenType.PercentSign, string.Empty, _position.Copy())); + break; + case '^': + Advance(); + tokens.Add(new Token(TokenType.Caret, string.Empty, _position.Copy())); + break; + case '=': + Advance(); + tokens.Add(new Token(TokenType.EqualSign, string.Empty, _position.Copy())); + break; + case '!': + Advance(); + tokens.Add(new Token(TokenType.ExclamationMark, string.Empty, _position.Copy())); + break; + case ',': + Advance(); + tokens.Add(new Token(TokenType.Comma, string.Empty, _position.Copy())); + break; + case '.': + Advance(); + tokens.Add(new Token(TokenType.Period, string.Empty, _position.Copy())); + break; + case '(': + Advance(); + tokens.Add(new Token(TokenType.LeftParenthesis, string.Empty, _position.Copy())); + break; + case ')': + Advance(); + tokens.Add(new Token(TokenType.RightParenthesis, string.Empty, _position.Copy())); + break; + case '[': + Advance(); + tokens.Add(new Token(TokenType.LeftSquareBracket, string.Empty, _position.Copy())); + break; + case ']': + Advance(); + tokens.Add(new Token(TokenType.RightSquareBracket, string.Empty, _position.Copy())); + break; + case '{': + Advance(); + tokens.Add(new Token(TokenType.LeftCurlyBracket, string.Empty, _position.Copy())); + break; + case '}': + Advance(); + tokens.Add(new Token(TokenType.RightCurlyBracket, string.Empty, _position.Copy())); + break; + case '&': + Advance(); + tokens.Add(new Token(TokenType.Ampersand, string.Empty, _position.Copy())); + break; + case '|': + Advance(); + tokens.Add(new Token(TokenType.VerticalBar, string.Empty, _position.Copy())); + break; + case '\\': + Advance(); + tokens.Add(new Token(TokenType.Backslash, string.Empty, _position.Copy())); + break; + case '~': + Advance(); + tokens.Add(new Token(TokenType.Tilde, string.Empty, _position.Copy())); + break; + default: + if (char.IsLetter(_currentChar) || _currentChar == '_') + { + tokens.Add(CompileIdentifier()); + break; + } + else if (char.IsDigit(_currentChar)) + { + StringBuilder numberValue = new StringBuilder(); + Position numberTokenStartPosition = _position.Copy(); + bool hasPeriod = false; + + while(!_reachedEndFlag && (char.IsDigit(_currentChar) || _currentChar == '.')) + { + if (_currentChar == '.') + { + if (hasPeriod || !char.IsDigit(Peek())) + break; + hasPeriod = true; + } + + numberValue.Append(_currentChar); + Advance(); + } + + if (hasPeriod) + tokens.Add(new Token(TokenType.FloatingPoint, numberValue.ToString(), numberTokenStartPosition, _position.Copy())); + else + tokens.Add(new Token(TokenType.Integer, numberValue.ToString(), numberTokenStartPosition, _position.Copy())); + break; + } + else + { + Position errorStartPosition = _position.Copy(); + char unknownCharacter = _currentChar; + Advance(); + + error = new UnknownCharacterError($"'{unknownCharacter}'", errorStartPosition, _position); + return false; + } + } + } + + tokens.Add(new Token(TokenType.EndOfFile, string.Empty, _position.Copy())); + return true; + } + + /// + /// Creates a stringlike type (, , ) object. + /// + /// The value to enclose the stringlike. + /// The identifying of the . + /// Any that occured in creating the stringlike; if none occured. + /// The created . + private Token CompileStringLike(char enclosingChar, TokenType type, out Error? error) + { + error = null; + + StringBuilder toReturn = new StringBuilder(); + Position startPosition = _position.Copy(); + bool escapeChar = false; + bool countingUTF16 = false; + bool countingUTF32 = false; + int UTFCount = 0; + string hexValue = string.Empty; + Position hexStartPosition = startPosition; + Advance(); + + while (!_reachedEndFlag && (_currentChar != enclosingChar || escapeChar || countingUTF16 || countingUTF32)) + { + if (countingUTF16) + { + if ((_currentChar >= 'a' && _currentChar <= 'f') || (_currentChar >= 'A' && _currentChar <= 'F') || (_currentChar >= '0' && _currentChar <= '9')) + { + UTFCount++; + hexValue += _currentChar; + } + else + { + Position endPosition = _position.Copy(); + endPosition.Advance(); + + error = new InvalidHexValueError("UTF-16 hexadecimal values must be 4 characters long and only contain digits and/or the letters A to F", hexStartPosition, endPosition); + break; + } + + if (UTFCount >= 4) + { + toReturn.Append(Encoding.Unicode.GetChars(new byte[2] { Convert.ToByte(hexValue[2..4], 16), Convert.ToByte(hexValue[0..2], 16) })); + countingUTF16 = false; + } + } + else if (countingUTF32) + { + if ((_currentChar >= 'a' && _currentChar <= 'f') || (_currentChar >= 'A' && _currentChar <= 'F') || (_currentChar >= '0' && _currentChar <= '9')) + { + UTFCount++; + hexValue += _currentChar; + } + else + { + Position endPosition = _position.Copy(); + endPosition.Advance(); + + error = new InvalidHexValueError("UTF-32 hexadecimal values must be 6 characters long and only contain digits and/or the letters A to F", hexStartPosition, endPosition); + break; + } + + if (UTFCount >= 6) + { + if (Convert.ToInt32(hexValue, 16) > 1114111) + { + Position endPosition = _position.Copy(); + endPosition.Advance(); + + error = new InvalidHexValueError("UTF-32 hexadecimal values must be in range 000000 - 10FFFF", hexStartPosition, endPosition); + break; + } + else + toReturn.Append(Encoding.UTF32.GetChars(new byte[4] { Convert.ToByte(hexValue[4..6], 16), Convert.ToByte(hexValue[2..4], 16), Convert.ToByte(hexValue[0..2], 16), 0 })); + countingUTF32 = false; + } + } + else if (escapeChar) + { + switch (_currentChar) + { + case 'u': + hexValue = string.Empty; + countingUTF16 = true; + + hexStartPosition = _position.Copy(); + hexStartPosition.Advance(); + break; + case 'U': + hexValue = string.Empty; + countingUTF32 = true; + + hexStartPosition = _position.Copy(); + hexStartPosition.Advance(); + break; + case 'n': + toReturn.Append('\n'); + break; + case 't': + toReturn.Append('\t'); + break; + case 'b': + toReturn.Append('\b'); + break; + case 'r': + toReturn.Append('\r'); + break; + case '0': + toReturn.Append('\0'); + break; + case 'f': + toReturn.Append('\f'); + break; + case 'v': + toReturn.Append('\v'); + break; + default: + toReturn.Append(_currentChar); + break; + } + + escapeChar = false; + } + else if (_currentChar == '\\') + escapeChar = true; + else + toReturn.Append(_currentChar); + + Advance(); + } + + if (_reachedEndFlag || _currentChar != enclosingChar) + error = new InvalidGrammarError($"Expected '{enclosingChar}'", _position.Copy(), _position); + + Advance(); + return new Token(type, toReturn.ToString(), startPosition, _position.Copy()); + } + + /// + /// Creates and assignment type (, , etc) objects. + /// + /// The created . + private Token CompileColon() + { + Position startPosition = _position.Copy(); + Advance(); + + switch (_currentChar) + { + case '+': + Advance(); + return new Token(TokenType.AssignmentAddition, string.Empty, startPosition, _position.Copy()); + case '-': + Advance(); + return new Token(TokenType.AssignmentSubtraction, string.Empty, startPosition, _position.Copy()); + case '*': + Advance(); + return new Token(TokenType.AssignmentMultiplication, string.Empty, startPosition, _position.Copy()); + case '/': + Advance(); + return new Token(TokenType.AssignmentDivision, string.Empty, startPosition, _position.Copy()); + case '%': + Advance(); + return new Token(TokenType.AssignmentModulo, string.Empty, startPosition, _position.Copy()); + case '^': + Advance(); + return new Token(TokenType.AssignmentPower, string.Empty, startPosition, _position.Copy()); + case '&': + Advance(); + return new Token(TokenType.AssignmentBitwiseAnd, string.Empty, startPosition, _position.Copy()); + case '|': + Advance(); + return new Token(TokenType.AssignmentBitwiseOr, string.Empty, startPosition, _position.Copy()); + case '\\': + Advance(); + return new Token(TokenType.AssignmentBitwiseXOr, string.Empty, startPosition, _position.Copy()); + case '<': + Advance(); + return new Token(TokenType.AssignmentBitwiseLeftShift, string.Empty, startPosition, _position.Copy()); + case '>': + Advance(); + return new Token(TokenType.AssignmentBitwiseRightShift, string.Empty, startPosition, _position.Copy()); + default: + return new Token(TokenType.Colon, string.Empty, startPosition, _position.Copy()); + } + } + + /// + /// Creates , keyword type (, , etc) and qeyword type (, , etc) objects. + /// + /// The created . + private Token CompileIdentifier() + { + Position startPosition = _position.Copy(); + StringBuilder idValue = new StringBuilder(); + + while (!_reachedEndFlag && (char.IsLetterOrDigit(_currentChar) || _currentChar == '_')) + { + idValue.Append(_currentChar); + Advance(); + } + + string value = idValue.ToString(); + switch (value) + { + case "item": + return new Token(TokenType.KeywordItem, string.Empty, startPosition, _position.Copy()); + case "and": + return new Token(TokenType.KeywordAnd, string.Empty, startPosition, _position.Copy()); + case "or": + return new Token(TokenType.KeywordOr, string.Empty, startPosition, _position.Copy()); + case "invert": + return new Token(TokenType.KeywordInvert, string.Empty, startPosition, _position.Copy()); + case "if": + return new Token(TokenType.KeywordIf, string.Empty, startPosition, _position.Copy()); + case "else": + return new Token(TokenType.KeywordElse, string.Empty, startPosition, _position.Copy()); + case "do": + return new Token(TokenType.KeywordDo, string.Empty, startPosition, _position.Copy()); + case "count": + return new Token(TokenType.KeywordCount, string.Empty, startPosition, _position.Copy()); + case "from": + return new Token(TokenType.KeywordFrom, string.Empty, startPosition, _position.Copy()); + case "as": + return new Token(TokenType.KeywordAs, string.Empty, startPosition, _position.Copy()); + case "to": + return new Token(TokenType.KeywordTo, string.Empty, startPosition, _position.Copy()); + case "step": + return new Token(TokenType.KeywordStep, string.Empty, startPosition, _position.Copy()); + case "while": + return new Token(TokenType.KeywordWhile, string.Empty, startPosition, _position.Copy()); + case "function": + return new Token(TokenType.KeywordFunction, string.Empty, startPosition, _position.Copy()); + case "special": + return new Token(TokenType.KeywordSpecial, string.Empty, startPosition, _position.Copy()); + case "with": + return new Token(TokenType.KeywordWith, string.Empty, startPosition, _position.Copy()); + case "end": + return new Token(TokenType.KeywordEnd, string.Empty, startPosition, _position.Copy()); + case "return": + return new Token(TokenType.KeywordReturn, string.Empty, startPosition, _position.Copy()); + case "skip": + return new Token(TokenType.KeywordSkip, string.Empty, startPosition, _position.Copy()); + case "stop": + return new Token(TokenType.KeywordStop, string.Empty, startPosition, _position.Copy()); + case "try": + return new Token(TokenType.KeywordTry, string.Empty, startPosition, _position.Copy()); + case "error": + return new Token(TokenType.KeywordError, string.Empty, startPosition, _position.Copy()); + case "in": + return new Token(TokenType.KeywordIn, string.Empty, startPosition, _position.Copy()); + case "object": + return new Token(TokenType.KeywordObject, string.Empty, startPosition, _position.Copy()); + case "global": + return new Token(TokenType.KeywordGlobal, string.Empty, startPosition, _position.Copy()); + case "include": + return new Token(TokenType.KeywordInclude, string.Empty, startPosition, _position.Copy()); + case "all": + return new Token(TokenType.KeywordAll, string.Empty, startPosition, _position.Copy()); + case "f": + return new Token(TokenType.QeywordF, value, startPosition, _position.Copy()); + case "l": + return new Token(TokenType.QeywordL, value, startPosition, _position.Copy()); + case "e": + return new Token(TokenType.QeywordE, value, startPosition, _position.Copy()); + case "c": + return new Token(TokenType.QeywordC, value, startPosition, _position.Copy()); + case "t": + return new Token(TokenType.QeywordT, value, startPosition, _position.Copy()); + case "n": + return new Token(TokenType.QeywordN, value, startPosition, _position.Copy()); + case "w": + return new Token(TokenType.QeywordW, value, startPosition, _position.Copy()); + case "fd": + return new Token(TokenType.QeywordFD, value, startPosition, _position.Copy()); + case "sd": + return new Token(TokenType.QeywordSD, value, startPosition, _position.Copy()); + case "od": + return new Token(TokenType.QeywordOD, value, startPosition, _position.Copy()); + case "i": + return new Token(TokenType.QeywordI, value, startPosition, _position.Copy()); + case "s": + return new Token(TokenType.QeywordS, value, startPosition, _position.Copy()); + case "d": + return new Token(TokenType.QeywordD, value, startPosition, _position.Copy()); + case "g": + return new Token(TokenType.QeywordG, value, startPosition, _position.Copy()); + case "v": + return new Token(TokenType.QeywordV, value, startPosition, _position.Copy()); + default: + return new Token(TokenType.Identifier, value, startPosition, _position.Copy()); + } + } + } +} diff --git a/src/EzrShell.cs b/src/EzrShell.cs new file mode 100644 index 0000000..3cb7d77 --- /dev/null +++ b/src/EzrShell.cs @@ -0,0 +1,59 @@ +using System; +using System.IO; +using System.Text; +using System.Collections.Generic; + +namespace EzrSquared.EzrShell +{ + using EzrGeneral; + using EzrErrors; + using EzrLexer; + + /// + /// The built-in shell for ezrSquared. + /// + internal class Shell + { + private const string _ezrVersion = "0.1.0"; + private const string _projectLink = "https://github.com/Uralstech/ezrSquared/"; + private const string _documentationLink = "https://uralstech.github.io/ezrSquared/Introduction.html"; + private const string _issuesLink = "https://github.com/Uralstech/ezrSquared/issues"; + private const string _startUp = " ___ | ezr² v{0} Built-In Shell\n |_ ) | Online documentation:\n ___ ____ _ __ / / | {1}\n / _ \\ |_ / | '__| /___| | Feature requests and bug reports:\n | __/ / / | | | {2}\n \\___| /___| |_| | GitHub repository:\n___________________________| {3}"; + + private static void PrintLexerOutput(string file, string script) + { + if (new Lexer(file, script).Tokenize(out List tokens, out Error? error)) + { + for (int i = 0; i < tokens.Count; i++) + Console.WriteLine($"( {tokens[i].Value}, {Enum.GetName(typeof(TokenType), tokens[i].Type)} )"); + } + else if (error != null) + Console.WriteLine(error.ToString()); + } + + public static void Main() + { + string filePath = string.Empty; + + string[] commandLineArguments = Environment.GetCommandLineArgs(); + if (commandLineArguments.Length > 1 && File.Exists(commandLineArguments[1])) + { + filePath = commandLineArguments[1]; + PrintLexerOutput(filePath, File.ReadAllText(filePath)); + } + else + { + Console.OutputEncoding = Encoding.Unicode; + Console.WriteLine(string.Format(_startUp, _ezrVersion, _documentationLink, _issuesLink, _projectLink)); + while (true) + { + Console.Write(">>> "); + string? input = Console.ReadLine(); + + if (!string.IsNullOrEmpty(input)) + PrintLexerOutput("ezr² Built-In Shell", input); + } + } + } + } +} \ No newline at end of file diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj new file mode 100644 index 0000000..7829b95 --- /dev/null +++ b/src/EzrSquared.csproj @@ -0,0 +1,24 @@ + + + Exe + win-x64 + net7.0-windows10.0.22621.0 + 7.0 + True + False + + EzrSquared + EzrSquared.EzrShell.Shell + disable + enable + embedded + + Icon.ico + D:\Code\csharp\ezrSquared\src\AutoGeneratedAssemblyInfo.cs + D:\Code\csharp\ezrSquared\bin\ezrSquared\ + D:\Code\csharp\ezrSquared\obj\ezrSquared\ + + + true + + diff --git a/Graphics/Icon.ico b/src/Icon.ico similarity index 100% rename from Graphics/Icon.ico rename to src/Icon.ico diff --git a/Installer/environment.iss b/src/installer/environment.iss similarity index 100% rename from Installer/environment.iss rename to src/installer/environment.iss diff --git a/Installer/ezrSquared 32-bit.iss b/src/installer/ezrSquared 32-bit.iss similarity index 81% rename from Installer/ezrSquared 32-bit.iss rename to src/installer/ezrSquared 32-bit.iss index d5b613f..19f0480 100644 --- a/Installer/ezrSquared 32-bit.iss +++ b/src/installer/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "prerelease-1.5.1.3.0" +#define MyAppVersion "1.0.0" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" @@ -34,9 +34,9 @@ InfoAfterFile=D:\Code\csharp\ezrSquared\Changelog.txt ; Remove the following line to run in administrative install mode (install for all users.) PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog -OutputDir=D:\Code\csharp\ezrSquared\Installer\bin +OutputDir=D:\Code\csharp\ezrSquared\bin\Installer\ OutputBaseFilename=ezrSquared Installer (Windows 32-bit) -SetupIconFile=D:\Code\csharp\ezrSquared\Graphics\Icon.ico +SetupIconFile=D:\Code\csharp\ezrSquared\src\Icon.ico Compression=lzma SolidCompression=yes WizardStyle=modern @@ -70,11 +70,11 @@ Name: "{app}\Libraries" [Files] Source: "D:\Code\csharp\ezrSquared\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion -Source: "D:\Code\csharp\ezrSquared\bin\Release\net7.0\win-x86\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion -Source: "D:\Code\csharp\ezrSquared\bin\Release\net7.0\win-x86\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs -Source: "D:\Code\csharp\ezrSquared\Offline Site\ezrSquared Offline\*"; DestDir: "{app}\Documentation"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: docs -Source: "D:\Code\csharp\ezrSquared\Libraries\io\bin\Release\net7.0\win-x86\io.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs -Source: "D:\Code\csharp\ezrSquared\Libraries\std\bin\Release\net7.0\win-x86\std.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs +Source: "D:\Code\csharp\ezrSquared\bin\ezrSquared\Release\net7.0-windows10.0.22621.0\win-x86\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion +Source: "D:\Code\csharp\ezrSquared\bin\ezrSquared\Release\net7.0-windows10.0.22621.0\win-x86\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "D:\Code\csharp\ezrSquared\docs\offline\_site\*"; DestDir: "{app}\Documentation"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: docs +Source: "D:\Code\csharp\ezrSquared\bin\Libraries\IO\Release\net7.0-windows10.0.22621.0\win-x86\IO.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs +Source: "D:\Code\csharp\ezrSquared\bin\Libraries\STD\Release\net7.0-windows10.0.22621.0\win-x86\STD.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Registry] diff --git a/Installer/ezrSquared 64-bit.iss b/src/installer/ezrSquared 64-bit.iss similarity index 81% rename from Installer/ezrSquared 64-bit.iss rename to src/installer/ezrSquared 64-bit.iss index 9c6eacb..d7863a7 100644 --- a/Installer/ezrSquared 64-bit.iss +++ b/src/installer/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "prerelease-1.5.1.3.0" +#define MyAppVersion "1.0.0" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" @@ -35,9 +35,9 @@ InfoAfterFile=D:\Code\csharp\ezrSquared\Changelog.txt ; Remove the following line to run in administrative install mode (install for all users.) PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog -OutputDir=D:\Code\csharp\ezrSquared\Installer\bin +OutputDir=D:\Code\csharp\ezrSquared\bin\Installer\ OutputBaseFilename=ezrSquared Installer (Windows 64-bit) -SetupIconFile=D:\Code\csharp\ezrSquared\Graphics\Icon.ico +SetupIconFile=D:\Code\csharp\ezrSquared\src\Icon.ico Compression=lzma SolidCompression=yes WizardStyle=modern @@ -71,11 +71,11 @@ Name: "{app}\Libraries" [Files] Source: "D:\Code\csharp\ezrSquared\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion -Source: "D:\Code\csharp\ezrSquared\bin\Release\net7.0\win-x64\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion -Source: "D:\Code\csharp\ezrSquared\bin\Release\net7.0\win-x64\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs -Source: "D:\Code\csharp\ezrSquared\Offline Site\ezrSquared Offline\*"; DestDir: "{app}\Documentation"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: docs -Source: "D:\Code\csharp\ezrSquared\Libraries\io\bin\Release\net7.0\win-x64\io.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs -Source: "D:\Code\csharp\ezrSquared\Libraries\std\bin\Release\net7.0\win-x64\std.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs +Source: "D:\Code\csharp\ezrSquared\bin\ezrSquared\Release\net7.0-windows10.0.22621.0\win-x64\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion +Source: "D:\Code\csharp\ezrSquared\bin\ezrSquared\Release\net7.0-windows10.0.22621.0\win-x64\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "D:\Code\csharp\ezrSquared\docs\offline\_site\*"; DestDir: "{app}\Documentation"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: docs +Source: "D:\Code\csharp\ezrSquared\bin\Libraries\IO\Release\net7.0-windows10.0.22621.0\win-x64\IO.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs +Source: "D:\Code\csharp\ezrSquared\bin\Libraries\STD\Release\net7.0-windows10.0.22621.0\win-x64\STD.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Registry] diff --git a/tests/full_test.ezr2 b/tests/full_test.ezr2 new file mode 100644 index 0000000..f010be0 --- /dev/null +++ b/tests/full_test.ezr2 @@ -0,0 +1 @@ +@ TODO \ No newline at end of file diff --git a/Tests/snake.ezr2 b/tests/graphics_test_01.ezr2 similarity index 100% rename from Tests/snake.ezr2 rename to tests/graphics_test_01.ezr2 diff --git a/Tests/gameTest.ezr2 b/tests/graphics_test_02.ezr2 similarity index 100% rename from Tests/gameTest.ezr2 rename to tests/graphics_test_02.ezr2 diff --git a/Tests/consoleTest.ezr2 b/tests/library_test.ezr2 similarity index 100% rename from Tests/consoleTest.ezr2 rename to tests/library_test.ezr2 From fa425c5c02b3821265df36f9ac39e70174f3d951 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 10 May 2023 19:05:25 +0530 Subject: [PATCH 002/113] Updated gitignore! --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 87b3f24..0ec652c 100644 --- a/.gitignore +++ b/.gitignore @@ -364,6 +364,7 @@ FodyWeavers.xsd # -------------------------------------------------- -graphics/ +[Gg]raphics/ +[Ll]ibraries/ docs/offline/_site/ docs/offline/ezrSquared.Offline.Documentation.zip \ No newline at end of file From 350b565767bdf841546909e5498ed8e42cc9fc82 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 12 Sep 2023 13:17:36 +0530 Subject: [PATCH 003/113] Added the new Parser! --- src/AutoGeneratedAssemblyInfo.cs | 2 +- src/{EzrGeneral.cs => EzrCommon.cs} | 65 +- src/EzrErrors.cs | 56 +- src/EzrGrammar.txt | 157 +++ src/EzrLexer.cs | 196 +-- src/EzrNodes.cs | 774 +++++++++++ src/EzrParser.cs | 1955 +++++++++++++++++++++++++++ src/EzrShell.cs | 198 ++- src/EzrSquared.csproj | 4 + 9 files changed, 3244 insertions(+), 163 deletions(-) rename src/{EzrGeneral.cs => EzrCommon.cs} (81%) create mode 100644 src/EzrGrammar.txt create mode 100644 src/EzrNodes.cs create mode 100644 src/EzrParser.cs diff --git a/src/AutoGeneratedAssemblyInfo.cs b/src/AutoGeneratedAssemblyInfo.cs index c36e89c..aaf8897 100644 --- a/src/AutoGeneratedAssemblyInfo.cs +++ b/src/AutoGeneratedAssemblyInfo.cs @@ -11,7 +11,7 @@ using System; using System.Reflection; -[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Runtime.Versioning.TargetPlatformAttribute("Windows10.0.22621.0")] [assembly: System.Runtime.Versioning.SupportedOSPlatformAttribute("Windows7.0")] diff --git a/src/EzrGeneral.cs b/src/EzrCommon.cs similarity index 81% rename from src/EzrGeneral.cs rename to src/EzrCommon.cs index 3e4aa81..0079831 100644 --- a/src/EzrGeneral.cs +++ b/src/EzrCommon.cs @@ -1,4 +1,4 @@ -namespace EzrSquared.EzrGeneral +namespace EzrSquared.EzrCommon { /// /// The representation of a position in the script. @@ -61,11 +61,24 @@ public Position Copy() return new Position(Index, Line, File, Script); } } - + + /// + /// The type group of a . + /// + public enum TokenTypeGroup : ushort + { + Value, + Keyword, + Qeyword, + AssignmentSymbol, + Symbol, + Special + } + /// /// The identifying type of a . /// - public enum TokenType : int + public enum TokenType : ushort { // Values Integer, @@ -73,12 +86,12 @@ public enum TokenType : int String, Character, CharacterList, - Identifier, // Keywords KeywordAnd, KeywordOr, KeywordInvert, + KeywordNot, KeywordIn, KeywordGlobal, KeywordItem, @@ -121,7 +134,7 @@ public enum TokenType : int QeywordG, QeywordV, - // One-character types + // Symbols Plus, HyphenMinus, Asterisk, @@ -132,7 +145,6 @@ public enum TokenType : int VerticalBar, Backslash, Tilde, - Colon, LeftParenthesis, RightParenthesis, LeftSquareBracket, @@ -145,10 +157,14 @@ public enum TokenType : int GreaterThanSign, Comma, Period, - - // Two-character types BitwiseLeftShift, BitwiseRightShift, + LessThanOrEqual, + GreaterThanOrEqual, + Arrow, + + // Assignment symbols + Colon, AssignmentAddition, AssignmentSubtraction, AssignmentMultiplication, @@ -160,17 +176,16 @@ public enum TokenType : int AssignmentBitwiseXOr, AssignmentBitwiseLeftShift, AssignmentBitwiseRightShift, - LessThanOrEqual, - GreaterThanOrEqual, - Arrow, // Special + Identifier, NewLine, - EndOfFile + EndOfFile, + Invalid } /// - /// The smallest component in the script, grouped together in Nodes (TODO) to from structures of code (math expressions, variable assignment, if statements, etc). + /// The smallest component in the script identified by the , grouped together into objects to from source code constructs. /// public class Token { @@ -179,6 +194,11 @@ public class Token /// public readonly TokenType Type; + /// + /// The of the . + /// + public readonly TokenTypeGroup TypeGroup; + /// /// The value of the ; may be empty. /// @@ -194,16 +214,23 @@ public class Token /// public readonly Position EndPosition; + public static Token GetInvalidToken(Position startPosition, Position? endPosition) + { + return new Token(TokenType.Invalid, TokenTypeGroup.Special, string.Empty, startPosition, endPosition); + } + /// /// Creates a new object. /// /// The identifying of the . + /// The of the . /// The value of the ; may be empty. /// The starting of the in the script. /// The ending of the in the script. If not given, copies and advances it. - public Token(TokenType type, string value, Position startPosition, Position? endPosition = null) + public Token(TokenType type, TokenTypeGroup typeGroup, string value, Position startPosition, Position? endPosition = null) { Type = type; + TypeGroup = typeGroup; Value = value; StartPosition = startPosition; @@ -216,15 +243,9 @@ public Token(TokenType type, string value, Position startPosition, Position? end } } - /// - /// Compares and with the given and . - /// - /// The value to compare to . - /// The value to compare to . - /// if both and match and respectively; otherwise . - public bool CheckToken(TokenType type, string value) + public override string ToString() { - return Type == type && Value == value; + return $"Token({Type}, {TypeGroup}, \"{Value}\")"; } } } \ No newline at end of file diff --git a/src/EzrErrors.cs b/src/EzrErrors.cs index 3d5429d..fab55cb 100644 --- a/src/EzrErrors.cs +++ b/src/EzrErrors.cs @@ -3,20 +3,20 @@ namespace EzrSquared.EzrErrors { - using EzrGeneral; + using EzrCommon; /// - /// The base of all other, more specific, error classes. Only for inheritance! + /// The base of all other, more specific, error classes. /// public abstract class Error { /// /// The name of the . /// - internal readonly string _name; + internal readonly string _title; /// - /// The reason why the occured. + /// The reason why the occurred. /// internal readonly string _details; @@ -33,13 +33,13 @@ public abstract class Error /// /// Creates a new object. /// - /// The name of the . - /// The reason why the occured. + /// The title of the . + /// The reason why the occurred. /// The starting of the . /// The ending of the . - public Error(string name, string details, Position startPosition, Position endPosition) + public Error(string title, string details, Position startPosition, Position endPosition) { - _name = name; + _title = title; _details = details; _startPosition = startPosition; _endPosition = endPosition; @@ -51,7 +51,7 @@ public Error(string name, string details, Position startPosition, Position endPo /// The formatted text. public override string ToString() { - return $"(error) {_name}: {_details} -> File \"{_startPosition.File}\", line {_startPosition.Line}\n{StringWithUnderline()}"; + return $"{_title} in {_startPosition.File}, line {_startPosition.Line}: {_details}\n{StringWithUnderline()}"; } /// @@ -73,15 +73,15 @@ internal string StringWithUnderline() /// /// The returned when an unknown character is identified in the script. /// - internal class UnknownCharacterError : Error + internal class UnexpectedCharacterError : Error { /// - /// Creates a new object. + /// Creates a new object. /// - /// The reason why the occured. - /// The starting of the . - /// The ending of the . - public UnknownCharacterError(string details, Position startPosition, Position endPosition) : base("Unknown character", details, startPosition, endPosition) { } + /// The character that caused the . + /// The starting of the . + /// The ending of the . + public UnexpectedCharacterError(char character, Position startPosition, Position endPosition) : base("Unexpected character", $"{character}", startPosition, endPosition) { } } /// @@ -92,7 +92,7 @@ internal class InvalidHexValueError : Error /// /// Creates a new object. /// - /// The reason why the occured. + /// The reason why the occurred. /// The starting of the . /// The ending of the . public InvalidHexValueError(string details, Position startPosition, Position endPosition) : base("Invalid hexadecimal value", details, startPosition, endPosition) { } @@ -106,9 +106,31 @@ internal class InvalidGrammarError : Error /// /// Creates a new object. /// - /// The reason why the occured. + /// The reason why the occurred. /// The starting of the . /// The ending of the . public InvalidGrammarError(string details, Position startPosition, Position endPosition) : base("Invalid grammar", details, startPosition, endPosition) { } } + + /// + /// The returned when multiple objects need to be returned to the user. + /// + internal class StackedError : Error + { + /// + /// Creates a new object. + /// + /// The 'parent' error, or the error that occurred first. + /// The 'child' error, or the error that occurred because of the . + public StackedError(Error parent, Error child) : base("Multiple errors", string.Join("\n\nDue to the above error, another one occurred:\n", new Error[2] { parent, child }), parent._startPosition, parent._endPosition) { } + + /// + /// Creates the formatted text representation of the , which shows all child objects as the 'details'. + /// + /// The formatted text. + public override string ToString() + { + return _details; + } + } } \ No newline at end of file diff --git a/src/EzrGrammar.txt b/src/EzrGrammar.txt new file mode 100644 index 0000000..c4234ae --- /dev/null +++ b/src/EzrGrammar.txt @@ -0,0 +1,157 @@ +ezrSquared syntax +================= + +Definitions +----------- + +'\n' : new line or semicolon character +| : or ++ : can have more than one instance of +? : optional +'' : symbol(s) +"" : qeyword or keyword +[] : not structure +; : comment + +Structures +---------- + +; 'statements' structures can contain multiple 'statement' structures +statements: + statement + | (statement '\n')+ + +; 'statement' structures can contain return, skip or stop expressions or 'expression' structures +statement: + "return" expression? + | "skip" + | "stop" + | expression + +; 'expression' structures can contain item definition expressions or 'quick-expression' structures +expression: + "global"? "item"? (([identifier] | [qeyword]) | comparison) (':' | ':+' | ':-' | ':*' | ':/' | ':%' | ':^' | ':&' | ':|' | ':\' | ':<' | ':>') expression + | quick-expression + +; 'quick-expression' structures can contain QuickSyntax item definition expressions or 'junction' structures +quick-expression: + '!' "g"? "d"? (([identifier] | [qeyword]) | junction) (':' | ':+' | ':-' | ':*' | ':/' | ':%' | ':^' | ':&' | ':|' | ':\' | ':<' | ':>') expression + | junction + +; 'junction' structures can contain 'and' or 'or' comparison expressions or 'inversion' structures +junction: + inversion ("and" | "or") inversion + | inversion + +; 'inversion' structures can contain inversion expressions or 'comparison' structures +inversion: + '!' "v" expression + | "invert" expression + | comparison + +; 'comparison' structures can contain equality, inequality, lesser than, greater than, lesser than or equality, greater than or equality, +; is-contained-in or not-contained-in comparison expressions or 'bitwise-or' structures +comparison: + bitwise-or ('=' | '!' | '<' | '>' | '<=' | '>=' | "not" "in" | "in") bitwise-or + | bitwise-or + +; 'bitwise-or' structures can contain bitwise-or expressions or 'bitwise-xor' structures +bitwise-or: + bitwise-xor '|' bitwise-xor + | bitwise-xor + +; 'bitwise-xor' structures can contain bitwise-xor expressions or 'bitwise-and' structures +bitwise-xor: + bitwise-and '\' bitwise-and + | bitwise-and + +; 'bitwise-and' structures can contain bitwise-and expressions or 'bitwise-shift' structures +bitwise-and: + bitwise-shift '&' bitwise-shift + | bitwise-shift + +; 'bitwise-shift' structures can contain bitwise-left-shift or bitwise-right-shift expressions or 'arithmetic-expression' structures +bitwise-shift: + arithmetic-expression ('<<' | '>>') arithmetic-expression + | arithmetic-expression + +; 'arithmetic-expression' structures can contain addition or subtraction expressions or 'term' structures +arithmetic-expression: + term ('+' | '-') term + | term + +; 'term' structures can contain multiplication, division or modulus expressions or 'factor' structures +term: + factor ('*' | '/' | '%') factor + | factor + +; 'factor' structures can contain positive, negative or bitwise-inversion unary expressions or 'power' structures +factor: + ('+' | '-' | '~') factor + | power + +; 'power' structures can contain power expression or 'object-call' structures +power: + object-call '^' object-call + | object-call + +; 'object-attribute-access' structures can contain object attribute access expressions or 'call' structures +object-attribute-access: + call '.' object-call + | call + +; 'call' structures can contain function/object creation call expressions or 'atom' structures +call: + atom '(' '\n'+? (expression '\n'+? (',' '\n'+? expression '\n'+?)+?)? ')' + | atom + +; 'atom' structures can contain literal value definition, variable access, parenthetical, array definition, list definition, dictionary definition expressions and 'if-expression' structures +atom: + ([integer] | [floating point] | [string] | [character] | [character list]) + | "global"? ([identifier] | [qeyword]) + | '(' '\n'+? expression '\n'+? ')' + | '(' '\n'+? (expression '\n'+? ',' '\n'+? (expression '\n'+? (',' '\n'+? expression '\n'+?)+?)?)? ')' + | '[' '\n'+? (expression '\n'+? (',' '\n'+? expression '\n'+?)+?)? ']' + | '{' '\n'+? (expression '\n'+? ':' '\n'+? expression '\n'+? (',' '\n'+? expression '\n'+? ':' '\n'+? expression '\n'+?)+?)? '}' + | if-expression + | count-expression + | while-expression + | try-expression + | function-definition-expression + | object-definition-expression + | include-expression + +; 'if-expression' structures contain declarations of conditional if-else-if-else expressions. +if-expression: + "if" expression "do" statements ("else" "if" expression "do" statements)+? ("else" "do" statements)? "end" + | "if" expression "do" statement ("else" "if" expression "do" statement)+? ("else" "do" statement)? + +; 'count-expression' structures contain declarations of count loops, which are like for loops in C#. +count-expression: + "count" ("from" expression)? "to" expression ("step" expression)? ("as" expression)? "do" statements "end" + | "count" ("from" expression)? "to" expression ("step" expression)? ("as" expression)? "do" statement + +; 'while-expression' structures contain declarations of while loops. +while-expression: + "while" expression "do" statements "end" + | "while" expression "do" statement + +; 'try-expression' structures contain declarations of try-error blocks, which are like try-catch blocks in C#. +try-expression: + "try" "do" statements ("error" expression ("as" expression)? "do" statements)+? ("error" ("as" expression)? "do" statements)? "end" + | "try" "do" statement ("error" expression ("as" expression)? "do" statement)+? ("error" ("as" expression)? "do" statement)? + +; 'function-definition-expression' structures contain declarations of functions. +function-definition-expression: + "function" expression? ("with" expression (',' expression)+?)? "do" statements "end" + | "function" expression? ("with" expression (',' expression)+?)? "do" statement + +; 'object-definition-expression' structures contain declarations of objects. +object-definition-expression: + "object" expression? ("with" expression (',' expression)+?)? ("from" expression (',' expression)+?)? "do" statements "end" + | "object" expression? ("with" expression (',' expression)+?)? ("from" expression (',' expression)+?)? "do" statement + +; 'include-expression' structures contain declarations of include expressions, which are like using statements in C#. +include-expression: + "include" expression ("as" expression)? + | "include" expression "from" expression ("as" expression)? \ No newline at end of file diff --git a/src/EzrLexer.cs b/src/EzrLexer.cs index 3a5584f..f8e1acc 100644 --- a/src/EzrLexer.cs +++ b/src/EzrLexer.cs @@ -4,11 +4,11 @@ namespace EzrSquared.EzrLexer { - using EzrGeneral; + using EzrCommon; using EzrErrors; /// - /// The ezrSquared Lexer or Tokenizer. The job of the Lexer is to convert the user input (code) into objects to be given as the input to the Parser (TODO). + /// The ezrSquared Lexer or Tokenizer. The job of the Lexer is to convert the user input (code) into objects to be given as the input to the . /// public class Lexer { @@ -18,7 +18,7 @@ public class Lexer private readonly string _file; /// - /// The script as text. + /// The script to be tokenized. /// private readonly string _script; @@ -41,7 +41,7 @@ public class Lexer /// Creates a new object. /// /// The file name/path of the script. - /// The script as text. + /// The script to be tokenized. public Lexer(string file, string script) { _file = file; @@ -57,13 +57,11 @@ public Lexer(string file, string script) private void Advance() { _position.Advance(_currentChar); + if (_position.Index < _script.Length) _currentChar = _script[_position.Index]; else - { - _currentChar = '\0'; _reachedEndFlag = true; - } } /// @@ -83,7 +81,7 @@ private char Peek() /// Creates a of objects from the given script. /// /// The created of objects. - /// Any that occured in the lexing; if none occured. + /// Any that occurred in the lexing; if none occurred. /// if the lexing succeeded without any errors; otherwise . public bool Tokenize(out List tokens, out Error? error) { @@ -100,8 +98,8 @@ public bool Tokenize(out List tokens, out Error? error) break; case ';': case '\n': + tokens.Add(new Token(TokenType.NewLine, TokenTypeGroup.Special, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.NewLine, string.Empty, _position.Copy())); break; case '@': Advance(); @@ -133,15 +131,15 @@ public bool Tokenize(out List tokens, out Error? error) if (_currentChar == '=') { Advance(); - tokens.Add(new Token(TokenType.LessThanOrEqual, string.Empty, lessThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.LessThanOrEqual, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); } else if (_currentChar == '<') { Advance(); - tokens.Add(new Token(TokenType.BitwiseLeftShift, string.Empty, lessThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.BitwiseLeftShift, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); } else - tokens.Add(new Token(TokenType.LessThanSign, string.Empty, lessThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.LessThanSign, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); break; case '>': Position greaterThanTokenStartPosition = _position.Copy(); @@ -150,15 +148,15 @@ public bool Tokenize(out List tokens, out Error? error) if (_currentChar == '=') { Advance(); - tokens.Add(new Token(TokenType.GreaterThanOrEqual, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.GreaterThanOrEqual, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); } else if (_currentChar == '>') { Advance(); - tokens.Add(new Token(TokenType.BitwiseRightShift, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.BitwiseRightShift, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); } else - tokens.Add(new Token(TokenType.GreaterThanSign, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.GreaterThanSign, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); break; case '-': Position minusTokenStartPosition = _position.Copy(); @@ -167,86 +165,86 @@ public bool Tokenize(out List tokens, out Error? error) if (_currentChar == '>') { Advance(); - tokens.Add(new Token(TokenType.Arrow, string.Empty, minusTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.Arrow, TokenTypeGroup.Symbol, string.Empty, minusTokenStartPosition, _position.Copy())); } else - tokens.Add(new Token(TokenType.HyphenMinus, string.Empty, minusTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.HyphenMinus, TokenTypeGroup.Symbol, string.Empty, minusTokenStartPosition, _position.Copy())); break; case '+': + tokens.Add(new Token(TokenType.Plus, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.Plus, string.Empty, _position.Copy())); break; case '*': + tokens.Add(new Token(TokenType.Asterisk, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.Asterisk, string.Empty, _position.Copy())); break; case '/': + tokens.Add(new Token(TokenType.Slash, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.Slash, string.Empty, _position.Copy())); break; case '%': + tokens.Add(new Token(TokenType.PercentSign, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.PercentSign, string.Empty, _position.Copy())); break; case '^': + tokens.Add(new Token(TokenType.Caret, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.Caret, string.Empty, _position.Copy())); break; case '=': + tokens.Add(new Token(TokenType.EqualSign, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.EqualSign, string.Empty, _position.Copy())); break; case '!': + tokens.Add(new Token(TokenType.ExclamationMark, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.ExclamationMark, string.Empty, _position.Copy())); break; case ',': + tokens.Add(new Token(TokenType.Comma, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.Comma, string.Empty, _position.Copy())); break; case '.': + tokens.Add(new Token(TokenType.Period, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.Period, string.Empty, _position.Copy())); break; case '(': + tokens.Add(new Token(TokenType.LeftParenthesis, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.LeftParenthesis, string.Empty, _position.Copy())); break; case ')': + tokens.Add(new Token(TokenType.RightParenthesis, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.RightParenthesis, string.Empty, _position.Copy())); break; case '[': + tokens.Add(new Token(TokenType.LeftSquareBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.LeftSquareBracket, string.Empty, _position.Copy())); break; case ']': + tokens.Add(new Token(TokenType.RightSquareBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.RightSquareBracket, string.Empty, _position.Copy())); break; case '{': + tokens.Add(new Token(TokenType.LeftCurlyBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.LeftCurlyBracket, string.Empty, _position.Copy())); break; case '}': + tokens.Add(new Token(TokenType.RightCurlyBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.RightCurlyBracket, string.Empty, _position.Copy())); break; case '&': + tokens.Add(new Token(TokenType.Ampersand, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.Ampersand, string.Empty, _position.Copy())); break; case '|': + tokens.Add(new Token(TokenType.VerticalBar, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.VerticalBar, string.Empty, _position.Copy())); break; case '\\': + tokens.Add(new Token(TokenType.Backslash, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.Backslash, string.Empty, _position.Copy())); break; case '~': + tokens.Add(new Token(TokenType.Tilde, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); - tokens.Add(new Token(TokenType.Tilde, string.Empty, _position.Copy())); break; default: if (char.IsLetter(_currentChar) || _currentChar == '_') @@ -274,9 +272,9 @@ public bool Tokenize(out List tokens, out Error? error) } if (hasPeriod) - tokens.Add(new Token(TokenType.FloatingPoint, numberValue.ToString(), numberTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.FloatingPoint, TokenTypeGroup.Value, numberValue.ToString(), numberTokenStartPosition, _position.Copy())); else - tokens.Add(new Token(TokenType.Integer, numberValue.ToString(), numberTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.Integer, TokenTypeGroup.Value, numberValue.ToString(), numberTokenStartPosition, _position.Copy())); break; } else @@ -285,13 +283,13 @@ public bool Tokenize(out List tokens, out Error? error) char unknownCharacter = _currentChar; Advance(); - error = new UnknownCharacterError($"'{unknownCharacter}'", errorStartPosition, _position); + error = new UnexpectedCharacterError(unknownCharacter, errorStartPosition, _position); return false; } } } - tokens.Add(new Token(TokenType.EndOfFile, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.EndOfFile, TokenTypeGroup.Special, string.Empty, _position.Copy())); return true; } @@ -300,7 +298,7 @@ public bool Tokenize(out List tokens, out Error? error) /// /// The value to enclose the stringlike. /// The identifying of the . - /// Any that occured in creating the stringlike; if none occured. + /// Any that occurred in creating the stringlike; if none occurred. /// The created . private Token CompileStringLike(char enclosingChar, TokenType type, out Error? error) { @@ -429,7 +427,7 @@ private Token CompileStringLike(char enclosingChar, TokenType type, out Error? e error = new InvalidGrammarError($"Expected '{enclosingChar}'", _position.Copy(), _position); Advance(); - return new Token(type, toReturn.ToString(), startPosition, _position.Copy()); + return new Token(type, TokenTypeGroup.Value, toReturn.ToString(), startPosition, _position.Copy()); } /// @@ -445,39 +443,39 @@ private Token CompileColon() { case '+': Advance(); - return new Token(TokenType.AssignmentAddition, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentAddition, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); case '-': Advance(); - return new Token(TokenType.AssignmentSubtraction, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentSubtraction, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); case '*': Advance(); - return new Token(TokenType.AssignmentMultiplication, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentMultiplication, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); case '/': Advance(); - return new Token(TokenType.AssignmentDivision, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentDivision, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); case '%': Advance(); - return new Token(TokenType.AssignmentModulo, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentModulo, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); case '^': Advance(); - return new Token(TokenType.AssignmentPower, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentPower, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); case '&': Advance(); - return new Token(TokenType.AssignmentBitwiseAnd, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentBitwiseAnd, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); case '|': Advance(); - return new Token(TokenType.AssignmentBitwiseOr, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentBitwiseOr, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); case '\\': Advance(); - return new Token(TokenType.AssignmentBitwiseXOr, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentBitwiseXOr, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); case '<': Advance(); - return new Token(TokenType.AssignmentBitwiseLeftShift, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentBitwiseLeftShift, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); case '>': Advance(); - return new Token(TokenType.AssignmentBitwiseRightShift, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentBitwiseRightShift, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); default: - return new Token(TokenType.Colon, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.Colon, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); } } @@ -500,92 +498,94 @@ private Token CompileIdentifier() switch (value) { case "item": - return new Token(TokenType.KeywordItem, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordItem, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "and": - return new Token(TokenType.KeywordAnd, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordAnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "or": - return new Token(TokenType.KeywordOr, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordOr, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "invert": - return new Token(TokenType.KeywordInvert, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordInvert, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "if": - return new Token(TokenType.KeywordIf, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordIf, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "else": - return new Token(TokenType.KeywordElse, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordElse, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "do": - return new Token(TokenType.KeywordDo, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordDo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "count": - return new Token(TokenType.KeywordCount, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordCount, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "from": - return new Token(TokenType.KeywordFrom, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordFrom, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "as": - return new Token(TokenType.KeywordAs, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordAs, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "to": - return new Token(TokenType.KeywordTo, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordTo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "step": - return new Token(TokenType.KeywordStep, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordStep, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "while": - return new Token(TokenType.KeywordWhile, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordWhile, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "function": - return new Token(TokenType.KeywordFunction, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordFunction, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "special": - return new Token(TokenType.KeywordSpecial, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordSpecial, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "with": - return new Token(TokenType.KeywordWith, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordWith, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "end": - return new Token(TokenType.KeywordEnd, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordEnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "return": - return new Token(TokenType.KeywordReturn, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordReturn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "skip": - return new Token(TokenType.KeywordSkip, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordSkip, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "stop": - return new Token(TokenType.KeywordStop, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordStop, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "try": - return new Token(TokenType.KeywordTry, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordTry, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "error": - return new Token(TokenType.KeywordError, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordError, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); + case "not": + return new Token(TokenType.KeywordNot, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "in": - return new Token(TokenType.KeywordIn, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordIn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "object": - return new Token(TokenType.KeywordObject, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordObject, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "global": - return new Token(TokenType.KeywordGlobal, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordGlobal, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "include": - return new Token(TokenType.KeywordInclude, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordInclude, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "all": - return new Token(TokenType.KeywordAll, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.KeywordAll, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); case "f": - return new Token(TokenType.QeywordF, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordF, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "l": - return new Token(TokenType.QeywordL, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordL, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "e": - return new Token(TokenType.QeywordE, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordE, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "c": - return new Token(TokenType.QeywordC, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordC, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "t": - return new Token(TokenType.QeywordT, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordT, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "n": - return new Token(TokenType.QeywordN, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordN, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "w": - return new Token(TokenType.QeywordW, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordW, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "fd": - return new Token(TokenType.QeywordFD, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordFD, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "sd": - return new Token(TokenType.QeywordSD, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordSD, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "od": - return new Token(TokenType.QeywordOD, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordOD, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "i": - return new Token(TokenType.QeywordI, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordI, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "s": - return new Token(TokenType.QeywordS, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordS, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "d": - return new Token(TokenType.QeywordD, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordD, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "g": - return new Token(TokenType.QeywordG, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordG, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); case "v": - return new Token(TokenType.QeywordV, value, startPosition, _position.Copy()); + return new Token(TokenType.QeywordV, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); default: - return new Token(TokenType.Identifier, value, startPosition, _position.Copy()); + return new Token(TokenType.Identifier, TokenTypeGroup.Special, value, startPosition, _position.Copy()); } } } -} +} \ No newline at end of file diff --git a/src/EzrNodes.cs b/src/EzrNodes.cs new file mode 100644 index 0000000..db50297 --- /dev/null +++ b/src/EzrNodes.cs @@ -0,0 +1,774 @@ +using System.Collections.Generic; + +namespace EzrSquared.EzrNodes +{ + using EzrCommon; + + /// + /// The representation of an ezrSquared source code construct. This is the base class of all nodes. Only for inheritance! + /// + public abstract class Node + { + /// + /// The starting of the . + /// + public Position StartPosition; + + /// + /// The ending of the . + /// + public Position EndPosition; + + /// + /// Creates a new object. + /// + /// The starting of the . + /// The ending of the . + public Node(Position startPosition, Position endPosition) + { + StartPosition = startPosition; + EndPosition = endPosition; + } + + public override string ToString() + { + return "Node()"; + } + } + + /// + /// The dummy invalid structure. For returning instead of if an occurs during parsing. + /// + public class InvalidNode : Node + { + /// + /// The static object. + /// + public static InvalidNode StaticInvalidNode = new InvalidNode(new Position(-1, -1, string.Empty, string.Empty), new Position(0, -1, string.Empty, string.Empty)); + + /// + /// Creates a new object. + /// + /// The starting of the . + /// The ending of the . + public InvalidNode(Position startPosition, Position endPosition) : base(startPosition, endPosition) { } + + public override string ToString() + { + return "InvalidNode()"; + } + } + + /// + /// The structure of a simple value like literals and variables. + /// + public class ValueNode : Node + { + /// + /// The value the represents. + /// + public Token Value; + + /// + /// Creates a new object. + /// + /// The value the represents, a object of the same type as must be used with the . + /// The starting of the . + /// The ending of the . + public ValueNode(Token value, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Value = value; + } + + public override string ToString() + { + return $"ValueNode({Value.Value})"; + } + } + + /// + /// The structure for an arraylike (array or list). + /// + public class ArrayLikeNode : Node + { + /// + /// The elements of the arraylike. + /// + public List Elements; + + /// + /// The check for if the should create a list instead of an array. + /// + public bool CreateList; + + /// + /// Creates a new object. + /// + /// The elements of the arraylike. + /// The check for if the should create a list instead of an array. + /// The starting of the . + /// The ending of the . + public ArrayLikeNode(List elements, bool createList, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Elements = elements; + CreateList = createList; + } + + public override string ToString() + { + string[] elements = new string[Elements.Count]; + for (int i = 0; i < Elements.Count; i++) + elements[i] = Elements[i].ToString(); + + return $"ArrayLikeNode([{string.Join(", ", elements)}], {CreateList})"; + } + } + + /// + /// The structure for a dictionary. + /// + public class DictionaryNode : Node + { + /// + /// The key-value pairs of the dictionary. + /// + public List KeyValuePairs; + + /// + /// Creates a new object. + /// + /// The key-value pairs of the dictionary. + /// The starting of the . + /// The ending of the . + public DictionaryNode(List keyValuePairs, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + KeyValuePairs = keyValuePairs; + } + + public override string ToString() + { + string[] keyValuePairs = new string[KeyValuePairs.Count]; + for (int i = 0; i < KeyValuePairs.Count; i++) + keyValuePairs[i] = $"{keyValuePairs[i][0]} : {keyValuePairs[i][1]}"; + return $"DictionaryNode([{string.Join(", ", keyValuePairs)}])"; + } + } + + /// + /// The structure for a binary operation. + /// + public class BinaryOperationNode : Node + { + /// + /// The first operand of the binary operation. + /// + public Node Left; + + /// + /// The second operand of the binary operation. + /// + public Node Right; + + /// + /// The operator of the binary operation. + /// + public TokenType Operator; + + /// + /// Creates a new object. + /// + /// The first operand of the binary operation. + /// The second operand of the binary operation. + /// The operator of the binary operation. + /// The starting of the . + /// The ending of the . + public BinaryOperationNode(Node left, Node right, TokenType @operator, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Left = left; + Right = right; + Operator = @operator; + } + + public override string ToString() + { + return $"BinaryOperationNode({Left}, {Operator}, {Right})"; + } + } + + /// + /// The structure for a unary operation. + /// + public class UnaryOperationNode : Node + { + /// + /// The operand of the unary operation. + /// + public Node Operand; + + /// + /// The operator of the unary operation. + /// + public TokenType Operator; + + /// + /// Creates a new object. + /// + /// The operand of the unary operation. + /// The operator of the unary operation. + /// The starting of the . + /// The ending of the . + public UnaryOperationNode(Node operand, TokenType @operator, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Operand = operand; + Operator = @operator; + } + + public override string ToString() + { + return $"UnaryOperationNode({Operand}, {Operator})"; + } + } + + /// + /// The structure for accesing a variable from the context. + /// + public class VariableAccessNode : Node + { + /// + /// The name of the variable to access. + /// + public Token Name; + + /// + /// The check for if the variable access is from the global or local context. + /// + public bool GlobalAccess; + + /// + /// Creates a new object. + /// + /// The name of the variable, a object of type . + /// The check for if the variable access is from the global or local context. + /// The starting of the . + /// The ending of the . + public VariableAccessNode(Token name, bool globalAccess, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Name = name; + GlobalAccess = globalAccess; + } + + public override string ToString() + { + return $"VariableAccessNode({Name.Value}, {GlobalAccess})"; + } + } + + /// + /// The structure for assigning a value to a variable in the context. + /// + public class NodeVariableAssignmentNode : Node + { + /// + /// The variable to be assigned to. + /// + public Node Variable; + + /// + /// The operation , if not , between the existing value of and . The result of the operation will be assigned to . + /// + public TokenType AssignmentOperator; + + /// + /// The value to be assigned to . + /// + public Node Value; + + /// + /// The check for if the variable assignment is to the global or local context. Irrelevant if the variable to be assigned to is in a local context. + /// + public bool GlobalAssignment; + + /// + /// Creates a new object. + /// + /// The variable to be assigned to. + /// The operation , if not , between the existing value of and . The result of the operation will be assigned to . + /// The value to be assigned to . + /// The check for if the variable assignment is to the global or local context. Irrelevant if the variable to be assigned to is in a local context. + /// The starting of the . + /// The ending of the . + public NodeVariableAssignmentNode(Node variable, TokenType assignmentOperator, Node value, bool globalAssignment, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Variable = variable; + AssignmentOperator = assignmentOperator; + Value = value; + GlobalAssignment = globalAssignment; + } + + public override string ToString() + { + return $"NodeVariableAssignmentNode({Variable}, {AssignmentOperator}, {Value}, {GlobalAssignment})"; + } + } + + /// + /// The structure for assigning a value to a variable in the context. + /// + public class TokenVariableAssignmentNode : Node + { + /// + /// The variable to be assigned to. + /// + public Token Variable; + + /// + /// The operation , if not , between the existing value of and . The result of the operation will be assigned to . + /// + public TokenType AssignmentOperator; + + /// + /// The value to be assigned to . + /// + public Node Value; + + /// + /// The check for if the variable assignment is to the global or local context. Irrelevant if the variable to be assigned to is in a local context. + /// + public bool GlobalAssignment; + + /// + /// Creates a new object. + /// + /// The variable to be assigned to. + /// The operation , if not , between the existing value of and . The result of the operation will be assigned to . + /// The value to be assigned to . + /// The check for if the variable assignment is to the global or local context. Irrelevant if the variable to be assigned to is in a local context. + /// The starting of the . + /// The ending of the . + public TokenVariableAssignmentNode(Token variable, TokenType assignmentOperator, Node value, bool globalAssignment, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Variable = variable; + AssignmentOperator = assignmentOperator; + Value = value; + GlobalAssignment = globalAssignment; + } + + public override string ToString() + { + return $"TokenVariableAssignmentNode({Variable.Value}, {AssignmentOperator}, {Value}, {GlobalAssignment})"; + } + } + + /// + /// The structure for a function call. + /// + public class CallNode : Node + { + /// + /// The function to be called. + /// + public Node FunctionToCall; + + /// + /// The array of arguments. + /// + public List Arguments; + + /// + /// Creates a new object. + /// + /// The function to be called. + /// The array of arguments. + /// The starting of the . + /// The ending of the . + public CallNode(Node functionToCall, List arguments, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + FunctionToCall = functionToCall; + Arguments = arguments; + } + + public override string ToString() + { + string[] arguments = new string[Arguments.Count]; + for (int i = 0; i < Arguments.Count; i++) + arguments[i] = Arguments[i].ToString(); + + return $"CallNode({FunctionToCall}, [{string.Join(", ", arguments)}])"; + } + } + + /// + /// The structure for an if expression. + /// + public class IfNode : Node + { + /// + /// The cases of the if expression. + /// + public List Cases; + + /// + /// The body of the else case. + /// + public Node? ElseCase; + + /// + /// Creates a new object. + /// + /// The cases of the if expression. + /// The body of the else case. + /// The starting of the . + /// The ending of the . + public IfNode(List cases, Node? elseCase, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Cases = cases; + ElseCase = elseCase; + } + + public override string ToString() + { + string?[] cases = new string[Cases.Count]; + for (int i = 0; i < Cases.Count; i++) + cases[i] = $"({Cases[i][0]}, {Cases[i][1]})"; + + return $"IfNode([{string.Join(", ", cases)}], {ElseCase})"; + } + } + + /// + /// The structure for a count expression. + /// + public class CountNode : Node + { + /// + /// The amount to count to. + /// + public Node To; + + /// + /// The amount to count from - optional. + /// + public Node? From; + + /// + /// The increment of each iteration - optional. + /// + public Node? Step; + + /// + /// The variable to store the iteration in - optional. + /// + public Node? As; + + /// + /// The body of the count loop. + /// + public Node Body; + + /// + /// Creates a new object. + /// + /// The amount to count to. + /// The amount to count from - optional. + /// The increment of each iteration - optional. + /// The variable to store the iteration in - optional. + /// The body of the count loop. + /// The starting of the . + /// The ending of the . + public CountNode(Node to, Node? from, Node? step, Node? @as, Node body, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + To = to; + From = from; + Step = step; + As = @as; + Body = body; + } + + public override string ToString() + { + return $"CountNode({To}, {From}, {Step}, {As}, {Body})"; + } + } + + /// + /// The structure for an while expression. + /// + public class WhileNode : Node + { + /// + /// The condition of the while loop. + /// + public Node Condition; + + /// + /// The body of the while loop. + /// + public Node Body; + + /// + /// Creates a new object. + /// + /// The condition of the while loop. + /// The body of the while loop. + /// The starting of the . + /// The ending of the . + public WhileNode(Node condition, Node body, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Condition = condition; + Body = body; + } + + public override string ToString() + { + return $"WhileNode({Condition}, {Body})"; + } + } + + /// + /// The structure for a try expression. + /// + public class TryNode : Node + { + /// + /// The try block. + /// + public Node Block; + + /// + /// The error cases of the try expression. + /// + public List Cases; + + /// + /// The (optional) where the error will be stored and the body of the empty else case. + /// + public Node?[]? EmptyCase; + + /// + /// Creates a new object. + /// + /// The try block. + /// The error cases of the try expression. + /// The (optional) where the error will be stored and the body of the empty else case. + /// The starting of the . + /// The ending of the . + public TryNode(Node block, List cases, Node?[]? emptyCase, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Block = block; + Cases = cases; + EmptyCase = emptyCase; + } + + public override string ToString() + { + string?[] cases = new string[Cases.Count]; + for (int i = 0; i < Cases.Count; i++) + cases[i] = $"({Cases[i][0]}, {Cases[i][1]}, {Cases[i][2]})"; + + return (EmptyCase != null) ? $"TryNode({Block}, [{string.Join(", ", cases)}], ({EmptyCase[0]}, {EmptyCase[1]}))" : $"TryNode({Block}, [{string.Join(", ", cases)}], )"; + } + } + + /// + /// The structure for a function definition. + /// + public class FunctionDefinitionNode : Node + { + /// + /// The (optional) name of the function. + /// + public Node? Name; + + /// + /// The parameters of the function. + /// + public List Parameters; + + /// + /// The body of the function. + /// + public Node Body; + + /// + /// Creates a new object. + /// + /// The (optional) name of the function. + /// The parameters of the function. + /// The body of the function. + /// The starting of the . + /// The ending of the . + public FunctionDefinitionNode(Node? name, List parameters, Node body, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Name = name; + Parameters = parameters; + Body = body; + } + + public override string ToString() + { + string?[] parameters = new string[Parameters.Count]; + for (int i = 0; i < Parameters.Count; i++) + parameters[i] = Parameters[i].ToString(); + + return $"FunctionDefinitionNode({Name}, [{string.Join(", ", parameters)}], {Body})"; + } + } + + /// + /// The structure for an object definition. + /// + public class ObjectDefinitionNode : Node + { + /// + /// The (optional) name of the object. + /// + public Node? Name; + + /// + /// The creation parameters of the object. + /// + public List Parameters; + + /// + /// The parents of the object. + /// + public List Parents; + + /// + /// The body of the object. + /// + public Node Body; + + /// + /// Creates a new object. + /// + /// The (optional) name of the object. + /// The creation parameters of the object. + /// The parents of the object. + /// The body of the object. + /// The starting of the . + /// The ending of the . + public ObjectDefinitionNode(Node? name, List parameters, List parents, Node body, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Name = name; + Parameters = parameters; + Parents = parents; + Body = body; + } + + public override string ToString() + { + string?[] parameters = new string[Parameters.Count]; + for (int i = 0; i < Parameters.Count; i++) + parameters[i] = Parameters[i].ToString(); + + string?[] parents = new string[Parents.Count]; + for (int i = 0; i < Parents.Count; i++) + parents[i] = Parents[i].ToString(); + + return $"ObjectDefinitionNode({Name}, [{string.Join(", ", parameters)}], [{string.Join(", ", parents)}], {Body})"; + } + } + + /// + /// The structure for an include expression. + /// + public class IncludeNode : Node + { + /// + /// The script to include. + /// + Node Script; + + /// + /// The (optional) specific sub-structure or object to be included from the script. + /// + Node? SubStructure; + + /// + /// Specifies if all contents of the script need to be dumped into the current context. + /// + bool IsDumped; + + /// + /// The (optional) nickname of the object to be included. + /// + Node? Nickname; + + /// + /// Creates a new object. + /// + /// The script to include. + /// The (optional) specific sub-structure or object to be included from the script. + /// Specifies if all contents of the script need to be dumped into the current context. + /// The (optional) nickname of the object to be included. + /// The starting of the . + /// The ending of the . + public IncludeNode(Node script, Node? subStructure, bool isDumped, Node? nickname, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Script = script; + SubStructure = subStructure; + IsDumped = isDumped; + Nickname = nickname; + } + + public override string ToString() + { + return $"IncludeNode({Script}, {SubStructure}, {IsDumped}, {Nickname})"; + } + } + + /// + /// The structure for a return statement. + /// + public class ReturnNode : Node + { + /// + /// The optional value to be returned. + /// + public Node? Value; + + /// + /// Creates a new object. + /// + /// The optional value to be returned. + /// The starting of the . + /// The ending of the . + public ReturnNode(Node? value, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + Value = value; + } + + public override string ToString() + { + return $"ReturnNode({Value})"; + } + } + + /// + /// The structure for a statement or expression without any value (used as skip and stop statement nodes). + /// + public class NoValueNode : Node + { + /// + /// The identifying of the . + /// + public TokenType ValueType; + + /// + /// Creates a new object. + /// + /// The identifying of the . + /// The starting of the . + /// The ending of the . + public NoValueNode(TokenType valueType, Position startPosition, Position endPosition) : base(startPosition, endPosition) + { + ValueType = valueType; + } + + public override string ToString() + { + return $"NoValueNode({ValueType})"; + } + } +} diff --git a/src/EzrParser.cs b/src/EzrParser.cs new file mode 100644 index 0000000..b5c6bce --- /dev/null +++ b/src/EzrParser.cs @@ -0,0 +1,1955 @@ +using System.Collections.Generic; +using System.Linq; +using System; + +namespace EzrSquared.EzrParser +{ + using EzrCommon; + using EzrNodes; + using EzrErrors; + + /// + /// The ezrSquared Parser. The job of the Parser is to convert the input objects from the into objects to be given as the input to the Interpreter (TODO). + /// + public class Parser + { + /// + /// The of objects to be parsed. + /// + private List _tokens; + + /// + /// The index of the object currently being parsed in the . + /// + private int _index; + + /// + /// The object currently being parsed at of . + /// + private Token _currentToken; + + /// + /// The boolean check for if normal syntax or QuickSyntax is being used. + /// + private bool _usingQuickSyntax; + + /// + /// The boolean check for if QuickSyntax was being used previously in parsing. + /// + private bool _wasUsingQuickSyntax; + + /// + /// Creates a new object. + /// + /// The of objects to be parsed. + public Parser(List tokens) + { + _tokens = tokens; + _currentToken = Token.GetInvalidToken(new Position(0, 0, string.Empty, string.Empty), null); + _index = -1; + _usingQuickSyntax = false; + _wasUsingQuickSyntax = false; + + Advance(); + } + + /// + /// Advances to the next object in . + /// + private void Advance() + { + _index++; + + if (_index >= 0 && _index < _tokens.Count) + _currentToken = _tokens[_index]; + else + _currentToken = Token.GetInvalidToken(_currentToken.StartPosition, _currentToken.EndPosition); + } + + /// + /// Reverses back to the object at - in . + /// + /// The number of positions to reverse in . + private void Reverse(int reverseCount = 1) + { + _index -= reverseCount; + + if (_index >= 0 && _index < _tokens.Count) + _currentToken = _tokens[_index]; + else + _currentToken = Token.GetInvalidToken(_currentToken.StartPosition, _currentToken.EndPosition); + } + + /// + /// Peeks at the previous object from in . + /// + /// The object. + private Token PeekPrevious() + { + int previousIndex = _index - 1; + if (previousIndex < 0 || previousIndex >= _tokens.Count) + _currentToken = Token.GetInvalidToken(_currentToken.StartPosition, _currentToken.EndPosition); + return _tokens[previousIndex]; + } + + /// + /// Registers the use of QuickSyntax. + /// + private void RegisterQuickSyntaxUse() + { + _wasUsingQuickSyntax = _usingQuickSyntax; + _usingQuickSyntax = true; + } + + /// + /// Unregisters the use of QuickSyntax. + /// + private void UnregisterQuickSyntaxUse() + { + _usingQuickSyntax = _wasUsingQuickSyntax; + } + + /// + /// Advances through objects until a object of any other has been reached. + /// + /// The object to register the advancements. + /// The number of advancements. + private int SkipNewLines(ParseResult result) + { + int newLineCount = 0; + while (_currentToken.Type == TokenType.NewLine) + { + result.RegisterAdvance(); + Advance(); + + newLineCount++; + } + + return newLineCount; + } + + /// + /// Parses . + /// + /// The object. + public ParseResult Parse() + { + ParseResult result = Statements(); + if (result.Error == null && _currentToken.Type != TokenType.EndOfFile) + return result.Failure(10, new InvalidGrammarError("Did not expect this!", _currentToken.StartPosition, _currentToken.EndPosition)); + return result; + } + + /// + /// Tries creating a . + /// + /// The function to call for the first operand. + /// The function to call for the second operand. If , defaults to . + /// The operator object(s). + /// The object. + private ParseResult BinaryOperation(Func left, Func? right, params TokenType[] operators) + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + + if (right == null) + right = left; + + Node leftNode = result.Register(left()); + if (result.Error != null) + return result; + + SkipNewLines(result); + while (operators.Contains(_currentToken.Type)) + { + TokenType @operator = _currentToken.Type; + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + Node rightNode = result.Register(right()); + if (result.Error != null) + return result; + + leftNode = new BinaryOperationNode(leftNode, rightNode, @operator, startPosition, _currentToken.EndPosition); + SkipNewLines(result); + } + + return result.Success(leftNode); + } + + /// + /// Tries creating a 'statements' structure. + /// + /// The object. + private ParseResult Statements() + { + ParseResult result = new ParseResult(); + List statements = new List(); + Position startPosition = _currentToken.StartPosition; + + SkipNewLines(result); + + Node statement = result.Register(Statement()); + if (result.Error != null) + return result; + statements.Add(statement); + + while (true) + { + // NOTE: Qeyword 'l' for 'else if' is deprecated, use Qeyword 'e' instead in format: + // 'e [check]: [statement(s)]' + + int newLineCount = SkipNewLines(result); + if (newLineCount == 0 || _currentToken.Type == TokenType.EndOfFile + || _currentToken.Type == TokenType.KeywordEnd + || _currentToken.Type == TokenType.KeywordElse + || _currentToken.Type == TokenType.KeywordError + || (_usingQuickSyntax + && (_currentToken.Type == TokenType.QeywordL + || _currentToken.Type == TokenType.QeywordE + || _currentToken.Type == TokenType.QeywordS))) + break; + + statement = result.Register(Statement()); + if (result.Error != null) + return result; + statements.Add(statement); + } + + return result.Success(new ArrayLikeNode(statements, false, startPosition, _currentToken.EndPosition)); + } + + /// + /// Tries creating a 'statement' structure. + /// + /// The object. + private ParseResult Statement() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + + Node expression; + if (_currentToken.Type == TokenType.KeywordReturn) + { + Position possibleEndPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + + if (_currentToken.Type == TokenType.NewLine + || _currentToken.Type == TokenType.EndOfFile + || _currentToken.Type == TokenType.KeywordEnd + || _currentToken.Type == TokenType.KeywordElse + || _currentToken.Type == TokenType.KeywordError + || (_usingQuickSyntax + && (_currentToken.Type == TokenType.QeywordL + || _currentToken.Type == TokenType.QeywordE + || _currentToken.Type == TokenType.QeywordS))) + return result.Success(new ReturnNode(null, startPosition, possibleEndPosition)); + + expression = result.Register(Expression()); + if (result.Error != null) + return result; + + return result.Success(new ReturnNode(expression, startPosition, _currentToken.EndPosition)); + } + else if (_currentToken.Type == TokenType.KeywordSkip || _currentToken.Type == TokenType.KeywordStop) + { + Position endPosition = _currentToken.EndPosition; + TokenType currentTokenType = _currentToken.Type; + result.RegisterAdvance(); + Advance(); + + return result.Success(new NoValueNode(currentTokenType, startPosition, endPosition)); + } + + expression = result.Register(Expression()); + if (result.Error != null) + return result.Failure(4, new InvalidGrammarError("Expected a statement!", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Success(expression); + } + + /// + /// Tries creating a 'expression' structure. + /// + /// In cases where the variable assignment expression requires the 'item' keyword, set this to . + /// The object. + private ParseResult Expression(bool itemKeywordRequired = false) + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + + bool globalAssignment = false; + bool usedItemKeyword = false; + + if (_currentToken.Type == TokenType.KeywordGlobal) + { + globalAssignment = true; + result.RegisterAdvance(); + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordItem) + { + usedItemKeyword = true; + result.RegisterAdvance(); + Advance(); + } + else if (itemKeywordRequired) + { + Node node_ = result.Register(QuickExpression()); + if (result.Error != null) + return result.Failure(4, new InvalidGrammarError("Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Success(node_); + } + + if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) + { + Token possibleVariable = _currentToken; + result.RegisterAdvance(); + Advance(); + + if (_currentToken.TypeGroup != TokenTypeGroup.AssignmentSymbol) + { + Reverse(); + result.ReverseAdvancement(); + + Node variable = result.Register(Junction()); + if (result.Error != null) + return result; + + if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) + { + TokenType assignmentOperator = _currentToken.Type; + result.RegisterAdvance(); + Advance(); + + Node value = result.Register(Expression()); + if (result.Error != null) + return result; + + return result.Success(new NodeVariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + } + else if (usedItemKeyword) + return result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + { + Reverse(result.AdvanceCount); + result.Reset(); + } + } + else + { + TokenType assignmentOperator = _currentToken.Type; + result.RegisterAdvance(); + Advance(); + + Node value = result.Register(Expression()); + if (result.Error != null) + return result; + + return result.Success(new TokenVariableAssignmentNode(possibleVariable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + } + } + else + { + if (usedItemKeyword) + return result.Failure(10, new InvalidGrammarError("Expected a variable name! The variable name is what will be assigned the value in a variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + { + Reverse(result.AdvanceCount); + result.Reset(); + } + } + + Node node = result.Register(QuickExpression()); + if (result.Error != null) + return result.Failure(4, new InvalidGrammarError("Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Success(node); + } + + /// + /// Tries creating a 'quick-expression' structure. + /// + /// The object. + private ParseResult QuickExpression() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + + if (_currentToken.Type == TokenType.ExclamationMark) + { + result.RegisterAdvance(); + Advance(); + + bool globalAssignment = false; + bool usedItemKeyword = false; + if (_currentToken.Type == TokenType.QeywordG) + { + globalAssignment = true; + result.RegisterAdvance(); + Advance(); + } + + if (_currentToken.Type == TokenType.QeywordD) + { + usedItemKeyword = true; + result.RegisterAdvance(); + Advance(); + } + + if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) + { + Token possibleVariable = _currentToken; + result.RegisterAdvance(); + Advance(); + + if (_currentToken.TypeGroup != TokenTypeGroup.AssignmentSymbol) + { + Reverse(); + result.ReverseAdvancement(); + + Node variable = result.Register(Junction()); + if (result.Error != null) + return result; + + if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) + { + TokenType assignmentOperator = _currentToken.Type; + result.RegisterAdvance(); + Advance(); + + Node value = result.Register(Expression()); + if (result.Error != null) + return result; + + return result.Success(new NodeVariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + } + else if (usedItemKeyword) + return result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + { + Reverse(result.AdvanceCount); + result.Reset(); + } + } + else + { + TokenType assignmentOperator = _currentToken.Type; + result.RegisterAdvance(); + Advance(); + + Node value = result.Register(Expression()); + if (result.Error != null) + return result; + + return result.Success(new TokenVariableAssignmentNode(possibleVariable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + } + } + else + { + if (usedItemKeyword) + return result.Failure(10, new InvalidGrammarError("Expected a variable name! The variable name is what will be assigned the value in a variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + { + Reverse(result.AdvanceCount); + result.Reset(); + } + } + } + + Node node = result.Register(Junction()); + if (result.Error != null) + return result.Failure(4, new InvalidGrammarError("Expected a QuickSyntax expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Success(node); + } + + /// + /// Tries creating a 'junction' structure. + /// + /// The object. + private ParseResult Junction() + { + return BinaryOperation(Inversion, null, TokenType.KeywordAnd, TokenType.KeywordOr); + } + + /// + /// Tries creating a 'inversion' structure. + /// + /// The object. + private ParseResult Inversion() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + + if (_currentToken.Type == TokenType.ExclamationMark) + { + result.RegisterAdvance(); + Advance(); + + if (_currentToken.Type == TokenType.QeywordV) + { + TokenType @operator = _currentToken.Type; + result.RegisterAdvance(); + Advance(); + + Node operand = result.Register(Expression()); + if (result.Error != null) + return result; + + return result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); + } + else + { + Reverse(result.AdvanceCount); + result.Reset(); + } + } + else if (_currentToken.Type == TokenType.KeywordInvert) + { + TokenType @operator = _currentToken.Type; + result.RegisterAdvance(); + Advance(); + + Node operand = result.Register(Expression()); + if (result.Error != null) + return result; + + return result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); + } + + Node node = result.Register(Comparison()); + if (result.Error != null) + return result.Failure(4, new InvalidGrammarError("Expected an inversion expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Success(node); + } + + /// + /// Tries creating a 'comparison' structure. + /// + /// The object. + private ParseResult Comparison() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + + Node left = result.Register(BitwiseOr()); + if (result.Error != null) + return result; + + SkipNewLines(result); + while (_currentToken.Type == TokenType.EqualSign + || _currentToken.Type == TokenType.ExclamationMark + || _currentToken.Type == TokenType.LessThanSign + || _currentToken.Type == TokenType.GreaterThanSign + || _currentToken.Type == TokenType.LessThanOrEqual + || _currentToken.Type == TokenType.GreaterThanOrEqual + || _currentToken.Type == TokenType.KeywordNot + || _currentToken.Type == TokenType.KeywordIn) + { + TokenType @operator = _currentToken.Type; + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + if (@operator == TokenType.KeywordNot) + { + if (_currentToken.Type != TokenType.KeywordIn) + return result.Failure(10, new InvalidGrammarError("Expected the 'in' keyword! The 'in' keyword is the second part of a check-not-in operation.", _currentToken.StartPosition, _currentToken.EndPosition)); + result.RegisterAdvance(); + Advance(); + } + + Node rightNode = result.Register(BitwiseOr()); + if (result.Error != null) + return result; + + left = new BinaryOperationNode(left, rightNode, @operator, startPosition, _currentToken.EndPosition); + SkipNewLines(result); + } + + return result.Success(left); + } + + /// + /// Tries creating a 'bitwise-or' structure. + /// + /// The object. + private ParseResult BitwiseOr() + { + return BinaryOperation(BitwiseXOr, null, TokenType.VerticalBar); + } + + /// + /// Tries creating a 'bitwise-xor' structure. + /// + /// The object. + private ParseResult BitwiseXOr() + { + return BinaryOperation(BitwiseAnd, null, TokenType.Backslash); + } + + /// + /// Tries creating a 'bitwise-and' structure. + /// + /// The object. + private ParseResult BitwiseAnd() + { + return BinaryOperation(BitwiseShift, null, TokenType.Ampersand); + } + + /// + /// Tries creating a 'bitwise-shift' structure. + /// + /// The object. + private ParseResult BitwiseShift() + { + return BinaryOperation(ArithmeticExpression, null, TokenType.BitwiseLeftShift, TokenType.BitwiseRightShift); + } + + /// + /// Tries creating a 'arithmetic-expression' structure. + /// + /// The object. + private ParseResult ArithmeticExpression() + { + return BinaryOperation(Term, null, TokenType.Plus, TokenType.HyphenMinus); + } + + /// + /// Tries creating a 'term' structure. + /// + /// The object. + private ParseResult Term() + { + return BinaryOperation(Factor, null, TokenType.Asterisk, TokenType.Slash, TokenType.PercentSign); + } + + /// + /// Tries creating a 'factor' structure. + /// + /// The object. + private ParseResult Factor() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + + TokenType @operator = _currentToken.Type; + if (@operator == TokenType.Plus || @operator == TokenType.HyphenMinus || @operator == TokenType.Tilde) + { + result.RegisterAdvance(); + Advance(); + + Node operand = result.Register(Factor()); + if (result.Error != null) + return result; + + return result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); + } + + return Power(); + } + + /// + /// Tries creating a 'power' structure. + /// + /// The object. + private ParseResult Power() + { + return BinaryOperation(ObjectAttributeAccess, null, TokenType.Caret); + } + + /// + /// Tries creating a 'object-attribute-access' structure. + /// + /// The object. + private ParseResult ObjectAttributeAccess() + { + return BinaryOperation(Call, ObjectAttributeAccess, TokenType.Period); + } + + /// + /// Tries creating a 'call' structure. + /// + /// The object. + private ParseResult Call() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + + Node node = result.Register(Atom()); + if (result.Error != null) + return result; + + if(_currentToken.Type == TokenType.LeftParenthesis) + { + result.RegisterAdvance(); + Advance(); + + Position possibleErrorStartPosition = _currentToken.StartPosition; + + SkipNewLines(result); + Position endPosition; + List arguments = new List(); + if (_currentToken.Type == TokenType.RightParenthesis) + { + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else + { + + arguments.Add(result.Register(Expression())); + if (result.Error != null) + return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); + // return result.Failure(5, new InvalidGrammarError("Expected an expression or right-parenthesis symbol! The right-parenthesis ends the function/object call expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + + SkipNewLines(result); + while (_currentToken.Type == TokenType.Comma) + { + possibleErrorStartPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + arguments.Add(result.Register(Expression())); + if (result.Error != null) + return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); + SkipNewLines(result); + } + + if (_currentToken.Type != TokenType.RightParenthesis) + return result.Failure(10, new InvalidGrammarError("Expected a comma or right-parenthesis symbol! Commas are used to seperate the arguments of the function/object call expression, and the right-parenthesis is used to end it.", _currentToken.StartPosition, _currentToken.EndPosition)); + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + + return result.Success(new CallNode(node, arguments, startPosition, endPosition)); + } + return result.Success(node); + } + + /// + /// Tries creating a 'atom' structure. + /// + /// The object. + private ParseResult Atom() + { + ParseResult result = new ParseResult(); + + Token startToken = _currentToken; + if(startToken.TypeGroup == TokenTypeGroup.Value) + { + result.RegisterAdvance(); + Advance(); + + return result.Success(new ValueNode(startToken, startToken.StartPosition, startToken.EndPosition)); + } + else if (startToken.Type == TokenType.Identifier || startToken.TypeGroup == TokenTypeGroup.Qeyword) + { + result.RegisterAdvance(); + Advance(); + + return result.Success(new VariableAccessNode(startToken, false, startToken.StartPosition, startToken.EndPosition)); + } + else + { + switch (startToken.Type) + { + case TokenType.KeywordGlobal: + result.RegisterAdvance(); + Advance(); + + if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) + { + Token variable = _currentToken; + Position endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + + return result.Success(new VariableAccessNode(variable, true, startToken.StartPosition, endPosition)); + } + return result.Failure(10, new InvalidGrammarError("Expected a variable name or the 'item' keyword! The variable name is used to access a global variable in a global variable access expression and the 'item' keyword is used to assign to a global variable in a global variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + case TokenType.LeftParenthesis: + Node arrayNode = result.Register(ArrayStructure()); + if (result.Error != null) + return result; + return result.Success(arrayNode); + case TokenType.LeftSquareBracket: + Node encapsulatedListNode = result.Register(ListStructure()); + if (result.Error != null) + return result; + return result.Success(encapsulatedListNode); + case TokenType.LeftCurlyBracket: + Node dictionaryNode = result.Register(DictionaryStructure()); + if (result.Error != null) + return result; + return result.Success(dictionaryNode); + case TokenType.KeywordIf: + Node ifNode = result.Register(IfStructure()); + if (result.Error != null) + return result; + return result.Success(ifNode); + case TokenType.KeywordCount: + Node countNode = result.Register(CountStructure()); + if (result.Error != null) + return result; + return result.Success(countNode); + case TokenType.KeywordWhile: + Node whileNode = result.Register(WhileStructure()); + if (result.Error != null) + return result; + return result.Success(whileNode); + case TokenType.KeywordTry: + Node tryNode = result.Register(TryStructure()); + if (result.Error != null) + return result; + return result.Success(tryNode); + case TokenType.KeywordFunction: + Node functionDefinitionNode = result.Register(FunctionDefinitionStructure()); + if (result.Error != null) + return result; + return result.Success(functionDefinitionNode); + case TokenType.KeywordObject: + Node objectDefinitionNode = result.Register(ObjectDefinitionStructure()); + if (result.Error != null) + return result; + return result.Success(objectDefinitionNode); + case TokenType.KeywordInclude: + Node includeNode = result.Register(IncludeStructure()); + if (result.Error != null) + return result; + return result.Success(includeNode); + default: + return result.Failure(4, new InvalidGrammarError("Expected an integer, float, string, character, character list, identifier, 'if' expression, 'count' expression, 'while' expression and so on.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + } + } + + /// + /// Creates the structure of an array, an with set to OR a parenthetical expression. Starts from , which should be of . + /// + /// The object. + private ParseResult ArrayStructure() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + Position possibleErrorStartPosition = _currentToken.StartPosition; + List elements = new List(); + bool isArray = false; + + SkipNewLines(result); + Position endPosition; + if (_currentToken.Type == TokenType.RightParenthesis) + { + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else + { + elements.Add(result.Register(Expression())); + if (result.Error != null) + return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array/parenthetical expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); + // return result.Failure(5, new InvalidGrammarError("Expected an expression or right-parenthesis symbol! The right-parenthesis closes off an empty array.", _currentToken.StartPosition, _currentToken.EndPosition)); + + SkipNewLines(result); + while (_currentToken.Type == TokenType.Comma) + { + isArray = true; + possibleErrorStartPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + if (_currentToken.Type == TokenType.RightParenthesis && elements.Count == 1) + break; + + Node element = result.Register(Expression()); + if (result.Error != null) + { + if (elements.Count > 1) + return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); + + Position errorStartPosition = possibleErrorStartPosition.Copy(); + errorStartPosition.Advance(); + return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array must end with a right-parenthesis.", errorStartPosition, _currentToken.EndPosition))); + } + + elements.Add(element); + SkipNewLines(result); + } + + if (_currentToken.Type != TokenType.RightParenthesis) + { + if (isArray) + return result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! Commas seperate the elements of the array, while the right-parenthesis ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! The comma is used to create an array and seperate it's elements, while the right-parenthesis declares the end of a parenthetical expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + + if (!isArray && elements.Count > 0) + return result.Success(elements[0]); + return result.Success(new ArrayLikeNode(elements, false, startPosition, endPosition)); + } + + /// + /// Creates the structure of a list, an with set to . Starts from , which should be of . + /// + /// The object. + private ParseResult ListStructure() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + Position possibleErrorStartPosition = _currentToken.StartPosition; + + SkipNewLines(result); + Position endPosition; + List elements = new List(); + if (_currentToken.Type == TokenType.RightSquareBracket) + { + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else + { + elements.Add(result.Register(Expression())); + if (result.Error != null) + return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); + // return result.Failure(5, new InvalidGrammarError("Expected an expression or right-square-bracket symbol! The right-square-bracket ends the list expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + + SkipNewLines(result); + while (_currentToken.Type == TokenType.Comma) + { + possibleErrorStartPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + elements.Add(result.Register(Expression())); + if (result.Error != null) + return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); + SkipNewLines(result); + } + + if (_currentToken.Type != TokenType.RightSquareBracket) + return result.Failure(10, new InvalidGrammarError("Expected a comma or a right-square-bracket symbol! Commas are used to seperate elements in the list, while the right-square-bracket ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + + return result.Success(new ArrayLikeNode(elements, true, startPosition, endPosition)); + } + + /// + /// Creates the structure of a dictionary. Starts from , which should be of . + /// + /// The object. + private ParseResult DictionaryStructure() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + Position possibleErrorStartPosition = _currentToken.StartPosition; + List pairs = new List(); + + SkipNewLines(result); + Position endPosition; + if (_currentToken.Type == TokenType.RightCurlyBracket) + { + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else + { + Node left = result.Register(Expression(true)); + if (result.Error != null) + return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); + // return result.Failure(5, new InvalidGrammarError("Expected an expression or a right-curly-bracket symbol! The right-curly-bracket declares the end of the dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + + SkipNewLines(result); + + // NOTE: Breaking change - assignment symbols will break this. + if (_currentToken.Type != TokenType.Colon) + return result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and it's value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + Node right = result.Register(Expression()); + if (result.Error != null) + return result; + + pairs.Add(new Node[2] { left, right }); + SkipNewLines(result); + + while (_currentToken.Type == TokenType.Comma) + { + possibleErrorStartPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + left = result.Register(Expression(true)); + if (result.Error != null) + return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); + + SkipNewLines(result); + if (_currentToken.Type != TokenType.Colon) + return result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and it's value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + right = result.Register(Expression()); + if (result.Error != null) + return result; + + pairs.Add(new Node[2] { left, right }); + SkipNewLines(result); + } + + if (_currentToken.Type != TokenType.RightCurlyBracket) + return result.Failure(10, new InvalidGrammarError("Expected a comma or right-curly-bracket symbol! Commas are used to seperate key-value pairs in the dictionary, and the right-curly-bracket declares it's end.", _currentToken.StartPosition, _currentToken.EndPosition)); + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + + return result.Success(new DictionaryNode(pairs, startPosition, endPosition)); + } + + /// + /// Creates the structure of an if expression. Starts from , which should be of . + /// + /// The object. + private ParseResult IfStructure() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + List cases = new List(); + Node? elseCase = null; + + Node condition = result.Register(Expression()); + if (result.Error != null) + return result; + + if (_currentToken.Type != TokenType.KeywordDo) + return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + result.RegisterAdvance(); + Advance(); + + Node body; + if (_currentToken.Type == TokenType.NewLine) + { + result.RegisterAdvance(); + Advance(); + + body = result.Register(Statements()); + if (result.Error != null) + return result; + + Position endPosition; + cases.Add(new Node[2] { condition, body }); + if (_currentToken.Type == TokenType.KeywordEnd) + { + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else if (_currentToken.Type == TokenType.KeywordElse) + { + while (_currentToken.Type == TokenType.KeywordElse) + { + result.RegisterAdvance(); + Advance(); + + if (_currentToken.Type == TokenType.KeywordIf) + { + if (elseCase != null) + return result.Failure(10, new InvalidGrammarError("The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + + result.RegisterAdvance(); + Advance(); + + condition = result.Register(Expression()); + if (result.Error != null) + return result; + + if (_currentToken.Type != TokenType.KeywordDo) + return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + result.RegisterAdvance(); + Advance(); + + body = result.Register(Statements()); + if (result.Error != null) + return result; + + cases.Add(new Node[2] { condition, body }); + } + else if (_currentToken.Type != TokenType.KeywordDo) + return result.Failure(10, new InvalidGrammarError("Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + { + if (elseCase != null) + return result.Failure(10, new InvalidGrammarError("There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + + result.RegisterAdvance(); + Advance(); + + elseCase = result.Register(Statements()); + if (result.Error != null) + return result; + } + } + + if (_currentToken.Type != TokenType.KeywordEnd) + { + if (elseCase == null) + return result.Failure(10, new InvalidGrammarError("Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else + return result.Failure(10, new InvalidGrammarError("Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + + return result.Success(new IfNode(cases, elseCase, startPosition, endPosition)); + } + + body = result.Register(Statement()); + if (result.Error != null) + return result; + + cases.Add(new Node[2] { condition, body }); + while (_currentToken.Type == TokenType.KeywordElse) + { + result.RegisterAdvance(); + Advance(); + + if (_currentToken.Type == TokenType.KeywordIf) + { + if (elseCase != null) + return result.Failure(10, new InvalidGrammarError("The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + + result.RegisterAdvance(); + Advance(); + + condition = result.Register(Expression()); + if (result.Error != null) + return result; + + if (_currentToken.Type != TokenType.KeywordDo) + return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + result.RegisterAdvance(); + Advance(); + + body = result.Register(Statement()); + if (result.Error != null) + return result; + + cases.Add(new Node[2] { condition, body }); + } + else if (_currentToken.Type != TokenType.KeywordDo) + return result.Failure(10, new InvalidGrammarError("Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + { + if (elseCase != null) + return result.Failure(10, new InvalidGrammarError("There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + + result.RegisterAdvance(); + Advance(); + + elseCase = result.Register(Statement()); + if (result.Error != null) + return result; + } + } + + return result.Success(new IfNode(cases, elseCase, startPosition, PeekPrevious().EndPosition)); + } + + /// + /// Creates the structure of a count expression. Starts from , which should be of . + /// + /// The object. + private ParseResult CountStructure() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + Node to = InvalidNode.StaticInvalidNode; + Node? from = null; + Node? step = null; + Node? @as = null; + + if (_currentToken.Type == TokenType.KeywordFrom) + { + result.RegisterAdvance(); + Advance(); + + from = result.Register(Expression()); + if (result.Error != null) + return result; + } + + if (_currentToken.Type != TokenType.KeywordTo) + { + if (from == null) + return result.Failure(10, new InvalidGrammarError("Expected the 'to' or 'from' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop, and the optional 'from' keyword and the following expression is the amount to count from.", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Failure(10, new InvalidGrammarError("Expected the 'to' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + result.RegisterAdvance(); + Advance(); + + if (_currentToken.Type == TokenType.KeywordStep) + { + result.RegisterAdvance(); + Advance(); + + step = result.Register(Expression()); + if (result.Error != null) + return result; + } + + if (_currentToken.Type == TokenType.KeywordAs) + { + result.RegisterAdvance(); + Advance(); + + @as = result.Register(Expression()); + if (result.Error != null) + return result; + } + + if (_currentToken.Type != TokenType.KeywordDo) + { + if (step == null && @as == null) + return result.Failure(10, new InvalidGrammarError("Expected the 'do', 'step' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, the optional 'step' keyword and the following expression is the increment, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); + else if (@as == null) + return result.Failure(10, new InvalidGrammarError("Expected the 'do' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + result.RegisterAdvance(); + Advance(); + + Node body; + Position endPosition; + if (_currentToken.Type == TokenType.NewLine) + { + result.RegisterAdvance(); + Advance(); + + body = result.Register(Statements()); + if (result.Error != null) + return result; + + if (_currentToken.Type != TokenType.KeywordEnd) + return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else + { + body = result.Register(Statement()); + if (result.Error != null) + return result; + + endPosition = PeekPrevious().EndPosition; + } + + return result.Success(new CountNode(to, from, step, @as, body, startPosition, endPosition)); + } + + /// + /// Creates the structure of a while expression. Starts from , which should be of . + /// + /// The object. + private ParseResult WhileStructure() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + Node condition = result.Register(Expression()); + if (result.Error != null) + return result; + + if (_currentToken.Type != TokenType.KeywordDo) + return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + result.RegisterAdvance(); + Advance(); + + Node body; + Position endPosition; + if (_currentToken.Type == TokenType.NewLine) + { + result.RegisterAdvance(); + Advance(); + + body = result.Register(Statements()); + if (result.Error != null) + return result; + + if (_currentToken.Type != TokenType.KeywordEnd) + return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else + { + body = result.Register(Statement()); + if (result.Error != null) + return result; + + endPosition = PeekPrevious().EndPosition; + } + + return result.Success(new WhileNode(condition, body, startPosition, endPosition)); + } + + /// + /// Creates the structure of a try expression. Starts from , which should be of . + /// + /// The object. + private ParseResult TryStructure() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + Node block; + List cases = new List(); + Node?[]? emptyCase = null; + + if (_currentToken.Type != TokenType.KeywordDo) + return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + result.RegisterAdvance(); + Advance(); + + Node body; + if (_currentToken.Type == TokenType.NewLine) + { + result.RegisterAdvance(); + Advance(); + + block = result.Register(Statements()); + if (result.Error != null) + return result; + + Position endPosition; + if (_currentToken.Type == TokenType.KeywordEnd) + { + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else if (_currentToken.Type == TokenType.KeywordError) + { + while (_currentToken.Type == TokenType.KeywordError) + { + result.RegisterAdvance(); + Advance(); + + Node? error = null; + bool isErrorNull = true; + + ErrorExpressionEvaluation: + bool isAsKeyword = _currentToken.Type == TokenType.KeywordAs; + if (_currentToken.Type == TokenType.KeywordDo || isAsKeyword) + { + if (emptyCase != null) + return result.Failure(10, new InvalidGrammarError("There should only be one empty \"error\" expression! You cannot have multiple \"error\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + + Node? @as = null; + if (isAsKeyword) + { + result.RegisterAdvance(); + Advance(); + + @as = result.Register(Expression()); + if (result.Error != null) + return result; + + if (_currentToken.Type != TokenType.KeywordDo) + return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + result.RegisterAdvance(); + Advance(); + + body = result.Register(Statements()); + if (result.Error != null) + return result; + + if (error != null) + cases.Add(new Node?[3] { error, @as, body }); + else + emptyCase = new Node?[2] { @as, body }; + } + else if (isErrorNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) + { + if (emptyCase != null) + { + Token previous = PeekPrevious(); + return result.Failure(10, new InvalidGrammarError("There can't be any \"error\" expressions after an empty \"error\" expression!", previous.StartPosition, previous.EndPosition)); + } + + error = result.Register(Expression()); + if (result.Error != null) + return result; + + isErrorNull = false; + goto ErrorExpressionEvaluation; + } + else if (isErrorNull) + return result.Failure(10, new InvalidGrammarError("Expected an expression or the 'as' or 'do' keywords! An expression after the 'error' keyword defines what error(s) will lead to the \"error\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + return result.Failure(10, new InvalidGrammarError("Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + if (_currentToken.Type != TokenType.KeywordEnd) + { + if (emptyCase == null) + return result.Failure(10, new InvalidGrammarError("Expected the 'error' or 'end' keywords! The 'error' keyword defines the start of an \"error\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else + return result.Failure(10, new InvalidGrammarError("Expected the 'error' or 'end' keywords! The 'error' keyword defines the start of an \"error\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + + return result.Success(new TryNode(block, cases, emptyCase, startPosition, endPosition)); + } + + block = result.Register(Statement()); + if (result.Error != null) + return result; + + while (_currentToken.Type == TokenType.KeywordError) + { + result.RegisterAdvance(); + Advance(); + + Node? error = null; + bool isErrorNull = true; + + ErrorExpressionEvaluation: + bool isAsKeyword = _currentToken.Type == TokenType.KeywordAs; + if (_currentToken.Type == TokenType.KeywordDo || isAsKeyword) + { + if (emptyCase != null) + return result.Failure(10, new InvalidGrammarError("There should only be one empty \"error\" expression! You cannot have multiple \"error\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + + Node? @as = null; + if (isAsKeyword) + { + result.RegisterAdvance(); + Advance(); + + @as = result.Register(Expression()); + if (result.Error != null) + return result; + + if (_currentToken.Type != TokenType.KeywordDo) + return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + result.RegisterAdvance(); + Advance(); + + body = result.Register(Statement()); + if (result.Error != null) + return result; + + if (error != null) + cases.Add(new Node?[3] { error, @as, body }); + else + emptyCase = new Node?[2] { @as, body }; + } + else if (isErrorNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) + { + if (emptyCase != null) + { + Token previous = PeekPrevious(); + return result.Failure(10, new InvalidGrammarError("There can't be any \"error\" expressions after an empty \"error\" expression!", previous.StartPosition, previous.EndPosition)); + } + + error = result.Register(Expression()); + if (result.Error != null) + return result; + + isErrorNull = false; + goto ErrorExpressionEvaluation; + } + else if (isErrorNull) + return result.Failure(10, new InvalidGrammarError("Expected an expression or the 'as' or 'do' keywords! An expression after the 'error' keyword defines what error(s) will lead to the \"error\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + return result.Failure(10, new InvalidGrammarError("Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + return result.Success(new TryNode(block, cases, emptyCase, startPosition, PeekPrevious().EndPosition)); + } + + /// + /// Creates the structure of a function definition expression. Starts from , which should be of . + /// + /// The object. + private ParseResult FunctionDefinitionStructure() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + Node? name = null; + List parameters = new List(); + Node body; + + Position endPosition; + bool isNameNull = true; + + FunctionDefinitionEvaluation: + bool isWithKeyword = _currentToken.Type == TokenType.KeywordWith; + if (_currentToken.Type == TokenType.KeywordDo || isWithKeyword) + { + if (isWithKeyword) + { + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + parameters.Add(result.Register(Expression())); + if (result.Error != null) + return result; + + SkipNewLines(result); + while (_currentToken.Type == TokenType.Comma) + { + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + parameters.Add(result.Register(Expression())); + if (result.Error != null) + return result; + + SkipNewLines(result); + } + + if (_currentToken.Type != TokenType.KeywordDo) + return result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parameter and the 'do' keyword declares the start of the body of the \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + result.RegisterAdvance(); + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + { + result.RegisterAdvance(); + Advance(); + + body = result.Register(Statements()); + if (result.Error != null) + return result; + + if (_currentToken.Type != TokenType.KeywordEnd) + return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else + { + body = result.Register(Statement()); + if (result.Error != null) + return result; + + endPosition = PeekPrevious().EndPosition; + } + } + else if (isNameNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) + { + name = result.Register(Expression()); + if (result.Error != null) + return result; + + isNameNull = false; + goto FunctionDefinitionEvaluation; + } + else if (isNameNull) + return result.Failure(10, new InvalidGrammarError("Expected an expression or the 'with' or 'do' keywords! An expression after the 'function' keyword defines the name, the 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); + else + return result.Failure(10, new InvalidGrammarError("Expected the 'with' or 'do' keywords! The 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); + + return result.Success(new FunctionDefinitionNode(name, parameters, body, startPosition, endPosition)); + } + + // 'special' expressions are gone. + + /// + /// Creates the structure of an object definition expression. Starts from , which should be of . + /// + /// The object. + private ParseResult ObjectDefinitionStructure() + { + // The parents of the object are now defined after the 'from' keyword like an array. The 'from' keyword must come before the 'do' keyword and after the 'with' keyword. + + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + Node? name = null; + List parameters = new List(); + List parents = new List(); + Node body; + + Position endPosition; + bool isNameNull = true; + + ObjectDefinitionEvaluation: + bool isWithKeyword = _currentToken.Type == TokenType.KeywordWith; + bool isFromKeyword = _currentToken.Type == TokenType.KeywordFrom; + if (_currentToken.Type == TokenType.KeywordDo || isWithKeyword || isFromKeyword) + { + if (isWithKeyword) + { + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + parameters.Add(result.Register(Expression())); + if (result.Error != null) + return result; + + SkipNewLines(result); + while (_currentToken.Type == TokenType.Comma) + { + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + parameters.Add(result.Register(Expression())); + if (result.Error != null) + return result; + + SkipNewLines(result); + } + + isFromKeyword = _currentToken.Type == TokenType.KeywordFrom; + if (_currentToken.Type != TokenType.KeywordDo && !isFromKeyword) + return result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'from' or 'do' keywords! The comma symbol and the following expression defines another parameter, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + if (isFromKeyword) + { + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + parents.Add(result.Register(Expression())); + if (result.Error != null) + return result; + + SkipNewLines(result); + while (_currentToken.Type == TokenType.Comma) + { + result.RegisterAdvance(); + Advance(); + + SkipNewLines(result); + parents.Add(result.Register(Expression())); + if (result.Error != null) + return result; + + SkipNewLines(result); + } + + if (_currentToken.Type != TokenType.KeywordDo) + return result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parent and the 'do' keyword declares the start of the body of the \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + result.RegisterAdvance(); + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + { + result.RegisterAdvance(); + Advance(); + + body = result.Register(Statements()); + if (result.Error != null) + return result; + + if (_currentToken.Type != TokenType.KeywordEnd) + return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + + endPosition = _currentToken.EndPosition; + result.RegisterAdvance(); + Advance(); + } + else + { + body = result.Register(Statement()); + if (result.Error != null) + return result; + + endPosition = PeekPrevious().EndPosition; + } + } + else if (isNameNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) + { + name = result.Register(Expression()); + if (result.Error != null) + return result; + + isNameNull = false; + goto ObjectDefinitionEvaluation; + } + else if (isNameNull) + return result.Failure(10, new InvalidGrammarError("Expected an expression or the 'with', 'from' or 'do' keywords! An expression after the 'object' keyword defines the name, the 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\".", _currentToken.StartPosition, _currentToken.EndPosition)); + else + return result.Failure(10, new InvalidGrammarError("Expected the 'with', 'from' or 'do' keywords! The 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\".", _currentToken.StartPosition, _currentToken.EndPosition)); + + return result.Success(new ObjectDefinitionNode(name, parameters, parents, body, startPosition, endPosition)); + } + + /// + /// Creates the structure of an include expression. Starts from , which should be of . + /// + /// The object. + private ParseResult IncludeStructure() + { + ParseResult result = new ParseResult(); + Position startPosition = _currentToken.StartPosition; + result.RegisterAdvance(); + Advance(); + + Node? subStructure = null; + Node? nickname = null; + bool isDumped = false; + Node script; + + if (_currentToken.Type != TokenType.KeywordAll && _currentToken.Type != TokenType.Comma) + { + subStructure = result.Register(Expression()); + if (result.Error != null) + return result; + } + else + { + isDumped = true; + result.RegisterAdvance(); + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordFrom) + { + result.RegisterAdvance(); + Advance(); + + script = result.Register(Expression()); + if (result.Error != null) + return result; + } + else if (subStructure != null) + { + script = subStructure; + subStructure = null; + } + else + return result.Failure(10, new InvalidGrammarError("Expected the 'from' keyword! If a specific object being included from a script (when the object's name is provided after the 'include' keyword) or if the whole script is added to the script (using the 'all' keyword or a comma symbol after the 'include' keyword), the 'from' keyword followed by an expression declaring the script's name or path must be provided.", _currentToken.StartPosition, _currentToken.EndPosition)); + + if (_currentToken.Type == TokenType.KeywordAs) + { + result.RegisterAdvance(); + Advance(); + + nickname = result.Register(Expression()); + if (result.Error != null) + return result; + } + + return result.Success(new IncludeNode(script, subStructure, isDumped, nickname, startPosition, PeekPrevious().EndPosition)); + } + } + + /// + /// The type of the object that is returned as the result of parsing done by the . + /// + public class ParseResult + { + /// + /// The that occurred while parsing, if any. + /// + public Error? Error; + + /// + /// The which is the result of the parsing. + /// + public Node Node; + + /// + /// The amount of times the advanced. + /// + public int AdvanceCount; + + /// + /// The amount of times the will have to reverse if an occurred in a call. + /// + public int ReverseCount; + + /// + /// The priority of the error held in the . + /// + private int ErrorPriority; + + /// + /// Creates a new object. + /// + public ParseResult() + { + Error = null; + Node = InvalidNode.StaticInvalidNode; + AdvanceCount = 0; + ReverseCount = 0; + ErrorPriority = 0; + } + + /// + /// Resets the object to initialized state. + /// + public void Reset() + { + Error = null; + Node = InvalidNode.StaticInvalidNode; + AdvanceCount = 0; + ReverseCount = 0; + ErrorPriority = 0; + } + + /// + /// Registers an advancement by the . + /// + public void RegisterAdvance() + { + AdvanceCount++; + } + + /// + /// Reverses number of advancements. + /// + /// The number of advancements to reverse by. + public void ReverseAdvancement(int reverseCount = 1) + { + AdvanceCount -= reverseCount; + } + + /// + /// Registers the from a parsing function. + /// + /// The result of the parsing function. + /// The object of . + public Node Register(ParseResult result) + { + AdvanceCount += result.AdvanceCount; + if (result.Error != null) + { + ErrorPriority = result.ErrorPriority; + Error = result.Error; + } + + return result.Node; + } + + /// + /// Tries registering the from a parsing function. + /// + /// The result of the parsing function. + /// The object of , if an occurred. + /// if has no ; otherwise . + public bool TryRegister(ParseResult result, out Node node) + { + if (result.Error != null) + { + ReverseCount = result.AdvanceCount; + node = InvalidNode.StaticInvalidNode; + return false; + } + + AdvanceCount += result.AdvanceCount; + node = result.Node; + return true; + } + + /// + /// Sets as the result of successful parsing. + /// + /// The result of the parsing. + /// The same object. + public ParseResult Success(Node node) + { + Node = node; + return this; + } + + /// + /// Sets as the result of failed parsing. + /// + /// + /// If the of is greater than or equal to the + /// of , then will override . + /// + /// The priority/fatality of the failure. + /// The that occurred in parsing. + /// The same object. + public ParseResult Failure(int priority, Error error) + { + if (Error == null || ErrorPriority <= priority || AdvanceCount == 0) + { + ErrorPriority = priority; + Error = error; + } + + return this; + } + } +} diff --git a/src/EzrShell.cs b/src/EzrShell.cs index 3cb7d77..1ab71bd 100644 --- a/src/EzrShell.cs +++ b/src/EzrShell.cs @@ -5,55 +5,203 @@ namespace EzrSquared.EzrShell { - using EzrGeneral; + using EzrCommon; using EzrErrors; using EzrLexer; + using EzrParser; /// /// The built-in shell for ezrSquared. /// internal class Shell { - private const string _ezrVersion = "0.1.0"; - private const string _projectLink = "https://github.com/Uralstech/ezrSquared/"; - private const string _documentationLink = "https://uralstech.github.io/ezrSquared/Introduction.html"; - private const string _issuesLink = "https://github.com/Uralstech/ezrSquared/issues"; - private const string _startUp = " ___ | ezr² v{0} Built-In Shell\n |_ ) | Online documentation:\n ___ ____ _ __ / / | {1}\n / _ \\ |_ / | '__| /___| | Feature requests and bug reports:\n | __/ / / | | | {2}\n \\___| /___| |_| | GitHub repository:\n___________________________| {3}"; + private const string Version = "0.1.0"; - private static void PrintLexerOutput(string file, string script) + private const string ConsoleGraphicsInfo = $""" + | ezr² v{Version} + | Online documentation: + | https://uralstech.github.io/ezrSquared/Introduction.html + | Feature requests and bug reports: + | https://github.com/Uralstech/ezrSquared/issues + | GitHub repository: + __________________________| https://github.com/Uralstech/ezrSquared/ + """; + + private const string ConsoleGraphicsLetterE = """ + + + ___ + / _ \ + | __/ + \___| + """; + private const string ConsoleGraphicsLetterZ = """ + + + ____ + |_ / + / / + /___| + """; + private const string ConsoleGraphicsLetterR = """ + + + _ __ + | '__| + | | + |_| + """; + private const string ConsoleGraphicsSquaredSymbol = """ + ___ + |_ ) + / / + /___| + + + """; + + private static void PrintSmallConsoleGraphics() { - if (new Lexer(file, script).Tokenize(out List tokens, out Error? error)) - { - for (int i = 0; i < tokens.Count; i++) - Console.WriteLine($"( {tokens[i].Value}, {Enum.GetName(typeof(TokenType), tokens[i].Type)} )"); - } - else if (error != null) - Console.WriteLine(error.ToString()); + Console.Clear(); + Console.BackgroundColor = ConsoleColor.Black; + Console.SetCursorPosition(0, 0); + + Console.ForegroundColor = ConsoleColor.Green; + Console.Write('e'); + + Console.ForegroundColor = ConsoleColor.Red; + Console.Write('z'); + + Console.ForegroundColor = ConsoleColor.Blue; + Console.Write('r'); + + Console.ForegroundColor = ConsoleColor.Yellow; + Console.Write('²'); + + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine($" v{Version}"); } - public static void Main() + private static void PrintBigConsoleGraphics() { - string filePath = string.Empty; + Console.Clear(); + Console.BackgroundColor = ConsoleColor.Black; + + Console.SetCursorPosition(0, 0); + Console.ForegroundColor = ConsoleColor.White; + Console.Write(ConsoleGraphicsInfo); + + Console.ForegroundColor = ConsoleColor.Yellow; + Console.SetCursorPosition(0, 0); + Console.Write(ConsoleGraphicsSquaredSymbol); + + Console.ForegroundColor = ConsoleColor.Blue; + Console.SetCursorPosition(0, 0); + Console.Write(ConsoleGraphicsLetterR); + + Console.ForegroundColor = ConsoleColor.Red; + Console.SetCursorPosition(0, 0); + Console.Write(ConsoleGraphicsLetterZ); + Console.ForegroundColor = ConsoleColor.Green; + Console.SetCursorPosition(0, 0); + Console.Write(ConsoleGraphicsLetterE); + Console.Write("\n\n"); + } + + public static void Main(string[] args) + { + string filePath; string[] commandLineArguments = Environment.GetCommandLineArgs(); - if (commandLineArguments.Length > 1 && File.Exists(commandLineArguments[1])) + if (commandLineArguments.Length == 1) + filePath = string.Empty; + else if (commandLineArguments.Length > 1 && File.Exists(commandLineArguments[1])) { filePath = commandLineArguments[1]; - PrintLexerOutput(filePath, File.ReadAllText(filePath)); + //PrintLexerOutput(filePath, File.ReadAllText(filePath)); + + Console.WriteLine("Press any key to continue..."); + Console.ReadKey(); + return; + } + else + { + ConsoleColor previousForegroundColor = Console.ForegroundColor; + ConsoleColor previousBackgroundColor = Console.BackgroundColor; + + Console.ForegroundColor = ConsoleColor.Red; + Console.BackgroundColor = ConsoleColor.Black; + Console.WriteLine("Intended use (square brackets indicate optional arguments): ezrSquared [file.ezr2] [file.eout]"); + + Console.ForegroundColor = previousForegroundColor; + Console.BackgroundColor = previousBackgroundColor; + return; } + + Console.OutputEncoding = Encoding.Unicode; + +#if PLATFORM_WINDOWS + if (Console.WindowWidth > 84) + PrintBigConsoleGraphics(); else + PrintSmallConsoleGraphics(); +#else + PrintConsoleGraphic(); +#endif + + while (true) { - Console.OutputEncoding = Encoding.Unicode; - Console.WriteLine(string.Format(_startUp, _ezrVersion, _documentationLink, _issuesLink, _projectLink)); - while (true) + string? input = GetInput(); + + if (!string.IsNullOrEmpty(input)) { - Console.Write(">>> "); - string? input = Console.ReadLine(); + PrintLexerOutput("shell", input, out List tokens, out Error? error); + if (error != null) + { + PrintError(error.ToString()); + continue; + } + + ParseResult result = new Parser(tokens).Parse(); + if (result.Error != null) + { + PrintError(result.Error.ToString()); + continue; + } - if (!string.IsNullOrEmpty(input)) - PrintLexerOutput("ezr² Built-In Shell", input); + PrintResult(result.Node.ToString()); } } } + + private static void PrintError(string error) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(error); + } + + private static void PrintResult(string result) + { + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(result); + } + + private static string? GetInput() + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.Write(">>> "); + + return Console.ReadLine(); + } + + private static void PrintLexerOutput(string file, string script, out List tokens, out Error? error) + { + if (new Lexer(file, script).Tokenize(out tokens, out error)) + { + Console.ForegroundColor = ConsoleColor.Gray; + for (int i = 0; i < tokens.Count; i++) + Console.WriteLine($"( '{tokens[i].Value}', {Enum.GetName(typeof(TokenType), tokens[i].Type)}, {Enum.GetName(typeof(TokenTypeGroup), tokens[i].TypeGroup)} )"); + } + } } } \ No newline at end of file diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 7829b95..7f2b26d 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -21,4 +21,8 @@ true + + + PLATFORM_WINDOWS + From 7b0a83c326b454b0129df3855e7c99931be2c333 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 12 Sep 2023 21:55:12 +0530 Subject: [PATCH 004/113] Lots of bugfixes and a better shell! --- README.md | 8 +- src/AutoGeneratedAssemblyInfo.cs | 2 +- src/EzrErrors.cs | 12 +- src/EzrLexer.cs | 27 ++-- src/EzrNodes.cs | 8 +- src/EzrParser.cs | 24 +++- src/EzrShell.cs | 223 +++++++++++++++++++++++-------- tests/full_test.ezr2 | 208 +++++++++++++++++++++++++++- 8 files changed, 436 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index c05fd93..dc2506a 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,17 @@ # The `ezr²` Programming Language -**ezr², or ezrSquared when you can't use the `²` symbol - is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#!** +**ezr², or ezrSquared when you can't use the `²` symbol (or it's too inconvenient) - is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#!** More information and documentation about ezr² is available at ***https://uralstech.github.io/ezrSquared***! ## What's the 'ezrSquared-re' branch? ezrSquared is being rewritten from the ground up! Expect more features, better performance and better code documentation! +## Update! +I've finished the parser! Well, the important bits of it. Next what's left is (in no perticular order): +* QuickSyntax integration into the parser. +* Making the whole interpreter. +* Probably a lot more testing. + ## Contributing ezr² is an open source project and welcomes contributions from anyone who wants to improve it. diff --git a/src/AutoGeneratedAssemblyInfo.cs b/src/AutoGeneratedAssemblyInfo.cs index aaf8897..c36e89c 100644 --- a/src/AutoGeneratedAssemblyInfo.cs +++ b/src/AutoGeneratedAssemblyInfo.cs @@ -11,7 +11,7 @@ using System; using System.Reflection; -[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Runtime.Versioning.TargetPlatformAttribute("Windows10.0.22621.0")] [assembly: System.Runtime.Versioning.SupportedOSPlatformAttribute("Windows7.0")] diff --git a/src/EzrErrors.cs b/src/EzrErrors.cs index fab55cb..7bc25bf 100644 --- a/src/EzrErrors.cs +++ b/src/EzrErrors.cs @@ -61,12 +61,12 @@ public override string ToString() internal string StringWithUnderline() { string text = _startPosition.Script; - int start = Math.Max(text[0..((_startPosition.Index <= text.Length) ? _startPosition.Index : text.Length)].LastIndexOf('\n'), 0); + int start = Math.Max(text[0..((_startPosition.Index < text.Length) ? _startPosition.Index : text.Length)].LastIndexOf('\n'), 0); int end = text.IndexOf('\n', start + 1); if (end == -1) end = text.Length; - return new StringBuilder(text[start..end]).Append('\n').Append(' ', _startPosition.Index).Append('~', _endPosition.Index - _startPosition.Index).Replace("\t", string.Empty).ToString(); + return new StringBuilder(text[start..end]).Append('\n').Append(' ', _startPosition.Index - start).Append('~', _endPosition.Index - _startPosition.Index).Replace('\t', ' ').ToString(); } } @@ -75,6 +75,14 @@ internal string StringWithUnderline() /// internal class UnexpectedCharacterError : Error { + /// + /// Creates a new object. + /// + /// The character that caused the . + /// The starting of the . + /// The ending of the . + public UnexpectedCharacterError(string character, Position startPosition, Position endPosition) : base("Unexpected character", character, startPosition, endPosition) { } + /// /// Creates a new object. /// diff --git a/src/EzrLexer.cs b/src/EzrLexer.cs index f8e1acc..4a65c89 100644 --- a/src/EzrLexer.cs +++ b/src/EzrLexer.cs @@ -83,11 +83,10 @@ private char Peek() /// The created of objects. /// Any that occurred in the lexing; if none occurred. /// if the lexing succeeded without any errors; otherwise . - public bool Tokenize(out List tokens, out Error? error) + public Error? Tokenize(out List tokens) { + Error? error; tokens = new List(); - error = null; - while (!_reachedEndFlag) { switch (_currentChar) @@ -96,6 +95,17 @@ public bool Tokenize(out List tokens, out Error? error) case ' ': Advance(); break; + case '\r': + Position startPosition = _position.Copy(); + Advance(); + + if (_currentChar == '\n') + Advance(); + else + return new UnexpectedCharacterError("\\r", startPosition, _position); + + tokens.Add(new Token(TokenType.NewLine, TokenTypeGroup.Special, string.Empty, startPosition, _position.Copy())); + break; case ';': case '\n': tokens.Add(new Token(TokenType.NewLine, TokenTypeGroup.Special, string.Empty, _position.Copy())); @@ -109,17 +119,17 @@ public bool Tokenize(out List tokens, out Error? error) case '"': tokens.Add(CompileStringLike(_currentChar, TokenType.String, out error)); if (error != null) - return false; + return error; break; case '`': tokens.Add(CompileStringLike(_currentChar, TokenType.Character, out error)); if (error != null) - return false; + return error; break; case '\'': tokens.Add(CompileStringLike(_currentChar, TokenType.CharacterList, out error)); if (error != null) - return false; + return error; break; case ':': tokens.Add(CompileColon()); @@ -283,14 +293,13 @@ public bool Tokenize(out List tokens, out Error? error) char unknownCharacter = _currentChar; Advance(); - error = new UnexpectedCharacterError(unknownCharacter, errorStartPosition, _position); - return false; + return new UnexpectedCharacterError(unknownCharacter, errorStartPosition, _position); } } } tokens.Add(new Token(TokenType.EndOfFile, TokenTypeGroup.Special, string.Empty, _position.Copy())); - return true; + return null; } /// diff --git a/src/EzrNodes.cs b/src/EzrNodes.cs index db50297..e595a01 100644 --- a/src/EzrNodes.cs +++ b/src/EzrNodes.cs @@ -82,7 +82,7 @@ public ValueNode(Token value, Position startPosition, Position endPosition) : ba public override string ToString() { - return $"ValueNode({Value.Value})"; + return $"ValueNode({Value})"; } } @@ -149,7 +149,7 @@ public override string ToString() { string[] keyValuePairs = new string[KeyValuePairs.Count]; for (int i = 0; i < KeyValuePairs.Count; i++) - keyValuePairs[i] = $"{keyValuePairs[i][0]} : {keyValuePairs[i][1]}"; + keyValuePairs[i] = $"{KeyValuePairs[i][0]} : {KeyValuePairs[i][1]}"; return $"DictionaryNode([{string.Join(", ", keyValuePairs)}])"; } } @@ -259,7 +259,7 @@ public VariableAccessNode(Token name, bool globalAccess, Position startPosition, public override string ToString() { - return $"VariableAccessNode({Name.Value}, {GlobalAccess})"; + return $"VariableAccessNode({Name}, {GlobalAccess})"; } } @@ -355,7 +355,7 @@ public TokenVariableAssignmentNode(Token variable, TokenType assignmentOperator, public override string ToString() { - return $"TokenVariableAssignmentNode({Variable.Value}, {AssignmentOperator}, {Value}, {GlobalAssignment})"; + return $"TokenVariableAssignmentNode({Variable}, {AssignmentOperator}, {Value}, {GlobalAssignment})"; } } diff --git a/src/EzrParser.cs b/src/EzrParser.cs index b5c6bce..c87f48f 100644 --- a/src/EzrParser.cs +++ b/src/EzrParser.cs @@ -159,6 +159,8 @@ private ParseResult BinaryOperation(Func left, Func? r if (result.Error != null) return result; + int toReverseTo = result.AdvanceCount; + SkipNewLines(result); while (operators.Contains(_currentToken.Type)) { @@ -172,9 +174,14 @@ private ParseResult BinaryOperation(Func left, Func? r return result; leftNode = new BinaryOperationNode(leftNode, rightNode, @operator, startPosition, _currentToken.EndPosition); + toReverseTo = result.AdvanceCount; SkipNewLines(result); } + + int reverseCount = result.AdvanceCount - toReverseTo; + Reverse(reverseCount); + result.Reverse(reverseCount); return result.Success(leftNode); } @@ -312,7 +319,7 @@ private ParseResult Expression(bool itemKeywordRequired = false) if (_currentToken.TypeGroup != TokenTypeGroup.AssignmentSymbol) { Reverse(); - result.ReverseAdvancement(); + result.Reverse(); Node variable = result.Register(Junction()); if (result.Error != null) @@ -407,7 +414,7 @@ private ParseResult QuickExpression() if (_currentToken.TypeGroup != TokenTypeGroup.AssignmentSymbol) { Reverse(); - result.ReverseAdvancement(); + result.Reverse(); Node variable = result.Register(Junction()); if (result.Error != null) @@ -536,6 +543,8 @@ private ParseResult Comparison() Node left = result.Register(BitwiseOr()); if (result.Error != null) return result; + + int toReverseTo = result.AdvanceCount; SkipNewLines(result); while (_currentToken.Type == TokenType.EqualSign @@ -565,9 +574,14 @@ private ParseResult Comparison() return result; left = new BinaryOperationNode(left, rightNode, @operator, startPosition, _currentToken.EndPosition); + toReverseTo = result.AdvanceCount; SkipNewLines(result); } + + int reverseCount = result.AdvanceCount - toReverseTo; + Reverse(reverseCount); + result.Reverse(reverseCount); return result.Success(left); } @@ -1228,6 +1242,10 @@ private ParseResult CountStructure() result.RegisterAdvance(); Advance(); + to = result.Register(Expression()); + if (result.Error != null) + return result; + if (_currentToken.Type == TokenType.KeywordStep) { result.RegisterAdvance(); @@ -1878,7 +1896,7 @@ public void RegisterAdvance() /// Reverses number of advancements. /// /// The number of advancements to reverse by. - public void ReverseAdvancement(int reverseCount = 1) + public void Reverse(int reverseCount = 1) { AdvanceCount -= reverseCount; } diff --git a/src/EzrShell.cs b/src/EzrShell.cs index 1ab71bd..454d7b4 100644 --- a/src/EzrShell.cs +++ b/src/EzrShell.cs @@ -9,6 +9,7 @@ namespace EzrSquared.EzrShell using EzrErrors; using EzrLexer; using EzrParser; + using System.Diagnostics.Metrics; /// /// The built-in shell for ezrSquared. @@ -60,6 +61,25 @@ _ __ """; + private struct Settings + { + public bool IsInteractive; + public bool ShowLexerOutput; + public bool ShowParserOutput; + public string File; + + public Settings() + { + IsInteractive = false; + ShowLexerOutput = false; + ShowParserOutput = false; + File = string.Empty; + } + } + + private static ConsoleColor s_previousForegroundColor; + private static ConsoleColor s_previousBackgroundColor; + private static void PrintSmallConsoleGraphics() { Console.Clear(); @@ -109,99 +129,192 @@ private static void PrintBigConsoleGraphics() Console.Write("\n\n"); } - public static void Main(string[] args) + private static void ShowError(string message) + { + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(message); + } + + private static void ShowOutput(string message) + { + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(message); + } + + private static void ShowVerbose(string message) + { + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = ConsoleColor.DarkGray; + Console.WriteLine(message); + } + + private static string? GetShellInput() + { + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = ConsoleColor.Yellow; + + Console.Write(">>> "); + return Console.ReadLine(); + } + + private static bool ParseCommandLineArguments(string[] arguments, out Settings settings) { - string filePath; + settings = new Settings(); + bool isFirstArgument = true; + + for (int i = 1; i < arguments.Length; i++) + { + if (arguments[i] == "-l" || string.Compare(arguments[1], "--lexer-output", true) == 0) + settings.ShowLexerOutput = true; + else if (arguments[i] == "-p" || string.Compare(arguments[1], "--parser-output", true) == 0) + settings.ShowLexerOutput = true; + else if (File.Exists(arguments[i])) + settings.File = arguments[i]; + else if (isFirstArgument && (arguments[i] == "-h" || string.Compare(arguments[1], "--help", true) == 0)) + { + ShowOutput(""" + Help for the `ezrSquared` command: + Intended use: + ezrSquared [file] [-h or --help] [-l or --lexer-output] [-p or --parser-output] + + file : File/script to execute. If not given, starts in interative mode. + -h or --help : Show this help screen. + -l or --lexer-output : Show the output of the Lexer. Only for debugging purposes. + -p or --parser-output : Show the output of the Parser. Only for debugging purposes. + """); + return false; + } + else + { + ShowError("Intended use:\n\tezrSquared [file] [-i | --interactive] [-l | --lexer-output] [-p | --parser-output]"); + return false; + } + + isFirstArgument = false; + } + + return true; + } + + public static void Main() + { + s_previousBackgroundColor = Console.BackgroundColor; + s_previousForegroundColor = Console.ForegroundColor; + Console.OutputEncoding = Encoding.Unicode; + string[] commandLineArguments = Environment.GetCommandLineArgs(); - if (commandLineArguments.Length == 1) - filePath = string.Empty; - else if (commandLineArguments.Length > 1 && File.Exists(commandLineArguments[1])) + if (!ParseCommandLineArguments(commandLineArguments, out Settings settings)) + return; + +#if DEBUG + settings.ShowLexerOutput = true; + settings.ShowParserOutput = true; + + Console.Write("File to read (press the 'enter' key to enter interactive mode): "); + string? filePath = Console.ReadLine(); + + if (string.IsNullOrEmpty(filePath)) + settings.IsInteractive = true; + else if (File.Exists(filePath)) + settings.File = filePath; + else { - filePath = commandLineArguments[1]; - //PrintLexerOutput(filePath, File.ReadAllText(filePath)); + ShowError($"File not found: \"{filePath}\""); - Console.WriteLine("Press any key to continue..."); + Console.Write("Press any key to continue..."); Console.ReadKey(); - return; + + settings = new Settings(); } - else +#endif + + if (!string.IsNullOrEmpty(settings.File)) + ExecuteFile(settings); + else if (settings.IsInteractive) + InteractiveMode(settings); + + Console.BackgroundColor = s_previousBackgroundColor; + Console.ForegroundColor = s_previousForegroundColor; + } + + private static void ExecuteFile(Settings settings) + { + Lexer lexer = new Lexer(Path.GetFileNameWithoutExtension(settings.File), File.ReadAllText(settings.File, Encoding.UTF8).ReplaceLineEndings("\n")); + Error? error = lexer.Tokenize(out List tokens); + if (settings.ShowLexerOutput) { - ConsoleColor previousForegroundColor = Console.ForegroundColor; - ConsoleColor previousBackgroundColor = Console.BackgroundColor; + ShowVerbose("Lexer output:"); + for (int i = 0; i < tokens.Count; i++) + ShowVerbose($" - {tokens[i]}"); + } - Console.ForegroundColor = ConsoleColor.Red; - Console.BackgroundColor = ConsoleColor.Black; - Console.WriteLine("Intended use (square brackets indicate optional arguments): ezrSquared [file.ezr2] [file.eout]"); + if (error != null) + { + ShowError(error.ToString()); + return; + } - Console.ForegroundColor = previousForegroundColor; - Console.BackgroundColor = previousBackgroundColor; + Parser parser = new Parser(tokens); + ParseResult result = parser.Parse(); + if (result.Error != null) + { + ShowError(result.Error.ToString()); return; } - Console.OutputEncoding = Encoding.Unicode; + if (settings.ShowParserOutput) + ShowVerbose($"Parser output:\n{result.Node}"); + Console.Write("Press any key to continue..."); + Console.ReadKey(); + } + + private static void InteractiveMode(Settings settings) + { #if PLATFORM_WINDOWS if (Console.WindowWidth > 84) PrintBigConsoleGraphics(); else PrintSmallConsoleGraphics(); #else - PrintConsoleGraphic(); + PrintSmallConsoleGraphics(); #endif while (true) { - string? input = GetInput(); + string? input = GetShellInput(); if (!string.IsNullOrEmpty(input)) { - PrintLexerOutput("shell", input, out List tokens, out Error? error); + Lexer lexer = new Lexer("shell", input); + Error? error = lexer.Tokenize(out List tokens); + if (settings.ShowLexerOutput) + { + ShowVerbose("Lexer output:"); + for (int i = 0; i < tokens.Count; i++) + ShowVerbose($" - {tokens[i]}"); + } + if (error != null) { - PrintError(error.ToString()); + ShowError(error.ToString()); continue; } - ParseResult result = new Parser(tokens).Parse(); + Parser parser = new Parser(tokens); + ParseResult result = parser.Parse(); if (result.Error != null) { - PrintError(result.Error.ToString()); + ShowError(result.Error.ToString()); continue; } - PrintResult(result.Node.ToString()); + if (settings.ShowParserOutput) + ShowVerbose($"Parser output:\n{result.Node}"); } } } - - private static void PrintError(string error) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(error); - } - - private static void PrintResult(string result) - { - Console.ForegroundColor = ConsoleColor.White; - Console.WriteLine(result); - } - - private static string? GetInput() - { - Console.ForegroundColor = ConsoleColor.Yellow; - Console.Write(">>> "); - - return Console.ReadLine(); - } - - private static void PrintLexerOutput(string file, string script, out List tokens, out Error? error) - { - if (new Lexer(file, script).Tokenize(out tokens, out error)) - { - Console.ForegroundColor = ConsoleColor.Gray; - for (int i = 0; i < tokens.Count; i++) - Console.WriteLine($"( '{tokens[i].Value}', {Enum.GetName(typeof(TokenType), tokens[i].Type)}, {Enum.GetName(typeof(TokenTypeGroup), tokens[i].TypeGroup)} )"); - } - } } } \ No newline at end of file diff --git a/tests/full_test.ezr2 b/tests/full_test.ezr2 index f010be0..faabbff 100644 --- a/tests/full_test.ezr2 +++ b/tests/full_test.ezr2 @@ -1 +1,207 @@ -@ TODO \ No newline at end of file +@ This is still todo. + +@ "in" +show("----item test----") +item a: 2 +show(a) +item a: 3 +show(a) +show("----and/or test----") +show(a and 6) +show(a and 0) +show(a or 6) +show(a or 0) +show("----invert test----") +show(invert a) +show(invert true) +show(invert 0) +show(invert 65) +show("----if test----") +if a do +show("sds") +else do +show("sd") +end +if invert a do +show("sds") +else do +show("sd") +end +if invert a do +show("sds") +else if invert 1 do +show("sd") +else do +show("dssdf") +end +show("----count test----") +count from 0 to 10 as i do +show("sd") +end +count from 0 to 10 step 2 as i do +show("sd_") +end +count from 0 to 10 as i do +if i = 5 do +skip +end +show("sd" + i.as_string()) +end +count from 0 to 10 as i do +if i = 5 do +stop +end +show("sd2" + i.as_string()) +end +show("----while test----") +while a do +show(a) +item a: a - 1 +end +item a: 30 +while a do +item a: a - 1 +if a = 20 do +skip +end +show(a) +end +item a: 30 +while a do +item a: a - 1 +if a = 20 do +stop +end +show(a) +end +show("----func test----") +function name with args do +show(args) +end +function nameno do +show("noargs") +end +function retu do +return 2 +end +show(name("fdgffdf")) +show(nameno()) +show(retu()) +show("----try test----") +try do +1/0 +end +try do +1/0 +error do +show("errrrr") +end +try do +1/0 +error "math-error" do +show("errrrr") +error do +show("sdfsdf") +end +try do +1/0 +error "MAH" do +show("errrrr") +error do +show("sdfsdf") +end +show("----include/as test----") +include "time.py" +show(time.time()) +show(time.localTime(time.time())) +show(time.localTime(time.time()).readableTime()) +include "time.py" as t +show(t.time()) +show(t.localTime(t.time())) +show(t.localTime(t.time()).readableTime()) +show("----global test----") +function ChangeA with NewA do +show("a: " + a.as_string()) +function localChangeA with localNewA do +function local2ChangeA with local2NewA do +global item a: local2NewA +end +local2ChangeA(localNewA) +show("a: " + a.as_string()) +end +localChangeA(NewA) +end +ChangeA(123124) +show("----in test----") +show("sd" in (1,2,3)) +show("sd" in (1,"sd",3)) +show("sd" in [1,2,3]) +show("sd" in [1,"sd",3]) +show("----array test----") +show((1)) +show((1,)) +show((1,2,3)) +show((1,2,3)<=1) +show((1,2,3)*6) +show(((1,2,3)*6)/2) +show("----list test----") +show([1]) +show([1,2,3]) +show([1,2,3]<=1) +item a: [12,5,3] +show(a) +a + 2 +show(a) +a + [3,[3,4],4] +show(a) +show(a<=5<=1) +a - 5 +show(a) +show(a*2) +show(a/2) +show(a=a) +show(a!a) +show(a=[1,2,3]) +show(a![1,2,3]) +show("----dict test----") +show({1:2}) +show({1:2, 3:4, 5:6}) +show({1:2, 3:4, 5:6}<=1) +show({1:2, 3:4, 5:6}<=5) +item a: {1:2, 3:4, 5:6} +show(a) +a + {2:6} +show(a) +a + {1:8, 8:[1,2,3,(1,2,3)]} +show(a) +show(a<=8<=1) +show(a<=8<=3) +a - 8 +show(a) +show(a/2) +show(a=a) +show(a!a) +show(a={1:2, 3:4, 5:6}) +show(a!{1:2, 3:4, 5:6}) +show("----obj test----") +object obj do +item a: 4 +function name with args do +show("obj") +show(args) +end +end +object objtoo with args do +item a: args +function name do +show("obj") +show(args) +end +end +show(obj()) +show(obj().a) +show(obj().name("fsd")) +show(objtoo("dsfsfdfdsfsd")) +show(objtoo("dsfsfdfdsfsd").a) +show(objtoo("dsfsfdfdsfsd").name()) +show("----test complete----") \ No newline at end of file From ba46e7602cc80eab16ae4ce18d7d5d8da067a745 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 13 Sep 2023 00:49:46 +0530 Subject: [PATCH 005/113] More bugfixes, updated tests and minor improvements! --- Changelog.txt | 7 +- src/EzrErrors.cs | 26 ++- src/EzrParser.cs | 11 +- src/EzrShell.cs | 1 - tests/full_test.ezr2 | 432 ++++++++++++++++++++---------------- tests/graphics_test_02.ezr2 | 2 +- 6 files changed, 270 insertions(+), 209 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 70b58ee..c5b0c41 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,7 @@ CHANGELOG - What's new? + +* ezr² Rewrite - Part 2 [13-09-23] + * Completed rewriting the Parser (without QuickSyntax support) and its supporting components. -* ezr² Rewrite - Part 1 [10-05-23] - * Completed rewriting the Lexer and it's supporting components \ No newline at end of file +* ezr² Rewrite - Part 1 [10-05-23] + * Completed rewriting the Lexer and its supporting components. \ No newline at end of file diff --git a/src/EzrErrors.cs b/src/EzrErrors.cs index 7bc25bf..ecd7e20 100644 --- a/src/EzrErrors.cs +++ b/src/EzrErrors.cs @@ -1,5 +1,4 @@ -using System; -using System.Text; +using System.Text; namespace EzrSquared.EzrErrors { @@ -61,12 +60,27 @@ public override string ToString() internal string StringWithUnderline() { string text = _startPosition.Script; - int start = Math.Max(text[0..((_startPosition.Index < text.Length) ? _startPosition.Index : text.Length)].LastIndexOf('\n'), 0); - int end = text.IndexOf('\n', start + 1); + int start; + int end; + + int indexOfLastNewLine = text[0..((_startPosition.Index < text.Length) ? _startPosition.Index : text.Length)].LastIndexOf('\n'); + if (indexOfLastNewLine != -1 && indexOfLastNewLine != text.Length - 1) + start = indexOfLastNewLine + 1; + else if (indexOfLastNewLine == -1) + start = 0; + else + start = indexOfLastNewLine; + + end = text.IndexOf('\n', start + 1); if (end == -1) end = text.Length; - - return new StringBuilder(text[start..end]).Append('\n').Append(' ', _startPosition.Index - start).Append('~', _endPosition.Index - _startPosition.Index).Replace('\t', ' ').ToString(); + + return new StringBuilder(text[start..end]) + .Replace('\t', ' ') + .Append('\n') + .Append(' ', _startPosition.Index - start) + .Append('~', _endPosition.Index - _startPosition.Index) + .ToString(); } } diff --git a/src/EzrParser.cs b/src/EzrParser.cs index c87f48f..82f3f10 100644 --- a/src/EzrParser.cs +++ b/src/EzrParser.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using System; namespace EzrSquared.EzrParser @@ -162,7 +161,7 @@ private ParseResult BinaryOperation(Func left, Func? r int toReverseTo = result.AdvanceCount; SkipNewLines(result); - while (operators.Contains(_currentToken.Type)) + while (Array.IndexOf(operators, _currentToken.Type) != -1) { TokenType @operator = _currentToken.Type; result.RegisterAdvance(); @@ -903,7 +902,7 @@ private ParseResult ArrayStructure() { if (isArray) return result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! Commas seperate the elements of the array, while the right-parenthesis ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); - return result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! The comma is used to create an array and seperate it's elements, while the right-parenthesis declares the end of a parenthetical expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! The comma is used to create an array and seperate its elements, while the right-parenthesis declares the end of a parenthetical expression.", _currentToken.StartPosition, _currentToken.EndPosition)); } endPosition = _currentToken.EndPosition; @@ -1002,7 +1001,7 @@ private ParseResult DictionaryStructure() // NOTE: Breaking change - assignment symbols will break this. if (_currentToken.Type != TokenType.Colon) - return result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and it's value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); result.RegisterAdvance(); Advance(); @@ -1027,7 +1026,7 @@ private ParseResult DictionaryStructure() SkipNewLines(result); if (_currentToken.Type != TokenType.Colon) - return result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and it's value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); result.RegisterAdvance(); Advance(); @@ -1041,7 +1040,7 @@ private ParseResult DictionaryStructure() } if (_currentToken.Type != TokenType.RightCurlyBracket) - return result.Failure(10, new InvalidGrammarError("Expected a comma or right-curly-bracket symbol! Commas are used to seperate key-value pairs in the dictionary, and the right-curly-bracket declares it's end.", _currentToken.StartPosition, _currentToken.EndPosition)); + return result.Failure(10, new InvalidGrammarError("Expected a comma or right-curly-bracket symbol! Commas are used to seperate key-value pairs in the dictionary, and the right-curly-bracket declares its end.", _currentToken.StartPosition, _currentToken.EndPosition)); endPosition = _currentToken.EndPosition; result.RegisterAdvance(); Advance(); diff --git a/src/EzrShell.cs b/src/EzrShell.cs index 454d7b4..dc944ee 100644 --- a/src/EzrShell.cs +++ b/src/EzrShell.cs @@ -9,7 +9,6 @@ namespace EzrSquared.EzrShell using EzrErrors; using EzrLexer; using EzrParser; - using System.Diagnostics.Metrics; /// /// The built-in shell for ezrSquared. diff --git a/tests/full_test.ezr2 b/tests/full_test.ezr2 index faabbff..63f2c7c 100644 --- a/tests/full_test.ezr2 +++ b/tests/full_test.ezr2 @@ -1,207 +1,253 @@ @ This is still todo. - -@ "in" show("----item test----") -item a: 2 -show(a) -item a: 3 -show(a) + item a: 2 + show(a) + item a: 3 + show(a) + a: 4 + show(a) + a: 2 + show(a) + show("----and/or test----") -show(a and 6) -show(a and 0) -show(a or 6) -show(a or 0) + show(a and 6) + show(a and 0) + show(a or 6) + show(a or 0) + show("----invert test----") -show(invert a) -show(invert true) -show(invert 0) -show(invert 65) + show(invert a) + show(invert true) + show(invert 0) + show(invert 65) + show("----if test----") -if a do -show("sds") -else do -show("sd") -end -if invert a do -show("sds") -else do -show("sd") -end -if invert a do -show("sds") -else if invert 1 do -show("sd") -else do -show("dssdf") -end + if a do + show("sds") + else do + show("sd") + end + + if invert a do + show("sds") + else do + show("sd") + end + + if invert a do + show("sds") + else if invert 1 do + show("sd") + else do + show("dssdf") + end + show("----count test----") -count from 0 to 10 as i do -show("sd") -end -count from 0 to 10 step 2 as i do -show("sd_") -end -count from 0 to 10 as i do -if i = 5 do -skip -end -show("sd" + i.as_string()) -end -count from 0 to 10 as i do -if i = 5 do -stop -end -show("sd2" + i.as_string()) -end + count from 0 to 10 as i do + show("sd") + end + + count from 0 to 10 step 2 as i do + show("sd_") + end + + count from 0 to 10 as i do + if i = 5 do + skip + end + + show("sd" + i.as_string()) + end + + count from 0 to 10 as i do + if i = 5 do + stop + end + + show("sd2" + i.as_string()) + end + show("----while test----") -while a do -show(a) -item a: a - 1 -end -item a: 30 -while a do -item a: a - 1 -if a = 20 do -skip -end -show(a) -end -item a: 30 -while a do -item a: a - 1 -if a = 20 do -stop -end -show(a) -end -show("----func test----") -function name with args do -show(args) -end -function nameno do -show("noargs") -end -function retu do -return 2 -end -show(name("fdgffdf")) -show(nameno()) -show(retu()) + while a do + show(a) + item a: a - 1 + end + + item a: 30 + while a do + item a: a - 1 + if a = 20 do + skip + end + + show(a) + end + + item a: 30 + while a do + item a: a - 1 + if a = 20 do + stop + end + + show(a) + end + +show("----function test----") + function name with args do + show(args) + end + + function nameno do + show("noargs") + end + + function retu do + return 2 + end + + show(name("fdgffdf")) + show(nameno()) + show(retu()) + show("----try test----") -try do -1/0 -end -try do -1/0 -error do -show("errrrr") -end -try do -1/0 -error "math-error" do -show("errrrr") -error do -show("sdfsdf") -end -try do -1/0 -error "MAH" do -show("errrrr") -error do -show("sdfsdf") -end -show("----include/as test----") -include "time.py" -show(time.time()) -show(time.localTime(time.time())) -show(time.localTime(time.time()).readableTime()) -include "time.py" as t -show(t.time()) -show(t.localTime(t.time())) -show(t.localTime(t.time()).readableTime()) + try do + 1/0 + end + + try do + 1/0 + error do + show("errrrr") + end + + try do + 1/0 + error "math-error" do + show("errrrr") + error do + show("sdfsdf") + end + + try do + 1/0 + error "MAH" do + show("errrrr") + error do + show("sdfsdf") + end + +show("----include test----") + include "time.py" + show(time.time()) + show(time.localTime(time.time())) + show(time.localTime(time.time()).readableTime()) + include "time.py" as t + show(t.time()) + show(t.localTime(t.time())) + show(t.localTime(t.time()).readableTime()) + show("----global test----") -function ChangeA with NewA do -show("a: " + a.as_string()) -function localChangeA with localNewA do -function local2ChangeA with local2NewA do -global item a: local2NewA -end -local2ChangeA(localNewA) -show("a: " + a.as_string()) -end -localChangeA(NewA) -end -ChangeA(123124) + function ChangeA with NewA do + show("a: " + a.as_string()) + + function localChangeA with localNewA do + function local2ChangeA with local2NewA do + global item a: local2NewA + end + + local2ChangeA(localNewA) + show("a: " + a.as_string()) + end + + localChangeA(NewA) + end + + ChangeA(123124) + show("----in test----") -show("sd" in (1,2,3)) -show("sd" in (1,"sd",3)) -show("sd" in [1,2,3]) -show("sd" in [1,"sd",3]) + show("sd" in (1,2,3)) + show("sd" in (1,"sd",3)) + show("sd" in [1,2,3]) + show("sd" in [1,"sd",3]) + + show("sd" not in (1,2,3)) + show("sd" not in (1,"sd",3)) + show("sd" not in [1,2,3]) + show("sd" not in [1,"sd",3]) + show("----array test----") -show((1)) -show((1,)) -show((1,2,3)) -show((1,2,3)<=1) -show((1,2,3)*6) -show(((1,2,3)*6)/2) + show((1)) + show((1,)) + show((1,2,3)) + show((1,2,3)<=1) + show((1,2,3)*6) + show(((1,2,3)*6)/2) + show("----list test----") -show([1]) -show([1,2,3]) -show([1,2,3]<=1) -item a: [12,5,3] -show(a) -a + 2 -show(a) -a + [3,[3,4],4] -show(a) -show(a<=5<=1) -a - 5 -show(a) -show(a*2) -show(a/2) -show(a=a) -show(a!a) -show(a=[1,2,3]) -show(a![1,2,3]) + show([1]) + show([1,2,3]) + show([1,2,3]<=1) + item a: [12,5,3] + show(a) + a + 2 + show(a) + a + [3,[3,4],4] + show(a) + show(a<=5<=1) + a - 5 + show(a) + show(a*2) + show(a/2) + show(a=a) + show(a!a) + show(a=[1,2,3]) + show(a![1,2,3]) + show("----dict test----") -show({1:2}) -show({1:2, 3:4, 5:6}) -show({1:2, 3:4, 5:6}<=1) -show({1:2, 3:4, 5:6}<=5) -item a: {1:2, 3:4, 5:6} -show(a) -a + {2:6} -show(a) -a + {1:8, 8:[1,2,3,(1,2,3)]} -show(a) -show(a<=8<=1) -show(a<=8<=3) -a - 8 -show(a) -show(a/2) -show(a=a) -show(a!a) -show(a={1:2, 3:4, 5:6}) -show(a!{1:2, 3:4, 5:6}) -show("----obj test----") -object obj do -item a: 4 -function name with args do -show("obj") -show(args) -end -end -object objtoo with args do -item a: args -function name do -show("obj") -show(args) -end -end -show(obj()) -show(obj().a) -show(obj().name("fsd")) -show(objtoo("dsfsfdfdsfsd")) -show(objtoo("dsfsfdfdsfsd").a) -show(objtoo("dsfsfdfdsfsd").name()) + show({1:2}) + show({1:2, 3:4, 5:6}) + show({1:2, 3:4, 5:6}<=1) + show({1:2, 3:4, 5:6}<=5) + item a: {1:2, 3:4, 5:6} + show(a) + a + {2:6} + show(a) + a + {1:8, 8:[1,2,3,(1,2,3)]} + show(a) + show(a<=8<=1) + show(a<=8<=3) + a - 8 + show(a) + show(a/2) + show(a=a) + show(a!a) + show(a={1:2, 3:4, 5:6}) + show(a!{1:2, 3:4, 5:6}) + +show("----object test----") + object obj do + item a: 4 + + function name with args do + show("obj") + show(args) + end + end + + object objtoo with args do + item a: args + function name do + show("obj") + show(args) + end + end + + show(obj()) + show(obj().a) + show(obj().name("fsd")) + show(objtoo("dsfsfdfdsfsd")) + show(objtoo("dsfsfdfdsfsd").a) + show(objtoo("dsfsfdfdsfsd").name()) + show("----test complete----") \ No newline at end of file diff --git a/tests/graphics_test_02.ezr2 b/tests/graphics_test_02.ezr2 index f84e071..090fc8d 100644 --- a/tests/graphics_test_02.ezr2 +++ b/tests/graphics_test_02.ezr2 @@ -6,7 +6,7 @@ object integer2 with x, y do if type_of(x) ! "integer" do item this.x: x.as_integer() if type_of(y) ! "integer" do item this.y: y.as_integer() - special equals do other.x = x and other.y = y + function equals do other.x = x and other.y = y end object sprite with graphics, position do From f7819451825fa8b31f435414031717504d79e206 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 13 Sep 2023 01:17:24 +0530 Subject: [PATCH 006/113] Spacing of error tracebacks should now be consistent. --- src/EzrErrors.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/EzrErrors.cs b/src/EzrErrors.cs index ecd7e20..154d094 100644 --- a/src/EzrErrors.cs +++ b/src/EzrErrors.cs @@ -64,21 +64,22 @@ internal string StringWithUnderline() int end; int indexOfLastNewLine = text[0..((_startPosition.Index < text.Length) ? _startPosition.Index : text.Length)].LastIndexOf('\n'); - if (indexOfLastNewLine != -1 && indexOfLastNewLine != text.Length - 1) - start = indexOfLastNewLine + 1; - else if (indexOfLastNewLine == -1) - start = 0; - else + if (indexOfLastNewLine != -1) start = indexOfLastNewLine; + else + start = 0; + + while (char.IsWhiteSpace(text[start]) && start < text.Length - 1) + start++; end = text.IndexOf('\n', start + 1); if (end == -1) end = text.Length; - return new StringBuilder(text[start..end]) - .Replace('\t', ' ') + return new StringBuilder(" ") + .Append(text[start..end]) .Append('\n') - .Append(' ', _startPosition.Index - start) + .Append(' ', (_startPosition.Index - start) + 2) .Append('~', _endPosition.Index - _startPosition.Index) .ToString(); } From 13b89de50b82135b7ad859c416f3f4c052f4abb4 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 13 Sep 2023 01:49:50 +0530 Subject: [PATCH 007/113] Removed "Graphics" folder. --- Graphics/Icon (16x16).png | Bin 219 -> 0 bytes Graphics/Icon (24x24).png | Bin 267 -> 0 bytes Graphics/Icon (256x256).png | Bin 3543 -> 0 bytes Graphics/Icon (32x32).png | Bin 321 -> 0 bytes Graphics/Icon (48x48).png | Bin 417 -> 0 bytes Graphics/Icon (64x64).png | Bin 558 -> 0 bytes 6 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Graphics/Icon (16x16).png delete mode 100644 Graphics/Icon (24x24).png delete mode 100644 Graphics/Icon (256x256).png delete mode 100644 Graphics/Icon (32x32).png delete mode 100644 Graphics/Icon (48x48).png delete mode 100644 Graphics/Icon (64x64).png diff --git a/Graphics/Icon (16x16).png b/Graphics/Icon (16x16).png deleted file mode 100644 index 78d6410b7426399702f4b8e3af6a7a928bec3fbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`3p`yMLoEE0dw$A)ozKXt^X+$! z9?P?KsoX;X=`4~PS_&nV!(>@loL~L_-!9$oMrcCg|JvHXm}5ICjUTuF=P58`bYpYl zVJ_Iok|J?}VMen9+r(6cqk0WDd5Sp$;~dKDBJ~`;+ZP>q(91f(spPBzuL1Kl6CNd13s$iRI7vH+WJK;r*>eX#~3 zEWj52 zbg=;0^<<|ae5nUL50aD*V487R05c4xZcQU2X&DWq5ufWp7Jv)|se`dej%1ozKq%}f z_Q9aA06BtTae=eAM$c$e_W^R6CZ;|hISy!M0SPrCL8Tb^0GEzI->Lur5DtgHUXfal R00000NkvXXu0mjf008rZWN!cf diff --git a/Graphics/Icon (256x256).png b/Graphics/Icon (256x256).png deleted file mode 100644 index c1453a95397ced296520a79d62e59093956f8ef6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3543 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 TnwS9q0000+xe|;1i$0z zE|~q9x>;V6)^P^F6nJG$wiG(Kvr9_GLX*~e|K-^q56lJt)!YEsw=Juhxvu+C`sSOz z^B1mpjwdT%07g79I|X8R!?Y5okks7RBUk|g01N=r*ugvM&V0SFmLRe-{NzfZL$o-_bz@YO270YJUb6{|uT!K+?qFoRqGm|48u z<=}L0WZ{O~;A6}h0PdX_7)xOvD-cT;aSBlz*`xua249T=lLjCOz6u2l0QzW~y$_64 zp_~fD&PD2F)Bp^m5HJs_sGUYN6$n8j0~k85=XxIq1M36Efr>p)8UUp?^kW8}n7D^I z=?e{3zyMJ1sHMk|OVBgDs0+b3`>({CiEJ#-B3=lN-# z9Di^37st`Ahk87Gx{jX+02x3Dta`wE`be%K>uj)xmwA=%RSzHlWB?_w>H*qiQc7q( z9!)+YozJWJe9e<;yt_25o>%t(0-*E>WPoU*!%3j_GARL*JpkDX*(2P000F4%6UYFu zY*GTf`GD3vpt%tu0F9d<86froa-By$!Mqo!DS@18M4O?Z0mv-AUTT&1YF{RR=5u;YZQl#zCTOYtkN{}3A07Zp^>Z5ja|x7cd~0HRwf{4o zWB}4Qio@>%%=U9@P)c0IT*xGr+6*VHx06{g427R(}Wp z_H_Q=o}#%E)cOEV`iFFa1i<*dUs`HPKz!>f0g~1i0a)D%w~)Xs5X>h+y*0rl*_ Date: Wed, 13 Sep 2023 01:52:57 +0530 Subject: [PATCH 008/113] Added 'graphics' folder. --- .gitignore | 1 - graphics/Icon (14x14).png | Bin 0 -> 192 bytes graphics/Icon (16x16).png | Bin 0 -> 219 bytes graphics/Icon (24x24).png | Bin 0 -> 267 bytes graphics/Icon (256x256).png | Bin 0 -> 3543 bytes graphics/Icon (32x32).png | Bin 0 -> 321 bytes graphics/Icon (48x48).png | Bin 0 -> 417 bytes graphics/Icon (64x64).png | Bin 0 -> 558 bytes 8 files changed, 1 deletion(-) create mode 100644 graphics/Icon (14x14).png create mode 100644 graphics/Icon (16x16).png create mode 100644 graphics/Icon (24x24).png create mode 100644 graphics/Icon (256x256).png create mode 100644 graphics/Icon (32x32).png create mode 100644 graphics/Icon (48x48).png create mode 100644 graphics/Icon (64x64).png diff --git a/.gitignore b/.gitignore index 0ec652c..1ea2e1d 100644 --- a/.gitignore +++ b/.gitignore @@ -364,7 +364,6 @@ FodyWeavers.xsd # -------------------------------------------------- -[Gg]raphics/ [Ll]ibraries/ docs/offline/_site/ docs/offline/ezrSquared.Offline.Documentation.zip \ No newline at end of file diff --git a/graphics/Icon (14x14).png b/graphics/Icon (14x14).png new file mode 100644 index 0000000000000000000000000000000000000000..0f796eb84aa1599c67c112877da7745c5ef932d3 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0y_HcuDF5DWjglQ!};81S%smfjFy zrFBHFBUV5(RxFu$vHK=bS3V6tarNi*(fuMe3foU9oszduw7fmHbV^h7q^oKw5*`PH z(}kOU9b$REzm^_p00i_>zopr7y!3oL1X{` literal 0 HcmV?d00001 diff --git a/graphics/Icon (16x16).png b/graphics/Icon (16x16).png new file mode 100644 index 0000000000000000000000000000000000000000..78d6410b7426399702f4b8e3af6a7a928bec3fbf GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`3p`yMLoEE0dw$A)ozKXt^X+$! z9?P?KsoX;X=`4~PS_&nV!(>@loL~L_-!9$oMrcCg|JvHXm}5ICjUTuF=P58`bYpYl zVJ_Iok|J?}VMen9+r(6cqk0WDd5Sp$;~dKDBJ~`;+ZP>q(91f(spPBzuL1Kl6CNd13s$iRI7vH+WJK;r*>eX#~3 zEWj52 zbg=;0^<<|ae5nUL50aD*V487R05c4xZcQU2X&DWq5ufWp7Jv)|se`dej%1ozKq%}f z_Q9aA06BtTae=eAM$c$e_W^R6CZ;|hISy!M0SPrCL8Tb^0GEzI->Lur5DtgHUXfal R00000NkvXXu0mjf008rZWN!cf literal 0 HcmV?d00001 diff --git a/graphics/Icon (256x256).png b/graphics/Icon (256x256).png new file mode 100644 index 0000000000000000000000000000000000000000..c1453a95397ced296520a79d62e59093956f8ef6 GIT binary patch literal 3543 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 TnwS9q0000+xe|;1i$0z zE|~q9x>;V6)^P^F6nJG$wiG(Kvr9_GLX*~e|K-^q56lJt)!YEsw=Juhxvu+C`sSOz z^B1mpjwdT%07g79I|X8R!?Y5okks7RBUk|g01N=r*ugvM&V0SFmLRe-{NzfZL$o-_bz@YO270YJUb6{|uT!K+?qFoRqGm|48u z<=}L0WZ{O~;A6}h0PdX_7)xOvD-cT;aSBlz*`xua249T=lLjCOz6u2l0QzW~y$_64 zp_~fD&PD2F)Bp^m5HJs_sGUYN6$n8j0~k85=XxIq1M36Efr>p)8UUp?^kW8}n7D^I z=?e{3zyMJ1sHMk|OVBgDs0+b3`>({CiEJ#-B3=lN-# z9Di^37st`Ahk87Gx{jX+02x3Dta`wE`be%K>uj)xmwA=%RSzHlWB?_w>H*qiQc7q( z9!)+YozJWJe9e<;yt_25o>%t(0-*E>WPoU*!%3j_GARL*JpkDX*(2P000F4%6UYFu zY*GTf`GD3vpt%tu0F9d<86froa-By$!Mqo!DS@18M4O?Z0mv-AUTT&1YF{RR=5u;YZQl#zCTOYtkN{}3A07Zp^>Z5ja|x7cd~0HRwf{4o zWB}4Qio@>%%=U9@P)c0IT*xGr+6*VHx06{g427R(}Wp z_H_Q=o}#%E)cOEV`iFFa1i<*dUs`HPKz!>f0g~1i0a)D%w~)Xs5X>h+y*0rl*_ Date: Wed, 13 Sep 2023 13:25:48 +0530 Subject: [PATCH 009/113] Fixed intended usage message in EzrShell.cs. --- src/EzrShell.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EzrShell.cs b/src/EzrShell.cs index dc944ee..7fc311c 100644 --- a/src/EzrShell.cs +++ b/src/EzrShell.cs @@ -187,7 +187,7 @@ ezrSquared [file] [-h or --help] [-l or --lexer-output] [-p or --parser-output] } else { - ShowError("Intended use:\n\tezrSquared [file] [-i | --interactive] [-l | --lexer-output] [-p | --parser-output]"); + ShowError("Intended use:\n\tezrSquared [file] [-l | --lexer-output] [-p | --parser-output]"); return false; } From faf00280e9fbbba0e24b997f60b9289892190e8d Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 13 Sep 2023 23:57:57 +0530 Subject: [PATCH 010/113] Updated EzrLexer, EzrParser and EzrCommon for better performance! Also updated EzrGrammar.txt. --- src/EzrCommon.cs | 5 +- src/EzrGrammar.txt | 8 +- src/EzrLexer.cs | 3 +- src/EzrParser.cs | 1645 ++++++++++++++++++++++++-------------------- 4 files changed, 922 insertions(+), 739 deletions(-) diff --git a/src/EzrCommon.cs b/src/EzrCommon.cs index 0079831..8fffebd 100644 --- a/src/EzrCommon.cs +++ b/src/EzrCommon.cs @@ -214,10 +214,7 @@ public class Token /// public readonly Position EndPosition; - public static Token GetInvalidToken(Position startPosition, Position? endPosition) - { - return new Token(TokenType.Invalid, TokenTypeGroup.Special, string.Empty, startPosition, endPosition); - } + public static readonly Token Dummy = new Token(TokenType.Invalid, TokenTypeGroup.Special, string.Empty, new Position(int.MinValue, int.MinValue, string.Empty, string.Empty)); /// /// Creates a new object. diff --git a/src/EzrGrammar.txt b/src/EzrGrammar.txt index c4234ae..6e46b53 100644 --- a/src/EzrGrammar.txt +++ b/src/EzrGrammar.txt @@ -90,14 +90,14 @@ factor: ('+' | '-' | '~') factor | power -; 'power' structures can contain power expression or 'object-call' structures +; 'power' structures can contain power expression or 'object-attribute-access' structures power: - object-call '^' object-call - | object-call + object-attribute-access '^' object-attribute-access + | object-attribute-access ; 'object-attribute-access' structures can contain object attribute access expressions or 'call' structures object-attribute-access: - call '.' object-call + call '.' object-attribute-access | call ; 'call' structures can contain function/object creation call expressions or 'atom' structures diff --git a/src/EzrLexer.cs b/src/EzrLexer.cs index 4a65c89..98611f7 100644 --- a/src/EzrLexer.cs +++ b/src/EzrLexer.cs @@ -81,8 +81,7 @@ private char Peek() /// Creates a of objects from the given script. /// /// The created of objects. - /// Any that occurred in the lexing; if none occurred. - /// if the lexing succeeded without any errors; otherwise . + /// Any that occurred in the lexing; if none occurred. public Error? Tokenize(out List tokens) { Error? error; diff --git a/src/EzrParser.cs b/src/EzrParser.cs index 82f3f10..9350395 100644 --- a/src/EzrParser.cs +++ b/src/EzrParser.cs @@ -37,6 +37,11 @@ public class Parser /// private bool _wasUsingQuickSyntax; + /// + /// The object that holds the result of the parsing. + /// + private ParseResult _result; + /// /// Creates a new object. /// @@ -44,10 +49,11 @@ public class Parser public Parser(List tokens) { _tokens = tokens; - _currentToken = Token.GetInvalidToken(new Position(0, 0, string.Empty, string.Empty), null); + _currentToken = Token.Dummy; _index = -1; _usingQuickSyntax = false; _wasUsingQuickSyntax = false; + _result = new ParseResult(); Advance(); } @@ -61,8 +67,6 @@ private void Advance() if (_index >= 0 && _index < _tokens.Count) _currentToken = _tokens[_index]; - else - _currentToken = Token.GetInvalidToken(_currentToken.StartPosition, _currentToken.EndPosition); } /// @@ -75,8 +79,6 @@ private void Reverse(int reverseCount = 1) if (_index >= 0 && _index < _tokens.Count) _currentToken = _tokens[_index]; - else - _currentToken = Token.GetInvalidToken(_currentToken.StartPosition, _currentToken.EndPosition); } /// @@ -86,8 +88,9 @@ private void Reverse(int reverseCount = 1) private Token PeekPrevious() { int previousIndex = _index - 1; - if (previousIndex < 0 || previousIndex >= _tokens.Count) - _currentToken = Token.GetInvalidToken(_currentToken.StartPosition, _currentToken.EndPosition); + if (previousIndex < 0) + return Token.Dummy; + return _tokens[previousIndex]; } @@ -111,94 +114,86 @@ private void UnregisterQuickSyntaxUse() /// /// Advances through objects until a object of any other has been reached. /// - /// The object to register the advancements. - /// The number of advancements. - private int SkipNewLines(ParseResult result) + private void SkipNewLines() { - int newLineCount = 0; + if (_currentToken.Type != TokenType.NewLine) + return; + while (_currentToken.Type == TokenType.NewLine) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - - newLineCount++; } - - return newLineCount; } /// - /// Parses . + /// Parses the objects in . /// - /// The object. public ParseResult Parse() { - ParseResult result = Statements(); - if (result.Error == null && _currentToken.Type != TokenType.EndOfFile) - return result.Failure(10, new InvalidGrammarError("Did not expect this!", _currentToken.StartPosition, _currentToken.EndPosition)); - return result; + ParseStatements(); + if (_result.Error == null && _currentToken.Type != TokenType.EndOfFile) + _result.Failure(10, new InvalidGrammarError("Did not expect this!", _currentToken.StartPosition, _currentToken.EndPosition)); + return _result; } /// /// Tries creating a . /// /// The function to call for the first operand. - /// The function to call for the second operand. If , defaults to . + /// The function to call for the second operand. /// The operator object(s). - /// The object. - private ParseResult BinaryOperation(Func left, Func? right, params TokenType[] operators) + private void BinaryOperation(Action left, Action right, params TokenType[] operators) { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - if (right == null) - right = left; + left(); + Node leftNode = _result.Node; + if (_result.Error != null) + return; - Node leftNode = result.Register(left()); - if (result.Error != null) - return result; + int toReverseTo = _result.AdvanceCount; - int toReverseTo = result.AdvanceCount; - - SkipNewLines(result); + SkipNewLines(); while (Array.IndexOf(operators, _currentToken.Type) != -1) { TokenType @operator = _currentToken.Type; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - Node rightNode = result.Register(right()); - if (result.Error != null) - return result; + SkipNewLines(); + + right(); + Node rightNode = _result.Node; + if (_result.Error != null) + return; leftNode = new BinaryOperationNode(leftNode, rightNode, @operator, startPosition, _currentToken.EndPosition); - toReverseTo = result.AdvanceCount; - SkipNewLines(result); + toReverseTo = _result.AdvanceCount; + SkipNewLines(); } - int reverseCount = result.AdvanceCount - toReverseTo; + int reverseCount = _result.AdvanceCount - toReverseTo; Reverse(reverseCount); - result.Reverse(reverseCount); - return result.Success(leftNode); + _result.Reverse(reverseCount); + _result.Success(leftNode); } /// - /// Tries creating a 'statements' structure. + /// Tries parsing a 'statements' structure. /// - /// The object. - private ParseResult Statements() + private void ParseStatements() { - ParseResult result = new ParseResult(); List statements = new List(); Position startPosition = _currentToken.StartPosition; - SkipNewLines(result); + SkipNewLines(); - Node statement = result.Register(Statement()); - if (result.Error != null) - return result; + ParseStatement(); + Node statement = _result.Node; + if (_result.Error != null) + return; statements.Add(statement); while (true) @@ -206,8 +201,9 @@ private ParseResult Statements() // NOTE: Qeyword 'l' for 'else if' is deprecated, use Qeyword 'e' instead in format: // 'e [check]: [statement(s)]' - int newLineCount = SkipNewLines(result); - if (newLineCount == 0 || _currentToken.Type == TokenType.EndOfFile + int skipStart = _result.AdvanceCount; + SkipNewLines(); + if (_result.AdvanceCount - skipStart == 0 || _currentToken.Type == TokenType.EndOfFile || _currentToken.Type == TokenType.KeywordEnd || _currentToken.Type == TokenType.KeywordElse || _currentToken.Type == TokenType.KeywordError @@ -217,29 +213,28 @@ private ParseResult Statements() || _currentToken.Type == TokenType.QeywordS))) break; - statement = result.Register(Statement()); - if (result.Error != null) - return result; + ParseStatement(); + statement = _result.Node; + if (_result.Error != null) + return; statements.Add(statement); } - return result.Success(new ArrayLikeNode(statements, false, startPosition, _currentToken.EndPosition)); + _result.Success(new ArrayLikeNode(statements, false, startPosition, _currentToken.EndPosition)); } /// - /// Tries creating a 'statement' structure. + /// Tries parsing a 'statement' structure. /// - /// The object. - private ParseResult Statement() + private void ParseStatement() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; Node expression; if (_currentToken.Type == TokenType.KeywordReturn) { Position possibleEndPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.NewLine @@ -251,141 +246,162 @@ private ParseResult Statement() && (_currentToken.Type == TokenType.QeywordL || _currentToken.Type == TokenType.QeywordE || _currentToken.Type == TokenType.QeywordS))) - return result.Success(new ReturnNode(null, startPosition, possibleEndPosition)); + { + _result.Success(new ReturnNode(null, startPosition, possibleEndPosition)); + return; + } - expression = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + expression = _result.Node; + if (_result.Error != null) + return; - return result.Success(new ReturnNode(expression, startPosition, _currentToken.EndPosition)); + _result.Success(new ReturnNode(expression, startPosition, _currentToken.EndPosition)); + return; } else if (_currentToken.Type == TokenType.KeywordSkip || _currentToken.Type == TokenType.KeywordStop) { Position endPosition = _currentToken.EndPosition; TokenType currentTokenType = _currentToken.Type; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - return result.Success(new NoValueNode(currentTokenType, startPosition, endPosition)); + _result.Success(new NoValueNode(currentTokenType, startPosition, endPosition)); + return; } - expression = result.Register(Expression()); - if (result.Error != null) - return result.Failure(4, new InvalidGrammarError("Expected a statement!", _currentToken.StartPosition, _currentToken.EndPosition)); - return result.Success(expression); + ParseExpression(); + expression = _result.Node; + if (_result.Error != null) + _result.Failure(4, new InvalidGrammarError("Expected a statement!", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Success(expression); } /// - /// Tries creating a 'expression' structure. + /// Tries parsing an 'expression' structure. /// /// In cases where the variable assignment expression requires the 'item' keyword, set this to . - /// The object. - private ParseResult Expression(bool itemKeywordRequired = false) + private void ParseExpression(bool itemKeywordRequired = false) { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; bool globalAssignment = false; bool usedItemKeyword = false; + int startingAdvanceCount = _result.AdvanceCount; if (_currentToken.Type == TokenType.KeywordGlobal) { globalAssignment = true; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } if (_currentToken.Type == TokenType.KeywordItem) { usedItemKeyword = true; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else if (itemKeywordRequired) { - Node node_ = result.Register(QuickExpression()); - if (result.Error != null) - return result.Failure(4, new InvalidGrammarError("Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); - return result.Success(node_); + ParseQuickExpression(); + Node node_ = _result.Node; + if (_result.Error != null) + _result.Failure(4, new InvalidGrammarError("Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Success(node_); + return; } if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) { Token possibleVariable = _currentToken; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); if (_currentToken.TypeGroup != TokenTypeGroup.AssignmentSymbol) { Reverse(); - result.Reverse(); + _result.Reverse(); - Node variable = result.Register(Junction()); - if (result.Error != null) - return result; + ParseJunction(); + Node variable = _result.Node; + if (_result.Error != null) + return; if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) { TokenType assignmentOperator = _currentToken.Type; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - Node value = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + Node value = _result.Node; + if (_result.Error != null) + return; - return result.Success(new NodeVariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + _result.Success(new NodeVariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + return; } else if (usedItemKeyword) - return result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } else { - Reverse(result.AdvanceCount); - result.Reset(); + int reverseCount = _result.AdvanceCount - startingAdvanceCount; + Reverse(reverseCount); + _result.Reverse(reverseCount); } } else { TokenType assignmentOperator = _currentToken.Type; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - Node value = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + Node value = _result.Node; + if (_result.Error != null) + return; - return result.Success(new TokenVariableAssignmentNode(possibleVariable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + _result.Success(new TokenVariableAssignmentNode(possibleVariable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + return; } } + else if (usedItemKeyword) + { + _result.Failure(10, new InvalidGrammarError("Expected a variable name! The variable name is what will be assigned the value in a variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } else { - if (usedItemKeyword) - return result.Failure(10, new InvalidGrammarError("Expected a variable name! The variable name is what will be assigned the value in a variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - else - { - Reverse(result.AdvanceCount); - result.Reset(); - } + int reverseCount = _result.AdvanceCount - startingAdvanceCount; + Reverse(reverseCount); + _result.Reverse(reverseCount); } - Node node = result.Register(QuickExpression()); - if (result.Error != null) - return result.Failure(4, new InvalidGrammarError("Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); - return result.Success(node); + ParseQuickExpression(); + Node node = _result.Node; + if (_result.Error != null) + _result.Failure(4, new InvalidGrammarError("Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Success(node); } /// - /// Tries creating a 'quick-expression' structure. + /// Tries parsing a 'quick-expression' structure. /// - /// The object. - private ParseResult QuickExpression() + private void ParseQuickExpression() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; + int startingAdvanceCount = _result.AdvanceCount; if (_currentToken.Type == TokenType.ExclamationMark) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); bool globalAssignment = false; @@ -393,159 +409,175 @@ private ParseResult QuickExpression() if (_currentToken.Type == TokenType.QeywordG) { globalAssignment = true; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } if (_currentToken.Type == TokenType.QeywordD) { usedItemKeyword = true; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) { Token possibleVariable = _currentToken; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); if (_currentToken.TypeGroup != TokenTypeGroup.AssignmentSymbol) { Reverse(); - result.Reverse(); + _result.Reverse(); - Node variable = result.Register(Junction()); - if (result.Error != null) - return result; + ParseJunction(); + Node variable = _result.Node; + if (_result.Error != null) + return; if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) { TokenType assignmentOperator = _currentToken.Type; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - Node value = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + Node value = _result.Node; + if (_result.Error != null) + return; - return result.Success(new NodeVariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + _result.Success(new NodeVariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + return; } else if (usedItemKeyword) - return result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } else { - Reverse(result.AdvanceCount); - result.Reset(); + int reverseCount = _result.AdvanceCount - startingAdvanceCount; + Reverse(reverseCount); + _result.Reverse(reverseCount); } } else { TokenType assignmentOperator = _currentToken.Type; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - Node value = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + Node value = _result.Node; + if (_result.Error != null) + return; - return result.Success(new TokenVariableAssignmentNode(possibleVariable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + _result.Success(new TokenVariableAssignmentNode(possibleVariable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + return; } } + else if (usedItemKeyword) + { + _result.Failure(10, new InvalidGrammarError("Expected a variable name! The variable name is what will be assigned the value in a variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } else { - if (usedItemKeyword) - return result.Failure(10, new InvalidGrammarError("Expected a variable name! The variable name is what will be assigned the value in a variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - else - { - Reverse(result.AdvanceCount); - result.Reset(); - } + int reverseCount = _result.AdvanceCount - startingAdvanceCount; + Reverse(reverseCount); + _result.Reverse(reverseCount); } } - Node node = result.Register(Junction()); - if (result.Error != null) - return result.Failure(4, new InvalidGrammarError("Expected a QuickSyntax expression!", _currentToken.StartPosition, _currentToken.EndPosition)); - return result.Success(node); + ParseJunction(); + Node node = _result.Node; + if (_result.Error != null) + _result.Failure(4, new InvalidGrammarError("Expected a QuickSyntax expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Success(node); } /// - /// Tries creating a 'junction' structure. + /// Tries parsing a 'junction' structure. /// - /// The object. - private ParseResult Junction() + private void ParseJunction() { - return BinaryOperation(Inversion, null, TokenType.KeywordAnd, TokenType.KeywordOr); + BinaryOperation(ParseInversion, ParseInversion, TokenType.KeywordAnd, TokenType.KeywordOr); } /// - /// Tries creating a 'inversion' structure. + /// Tries parsing an 'inversion' structure. /// - /// The object. - private ParseResult Inversion() + private void ParseInversion() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; + int startingAdvanceCount = _result.AdvanceCount; if (_currentToken.Type == TokenType.ExclamationMark) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.QeywordV) { TokenType @operator = _currentToken.Type; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - Node operand = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + Node operand = _result.Node; + if (_result.Error != null) + return; - return result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); + _result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); + return; } else { - Reverse(result.AdvanceCount); - result.Reset(); + int reverseCount = _result.AdvanceCount - startingAdvanceCount; + Reverse(reverseCount); + _result.Reverse(reverseCount); } } else if (_currentToken.Type == TokenType.KeywordInvert) { TokenType @operator = _currentToken.Type; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - Node operand = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + Node operand = _result.Node; + if (_result.Error != null) + return; - return result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); + _result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); + return; } - Node node = result.Register(Comparison()); - if (result.Error != null) - return result.Failure(4, new InvalidGrammarError("Expected an inversion expression!", _currentToken.StartPosition, _currentToken.EndPosition)); - return result.Success(node); + ParseComparison(); + Node node = _result.Node; + if (_result.Error != null) + _result.Failure(4, new InvalidGrammarError("Expected an inversion expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Success(node); } /// - /// Tries creating a 'comparison' structure. + /// Tries parsing a 'comparison' structure. /// - /// The object. - private ParseResult Comparison() + private void ParseComparison() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - Node left = result.Register(BitwiseOr()); - if (result.Error != null) - return result; + ParseBitwiseOr(); + Node left = _result.Node; + if (_result.Error != null) + return; - int toReverseTo = result.AdvanceCount; + int toReverseTo = _result.AdvanceCount; - SkipNewLines(result); + SkipNewLines(); while (_currentToken.Type == TokenType.EqualSign || _currentToken.Type == TokenType.ExclamationMark || _currentToken.Type == TokenType.LessThanSign @@ -556,664 +588,770 @@ private ParseResult Comparison() || _currentToken.Type == TokenType.KeywordIn) { TokenType @operator = _currentToken.Type; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); + SkipNewLines(); if (@operator == TokenType.KeywordNot) { if (_currentToken.Type != TokenType.KeywordIn) - return result.Failure(10, new InvalidGrammarError("Expected the 'in' keyword! The 'in' keyword is the second part of a check-not-in operation.", _currentToken.StartPosition, _currentToken.EndPosition)); - result.RegisterAdvance(); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'in' keyword! The 'in' keyword is the second part of a check-not-in operation.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + _result.RegisterAdvance(); Advance(); } - Node rightNode = result.Register(BitwiseOr()); - if (result.Error != null) - return result; + ParseBitwiseOr(); + Node right = _result.Node; + if (_result.Error != null) + return; - left = new BinaryOperationNode(left, rightNode, @operator, startPosition, _currentToken.EndPosition); - toReverseTo = result.AdvanceCount; - SkipNewLines(result); + left = new BinaryOperationNode(left, right, @operator, startPosition, _currentToken.EndPosition); + toReverseTo = _result.AdvanceCount; + SkipNewLines(); } - int reverseCount = result.AdvanceCount - toReverseTo; + int reverseCount = _result.AdvanceCount - toReverseTo; Reverse(reverseCount); - result.Reverse(reverseCount); - return result.Success(left); + _result.Reverse(reverseCount); + _result.Success(left); } /// - /// Tries creating a 'bitwise-or' structure. + /// Tries parsing a 'bitwise-or' structure. /// - /// The object. - private ParseResult BitwiseOr() + private void ParseBitwiseOr() { - return BinaryOperation(BitwiseXOr, null, TokenType.VerticalBar); + BinaryOperation(ParseBitwiseXOr, ParseBitwiseXOr, TokenType.VerticalBar); } /// - /// Tries creating a 'bitwise-xor' structure. + /// Tries parsing a 'bitwise-xor' structure. /// - /// The object. - private ParseResult BitwiseXOr() + private void ParseBitwiseXOr() { - return BinaryOperation(BitwiseAnd, null, TokenType.Backslash); + BinaryOperation(ParseBitwiseAnd, ParseBitwiseAnd, TokenType.Backslash); } /// - /// Tries creating a 'bitwise-and' structure. + /// Tries parsing a 'bitwise-and' structure. /// - /// The object. - private ParseResult BitwiseAnd() + private void ParseBitwiseAnd() { - return BinaryOperation(BitwiseShift, null, TokenType.Ampersand); + BinaryOperation(ParseBitwiseShift, ParseBitwiseShift, TokenType.Ampersand); } /// /// Tries creating a 'bitwise-shift' structure. /// - /// The object. - private ParseResult BitwiseShift() + private void ParseBitwiseShift() { - return BinaryOperation(ArithmeticExpression, null, TokenType.BitwiseLeftShift, TokenType.BitwiseRightShift); + BinaryOperation(ParseArithmeticExpression, ParseArithmeticExpression, TokenType.BitwiseLeftShift, TokenType.BitwiseRightShift); } /// - /// Tries creating a 'arithmetic-expression' structure. + /// Tries parsing an 'arithmetic-expression' structure. /// - /// The object. - private ParseResult ArithmeticExpression() + private void ParseArithmeticExpression() { - return BinaryOperation(Term, null, TokenType.Plus, TokenType.HyphenMinus); + BinaryOperation(ParseTerm, ParseTerm, TokenType.Plus, TokenType.HyphenMinus); } /// - /// Tries creating a 'term' structure. + /// Tries parsing a 'term' structure. /// - /// The object. - private ParseResult Term() + private void ParseTerm() { - return BinaryOperation(Factor, null, TokenType.Asterisk, TokenType.Slash, TokenType.PercentSign); + BinaryOperation(ParseFactor, ParseFactor, TokenType.Asterisk, TokenType.Slash, TokenType.PercentSign); } /// - /// Tries creating a 'factor' structure. + /// Tries parsing a 'factor' structure. /// - /// The object. - private ParseResult Factor() + private void ParseFactor() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; TokenType @operator = _currentToken.Type; if (@operator == TokenType.Plus || @operator == TokenType.HyphenMinus || @operator == TokenType.Tilde) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - Node operand = result.Register(Factor()); - if (result.Error != null) - return result; + ParseFactor(); + Node operand = _result.Node; + if (_result.Error != null) + return; - return result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); + _result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); + return; } - return Power(); + ParsePower(); } /// - /// Tries creating a 'power' structure. + /// Tries parsing a 'power' structure. /// - /// The object. - private ParseResult Power() + private void ParsePower() { - return BinaryOperation(ObjectAttributeAccess, null, TokenType.Caret); + BinaryOperation(ParseObjectAttributeAccess, ParseObjectAttributeAccess, TokenType.Caret); } /// - /// Tries creating a 'object-attribute-access' structure. + /// Tries parsing an 'object-attribute-access' structure. /// - /// The object. - private ParseResult ObjectAttributeAccess() + private void ParseObjectAttributeAccess() { - return BinaryOperation(Call, ObjectAttributeAccess, TokenType.Period); + BinaryOperation(ParseCall, ParseObjectAttributeAccess, TokenType.Period); } /// - /// Tries creating a 'call' structure. + /// Tries parsing a 'call' structure. /// - /// The object. - private ParseResult Call() + private void ParseCall() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - Node node = result.Register(Atom()); - if (result.Error != null) - return result; + ParseAtom(); + Node node = _result.Node; + if (_result.Error != null) + return; if(_currentToken.Type == TokenType.LeftParenthesis) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Position possibleErrorStartPosition = _currentToken.StartPosition; - SkipNewLines(result); + SkipNewLines(); Position endPosition; List arguments = new List(); if (_currentToken.Type == TokenType.RightParenthesis) { endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else { + ParseExpression(); + arguments.Add(_result.Node); + if (_result.Error != null) + { + _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); + return; + } - arguments.Add(result.Register(Expression())); - if (result.Error != null) - return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); - // return result.Failure(5, new InvalidGrammarError("Expected an expression or right-parenthesis symbol! The right-parenthesis ends the function/object call expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - - SkipNewLines(result); + SkipNewLines(); while (_currentToken.Type == TokenType.Comma) { possibleErrorStartPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - arguments.Add(result.Register(Expression())); - if (result.Error != null) - return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); - SkipNewLines(result); + SkipNewLines(); + ParseExpression(); + arguments.Add(_result.Node); + if (_result.Error != null) + { + _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); + return; + } + SkipNewLines(); } if (_currentToken.Type != TokenType.RightParenthesis) - return result.Failure(10, new InvalidGrammarError("Expected a comma or right-parenthesis symbol! Commas are used to seperate the arguments of the function/object call expression, and the right-parenthesis is used to end it.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected a comma or right-parenthesis symbol! Commas are used to seperate the arguments of the function/object call expression, and the right-parenthesis is used to end it.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } - return result.Success(new CallNode(node, arguments, startPosition, endPosition)); + _result.Success(new CallNode(node, arguments, startPosition, endPosition)); + return; } - return result.Success(node); + + _result.Success(node); } /// - /// Tries creating a 'atom' structure. + /// Tries parsing a 'atom' structure. /// - /// The object. - private ParseResult Atom() + private void ParseAtom() { - ParseResult result = new ParseResult(); Token startToken = _currentToken; if(startToken.TypeGroup == TokenTypeGroup.Value) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - return result.Success(new ValueNode(startToken, startToken.StartPosition, startToken.EndPosition)); + _result.Success(new ValueNode(startToken, startToken.StartPosition, startToken.EndPosition)); + return; } else if (startToken.Type == TokenType.Identifier || startToken.TypeGroup == TokenTypeGroup.Qeyword) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - return result.Success(new VariableAccessNode(startToken, false, startToken.StartPosition, startToken.EndPosition)); + _result.Success(new VariableAccessNode(startToken, false, startToken.StartPosition, startToken.EndPosition)); + return; } else { switch (startToken.Type) { case TokenType.KeywordGlobal: - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) { Token variable = _currentToken; Position endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - return result.Success(new VariableAccessNode(variable, true, startToken.StartPosition, endPosition)); + _result.Success(new VariableAccessNode(variable, true, startToken.StartPosition, endPosition)); + return; } - return result.Failure(10, new InvalidGrammarError("Expected a variable name or the 'item' keyword! The variable name is used to access a global variable in a global variable access expression and the 'item' keyword is used to assign to a global variable in a global variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new InvalidGrammarError("Expected a variable name or the 'item' keyword! The variable name is used to access a global variable in a global variable access expression and the 'item' keyword is used to assign to a global variable in a global variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + break; case TokenType.LeftParenthesis: - Node arrayNode = result.Register(ArrayStructure()); - if (result.Error != null) - return result; - return result.Success(arrayNode); + ParseArrayOrParentheticalExpression(); + Node arrayNode = _result.Node; + if (_result.Error != null) + return; + _result.Success(arrayNode); + break; case TokenType.LeftSquareBracket: - Node encapsulatedListNode = result.Register(ListStructure()); - if (result.Error != null) - return result; - return result.Success(encapsulatedListNode); + ParseList(); + Node encapsulatedListNode = _result.Node; + if (_result.Error != null) + return; + _result.Success(encapsulatedListNode); + break; case TokenType.LeftCurlyBracket: - Node dictionaryNode = result.Register(DictionaryStructure()); - if (result.Error != null) - return result; - return result.Success(dictionaryNode); + ParseDictionary(); + Node dictionaryNode = _result.Node; + if (_result.Error != null) + return; + _result.Success(dictionaryNode); + break; case TokenType.KeywordIf: - Node ifNode = result.Register(IfStructure()); - if (result.Error != null) - return result; - return result.Success(ifNode); + ParseIfExpression(); + Node ifNode = _result.Node; + if (_result.Error != null) + return; + _result.Success(ifNode); + break; case TokenType.KeywordCount: - Node countNode = result.Register(CountStructure()); - if (result.Error != null) - return result; - return result.Success(countNode); + ParseCountExpression(); + Node countNode = _result.Node; + if (_result.Error != null) + return; + _result.Success(countNode); + break; case TokenType.KeywordWhile: - Node whileNode = result.Register(WhileStructure()); - if (result.Error != null) - return result; - return result.Success(whileNode); + ParseWhileExpression(); + Node whileNode = _result.Node; + if (_result.Error != null) + return; + _result.Success(whileNode); + break; case TokenType.KeywordTry: - Node tryNode = result.Register(TryStructure()); - if (result.Error != null) - return result; - return result.Success(tryNode); + ParseTryExpression(); + Node tryNode = _result.Node; + if (_result.Error != null) + return; + _result.Success(tryNode); + break; case TokenType.KeywordFunction: - Node functionDefinitionNode = result.Register(FunctionDefinitionStructure()); - if (result.Error != null) - return result; - return result.Success(functionDefinitionNode); + ParseFunctionDefinitionExpression(); + Node functionDefinitionNode = _result.Node; + if (_result.Error != null) + return; + _result.Success(functionDefinitionNode); + break; case TokenType.KeywordObject: - Node objectDefinitionNode = result.Register(ObjectDefinitionStructure()); - if (result.Error != null) - return result; - return result.Success(objectDefinitionNode); + ParseObjectDefinitionExpression(); + Node objectDefinitionNode = _result.Node; + if (_result.Error != null) + return; + _result.Success(objectDefinitionNode); + break; case TokenType.KeywordInclude: - Node includeNode = result.Register(IncludeStructure()); - if (result.Error != null) - return result; - return result.Success(includeNode); + ParseIncludeExpression(); + Node includeNode = _result.Node; + if (_result.Error != null) + return; + _result.Success(includeNode); + break; default: - return result.Failure(4, new InvalidGrammarError("Expected an integer, float, string, character, character list, identifier, 'if' expression, 'count' expression, 'while' expression and so on.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(4, new InvalidGrammarError("Expected an integer, float, string, character, character list, identifier, 'if' expression, 'count' expression, 'while' expression and so on.", _currentToken.StartPosition, _currentToken.EndPosition)); + break; } } } /// - /// Creates the structure of an array, an with set to OR a parenthetical expression. Starts from , which should be of . + /// Tries parsing an array, an with set to OR a parenthetical expression. Starts from , which should be of . /// - /// The object. - private ParseResult ArrayStructure() + private void ParseArrayOrParentheticalExpression() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Position possibleErrorStartPosition = _currentToken.StartPosition; List elements = new List(); bool isArray = false; - SkipNewLines(result); + SkipNewLines(); Position endPosition; if (_currentToken.Type == TokenType.RightParenthesis) { endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else { - elements.Add(result.Register(Expression())); - if (result.Error != null) - return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array/parenthetical expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); - // return result.Failure(5, new InvalidGrammarError("Expected an expression or right-parenthesis symbol! The right-parenthesis closes off an empty array.", _currentToken.StartPosition, _currentToken.EndPosition)); + ParseExpression(); + elements.Add(_result.Node); + if (_result.Error != null) + { + _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array/parenthetical expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); + return; + } - SkipNewLines(result); + SkipNewLines(); while (_currentToken.Type == TokenType.Comma) { isArray = true; possibleErrorStartPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); + SkipNewLines(); if (_currentToken.Type == TokenType.RightParenthesis && elements.Count == 1) break; - Node element = result.Register(Expression()); - if (result.Error != null) + ParseExpression(); + if (_result.Error != null) { if (elements.Count > 1) - return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); + { + _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); + return; + } Position errorStartPosition = possibleErrorStartPosition.Copy(); errorStartPosition.Advance(); - return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array must end with a right-parenthesis.", errorStartPosition, _currentToken.EndPosition))); + _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array must end with a right-parenthesis.", errorStartPosition, _currentToken.EndPosition))); } - elements.Add(element); - SkipNewLines(result); + elements.Add(_result.Node); + SkipNewLines(); } if (_currentToken.Type != TokenType.RightParenthesis) { if (isArray) - return result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! Commas seperate the elements of the array, while the right-parenthesis ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); - return result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! The comma is used to create an array and seperate its elements, while the right-parenthesis declares the end of a parenthetical expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! Commas seperate the elements of the array, while the right-parenthesis ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! The comma is used to create an array and seperate its elements, while the right-parenthesis declares the end of a parenthetical expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; } endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } if (!isArray && elements.Count > 0) - return result.Success(elements[0]); - return result.Success(new ArrayLikeNode(elements, false, startPosition, endPosition)); + _result.Success(elements[0]); + else + _result.Success(new ArrayLikeNode(elements, false, startPosition, endPosition)); } /// - /// Creates the structure of a list, an with set to . Starts from , which should be of . + /// Tries parsing a list, an with set to . Starts from , which should be of . /// - /// The object. - private ParseResult ListStructure() + private void ParseList() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Position possibleErrorStartPosition = _currentToken.StartPosition; - SkipNewLines(result); + SkipNewLines(); Position endPosition; List elements = new List(); if (_currentToken.Type == TokenType.RightSquareBracket) { endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else { - elements.Add(result.Register(Expression())); - if (result.Error != null) - return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); - // return result.Failure(5, new InvalidGrammarError("Expected an expression or right-square-bracket symbol! The right-square-bracket ends the list expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + ParseExpression(); + elements.Add(_result.Node); + if (_result.Error != null) + { + _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); + return; + } - SkipNewLines(result); + SkipNewLines(); while (_currentToken.Type == TokenType.Comma) { possibleErrorStartPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - elements.Add(result.Register(Expression())); - if (result.Error != null) - return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); - SkipNewLines(result); + SkipNewLines(); + + ParseExpression(); + elements.Add(_result.Node); + if (_result.Error != null) + { + _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); + return; + } + SkipNewLines(); } if (_currentToken.Type != TokenType.RightSquareBracket) - return result.Failure(10, new InvalidGrammarError("Expected a comma or a right-square-bracket symbol! Commas are used to seperate elements in the list, while the right-square-bracket ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected a comma or a right-square-bracket symbol! Commas are used to seperate elements in the list, while the right-square-bracket ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } - return result.Success(new ArrayLikeNode(elements, true, startPosition, endPosition)); + _result.Success(new ArrayLikeNode(elements, true, startPosition, endPosition)); } /// - /// Creates the structure of a dictionary. Starts from , which should be of . + /// Tries parsing a dictionary. Starts from , which should be of . /// - /// The object. - private ParseResult DictionaryStructure() + private void ParseDictionary() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Position possibleErrorStartPosition = _currentToken.StartPosition; List pairs = new List(); - SkipNewLines(result); + SkipNewLines(); Position endPosition; if (_currentToken.Type == TokenType.RightCurlyBracket) { endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else { - Node left = result.Register(Expression(true)); - if (result.Error != null) - return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); - // return result.Failure(5, new InvalidGrammarError("Expected an expression or a right-curly-bracket symbol! The right-curly-bracket declares the end of the dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + ParseExpression(true); + Node left = _result.Node; + if (_result.Error != null) + { + _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); + return; + } - SkipNewLines(result); + SkipNewLines(); - // NOTE: Breaking change - assignment symbols will break this. if (_currentToken.Type != TokenType.Colon) - return result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); - result.RegisterAdvance(); + { + _result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - Node right = result.Register(Expression()); - if (result.Error != null) - return result; + SkipNewLines(); + + ParseExpression(); + Node right = _result.Node; + if (_result.Error != null) + return; pairs.Add(new Node[2] { left, right }); - SkipNewLines(result); + SkipNewLines(); while (_currentToken.Type == TokenType.Comma) { possibleErrorStartPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - left = result.Register(Expression(true)); - if (result.Error != null) - return result.Failure(10, new StackedError(result.Error, new InvalidGrammarError("Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); + SkipNewLines(); - SkipNewLines(result); + ParseExpression(true); + left = _result.Node; + if (_result.Error != null) + { + _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); + return; + } + + SkipNewLines(); if (_currentToken.Type != TokenType.Colon) - return result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); - result.RegisterAdvance(); + { + _result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - right = result.Register(Expression()); - if (result.Error != null) - return result; + SkipNewLines(); + + ParseExpression(); + right = _result.Node; + if (_result.Error != null) + return; pairs.Add(new Node[2] { left, right }); - SkipNewLines(result); + SkipNewLines(); } if (_currentToken.Type != TokenType.RightCurlyBracket) - return result.Failure(10, new InvalidGrammarError("Expected a comma or right-curly-bracket symbol! Commas are used to seperate key-value pairs in the dictionary, and the right-curly-bracket declares its end.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected a comma or right-curly-bracket symbol! Commas are used to seperate key-value pairs in the dictionary, and the right-curly-bracket declares its end.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } - return result.Success(new DictionaryNode(pairs, startPosition, endPosition)); + _result.Success(new DictionaryNode(pairs, startPosition, endPosition)); } /// - /// Creates the structure of an if expression. Starts from , which should be of . + /// Tries parsing an if expression. Starts from , which should be of . /// - /// The object. - private ParseResult IfStructure() + private void ParseIfExpression() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); List cases = new List(); Node? elseCase = null; - Node condition = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + Node condition = _result.Node; + if (_result.Error != null) + return; if (_currentToken.Type != TokenType.KeywordDo) - return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - result.RegisterAdvance(); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + _result.RegisterAdvance(); Advance(); Node body; if (_currentToken.Type == TokenType.NewLine) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - body = result.Register(Statements()); - if (result.Error != null) - return result; + ParseStatements(); + body = _result.Node; + if (_result.Error != null) + return; Position endPosition; cases.Add(new Node[2] { condition, body }); if (_currentToken.Type == TokenType.KeywordEnd) { endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else if (_currentToken.Type == TokenType.KeywordElse) { while (_currentToken.Type == TokenType.KeywordElse) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.KeywordIf) { if (elseCase != null) - return result.Failure(10, new InvalidGrammarError("The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - condition = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + condition = _result.Node; + if (_result.Error != null) + return; if (_currentToken.Type != TokenType.KeywordDo) - return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - result.RegisterAdvance(); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + _result.RegisterAdvance(); Advance(); - body = result.Register(Statements()); - if (result.Error != null) - return result; + ParseStatements(); + body = _result.Node; + if (_result.Error != null) + return; cases.Add(new Node[2] { condition, body }); } else if (_currentToken.Type != TokenType.KeywordDo) - return result.Failure(10, new InvalidGrammarError("Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } else { if (elseCase != null) - return result.Failure(10, new InvalidGrammarError("There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - elseCase = result.Register(Statements()); - if (result.Error != null) - return result; + ParseStatements(); + elseCase = _result.Node; + if (_result.Error != null) + return; } } if (_currentToken.Type != TokenType.KeywordEnd) { if (elseCase == null) - return result.Failure(10, new InvalidGrammarError("Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new InvalidGrammarError("Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; } endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else - return result.Failure(10, new InvalidGrammarError("Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } - return result.Success(new IfNode(cases, elseCase, startPosition, endPosition)); + _result.Success(new IfNode(cases, elseCase, startPosition, endPosition)); + return; } - body = result.Register(Statement()); - if (result.Error != null) - return result; + ParseStatement(); + body = _result.Node; + if (_result.Error != null) + return; cases.Add(new Node[2] { condition, body }); while (_currentToken.Type == TokenType.KeywordElse) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.KeywordIf) { if (elseCase != null) - return result.Failure(10, new InvalidGrammarError("The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - condition = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + condition = _result.Node; + if (_result.Error != null) + return; if (_currentToken.Type != TokenType.KeywordDo) - return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - result.RegisterAdvance(); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + _result.RegisterAdvance(); Advance(); - body = result.Register(Statement()); - if (result.Error != null) - return result; + ParseStatement(); + body = _result.Node; + if (_result.Error != null) + return; cases.Add(new Node[2] { condition, body }); } else if (_currentToken.Type != TokenType.KeywordDo) - return result.Failure(10, new InvalidGrammarError("Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } else { if (elseCase != null) - return result.Failure(10, new InvalidGrammarError("There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - elseCase = result.Register(Statement()); - if (result.Error != null) - return result; + ParseStatement(); + elseCase = _result.Node; + if (_result.Error != null) + return; } } - return result.Success(new IfNode(cases, elseCase, startPosition, PeekPrevious().EndPosition)); + _result.Success(new IfNode(cases, elseCase, startPosition, PeekPrevious().EndPosition)); } /// - /// Creates the structure of a count expression. Starts from , which should be of . + /// Tries parsing a count expression. Starts from , which should be of . /// - /// The object. - private ParseResult CountStructure() + private void ParseCountExpression() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Node to = InvalidNode.StaticInvalidNode; @@ -1223,149 +1361,167 @@ private ParseResult CountStructure() if (_currentToken.Type == TokenType.KeywordFrom) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - from = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + from = _result.Node; + if (_result.Error != null) + return; } if (_currentToken.Type != TokenType.KeywordTo) { if (from == null) - return result.Failure(10, new InvalidGrammarError("Expected the 'to' or 'from' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop, and the optional 'from' keyword and the following expression is the amount to count from.", _currentToken.StartPosition, _currentToken.EndPosition)); - return result.Failure(10, new InvalidGrammarError("Expected the 'to' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new InvalidGrammarError("Expected the 'to' or 'from' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop, and the optional 'from' keyword and the following expression is the amount to count from.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Failure(10, new InvalidGrammarError("Expected the 'to' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; } - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - to = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + to = _result.Node; + if (_result.Error != null) + return; if (_currentToken.Type == TokenType.KeywordStep) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - step = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + step = _result.Node; + if (_result.Error != null) + return; } if (_currentToken.Type == TokenType.KeywordAs) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - @as = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + @as = _result.Node; + if (_result.Error != null) + return; } if (_currentToken.Type != TokenType.KeywordDo) { if (step == null && @as == null) - return result.Failure(10, new InvalidGrammarError("Expected the 'do', 'step' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, the optional 'step' keyword and the following expression is the increment, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new InvalidGrammarError("Expected the 'do', 'step' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, the optional 'step' keyword and the following expression is the increment, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); else if (@as == null) - return result.Failure(10, new InvalidGrammarError("Expected the 'do' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); - return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new InvalidGrammarError("Expected the 'do' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; } - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Node body; Position endPosition; if (_currentToken.Type == TokenType.NewLine) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - body = result.Register(Statements()); - if (result.Error != null) - return result; + ParseStatements(); + body = _result.Node; + if (_result.Error != null) + return; if (_currentToken.Type != TokenType.KeywordEnd) - return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else { - body = result.Register(Statement()); - if (result.Error != null) - return result; + ParseStatement(); + body = _result.Node; + if (_result.Error != null) + return; endPosition = PeekPrevious().EndPosition; } - return result.Success(new CountNode(to, from, step, @as, body, startPosition, endPosition)); + _result.Success(new CountNode(to, from, step, @as, body, startPosition, endPosition)); } /// - /// Creates the structure of a while expression. Starts from , which should be of . + /// Tries parsing a while expression. Starts from , which should be of . /// - /// The object. - private ParseResult WhileStructure() + private void ParseWhileExpression() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - Node condition = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + Node condition = _result.Node; + if (_result.Error != null) + return; if (_currentToken.Type != TokenType.KeywordDo) - return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); - result.RegisterAdvance(); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + _result.RegisterAdvance(); Advance(); Node body; Position endPosition; if (_currentToken.Type == TokenType.NewLine) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - body = result.Register(Statements()); - if (result.Error != null) - return result; + ParseStatements(); + body = _result.Node; + if (_result.Error != null) + return; if (_currentToken.Type != TokenType.KeywordEnd) - return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else { - body = result.Register(Statement()); - if (result.Error != null) - return result; + ParseStatement(); + body = _result.Node; + if (_result.Error != null) + return; endPosition = PeekPrevious().EndPosition; } - return result.Success(new WhileNode(condition, body, startPosition, endPosition)); + _result.Success(new WhileNode(condition, body, startPosition, endPosition)); } /// - /// Creates the structure of a try expression. Starts from , which should be of . + /// Tries parsing a try expression. Starts from , which should be of . /// - /// The object. - private ParseResult TryStructure() + private void ParseTryExpression() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Node block; @@ -1373,32 +1529,37 @@ private ParseResult TryStructure() Node?[]? emptyCase = null; if (_currentToken.Type != TokenType.KeywordDo) - return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - result.RegisterAdvance(); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + _result.RegisterAdvance(); Advance(); Node body; if (_currentToken.Type == TokenType.NewLine) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - block = result.Register(Statements()); - if (result.Error != null) - return result; + ParseStatements(); + block = _result.Node; + if (_result.Error != null) + return; Position endPosition; if (_currentToken.Type == TokenType.KeywordEnd) { endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else if (_currentToken.Type == TokenType.KeywordError) { while (_currentToken.Type == TokenType.KeywordError) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Node? error = null; @@ -1409,28 +1570,36 @@ private ParseResult TryStructure() if (_currentToken.Type == TokenType.KeywordDo || isAsKeyword) { if (emptyCase != null) - return result.Failure(10, new InvalidGrammarError("There should only be one empty \"error\" expression! You cannot have multiple \"error\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("There should only be one empty \"error\" expression! You cannot have multiple \"error\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } Node? @as = null; if (isAsKeyword) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - @as = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + @as = _result.Node; + if (_result.Error != null) + return; if (_currentToken.Type != TokenType.KeywordDo) - return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } } - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - body = result.Register(Statements()); - if (result.Error != null) - return result; + ParseStatements(); + body = _result.Node; + if (_result.Error != null) + return; if (error != null) cases.Add(new Node?[3] { error, @as, body }); @@ -1442,46 +1611,61 @@ private ParseResult TryStructure() if (emptyCase != null) { Token previous = PeekPrevious(); - return result.Failure(10, new InvalidGrammarError("There can't be any \"error\" expressions after an empty \"error\" expression!", previous.StartPosition, previous.EndPosition)); + _result.Failure(10, new InvalidGrammarError("There can't be any \"error\" expressions after an empty \"error\" expression!", previous.StartPosition, previous.EndPosition)); + return; } - error = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + error = _result.Node; + if (_result.Error != null) + return; isErrorNull = false; goto ErrorExpressionEvaluation; } else if (isErrorNull) - return result.Failure(10, new InvalidGrammarError("Expected an expression or the 'as' or 'do' keywords! An expression after the 'error' keyword defines what error(s) will lead to the \"error\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected an expression or the 'as' or 'do' keywords! An expression after the 'error' keyword defines what error(s) will lead to the \"error\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } else - return result.Failure(10, new InvalidGrammarError("Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } } if (_currentToken.Type != TokenType.KeywordEnd) { if (emptyCase == null) - return result.Failure(10, new InvalidGrammarError("Expected the 'error' or 'end' keywords! The 'error' keyword defines the start of an \"error\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new InvalidGrammarError("Expected the 'error' or 'end' keywords! The 'error' keyword defines the start of an \"error\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; } endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else - return result.Failure(10, new InvalidGrammarError("Expected the 'error' or 'end' keywords! The 'error' keyword defines the start of an \"error\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'error' or 'end' keywords! The 'error' keyword defines the start of an \"error\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } - return result.Success(new TryNode(block, cases, emptyCase, startPosition, endPosition)); + _result.Success(new TryNode(block, cases, emptyCase, startPosition, endPosition)); + return; } - block = result.Register(Statement()); - if (result.Error != null) - return result; + ParseStatement(); + block = _result.Node; + if (_result.Error != null) + return; while (_currentToken.Type == TokenType.KeywordError) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Node? error = null; @@ -1492,28 +1676,36 @@ private ParseResult TryStructure() if (_currentToken.Type == TokenType.KeywordDo || isAsKeyword) { if (emptyCase != null) - return result.Failure(10, new InvalidGrammarError("There should only be one empty \"error\" expression! You cannot have multiple \"error\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("There should only be one empty \"error\" expression! You cannot have multiple \"error\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } Node? @as = null; if (isAsKeyword) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - @as = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + @as = _result.Node; + if (_result.Error != null) + return; if (_currentToken.Type != TokenType.KeywordDo) - return result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } } - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - body = result.Register(Statement()); - if (result.Error != null) - return result; + ParseStatement(); + body = _result.Node; + if (_result.Error != null) + return; if (error != null) cases.Add(new Node?[3] { error, @as, body }); @@ -1525,34 +1717,40 @@ private ParseResult TryStructure() if (emptyCase != null) { Token previous = PeekPrevious(); - return result.Failure(10, new InvalidGrammarError("There can't be any \"error\" expressions after an empty \"error\" expression!", previous.StartPosition, previous.EndPosition)); + _result.Failure(10, new InvalidGrammarError("There can't be any \"error\" expressions after an empty \"error\" expression!", previous.StartPosition, previous.EndPosition)); + return; } - error = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + error = _result.Node; + if (_result.Error != null) + return; isErrorNull = false; goto ErrorExpressionEvaluation; } else if (isErrorNull) - return result.Failure(10, new InvalidGrammarError("Expected an expression or the 'as' or 'do' keywords! An expression after the 'error' keyword defines what error(s) will lead to the \"error\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - else - return result.Failure(10, new InvalidGrammarError("Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected an expression or the 'as' or 'do' keywords! An expression after the 'error' keyword defines what error(s) will lead to the \"error\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + else + { + _result.Failure(10, new InvalidGrammarError("Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } } - return result.Success(new TryNode(block, cases, emptyCase, startPosition, PeekPrevious().EndPosition)); + _result.Success(new TryNode(block, cases, emptyCase, startPosition, PeekPrevious().EndPosition)); } /// - /// Creates the structure of a function definition expression. Starts from , which should be of . + /// Tries parsing a function definition expression. Starts from , which should be of . /// - /// The object. - private ParseResult FunctionDefinitionStructure() + private void ParseFunctionDefinitionExpression() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Node? name = null; @@ -1568,90 +1766,107 @@ private ParseResult FunctionDefinitionStructure() { if (isWithKeyword) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - parameters.Add(result.Register(Expression())); - if (result.Error != null) - return result; + SkipNewLines(); + + ParseExpression(); + parameters.Add(_result.Node); + if (_result.Error != null) + return; - SkipNewLines(result); + SkipNewLines(); while (_currentToken.Type == TokenType.Comma) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - parameters.Add(result.Register(Expression())); - if (result.Error != null) - return result; + SkipNewLines(); + + ParseExpression(); + parameters.Add(_result.Node); + if (_result.Error != null) + return; - SkipNewLines(result); + SkipNewLines(); } if (_currentToken.Type != TokenType.KeywordDo) - return result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parameter and the 'do' keyword declares the start of the body of the \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parameter and the 'do' keyword declares the start of the body of the \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } } - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.NewLine) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - body = result.Register(Statements()); - if (result.Error != null) - return result; + ParseStatements(); + body = _result.Node; + if (_result.Error != null) + return; if (_currentToken.Type != TokenType.KeywordEnd) - return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else { - body = result.Register(Statement()); - if (result.Error != null) - return result; + ParseStatement(); + body = _result.Node; + if (_result.Error != null) + return; endPosition = PeekPrevious().EndPosition; } } else if (isNameNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) { - name = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + name = _result.Node; + if (_result.Error != null) + return; isNameNull = false; goto FunctionDefinitionEvaluation; } else if (isNameNull) - return result.Failure(10, new InvalidGrammarError("Expected an expression or the 'with' or 'do' keywords! An expression after the 'function' keyword defines the name, the 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected an expression or the 'with' or 'do' keywords! An expression after the 'function' keyword defines the name, the 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } else - return result.Failure(10, new InvalidGrammarError("Expected the 'with' or 'do' keywords! The 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'with' or 'do' keywords! The 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } - return result.Success(new FunctionDefinitionNode(name, parameters, body, startPosition, endPosition)); + _result.Success(new FunctionDefinitionNode(name, parameters, body, startPosition, endPosition)); } // 'special' expressions are gone. /// - /// Creates the structure of an object definition expression. Starts from , which should be of . + /// Tries parsing an object definition expression. Starts from , which should be of . /// - /// The object. - private ParseResult ObjectDefinitionStructure() + private void ParseObjectDefinitionExpression() { // The parents of the object are now defined after the 'from' keyword like an array. The 'from' keyword must come before the 'do' keyword and after the 'with' keyword. - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Node? name = null; @@ -1669,115 +1884,139 @@ private ParseResult ObjectDefinitionStructure() { if (isWithKeyword) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - parameters.Add(result.Register(Expression())); - if (result.Error != null) - return result; + SkipNewLines(); + + ParseExpression(); + parameters.Add(_result.Node); + if (_result.Error != null) + return; - SkipNewLines(result); + SkipNewLines(); while (_currentToken.Type == TokenType.Comma) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - parameters.Add(result.Register(Expression())); - if (result.Error != null) - return result; + SkipNewLines(); - SkipNewLines(result); + ParseExpression(); + parameters.Add(_result.Node); + if (_result.Error != null) + return; + + SkipNewLines(); } isFromKeyword = _currentToken.Type == TokenType.KeywordFrom; if (_currentToken.Type != TokenType.KeywordDo && !isFromKeyword) - return result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'from' or 'do' keywords! The comma symbol and the following expression defines another parameter, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'from' or 'do' keywords! The comma symbol and the following expression defines another parameter, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } } if (isFromKeyword) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - parents.Add(result.Register(Expression())); - if (result.Error != null) - return result; + SkipNewLines(); - SkipNewLines(result); + ParseExpression(); + parents.Add(_result.Node); + if (_result.Error != null) + return; + + SkipNewLines(); while (_currentToken.Type == TokenType.Comma) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - SkipNewLines(result); - parents.Add(result.Register(Expression())); - if (result.Error != null) - return result; + SkipNewLines(); + + ParseExpression(); + parents.Add(_result.Node); + if (_result.Error != null) + return; - SkipNewLines(result); + SkipNewLines(); } if (_currentToken.Type != TokenType.KeywordDo) - return result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parent and the 'do' keyword declares the start of the body of the \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parent and the 'do' keyword declares the start of the body of the \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } } - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.NewLine) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - body = result.Register(Statements()); - if (result.Error != null) - return result; + ParseStatements(); + body = _result.Node; + if (_result.Error != null) + return; if (_currentToken.Type != TokenType.KeywordEnd) - return result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } endPosition = _currentToken.EndPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } else { - body = result.Register(Statement()); - if (result.Error != null) - return result; + ParseStatement(); + body = _result.Node; + if (_result.Error != null) + return; endPosition = PeekPrevious().EndPosition; } } else if (isNameNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) { - name = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + name = _result.Node; + if (_result.Error != null) + return; isNameNull = false; goto ObjectDefinitionEvaluation; } else if (isNameNull) - return result.Failure(10, new InvalidGrammarError("Expected an expression or the 'with', 'from' or 'do' keywords! An expression after the 'object' keyword defines the name, the 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\".", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected an expression or the 'with', 'from' or 'do' keywords! An expression after the 'object' keyword defines the name, the 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\".", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } else - return result.Failure(10, new InvalidGrammarError("Expected the 'with', 'from' or 'do' keywords! The 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\".", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'with', 'from' or 'do' keywords! The 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\".", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } - return result.Success(new ObjectDefinitionNode(name, parameters, parents, body, startPosition, endPosition)); + _result.Success(new ObjectDefinitionNode(name, parameters, parents, body, startPosition, endPosition)); } /// - /// Creates the structure of an include expression. Starts from , which should be of . + /// Tries parsing an include expression. Starts from , which should be of . /// - /// The object. - private ParseResult IncludeStructure() + private void ParseIncludeExpression() { - ParseResult result = new ParseResult(); Position startPosition = _currentToken.StartPosition; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); Node? subStructure = null; @@ -1787,25 +2026,27 @@ private ParseResult IncludeStructure() if (_currentToken.Type != TokenType.KeywordAll && _currentToken.Type != TokenType.Comma) { - subStructure = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + subStructure = _result.Node; + if (_result.Error != null) + return; } else { isDumped = true; - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); } if (_currentToken.Type == TokenType.KeywordFrom) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - script = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + script = _result.Node; + if (_result.Error != null) + return; } else if (subStructure != null) { @@ -1813,19 +2054,23 @@ private ParseResult IncludeStructure() subStructure = null; } else - return result.Failure(10, new InvalidGrammarError("Expected the 'from' keyword! If a specific object being included from a script (when the object's name is provided after the 'include' keyword) or if the whole script is added to the script (using the 'all' keyword or a comma symbol after the 'include' keyword), the 'from' keyword followed by an expression declaring the script's name or path must be provided.", _currentToken.StartPosition, _currentToken.EndPosition)); + { + _result.Failure(10, new InvalidGrammarError("Expected the 'from' keyword! If a specific object being included from a script (when the object's name is provided after the 'include' keyword) or if the whole script is added to the script (using the 'all' keyword or a comma symbol after the 'include' keyword), the 'from' keyword followed by an expression declaring the script's name or path must be provided.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } if (_currentToken.Type == TokenType.KeywordAs) { - result.RegisterAdvance(); + _result.RegisterAdvance(); Advance(); - nickname = result.Register(Expression()); - if (result.Error != null) - return result; + ParseExpression(); + nickname = _result.Node; + if (_result.Error != null) + return; } - return result.Success(new IncludeNode(script, subStructure, isDumped, nickname, startPosition, PeekPrevious().EndPosition)); + _result.Success(new IncludeNode(script, subStructure, isDumped, nickname, startPosition, PeekPrevious().EndPosition)); } } @@ -1849,11 +2094,6 @@ public class ParseResult /// public int AdvanceCount; - /// - /// The amount of times the will have to reverse if an occurred in a call. - /// - public int ReverseCount; - /// /// The priority of the error held in the . /// @@ -1867,19 +2107,6 @@ public ParseResult() Error = null; Node = InvalidNode.StaticInvalidNode; AdvanceCount = 0; - ReverseCount = 0; - ErrorPriority = 0; - } - - /// - /// Resets the object to initialized state. - /// - public void Reset() - { - Error = null; - Node = InvalidNode.StaticInvalidNode; - AdvanceCount = 0; - ReverseCount = 0; ErrorPriority = 0; } @@ -1900,52 +2127,14 @@ public void Reverse(int reverseCount = 1) AdvanceCount -= reverseCount; } - /// - /// Registers the from a parsing function. - /// - /// The result of the parsing function. - /// The object of . - public Node Register(ParseResult result) - { - AdvanceCount += result.AdvanceCount; - if (result.Error != null) - { - ErrorPriority = result.ErrorPriority; - Error = result.Error; - } - - return result.Node; - } - - /// - /// Tries registering the from a parsing function. - /// - /// The result of the parsing function. - /// The object of , if an occurred. - /// if has no ; otherwise . - public bool TryRegister(ParseResult result, out Node node) - { - if (result.Error != null) - { - ReverseCount = result.AdvanceCount; - node = InvalidNode.StaticInvalidNode; - return false; - } - - AdvanceCount += result.AdvanceCount; - node = result.Node; - return true; - } - /// /// Sets as the result of successful parsing. /// /// The result of the parsing. /// The same object. - public ParseResult Success(Node node) + public void Success(Node node) { Node = node; - return this; } /// @@ -1958,15 +2147,13 @@ public ParseResult Success(Node node) /// The priority/fatality of the failure. /// The that occurred in parsing. /// The same object. - public ParseResult Failure(int priority, Error error) + public void Failure(int priority, Error error) { if (Error == null || ErrorPriority <= priority || AdvanceCount == 0) { ErrorPriority = priority; Error = error; } - - return this; } } } From 34670e2e71df8d4c124a4be1d27c1b592a16e591 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 14 Sep 2023 01:53:44 +0530 Subject: [PATCH 011/113] Removed PeekNext method in EzrLexer. It was only being used in one place. --- src/EzrLexer.cs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/EzrLexer.cs b/src/EzrLexer.cs index 98611f7..5227716 100644 --- a/src/EzrLexer.cs +++ b/src/EzrLexer.cs @@ -64,19 +64,6 @@ private void Advance() _reachedEndFlag = true; } - /// - /// Peeks one character in front of the current in the script. - /// - /// The character in front of the current ; if the next character is the end of the script. - private char Peek() - { - int peekIndex = _position.Index + 1; - if (peekIndex < _script.Length) - return _script[peekIndex]; - else - return '\0'; - } - /// /// Creates a of objects from the given script. /// @@ -271,7 +258,10 @@ private char Peek() { if (_currentChar == '.') { - if (hasPeriod || !char.IsDigit(Peek())) + int peekIndex = _position.Index + 1; + char next = (peekIndex < _script.Length) ? _script[peekIndex] : '\0'; + + if (hasPeriod || !char.IsDigit(next)) break; hasPeriod = true; } From a14460364a0786e97e5b682d2cf96bcfcc62c682 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 14 Sep 2023 19:55:08 +0530 Subject: [PATCH 012/113] It's faster now! - Changes to the Lexer. - '\r' characters are just skipped now. - All consecutive newlines are now grouped together into one TokenType.NewLine Token. - Changes to the Parser. - _result.RegisterAdvance() has been removed and functionality moved to Parser.Advance(), because all calls to it are succeeded by Parser.Advance(). - _result.Reverse() has also been removed for the same reasons. - SkipNewLines() has been removed as its functionality can now be replaced by a simple "if (_currentToken.Type == TokenType.NewLine) Advance();". - A few changes to EzrSquared.csproj. --- src/AutoGeneratedAssemblyInfo.cs | 2 - src/EzrErrors.cs | 10 +- src/EzrLexer.cs | 43 ++-- src/EzrParser.cs | 331 +++++++++++-------------------- src/EzrSquared.csproj | 6 +- 5 files changed, 151 insertions(+), 241 deletions(-) diff --git a/src/AutoGeneratedAssemblyInfo.cs b/src/AutoGeneratedAssemblyInfo.cs index c36e89c..8ae053f 100644 --- a/src/AutoGeneratedAssemblyInfo.cs +++ b/src/AutoGeneratedAssemblyInfo.cs @@ -12,8 +12,6 @@ using System.Reflection; [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] -[assembly: System.Runtime.Versioning.TargetPlatformAttribute("Windows10.0.22621.0")] -[assembly: System.Runtime.Versioning.SupportedOSPlatformAttribute("Windows7.0")] // Generated by the MSBuild WriteCodeFragment class. diff --git a/src/EzrErrors.cs b/src/EzrErrors.cs index 154d094..2ce8359 100644 --- a/src/EzrErrors.cs +++ b/src/EzrErrors.cs @@ -71,7 +71,7 @@ internal string StringWithUnderline() while (char.IsWhiteSpace(text[start]) && start < text.Length - 1) start++; - + end = text.IndexOf('\n', start + 1); if (end == -1) end = text.Length; @@ -90,14 +90,6 @@ internal string StringWithUnderline() /// internal class UnexpectedCharacterError : Error { - /// - /// Creates a new object. - /// - /// The character that caused the . - /// The starting of the . - /// The ending of the . - public UnexpectedCharacterError(string character, Position startPosition, Position endPosition) : base("Unexpected character", character, startPosition, endPosition) { } - /// /// Creates a new object. /// diff --git a/src/EzrLexer.cs b/src/EzrLexer.cs index 5227716..b4326d8 100644 --- a/src/EzrLexer.cs +++ b/src/EzrLexer.cs @@ -77,30 +77,20 @@ private void Advance() { switch (_currentChar) { + case '\r': case '\t': case ' ': Advance(); break; - case '\r': - Position startPosition = _position.Copy(); - Advance(); - - if (_currentChar == '\n') - Advance(); - else - return new UnexpectedCharacterError("\\r", startPosition, _position); - - tokens.Add(new Token(TokenType.NewLine, TokenTypeGroup.Special, string.Empty, startPosition, _position.Copy())); - break; case ';': case '\n': - tokens.Add(new Token(TokenType.NewLine, TokenTypeGroup.Special, string.Empty, _position.Copy())); - Advance(); + tokens.Add(CompileNewLines()); break; case '@': - Advance(); - while (!_reachedEndFlag && _currentChar != '\n') + do + { Advance(); + } while (!_reachedEndFlag && _currentChar != '\n'); break; case '"': tokens.Add(CompileStringLike(_currentChar, TokenType.String, out error)); @@ -291,6 +281,29 @@ private void Advance() return null; } + /// + /// Goes through newline characters and creates a single object with . + /// + /// The object. + private Token CompileNewLines() + { + Position startPosition = _position.Copy(); + while ((char.IsWhiteSpace(_currentChar) || _currentChar == '\r' || _currentChar == ';') && !_reachedEndFlag) + { + Advance(); + + if (_currentChar == '@') + { + do + { + Advance(); + } while (!_reachedEndFlag && _currentChar != '\n'); + } + } + + return new Token(TokenType.NewLine, TokenTypeGroup.Special, string.Empty, startPosition, _position.Copy()); + } + /// /// Creates a stringlike type (, , ) object. /// diff --git a/src/EzrParser.cs b/src/EzrParser.cs index 9350395..78203a0 100644 --- a/src/EzrParser.cs +++ b/src/EzrParser.cs @@ -49,13 +49,15 @@ public class Parser public Parser(List tokens) { _tokens = tokens; - _currentToken = Token.Dummy; - _index = -1; _usingQuickSyntax = false; _wasUsingQuickSyntax = false; _result = new ParseResult(); - Advance(); + _index = 0; + if (tokens.Count > _index) + _currentToken = _tokens[_index]; + else + _currentToken = Token.Dummy; } /// @@ -64,8 +66,9 @@ public Parser(List tokens) private void Advance() { _index++; + _result.AdvanceCount++; - if (_index >= 0 && _index < _tokens.Count) + if (_tokens.Count > _index) _currentToken = _tokens[_index]; } @@ -76,9 +79,8 @@ private void Advance() private void Reverse(int reverseCount = 1) { _index -= reverseCount; - - if (_index >= 0 && _index < _tokens.Count) - _currentToken = _tokens[_index]; + _result.AdvanceCount -= reverseCount; + _currentToken = _tokens[_index]; } /// @@ -111,21 +113,6 @@ private void UnregisterQuickSyntaxUse() _usingQuickSyntax = _wasUsingQuickSyntax; } - /// - /// Advances through objects until a object of any other has been reached. - /// - private void SkipNewLines() - { - if (_currentToken.Type != TokenType.NewLine) - return; - - while (_currentToken.Type == TokenType.NewLine) - { - _result.RegisterAdvance(); - Advance(); - } - } - /// /// Parses the objects in . /// @@ -153,15 +140,16 @@ private void BinaryOperation(Action left, Action right, params TokenType[] opera return; int toReverseTo = _result.AdvanceCount; + if (_currentToken.Type == TokenType.NewLine) + Advance(); - SkipNewLines(); while (Array.IndexOf(operators, _currentToken.Type) != -1) { TokenType @operator = _currentToken.Type; - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); right(); Node rightNode = _result.Node; @@ -170,13 +158,13 @@ private void BinaryOperation(Action left, Action right, params TokenType[] opera leftNode = new BinaryOperationNode(leftNode, rightNode, @operator, startPosition, _currentToken.EndPosition); toReverseTo = _result.AdvanceCount; - SkipNewLines(); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); } - int reverseCount = _result.AdvanceCount - toReverseTo; - Reverse(reverseCount); - _result.Reverse(reverseCount); + Reverse(_result.AdvanceCount - toReverseTo); _result.Success(leftNode); } @@ -188,7 +176,8 @@ private void ParseStatements() List statements = new List(); Position startPosition = _currentToken.StartPosition; - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); ParseStatement(); Node statement = _result.Node; @@ -201,9 +190,12 @@ private void ParseStatements() // NOTE: Qeyword 'l' for 'else if' is deprecated, use Qeyword 'e' instead in format: // 'e [check]: [statement(s)]' - int skipStart = _result.AdvanceCount; - SkipNewLines(); - if (_result.AdvanceCount - skipStart == 0 || _currentToken.Type == TokenType.EndOfFile + if (_currentToken.Type == TokenType.NewLine) + Advance(); + else + break; + + if (_currentToken.Type == TokenType.EndOfFile || _currentToken.Type == TokenType.KeywordEnd || _currentToken.Type == TokenType.KeywordElse || _currentToken.Type == TokenType.KeywordError @@ -234,7 +226,6 @@ private void ParseStatement() if (_currentToken.Type == TokenType.KeywordReturn) { Position possibleEndPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.NewLine @@ -263,7 +254,6 @@ private void ParseStatement() { Position endPosition = _currentToken.EndPosition; TokenType currentTokenType = _currentToken.Type; - _result.RegisterAdvance(); Advance(); _result.Success(new NoValueNode(currentTokenType, startPosition, endPosition)); @@ -293,14 +283,12 @@ private void ParseExpression(bool itemKeywordRequired = false) if (_currentToken.Type == TokenType.KeywordGlobal) { globalAssignment = true; - _result.RegisterAdvance(); Advance(); } if (_currentToken.Type == TokenType.KeywordItem) { usedItemKeyword = true; - _result.RegisterAdvance(); Advance(); } else if (itemKeywordRequired) @@ -317,13 +305,11 @@ private void ParseExpression(bool itemKeywordRequired = false) if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) { Token possibleVariable = _currentToken; - _result.RegisterAdvance(); Advance(); if (_currentToken.TypeGroup != TokenTypeGroup.AssignmentSymbol) { Reverse(); - _result.Reverse(); ParseJunction(); Node variable = _result.Node; @@ -333,7 +319,6 @@ private void ParseExpression(bool itemKeywordRequired = false) if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) { TokenType assignmentOperator = _currentToken.Type; - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -350,16 +335,11 @@ private void ParseExpression(bool itemKeywordRequired = false) return; } else - { - int reverseCount = _result.AdvanceCount - startingAdvanceCount; - Reverse(reverseCount); - _result.Reverse(reverseCount); - } + Reverse(_result.AdvanceCount - startingAdvanceCount); } else { TokenType assignmentOperator = _currentToken.Type; - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -377,11 +357,7 @@ private void ParseExpression(bool itemKeywordRequired = false) return; } else - { - int reverseCount = _result.AdvanceCount - startingAdvanceCount; - Reverse(reverseCount); - _result.Reverse(reverseCount); - } + Reverse(_result.AdvanceCount - startingAdvanceCount); ParseQuickExpression(); Node node = _result.Node; @@ -401,7 +377,6 @@ private void ParseQuickExpression() if (_currentToken.Type == TokenType.ExclamationMark) { - _result.RegisterAdvance(); Advance(); bool globalAssignment = false; @@ -409,27 +384,23 @@ private void ParseQuickExpression() if (_currentToken.Type == TokenType.QeywordG) { globalAssignment = true; - _result.RegisterAdvance(); Advance(); } if (_currentToken.Type == TokenType.QeywordD) { usedItemKeyword = true; - _result.RegisterAdvance(); Advance(); } if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) { Token possibleVariable = _currentToken; - _result.RegisterAdvance(); Advance(); if (_currentToken.TypeGroup != TokenTypeGroup.AssignmentSymbol) { Reverse(); - _result.Reverse(); ParseJunction(); Node variable = _result.Node; @@ -439,7 +410,6 @@ private void ParseQuickExpression() if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) { TokenType assignmentOperator = _currentToken.Type; - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -456,16 +426,11 @@ private void ParseQuickExpression() return; } else - { - int reverseCount = _result.AdvanceCount - startingAdvanceCount; - Reverse(reverseCount); - _result.Reverse(reverseCount); - } + Reverse(_result.AdvanceCount - startingAdvanceCount); } else { TokenType assignmentOperator = _currentToken.Type; - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -483,11 +448,7 @@ private void ParseQuickExpression() return; } else - { - int reverseCount = _result.AdvanceCount - startingAdvanceCount; - Reverse(reverseCount); - _result.Reverse(reverseCount); - } + Reverse(_result.AdvanceCount - startingAdvanceCount); } ParseJunction(); @@ -516,13 +477,11 @@ private void ParseInversion() if (_currentToken.Type == TokenType.ExclamationMark) { - _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.QeywordV) { TokenType @operator = _currentToken.Type; - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -534,16 +493,11 @@ private void ParseInversion() return; } else - { - int reverseCount = _result.AdvanceCount - startingAdvanceCount; - Reverse(reverseCount); - _result.Reverse(reverseCount); - } + Reverse(_result.AdvanceCount - startingAdvanceCount); } else if (_currentToken.Type == TokenType.KeywordInvert) { TokenType @operator = _currentToken.Type; - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -574,10 +528,11 @@ private void ParseComparison() Node left = _result.Node; if (_result.Error != null) return; - + int toReverseTo = _result.AdvanceCount; + if (_currentToken.Type == TokenType.NewLine) + Advance(); - SkipNewLines(); while (_currentToken.Type == TokenType.EqualSign || _currentToken.Type == TokenType.ExclamationMark || _currentToken.Type == TokenType.LessThanSign @@ -588,10 +543,11 @@ private void ParseComparison() || _currentToken.Type == TokenType.KeywordIn) { TokenType @operator = _currentToken.Type; - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + if (@operator == TokenType.KeywordNot) { if (_currentToken.Type != TokenType.KeywordIn) @@ -599,7 +555,6 @@ private void ParseComparison() _result.Failure(10, new InvalidGrammarError("Expected the 'in' keyword! The 'in' keyword is the second part of a check-not-in operation.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } - _result.RegisterAdvance(); Advance(); } @@ -610,13 +565,12 @@ private void ParseComparison() left = new BinaryOperationNode(left, right, @operator, startPosition, _currentToken.EndPosition); toReverseTo = _result.AdvanceCount; - SkipNewLines(); - } + if (_currentToken.Type == TokenType.NewLine) + Advance(); + } - int reverseCount = _result.AdvanceCount - toReverseTo; - Reverse(reverseCount); - _result.Reverse(reverseCount); + Reverse(_result.AdvanceCount - toReverseTo); _result.Success(left); } @@ -678,7 +632,6 @@ private void ParseFactor() TokenType @operator = _currentToken.Type; if (@operator == TokenType.Plus || @operator == TokenType.HyphenMinus || @operator == TokenType.Tilde) { - _result.RegisterAdvance(); Advance(); ParseFactor(); @@ -723,18 +676,18 @@ private void ParseCall() if(_currentToken.Type == TokenType.LeftParenthesis) { - _result.RegisterAdvance(); Advance(); Position possibleErrorStartPosition = _currentToken.StartPosition; - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + Position endPosition; List arguments = new List(); if (_currentToken.Type == TokenType.RightParenthesis) { endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else @@ -747,14 +700,17 @@ private void ParseCall() return; } - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + while (_currentToken.Type == TokenType.Comma) { possibleErrorStartPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + ParseExpression(); arguments.Add(_result.Node); if (_result.Error != null) @@ -762,7 +718,9 @@ private void ParseCall() _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); return; } - SkipNewLines(); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); } if (_currentToken.Type != TokenType.RightParenthesis) @@ -771,7 +729,6 @@ private void ParseCall() return; } endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } @@ -791,7 +748,6 @@ private void ParseAtom() Token startToken = _currentToken; if(startToken.TypeGroup == TokenTypeGroup.Value) { - _result.RegisterAdvance(); Advance(); _result.Success(new ValueNode(startToken, startToken.StartPosition, startToken.EndPosition)); @@ -799,7 +755,6 @@ private void ParseAtom() } else if (startToken.Type == TokenType.Identifier || startToken.TypeGroup == TokenTypeGroup.Qeyword) { - _result.RegisterAdvance(); Advance(); _result.Success(new VariableAccessNode(startToken, false, startToken.StartPosition, startToken.EndPosition)); @@ -810,14 +765,12 @@ private void ParseAtom() switch (startToken.Type) { case TokenType.KeywordGlobal: - _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) { Token variable = _currentToken; Position endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); _result.Success(new VariableAccessNode(variable, true, startToken.StartPosition, endPosition)); @@ -908,19 +861,19 @@ private void ParseAtom() private void ParseArrayOrParentheticalExpression() { Position startPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); Position possibleErrorStartPosition = _currentToken.StartPosition; List elements = new List(); bool isArray = false; - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + Position endPosition; if (_currentToken.Type == TokenType.RightParenthesis) { endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else @@ -933,15 +886,18 @@ private void ParseArrayOrParentheticalExpression() return; } - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + while (_currentToken.Type == TokenType.Comma) { isArray = true; possibleErrorStartPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + if (_currentToken.Type == TokenType.RightParenthesis && elements.Count == 1) break; @@ -960,7 +916,8 @@ private void ParseArrayOrParentheticalExpression() } elements.Add(_result.Node); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); } if (_currentToken.Type != TokenType.RightParenthesis) @@ -973,7 +930,6 @@ private void ParseArrayOrParentheticalExpression() } endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } @@ -989,18 +945,18 @@ private void ParseArrayOrParentheticalExpression() private void ParseList() { Position startPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); Position possibleErrorStartPosition = _currentToken.StartPosition; - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + Position endPosition; List elements = new List(); if (_currentToken.Type == TokenType.RightSquareBracket) { endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else @@ -1013,14 +969,16 @@ private void ParseList() return; } - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + while (_currentToken.Type == TokenType.Comma) { possibleErrorStartPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); ParseExpression(); elements.Add(_result.Node); @@ -1029,7 +987,9 @@ private void ParseList() _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); return; } - SkipNewLines(); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); } if (_currentToken.Type != TokenType.RightSquareBracket) @@ -1038,7 +998,6 @@ private void ParseList() return; } endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } @@ -1051,18 +1010,18 @@ private void ParseList() private void ParseDictionary() { Position startPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); Position possibleErrorStartPosition = _currentToken.StartPosition; List pairs = new List(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + Position endPosition; if (_currentToken.Type == TokenType.RightCurlyBracket) { endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else @@ -1075,17 +1034,18 @@ private void ParseDictionary() return; } - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); if (_currentToken.Type != TokenType.Colon) { _result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); ParseExpression(); Node right = _result.Node; @@ -1093,15 +1053,16 @@ private void ParseDictionary() return; pairs.Add(new Node[2] { left, right }); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); while (_currentToken.Type == TokenType.Comma) { possibleErrorStartPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); ParseExpression(true); left = _result.Node; @@ -1111,17 +1072,19 @@ private void ParseDictionary() return; } - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + if (_currentToken.Type != TokenType.Colon) { _result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); ParseExpression(); right = _result.Node; @@ -1129,7 +1092,8 @@ private void ParseDictionary() return; pairs.Add(new Node[2] { left, right }); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); } if (_currentToken.Type != TokenType.RightCurlyBracket) @@ -1139,7 +1103,6 @@ private void ParseDictionary() } endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } @@ -1152,7 +1115,6 @@ private void ParseDictionary() private void ParseIfExpression() { Position startPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); List cases = new List(); @@ -1169,13 +1131,11 @@ private void ParseIfExpression() return; } - _result.RegisterAdvance(); Advance(); Node body; if (_currentToken.Type == TokenType.NewLine) { - _result.RegisterAdvance(); Advance(); ParseStatements(); @@ -1188,14 +1148,12 @@ private void ParseIfExpression() if (_currentToken.Type == TokenType.KeywordEnd) { endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else if (_currentToken.Type == TokenType.KeywordElse) { while (_currentToken.Type == TokenType.KeywordElse) { - _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.KeywordIf) @@ -1206,7 +1164,6 @@ private void ParseIfExpression() return; } - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -1220,7 +1177,6 @@ private void ParseIfExpression() return; } - _result.RegisterAdvance(); Advance(); ParseStatements(); @@ -1243,7 +1199,6 @@ private void ParseIfExpression() return; } - _result.RegisterAdvance(); Advance(); ParseStatements(); @@ -1263,7 +1218,6 @@ private void ParseIfExpression() } endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else @@ -1284,7 +1238,6 @@ private void ParseIfExpression() cases.Add(new Node[2] { condition, body }); while (_currentToken.Type == TokenType.KeywordElse) { - _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.KeywordIf) @@ -1295,7 +1248,6 @@ private void ParseIfExpression() return; } - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -1309,7 +1261,6 @@ private void ParseIfExpression() return; } - _result.RegisterAdvance(); Advance(); ParseStatement(); @@ -1332,7 +1283,6 @@ private void ParseIfExpression() return; } - _result.RegisterAdvance(); Advance(); ParseStatement(); @@ -1351,7 +1301,6 @@ private void ParseIfExpression() private void ParseCountExpression() { Position startPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); Node to = InvalidNode.StaticInvalidNode; @@ -1361,7 +1310,6 @@ private void ParseCountExpression() if (_currentToken.Type == TokenType.KeywordFrom) { - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -1379,7 +1327,6 @@ private void ParseCountExpression() return; } - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -1389,7 +1336,6 @@ private void ParseCountExpression() if (_currentToken.Type == TokenType.KeywordStep) { - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -1400,7 +1346,6 @@ private void ParseCountExpression() if (_currentToken.Type == TokenType.KeywordAs) { - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -1420,14 +1365,12 @@ private void ParseCountExpression() return; } - _result.RegisterAdvance(); Advance(); Node body; Position endPosition; if (_currentToken.Type == TokenType.NewLine) { - _result.RegisterAdvance(); Advance(); ParseStatements(); @@ -1442,7 +1385,6 @@ private void ParseCountExpression() } endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else @@ -1464,7 +1406,6 @@ private void ParseCountExpression() private void ParseWhileExpression() { Position startPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -1477,14 +1418,12 @@ private void ParseWhileExpression() _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } - _result.RegisterAdvance(); Advance(); Node body; Position endPosition; if (_currentToken.Type == TokenType.NewLine) { - _result.RegisterAdvance(); Advance(); ParseStatements(); @@ -1499,7 +1438,6 @@ private void ParseWhileExpression() } endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else @@ -1521,7 +1459,6 @@ private void ParseWhileExpression() private void ParseTryExpression() { Position startPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); Node block; @@ -1534,13 +1471,11 @@ private void ParseTryExpression() return; } - _result.RegisterAdvance(); Advance(); Node body; if (_currentToken.Type == TokenType.NewLine) { - _result.RegisterAdvance(); Advance(); ParseStatements(); @@ -1552,14 +1487,12 @@ private void ParseTryExpression() if (_currentToken.Type == TokenType.KeywordEnd) { endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else if (_currentToken.Type == TokenType.KeywordError) { while (_currentToken.Type == TokenType.KeywordError) { - _result.RegisterAdvance(); Advance(); Node? error = null; @@ -1578,7 +1511,6 @@ private void ParseTryExpression() Node? @as = null; if (isAsKeyword) { - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -1593,7 +1525,6 @@ private void ParseTryExpression() } } - _result.RegisterAdvance(); Advance(); ParseStatements(); @@ -1645,7 +1576,6 @@ private void ParseTryExpression() } endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else @@ -1665,7 +1595,6 @@ private void ParseTryExpression() while (_currentToken.Type == TokenType.KeywordError) { - _result.RegisterAdvance(); Advance(); Node? error = null; @@ -1684,7 +1613,6 @@ private void ParseTryExpression() Node? @as = null; if (isAsKeyword) { - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -1699,7 +1627,6 @@ private void ParseTryExpression() } } - _result.RegisterAdvance(); Advance(); ParseStatement(); @@ -1750,7 +1677,6 @@ private void ParseTryExpression() private void ParseFunctionDefinitionExpression() { Position startPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); Node? name = null; @@ -1766,30 +1692,33 @@ private void ParseFunctionDefinitionExpression() { if (isWithKeyword) { - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); ParseExpression(); parameters.Add(_result.Node); if (_result.Error != null) return; - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + while (_currentToken.Type == TokenType.Comma) { - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); ParseExpression(); parameters.Add(_result.Node); if (_result.Error != null) return; - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); } if (_currentToken.Type != TokenType.KeywordDo) @@ -1799,12 +1728,10 @@ private void ParseFunctionDefinitionExpression() } } - _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.NewLine) { - _result.RegisterAdvance(); Advance(); ParseStatements(); @@ -1819,7 +1746,6 @@ private void ParseFunctionDefinitionExpression() } endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else @@ -1866,7 +1792,6 @@ private void ParseObjectDefinitionExpression() // The parents of the object are now defined after the 'from' keyword like an array. The 'from' keyword must come before the 'do' keyword and after the 'with' keyword. Position startPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); Node? name = null; @@ -1884,30 +1809,33 @@ private void ParseObjectDefinitionExpression() { if (isWithKeyword) { - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); ParseExpression(); parameters.Add(_result.Node); if (_result.Error != null) return; - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + while (_currentToken.Type == TokenType.Comma) { - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); ParseExpression(); parameters.Add(_result.Node); if (_result.Error != null) return; - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); } isFromKeyword = _currentToken.Type == TokenType.KeywordFrom; @@ -1920,30 +1848,33 @@ private void ParseObjectDefinitionExpression() if (isFromKeyword) { - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); ParseExpression(); parents.Add(_result.Node); if (_result.Error != null) return; - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + while (_currentToken.Type == TokenType.Comma) { - _result.RegisterAdvance(); Advance(); - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); ParseExpression(); parents.Add(_result.Node); if (_result.Error != null) return; - SkipNewLines(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); } if (_currentToken.Type != TokenType.KeywordDo) @@ -1953,12 +1884,10 @@ private void ParseObjectDefinitionExpression() } } - _result.RegisterAdvance(); Advance(); if (_currentToken.Type == TokenType.NewLine) { - _result.RegisterAdvance(); Advance(); ParseStatements(); @@ -1973,7 +1902,6 @@ private void ParseObjectDefinitionExpression() } endPosition = _currentToken.EndPosition; - _result.RegisterAdvance(); Advance(); } else @@ -2016,7 +1944,6 @@ private void ParseObjectDefinitionExpression() private void ParseIncludeExpression() { Position startPosition = _currentToken.StartPosition; - _result.RegisterAdvance(); Advance(); Node? subStructure = null; @@ -2034,13 +1961,11 @@ private void ParseIncludeExpression() else { isDumped = true; - _result.RegisterAdvance(); Advance(); } if (_currentToken.Type == TokenType.KeywordFrom) { - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -2061,7 +1986,6 @@ private void ParseIncludeExpression() if (_currentToken.Type == TokenType.KeywordAs) { - _result.RegisterAdvance(); Advance(); ParseExpression(); @@ -2110,23 +2034,6 @@ public ParseResult() ErrorPriority = 0; } - /// - /// Registers an advancement by the . - /// - public void RegisterAdvance() - { - AdvanceCount++; - } - - /// - /// Reverses number of advancements. - /// - /// The number of advancements to reverse by. - public void Reverse(int reverseCount = 1) - { - AdvanceCount -= reverseCount; - } - /// /// Sets as the result of successful parsing. /// diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 7f2b26d..1a8be45 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -2,10 +2,9 @@ Exe win-x64 - net7.0-windows10.0.22621.0 + net7.0 7.0 True - False EzrSquared EzrSquared.EzrShell.Shell @@ -19,7 +18,8 @@ D:\Code\csharp\ezrSquared\obj\ezrSquared\ - true + True + True From 1898f0bf67df52b71309bb79430e44ccf74419de Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 16 Sep 2023 00:29:12 +0530 Subject: [PATCH 013/113] More performance! - EzrCommon: - Added new Advance() function without currentChar argument as it was being used more often. - EzrParser - Updated ParseExpression() and ParseQuickExpression() functions! - New CurrentTokenInOperators() function in BinaryOperation() for checking if _currentToken is a desired operator. - In ParseInversion(), the checking order of the QuickSyntax and normal syntax versions of the expression has been switched. - In ParseAtom(), the creation of ValueNodes and local VariableAssignmentNodes have been moved to the 'default' case of the switch-case block for better readability. - All instances of null checking in all scripts have been changed from '== null' to 'is null' and '!= null' to 'is not null'. NOTE: The shell has not been updated as I am still experimenting performance updates for ezrSquared using stopwatches in EzrShell. --- src/EzrCommon.cs | 13 +- src/EzrErrors.cs | 4 +- src/EzrLexer.cs | 16 +- src/EzrNodes.cs | 72 ++----- src/EzrParser.cs | 532 ++++++++++++++++++++++------------------------- 5 files changed, 283 insertions(+), 354 deletions(-) diff --git a/src/EzrCommon.cs b/src/EzrCommon.cs index 8fffebd..672bca5 100644 --- a/src/EzrCommon.cs +++ b/src/EzrCommon.cs @@ -44,7 +44,7 @@ public Position(int index, int line, string file, string script) /// Advances the and increments by 1. If is a new-line character, is also incremented by 1. /// /// The character associated with the before advancing. - public void Advance(char currentChar = '\0') + public void Advance(char currentChar) { Index++; @@ -52,6 +52,15 @@ public void Advance(char currentChar = '\0') Line++; } + + /// + /// Advances the and increments by 1. + /// + public void Advance() + { + Index++; + } + /// /// Creates a copy of the object. /// @@ -231,7 +240,7 @@ public Token(TokenType type, TokenTypeGroup typeGroup, string value, Position st Value = value; StartPosition = startPosition; - if (endPosition != null) + if (endPosition is not null) EndPosition = endPosition; else { diff --git a/src/EzrErrors.cs b/src/EzrErrors.cs index 2ce8359..803a794 100644 --- a/src/EzrErrors.cs +++ b/src/EzrErrors.cs @@ -71,11 +71,11 @@ internal string StringWithUnderline() while (char.IsWhiteSpace(text[start]) && start < text.Length - 1) start++; - + end = text.IndexOf('\n', start + 1); if (end == -1) end = text.Length; - + return new StringBuilder(" ") .Append(text[start..end]) .Append('\n') diff --git a/src/EzrLexer.cs b/src/EzrLexer.cs index b4326d8..5f40566 100644 --- a/src/EzrLexer.cs +++ b/src/EzrLexer.cs @@ -1,6 +1,6 @@ using System; -using System.Text; using System.Collections.Generic; +using System.Text; namespace EzrSquared.EzrLexer { @@ -58,7 +58,7 @@ private void Advance() { _position.Advance(_currentChar); - if (_position.Index < _script.Length) + if (_script.Length > _position.Index) _currentChar = _script[_position.Index]; else _reachedEndFlag = true; @@ -94,17 +94,17 @@ private void Advance() break; case '"': tokens.Add(CompileStringLike(_currentChar, TokenType.String, out error)); - if (error != null) + if (error is not null) return error; break; case '`': tokens.Add(CompileStringLike(_currentChar, TokenType.Character, out error)); - if (error != null) + if (error is not null) return error; break; case '\'': tokens.Add(CompileStringLike(_currentChar, TokenType.CharacterList, out error)); - if (error != null) + if (error is not null) return error; break; case ':': @@ -244,7 +244,7 @@ private void Advance() Position numberTokenStartPosition = _position.Copy(); bool hasPeriod = false; - while(!_reachedEndFlag && (char.IsDigit(_currentChar) || _currentChar == '.')) + while (!_reachedEndFlag && (char.IsDigit(_currentChar) || _currentChar == '.')) { if (_currentChar == '.') { @@ -314,7 +314,7 @@ private Token CompileNewLines() private Token CompileStringLike(char enclosingChar, TokenType type, out Error? error) { error = null; - + StringBuilder toReturn = new StringBuilder(); Position startPosition = _position.Copy(); bool escapeChar = false; @@ -436,7 +436,7 @@ private Token CompileStringLike(char enclosingChar, TokenType type, out Error? e if (_reachedEndFlag || _currentChar != enclosingChar) error = new InvalidGrammarError($"Expected '{enclosingChar}'", _position.Copy(), _position); - + Advance(); return new Token(type, TokenTypeGroup.Value, toReturn.ToString(), startPosition, _position.Copy()); } diff --git a/src/EzrNodes.cs b/src/EzrNodes.cs index e595a01..303589c 100644 --- a/src/EzrNodes.cs +++ b/src/EzrNodes.cs @@ -264,12 +264,12 @@ public override string ToString() } /// - /// The structure for assigning a value to a variable in the context. + /// The structure for assigning a value to a variable in the context. /// - public class NodeVariableAssignmentNode : Node + public class VariableAssignmentNode : Node { /// - /// The variable to be assigned to. + /// The variable to be assigned to. /// public Node Variable; @@ -279,7 +279,7 @@ public class NodeVariableAssignmentNode : Node public TokenType AssignmentOperator; /// - /// The value to be assigned to . + /// The value to be assigned to . /// public Node Value; @@ -289,15 +289,15 @@ public class NodeVariableAssignmentNode : Node public bool GlobalAssignment; /// - /// Creates a new object. + /// Creates a new object. /// - /// The variable to be assigned to. + /// The variable to be assigned to. /// The operation , if not , between the existing value of and . The result of the operation will be assigned to . - /// The value to be assigned to . + /// The value to be assigned to . /// The check for if the variable assignment is to the global or local context. Irrelevant if the variable to be assigned to is in a local context. - /// The starting of the . - /// The ending of the . - public NodeVariableAssignmentNode(Node variable, TokenType assignmentOperator, Node value, bool globalAssignment, Position startPosition, Position endPosition) : base(startPosition, endPosition) + /// The starting of the . + /// The ending of the . + public VariableAssignmentNode(Node variable, TokenType assignmentOperator, Node value, bool globalAssignment, Position startPosition, Position endPosition) : base(startPosition, endPosition) { Variable = variable; AssignmentOperator = assignmentOperator; @@ -307,55 +307,7 @@ public NodeVariableAssignmentNode(Node variable, TokenType assignmentOperator, N public override string ToString() { - return $"NodeVariableAssignmentNode({Variable}, {AssignmentOperator}, {Value}, {GlobalAssignment})"; - } - } - - /// - /// The structure for assigning a value to a variable in the context. - /// - public class TokenVariableAssignmentNode : Node - { - /// - /// The variable to be assigned to. - /// - public Token Variable; - - /// - /// The operation , if not , between the existing value of and . The result of the operation will be assigned to . - /// - public TokenType AssignmentOperator; - - /// - /// The value to be assigned to . - /// - public Node Value; - - /// - /// The check for if the variable assignment is to the global or local context. Irrelevant if the variable to be assigned to is in a local context. - /// - public bool GlobalAssignment; - - /// - /// Creates a new object. - /// - /// The variable to be assigned to. - /// The operation , if not , between the existing value of and . The result of the operation will be assigned to . - /// The value to be assigned to . - /// The check for if the variable assignment is to the global or local context. Irrelevant if the variable to be assigned to is in a local context. - /// The starting of the . - /// The ending of the . - public TokenVariableAssignmentNode(Token variable, TokenType assignmentOperator, Node value, bool globalAssignment, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Variable = variable; - AssignmentOperator = assignmentOperator; - Value = value; - GlobalAssignment = globalAssignment; - } - - public override string ToString() - { - return $"TokenVariableAssignmentNode({Variable}, {AssignmentOperator}, {Value}, {GlobalAssignment})"; + return $"VariableAssignmentNode({Variable}, {AssignmentOperator}, {Value}, {GlobalAssignment})"; } } @@ -565,7 +517,7 @@ public override string ToString() for (int i = 0; i < Cases.Count; i++) cases[i] = $"({Cases[i][0]}, {Cases[i][1]}, {Cases[i][2]})"; - return (EmptyCase != null) ? $"TryNode({Block}, [{string.Join(", ", cases)}], ({EmptyCase[0]}, {EmptyCase[1]}))" : $"TryNode({Block}, [{string.Join(", ", cases)}], )"; + return (EmptyCase is not null) ? $"TryNode({Block}, [{string.Join(", ", cases)}], ({EmptyCase[0]}, {EmptyCase[1]}))" : $"TryNode({Block}, [{string.Join(", ", cases)}], )"; } } diff --git a/src/EzrParser.cs b/src/EzrParser.cs index 78203a0..9c236ad 100644 --- a/src/EzrParser.cs +++ b/src/EzrParser.cs @@ -1,11 +1,11 @@ -using System.Collections.Generic; -using System; +using System; +using System.Collections.Generic; namespace EzrSquared.EzrParser { using EzrCommon; - using EzrNodes; using EzrErrors; + using EzrNodes; /// /// The ezrSquared Parser. The job of the Parser is to convert the input objects from the into objects to be given as the input to the Interpreter (TODO). @@ -119,7 +119,7 @@ private void UnregisterQuickSyntaxUse() public ParseResult Parse() { ParseStatements(); - if (_result.Error == null && _currentToken.Type != TokenType.EndOfFile) + if (_result.Error is null && _currentToken.Type != TokenType.EndOfFile) _result.Failure(10, new InvalidGrammarError("Did not expect this!", _currentToken.StartPosition, _currentToken.EndPosition)); return _result; } @@ -132,28 +132,40 @@ public ParseResult Parse() /// The operator object(s). private void BinaryOperation(Action left, Action right, params TokenType[] operators) { + bool CurrentTokenInOperators() + { + int length = operators.Length; + for (int i = 0; i < length; i++) + { + if (_currentToken.Type == operators[i]) + return true; + } + + return false; + } + Position startPosition = _currentToken.StartPosition; left(); Node leftNode = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; int toReverseTo = _result.AdvanceCount; if (_currentToken.Type == TokenType.NewLine) Advance(); - while (Array.IndexOf(operators, _currentToken.Type) != -1) + while (CurrentTokenInOperators()) { TokenType @operator = _currentToken.Type; Advance(); if (_currentToken.Type == TokenType.NewLine) Advance(); - + right(); Node rightNode = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; leftNode = new BinaryOperationNode(leftNode, rightNode, @operator, startPosition, _currentToken.EndPosition); @@ -181,7 +193,7 @@ private void ParseStatements() ParseStatement(); Node statement = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; statements.Add(statement); @@ -207,7 +219,7 @@ private void ParseStatements() ParseStatement(); statement = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; statements.Add(statement); } @@ -244,7 +256,7 @@ private void ParseStatement() ParseExpression(); expression = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; _result.Success(new ReturnNode(expression, startPosition, _currentToken.EndPosition)); @@ -262,7 +274,7 @@ private void ParseStatement() ParseExpression(); expression = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) _result.Failure(4, new InvalidGrammarError("Expected a statement!", _currentToken.StartPosition, _currentToken.EndPosition)); else _result.Success(expression); @@ -285,7 +297,7 @@ private void ParseExpression(bool itemKeywordRequired = false) globalAssignment = true; Advance(); } - + if (_currentToken.Type == TokenType.KeywordItem) { usedItemKeyword = true; @@ -295,7 +307,7 @@ private void ParseExpression(bool itemKeywordRequired = false) { ParseQuickExpression(); Node node_ = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) _result.Failure(4, new InvalidGrammarError("Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); else _result.Success(node_); @@ -304,52 +316,31 @@ private void ParseExpression(bool itemKeywordRequired = false) if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) { - Token possibleVariable = _currentToken; - Advance(); - - if (_currentToken.TypeGroup != TokenTypeGroup.AssignmentSymbol) - { - Reverse(); - - ParseJunction(); - Node variable = _result.Node; - if (_result.Error != null) - return; - - if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) - { - TokenType assignmentOperator = _currentToken.Type; - Advance(); - - ParseExpression(); - Node value = _result.Node; - if (_result.Error != null) - return; + ParseJunction(); + Node variable = _result.Node; + if (_result.Error is not null) + return; - _result.Success(new NodeVariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); - return; - } - else if (usedItemKeyword) - { - _result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - Reverse(_result.AdvanceCount - startingAdvanceCount); - } - else + if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) { TokenType assignmentOperator = _currentToken.Type; Advance(); - + ParseExpression(); Node value = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; - - _result.Success(new TokenVariableAssignmentNode(possibleVariable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + + _result.Success(new VariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + return; + } + else if (usedItemKeyword) + { + _result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } + else + Reverse(_result.AdvanceCount - startingAdvanceCount); } else if (usedItemKeyword) { @@ -361,7 +352,7 @@ private void ParseExpression(bool itemKeywordRequired = false) ParseQuickExpression(); Node node = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) _result.Failure(4, new InvalidGrammarError("Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); else _result.Success(node); @@ -395,52 +386,31 @@ private void ParseQuickExpression() if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) { - Token possibleVariable = _currentToken; - Advance(); - - if (_currentToken.TypeGroup != TokenTypeGroup.AssignmentSymbol) - { - Reverse(); - - ParseJunction(); - Node variable = _result.Node; - if (_result.Error != null) - return; - - if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) - { - TokenType assignmentOperator = _currentToken.Type; - Advance(); - - ParseExpression(); - Node value = _result.Node; - if (_result.Error != null) - return; + ParseJunction(); + Node variable = _result.Node; + if (_result.Error is not null) + return; - _result.Success(new NodeVariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); - return; - } - else if (usedItemKeyword) - { - _result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - Reverse(_result.AdvanceCount - startingAdvanceCount); - } - else + if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) { TokenType assignmentOperator = _currentToken.Type; Advance(); ParseExpression(); Node value = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; - _result.Success(new TokenVariableAssignmentNode(possibleVariable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + _result.Success(new VariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); + return; + } + else if (usedItemKeyword) + { + _result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } + else + Reverse(_result.AdvanceCount - startingAdvanceCount); } else if (usedItemKeyword) { @@ -453,7 +423,7 @@ private void ParseQuickExpression() ParseJunction(); Node node = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) _result.Failure(4, new InvalidGrammarError("Expected a QuickSyntax expression!", _currentToken.StartPosition, _currentToken.EndPosition)); else _result.Success(node); @@ -474,8 +444,21 @@ private void ParseInversion() { Position startPosition = _currentToken.StartPosition; int startingAdvanceCount = _result.AdvanceCount; + + if (_currentToken.Type == TokenType.KeywordInvert) + { + TokenType @operator = _currentToken.Type; + Advance(); - if (_currentToken.Type == TokenType.ExclamationMark) + ParseExpression(); + Node operand = _result.Node; + if (_result.Error is not null) + return; + + _result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); + return; + } + else if (_currentToken.Type == TokenType.ExclamationMark) { Advance(); @@ -486,7 +469,7 @@ private void ParseInversion() ParseExpression(); Node operand = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; _result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); @@ -495,23 +478,10 @@ private void ParseInversion() else Reverse(_result.AdvanceCount - startingAdvanceCount); } - else if (_currentToken.Type == TokenType.KeywordInvert) - { - TokenType @operator = _currentToken.Type; - Advance(); - - ParseExpression(); - Node operand = _result.Node; - if (_result.Error != null) - return; - - _result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); - return; - } ParseComparison(); Node node = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) _result.Failure(4, new InvalidGrammarError("Expected an inversion expression!", _currentToken.StartPosition, _currentToken.EndPosition)); else _result.Success(node); @@ -526,7 +496,7 @@ private void ParseComparison() ParseBitwiseOr(); Node left = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; int toReverseTo = _result.AdvanceCount; @@ -560,7 +530,7 @@ private void ParseComparison() ParseBitwiseOr(); Node right = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; left = new BinaryOperationNode(left, right, @operator, startPosition, _currentToken.EndPosition); @@ -636,7 +606,7 @@ private void ParseFactor() ParseFactor(); Node operand = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; _result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); @@ -671,10 +641,10 @@ private void ParseCall() ParseAtom(); Node node = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; - if(_currentToken.Type == TokenType.LeftParenthesis) + if (_currentToken.Type == TokenType.LeftParenthesis) { Advance(); @@ -694,7 +664,7 @@ private void ParseCall() { ParseExpression(); arguments.Add(_result.Node); - if (_result.Error != null) + if (_result.Error is not null) { _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); return; @@ -713,7 +683,7 @@ private void ParseCall() ParseExpression(); arguments.Add(_result.Node); - if (_result.Error != null) + if (_result.Error is not null) { _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); return; @@ -735,7 +705,7 @@ private void ParseCall() _result.Success(new CallNode(node, arguments, startPosition, endPosition)); return; } - + _result.Success(node); } @@ -746,112 +716,110 @@ private void ParseAtom() { Token startToken = _currentToken; - if(startToken.TypeGroup == TokenTypeGroup.Value) + switch (startToken.Type) { - Advance(); + case TokenType.KeywordGlobal: + Advance(); - _result.Success(new ValueNode(startToken, startToken.StartPosition, startToken.EndPosition)); - return; - } - else if (startToken.Type == TokenType.Identifier || startToken.TypeGroup == TokenTypeGroup.Qeyword) - { - Advance(); + if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) + { + Token variable = _currentToken; + Position endPosition = _currentToken.EndPosition; + Advance(); - _result.Success(new VariableAccessNode(startToken, false, startToken.StartPosition, startToken.EndPosition)); - return; - } - else - { - switch (startToken.Type) - { - case TokenType.KeywordGlobal: + _result.Success(new VariableAccessNode(variable, true, startToken.StartPosition, endPosition)); + return; + } + _result.Failure(10, new InvalidGrammarError("Expected a variable name or the 'item' keyword! The variable name is used to access a global variable in a global variable access expression and the 'item' keyword is used to assign to a global variable in a global variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + break; + case TokenType.LeftParenthesis: + ParseArrayOrParentheticalExpression(); + Node arrayNode = _result.Node; + if (_result.Error is not null) + return; + _result.Success(arrayNode); + break; + case TokenType.LeftSquareBracket: + ParseList(); + Node encapsulatedListNode = _result.Node; + if (_result.Error is not null) + return; + _result.Success(encapsulatedListNode); + break; + case TokenType.LeftCurlyBracket: + ParseDictionary(); + Node dictionaryNode = _result.Node; + if (_result.Error is not null) + return; + _result.Success(dictionaryNode); + break; + case TokenType.KeywordIf: + ParseIfExpression(); + Node ifNode = _result.Node; + if (_result.Error is not null) + return; + _result.Success(ifNode); + break; + case TokenType.KeywordCount: + ParseCountExpression(); + Node countNode = _result.Node; + if (_result.Error is not null) + return; + _result.Success(countNode); + break; + case TokenType.KeywordWhile: + ParseWhileExpression(); + Node whileNode = _result.Node; + if (_result.Error is not null) + return; + _result.Success(whileNode); + break; + case TokenType.KeywordTry: + ParseTryExpression(); + Node tryNode = _result.Node; + if (_result.Error is not null) + return; + _result.Success(tryNode); + break; + case TokenType.KeywordFunction: + ParseFunctionDefinitionExpression(); + Node functionDefinitionNode = _result.Node; + if (_result.Error is not null) + return; + _result.Success(functionDefinitionNode); + break; + case TokenType.KeywordObject: + ParseObjectDefinitionExpression(); + Node objectDefinitionNode = _result.Node; + if (_result.Error is not null) + return; + _result.Success(objectDefinitionNode); + break; + case TokenType.KeywordInclude: + ParseIncludeExpression(); + Node includeNode = _result.Node; + if (_result.Error is not null) + return; + _result.Success(includeNode); + break; + default: + if (startToken.TypeGroup == TokenTypeGroup.Value) + { Advance(); - if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) - { - Token variable = _currentToken; - Position endPosition = _currentToken.EndPosition; - Advance(); + _result.Success(new ValueNode(startToken, startToken.StartPosition, startToken.EndPosition)); + return; + } + else if (startToken.Type == TokenType.Identifier || startToken.TypeGroup == TokenTypeGroup.Qeyword) + { + Advance(); - _result.Success(new VariableAccessNode(variable, true, startToken.StartPosition, endPosition)); - return; - } - _result.Failure(10, new InvalidGrammarError("Expected a variable name or the 'item' keyword! The variable name is used to access a global variable in a global variable access expression and the 'item' keyword is used to assign to a global variable in a global variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - break; - case TokenType.LeftParenthesis: - ParseArrayOrParentheticalExpression(); - Node arrayNode = _result.Node; - if (_result.Error != null) - return; - _result.Success(arrayNode); - break; - case TokenType.LeftSquareBracket: - ParseList(); - Node encapsulatedListNode = _result.Node; - if (_result.Error != null) - return; - _result.Success(encapsulatedListNode); - break; - case TokenType.LeftCurlyBracket: - ParseDictionary(); - Node dictionaryNode = _result.Node; - if (_result.Error != null) - return; - _result.Success(dictionaryNode); - break; - case TokenType.KeywordIf: - ParseIfExpression(); - Node ifNode = _result.Node; - if (_result.Error != null) - return; - _result.Success(ifNode); - break; - case TokenType.KeywordCount: - ParseCountExpression(); - Node countNode = _result.Node; - if (_result.Error != null) - return; - _result.Success(countNode); - break; - case TokenType.KeywordWhile: - ParseWhileExpression(); - Node whileNode = _result.Node; - if (_result.Error != null) - return; - _result.Success(whileNode); - break; - case TokenType.KeywordTry: - ParseTryExpression(); - Node tryNode = _result.Node; - if (_result.Error != null) - return; - _result.Success(tryNode); - break; - case TokenType.KeywordFunction: - ParseFunctionDefinitionExpression(); - Node functionDefinitionNode = _result.Node; - if (_result.Error != null) - return; - _result.Success(functionDefinitionNode); - break; - case TokenType.KeywordObject: - ParseObjectDefinitionExpression(); - Node objectDefinitionNode = _result.Node; - if (_result.Error != null) - return; - _result.Success(objectDefinitionNode); - break; - case TokenType.KeywordInclude: - ParseIncludeExpression(); - Node includeNode = _result.Node; - if (_result.Error != null) - return; - _result.Success(includeNode); - break; - default: - _result.Failure(4, new InvalidGrammarError("Expected an integer, float, string, character, character list, identifier, 'if' expression, 'count' expression, 'while' expression and so on.", _currentToken.StartPosition, _currentToken.EndPosition)); - break; - } + _result.Success(new VariableAccessNode(startToken, false, startToken.StartPosition, startToken.EndPosition)); + return; + } + + _result.Failure(4, new InvalidGrammarError("Expected an integer, float, string, character, character list, identifier, 'if' expression, 'count' expression, 'while' expression and so on.", _currentToken.StartPosition, _currentToken.EndPosition)); + break; } } @@ -880,7 +848,7 @@ private void ParseArrayOrParentheticalExpression() { ParseExpression(); elements.Add(_result.Node); - if (_result.Error != null) + if (_result.Error is not null) { _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array/parenthetical expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); return; @@ -902,7 +870,7 @@ private void ParseArrayOrParentheticalExpression() break; ParseExpression(); - if (_result.Error != null) + if (_result.Error is not null) { if (elements.Count > 1) { @@ -928,7 +896,7 @@ private void ParseArrayOrParentheticalExpression() _result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! The comma is used to create an array and seperate its elements, while the right-parenthesis declares the end of a parenthetical expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } - + endPosition = _currentToken.EndPosition; Advance(); } @@ -963,7 +931,7 @@ private void ParseList() { ParseExpression(); elements.Add(_result.Node); - if (_result.Error != null) + if (_result.Error is not null) { _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); return; @@ -982,12 +950,12 @@ private void ParseList() ParseExpression(); elements.Add(_result.Node); - if (_result.Error != null) + if (_result.Error is not null) { _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); return; } - + if (_currentToken.Type == TokenType.NewLine) Advance(); } @@ -1028,7 +996,7 @@ private void ParseDictionary() { ParseExpression(true); Node left = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) { _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); return; @@ -1036,7 +1004,7 @@ private void ParseDictionary() if (_currentToken.Type == TokenType.NewLine) Advance(); - + if (_currentToken.Type != TokenType.Colon) { _result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); @@ -1049,7 +1017,7 @@ private void ParseDictionary() ParseExpression(); Node right = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; pairs.Add(new Node[2] { left, right }); @@ -1066,7 +1034,7 @@ private void ParseDictionary() ParseExpression(true); left = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) { _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); return; @@ -1088,7 +1056,7 @@ private void ParseDictionary() ParseExpression(); right = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; pairs.Add(new Node[2] { left, right }); @@ -1122,7 +1090,7 @@ private void ParseIfExpression() ParseExpression(); Node condition = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type != TokenType.KeywordDo) @@ -1140,7 +1108,7 @@ private void ParseIfExpression() ParseStatements(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; Position endPosition; @@ -1158,7 +1126,7 @@ private void ParseIfExpression() if (_currentToken.Type == TokenType.KeywordIf) { - if (elseCase != null) + if (elseCase is not null) { _result.Failure(10, new InvalidGrammarError("The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; @@ -1168,7 +1136,7 @@ private void ParseIfExpression() ParseExpression(); condition = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type != TokenType.KeywordDo) @@ -1181,7 +1149,7 @@ private void ParseIfExpression() ParseStatements(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; cases.Add(new Node[2] { condition, body }); @@ -1193,7 +1161,7 @@ private void ParseIfExpression() } else { - if (elseCase != null) + if (elseCase is not null) { _result.Failure(10, new InvalidGrammarError("There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; @@ -1203,14 +1171,14 @@ private void ParseIfExpression() ParseStatements(); elseCase = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; } } if (_currentToken.Type != TokenType.KeywordEnd) { - if (elseCase == null) + if (elseCase is null) _result.Failure(10, new InvalidGrammarError("Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); else _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); @@ -1232,7 +1200,7 @@ private void ParseIfExpression() ParseStatement(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; cases.Add(new Node[2] { condition, body }); @@ -1242,7 +1210,7 @@ private void ParseIfExpression() if (_currentToken.Type == TokenType.KeywordIf) { - if (elseCase != null) + if (elseCase is not null) { _result.Failure(10, new InvalidGrammarError("The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; @@ -1252,7 +1220,7 @@ private void ParseIfExpression() ParseExpression(); condition = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type != TokenType.KeywordDo) @@ -1265,7 +1233,7 @@ private void ParseIfExpression() ParseStatement(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; cases.Add(new Node[2] { condition, body }); @@ -1277,7 +1245,7 @@ private void ParseIfExpression() } else { - if (elseCase != null) + if (elseCase is not null) { _result.Failure(10, new InvalidGrammarError("There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; @@ -1287,7 +1255,7 @@ private void ParseIfExpression() ParseStatement(); elseCase = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; } } @@ -1314,13 +1282,13 @@ private void ParseCountExpression() ParseExpression(); from = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; } if (_currentToken.Type != TokenType.KeywordTo) { - if (from == null) + if (from is null) _result.Failure(10, new InvalidGrammarError("Expected the 'to' or 'from' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop, and the optional 'from' keyword and the following expression is the amount to count from.", _currentToken.StartPosition, _currentToken.EndPosition)); else _result.Failure(10, new InvalidGrammarError("Expected the 'to' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); @@ -1331,7 +1299,7 @@ private void ParseCountExpression() ParseExpression(); to = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type == TokenType.KeywordStep) @@ -1340,7 +1308,7 @@ private void ParseCountExpression() ParseExpression(); step = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; } @@ -1350,15 +1318,15 @@ private void ParseCountExpression() ParseExpression(); @as = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; } if (_currentToken.Type != TokenType.KeywordDo) { - if (step == null && @as == null) + if (step is null && @as is null) _result.Failure(10, new InvalidGrammarError("Expected the 'do', 'step' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, the optional 'step' keyword and the following expression is the increment, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); - else if (@as == null) + else if (@as is null) _result.Failure(10, new InvalidGrammarError("Expected the 'do' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); else _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); @@ -1375,7 +1343,7 @@ private void ParseCountExpression() ParseStatements(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type != TokenType.KeywordEnd) @@ -1391,7 +1359,7 @@ private void ParseCountExpression() { ParseStatement(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; endPosition = PeekPrevious().EndPosition; @@ -1410,7 +1378,7 @@ private void ParseWhileExpression() ParseExpression(); Node condition = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type != TokenType.KeywordDo) @@ -1428,7 +1396,7 @@ private void ParseWhileExpression() ParseStatements(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type != TokenType.KeywordEnd) @@ -1444,7 +1412,7 @@ private void ParseWhileExpression() { ParseStatement(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; endPosition = PeekPrevious().EndPosition; @@ -1480,7 +1448,7 @@ private void ParseTryExpression() ParseStatements(); block = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; Position endPosition; @@ -1502,7 +1470,7 @@ private void ParseTryExpression() bool isAsKeyword = _currentToken.Type == TokenType.KeywordAs; if (_currentToken.Type == TokenType.KeywordDo || isAsKeyword) { - if (emptyCase != null) + if (emptyCase is not null) { _result.Failure(10, new InvalidGrammarError("There should only be one empty \"error\" expression! You cannot have multiple \"error\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; @@ -1515,7 +1483,7 @@ private void ParseTryExpression() ParseExpression(); @as = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type != TokenType.KeywordDo) @@ -1529,17 +1497,17 @@ private void ParseTryExpression() ParseStatements(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; - if (error != null) + if (error is not null) cases.Add(new Node?[3] { error, @as, body }); else emptyCase = new Node?[2] { @as, body }; } else if (isErrorNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) { - if (emptyCase != null) + if (emptyCase is not null) { Token previous = PeekPrevious(); _result.Failure(10, new InvalidGrammarError("There can't be any \"error\" expressions after an empty \"error\" expression!", previous.StartPosition, previous.EndPosition)); @@ -1548,7 +1516,7 @@ private void ParseTryExpression() ParseExpression(); error = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; isErrorNull = false; @@ -1568,7 +1536,7 @@ private void ParseTryExpression() if (_currentToken.Type != TokenType.KeywordEnd) { - if (emptyCase == null) + if (emptyCase is null) _result.Failure(10, new InvalidGrammarError("Expected the 'error' or 'end' keywords! The 'error' keyword defines the start of an \"error\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); else _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); @@ -1590,7 +1558,7 @@ private void ParseTryExpression() ParseStatement(); block = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; while (_currentToken.Type == TokenType.KeywordError) @@ -1604,7 +1572,7 @@ private void ParseTryExpression() bool isAsKeyword = _currentToken.Type == TokenType.KeywordAs; if (_currentToken.Type == TokenType.KeywordDo || isAsKeyword) { - if (emptyCase != null) + if (emptyCase is not null) { _result.Failure(10, new InvalidGrammarError("There should only be one empty \"error\" expression! You cannot have multiple \"error\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; @@ -1617,7 +1585,7 @@ private void ParseTryExpression() ParseExpression(); @as = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type != TokenType.KeywordDo) @@ -1631,17 +1599,17 @@ private void ParseTryExpression() ParseStatement(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; - if (error != null) + if (error is not null) cases.Add(new Node?[3] { error, @as, body }); else emptyCase = new Node?[2] { @as, body }; } else if (isErrorNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) { - if (emptyCase != null) + if (emptyCase is not null) { Token previous = PeekPrevious(); _result.Failure(10, new InvalidGrammarError("There can't be any \"error\" expressions after an empty \"error\" expression!", previous.StartPosition, previous.EndPosition)); @@ -1650,7 +1618,7 @@ private void ParseTryExpression() ParseExpression(); error = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; isErrorNull = false; @@ -1699,7 +1667,7 @@ private void ParseFunctionDefinitionExpression() ParseExpression(); parameters.Add(_result.Node); - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type == TokenType.NewLine) @@ -1714,7 +1682,7 @@ private void ParseFunctionDefinitionExpression() ParseExpression(); parameters.Add(_result.Node); - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type == TokenType.NewLine) @@ -1736,7 +1704,7 @@ private void ParseFunctionDefinitionExpression() ParseStatements(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type != TokenType.KeywordEnd) @@ -1752,7 +1720,7 @@ private void ParseFunctionDefinitionExpression() { ParseStatement(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; endPosition = PeekPrevious().EndPosition; @@ -1762,7 +1730,7 @@ private void ParseFunctionDefinitionExpression() { ParseExpression(); name = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; isNameNull = false; @@ -1816,7 +1784,7 @@ private void ParseObjectDefinitionExpression() ParseExpression(); parameters.Add(_result.Node); - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type == TokenType.NewLine) @@ -1831,7 +1799,7 @@ private void ParseObjectDefinitionExpression() ParseExpression(); parameters.Add(_result.Node); - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type == TokenType.NewLine) @@ -1855,7 +1823,7 @@ private void ParseObjectDefinitionExpression() ParseExpression(); parents.Add(_result.Node); - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type == TokenType.NewLine) @@ -1870,7 +1838,7 @@ private void ParseObjectDefinitionExpression() ParseExpression(); parents.Add(_result.Node); - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type == TokenType.NewLine) @@ -1892,7 +1860,7 @@ private void ParseObjectDefinitionExpression() ParseStatements(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; if (_currentToken.Type != TokenType.KeywordEnd) @@ -1908,7 +1876,7 @@ private void ParseObjectDefinitionExpression() { ParseStatement(); body = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; endPosition = PeekPrevious().EndPosition; @@ -1918,7 +1886,7 @@ private void ParseObjectDefinitionExpression() { ParseExpression(); name = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; isNameNull = false; @@ -1955,7 +1923,7 @@ private void ParseIncludeExpression() { ParseExpression(); subStructure = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; } else @@ -1970,10 +1938,10 @@ private void ParseIncludeExpression() ParseExpression(); script = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; } - else if (subStructure != null) + else if (subStructure is not null) { script = subStructure; subStructure = null; @@ -1983,14 +1951,14 @@ private void ParseIncludeExpression() _result.Failure(10, new InvalidGrammarError("Expected the 'from' keyword! If a specific object being included from a script (when the object's name is provided after the 'include' keyword) or if the whole script is added to the script (using the 'all' keyword or a comma symbol after the 'include' keyword), the 'from' keyword followed by an expression declaring the script's name or path must be provided.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } - + if (_currentToken.Type == TokenType.KeywordAs) { Advance(); ParseExpression(); nickname = _result.Node; - if (_result.Error != null) + if (_result.Error is not null) return; } @@ -2056,7 +2024,7 @@ public void Success(Node node) /// The same object. public void Failure(int priority, Error error) { - if (Error == null || ErrorPriority <= priority || AdvanceCount == 0) + if (Error is null || ErrorPriority <= priority || AdvanceCount == 0) { ErrorPriority = priority; Error = error; From 69b4368b096d15ed75660d1634c676dc0492fc2a Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 16 Sep 2023 01:23:53 +0530 Subject: [PATCH 014/113] Updated EzrShell. --- src/EzrShell.cs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/EzrShell.cs b/src/EzrShell.cs index 7fc311c..5a5cc42 100644 --- a/src/EzrShell.cs +++ b/src/EzrShell.cs @@ -1,7 +1,7 @@ using System; +using System.Collections.Generic; using System.IO; using System.Text; -using System.Collections.Generic; namespace EzrSquared.EzrShell { @@ -62,14 +62,12 @@ _ __ private struct Settings { - public bool IsInteractive; public bool ShowLexerOutput; public bool ShowParserOutput; public string File; public Settings() { - IsInteractive = false; ShowLexerOutput = false; ShowParserOutput = false; File = string.Empty; @@ -190,7 +188,7 @@ ezrSquared [file] [-h or --help] [-l or --lexer-output] [-p or --parser-output] ShowError("Intended use:\n\tezrSquared [file] [-l | --lexer-output] [-p | --parser-output]"); return false; } - + isFirstArgument = false; } @@ -214,11 +212,10 @@ public static void Main() Console.Write("File to read (press the 'enter' key to enter interactive mode): "); string? filePath = Console.ReadLine(); - if (string.IsNullOrEmpty(filePath)) - settings.IsInteractive = true; - else if (File.Exists(filePath)) + + if (File.Exists(filePath)) settings.File = filePath; - else + else if (!string.IsNullOrEmpty(filePath)) { ShowError($"File not found: \"{filePath}\""); @@ -231,7 +228,7 @@ public static void Main() if (!string.IsNullOrEmpty(settings.File)) ExecuteFile(settings); - else if (settings.IsInteractive) + else InteractiveMode(settings); Console.BackgroundColor = s_previousBackgroundColor; @@ -249,7 +246,7 @@ private static void ExecuteFile(Settings settings) ShowVerbose($" - {tokens[i]}"); } - if (error != null) + if (error is not null) { ShowError(error.ToString()); return; @@ -257,7 +254,7 @@ private static void ExecuteFile(Settings settings) Parser parser = new Parser(tokens); ParseResult result = parser.Parse(); - if (result.Error != null) + if (result.Error is not null) { ShowError(result.Error.ToString()); return; @@ -296,7 +293,7 @@ private static void InteractiveMode(Settings settings) ShowVerbose($" - {tokens[i]}"); } - if (error != null) + if (error is not null) { ShowError(error.ToString()); continue; @@ -304,7 +301,7 @@ private static void InteractiveMode(Settings settings) Parser parser = new Parser(tokens); ParseResult result = parser.Parse(); - if (result.Error != null) + if (result.Error is not null) { ShowError(result.Error.ToString()); continue; From 277f547d89ec1db002e2903ace6063be61da90be Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar <106602744+Uralstech@users.noreply.github.com> Date: Mon, 12 Feb 2024 20:40:09 +0530 Subject: [PATCH 015/113] Update README.md --- README.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index dc2506a..83daeff 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,18 @@ -# The `ezr²` Programming Language -**ezr², or ezrSquared when you can't use the `²` symbol (or it's too inconvenient) - is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#!** +# The `ezr²` Programming Language +**ezr², or ezrSquared when you can't use the `²` symbol (or it's too inconvenient) - is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#!** -More information and documentation about ezr² is available at ***https://uralstech.github.io/ezrSquared***! +More information and documentation about ezr² is available at ***https://uralstech.github.io/ezrSquared***! ## What's the 'ezrSquared-re' branch? ezrSquared is being rewritten from the ground up! Expect more features, better performance and better code documentation! ## Update! -I've finished the parser! Well, the important bits of it. Next what's left is (in no perticular order): -* QuickSyntax integration into the parser. -* Making the whole interpreter. -* Probably a lot more testing. +The development status of ezr² is now available [***here!***](https://github.com/users/Uralstech/projects/3) ## Contributing -ezr² is an open source project and welcomes contributions from anyone who wants to improve it. +ezr² is an open source project and welcomes contributions from anyone who wants to improve it. -If you want to contribute to ezr², please contact Uralstech at `info@uralstech.in`. +If you want to contribute to ezr², please contact Uralstech at `info@uralstech.in`. ## License -ezr² is licensed under the Apache 2.0 license. See LICENSE.txt for more details. \ No newline at end of file +ezr² is licensed under the Apache 2.0 license. See LICENSE.txt for more details. From 6403ff1e0b6008004b782262bce243ab5dd1ce4a Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar <106602744+Uralstech@users.noreply.github.com> Date: Sat, 24 Feb 2024 14:47:04 +0530 Subject: [PATCH 016/113] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83daeff..d2ef9d4 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ More information and documentation about ezr² is available at ***https://uralst ezrSquared is being rewritten from the ground up! Expect more features, better performance and better code documentation! ## Update! -The development status of ezr² is now available [***here!***](https://github.com/users/Uralstech/projects/3) +The development status of ezr² is now available on [***the ezr² project***](https://github.com/users/Uralstech/projects/3) and [***my blog***](https://uralstech.github.io/). ## Contributing ezr² is an open source project and welcomes contributions from anyone who wants to improve it. From 8b4ef2648542248cf1adda948bf22e037814bd9d Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sun, 4 Aug 2024 23:24:40 +0530 Subject: [PATCH 017/113] =?UTF-8?q?ezr=C2=B2=20RE=20(REwrite)=20v0.1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 267 ++ .gitignore | 8 +- README.md | 2 +- docs/CSAELs.markdown | 29 - docs/CSharp-and-ezrSquared.markdown | 23 + docs/Embedding-ezrSquared.markdown | 7 + docs/Gemfile | 3 +- docs/Gemfile.lock | 2 + docs/Get-started-with-CSAELs.markdown | 7 + ...ion.markdown => Learn-ezrSquared.markdown} | 84 +- docs/Multilingual-ezrSquared.markdown | 59 + docs/_config.yml | 2 + docs/index.markdown | 109 +- ezrSquared.sln | 6 + {src => graphics}/Icon.ico | Bin samples/tic_tac_toe_demo.ezr2 | 107 +- src/AccessMod.cs | 60 + src/AssemblyInfo.cs | 11 - src/AutoGeneratedAssemblyInfo.cs | 17 - src/Directory.Build.props | 12 +- src/Executor/CodeExecutor.cs | 98 + src/Executor/ExecutionResult.cs | 99 + src/EzrCommon.cs | 257 -- src/EzrErrors.cs | 151 -- src/EzrGrammar.txt | 144 +- src/EzrLexer.cs | 602 ----- src/EzrNodes.cs | 726 ------ src/EzrParser.cs | 2034 --------------- src/EzrShell.cs | 316 --- src/EzrSquared.csproj | 86 +- src/GlobalSuppressions.cs | 12 + src/Position.cs | 76 + .../Collections/RuntimeEzrObjectDictionary.cs | 278 ++ .../Collections/RuntimeEzrObjectList.cs | 110 + src/Runtime/Context.cs | 478 ++++ src/Runtime/Interpreter.cs | 1431 +++++++++++ src/Runtime/Nodes/BaseNodes.cs | 58 + .../Nodes/CollectionNodes/ArrayLikeNode.cs | 36 + .../Nodes/CollectionNodes/DictionaryNode.cs | 30 + .../DefineBlockNode.cs | 31 + .../VariableAccessNode.cs | 31 + .../VariableAssignmentNode.cs | 43 + .../ControlFlowStructureNodes/CountNode.cs | 49 + .../Nodes/ControlFlowStructureNodes/IfNode.cs | 36 + .../ControlFlowStructureNodes/TryNode.cs | 44 + .../ControlFlowStructureNodes/WhileNode.cs | 31 + src/Runtime/Nodes/ExecutableNodes/CallNode.cs | 36 + .../ExecutableNodes/ClassDefinitionNode.cs | 54 + .../ExecutableNodes/FunctionDefinitionNode.cs | 61 + .../Nodes/ExecutableNodes/IncludeNode.cs | 43 + .../Nodes/ExecutableNodes/ReturnNode.cs | 31 + .../OperationNodes/BinaryOperationNode.cs | 37 + .../OperationNodes/UnaryOperationNode.cs | 31 + src/Runtime/Nodes/SimpleNodes/NoValueNode.cs | 25 + src/Runtime/Nodes/SimpleNodes/ValueNode.cs | 25 + src/Runtime/Reference.cs | 166 ++ src/Runtime/ReferencePool.cs | 42 + src/Runtime/RuntimeResult.cs | 181 ++ src/Runtime/Types/BaseTypes.cs | 457 ++++ .../Builtins/EzrBuiltinFunctions.cs | 340 +++ .../Builtins/EzrBuiltinsUtility.cs | 95 + .../EzrSharpCompatibilityObjectInstance.cs | 93 + .../EzrSharpCompatibilityType.cs | 110 + .../EzrSharpCompatibilityWrapper.cs | 249 ++ .../EzrSharpCompatibilityConstructor.cs | 80 + .../EzrSharpCompatibilityExecutable.cs | 126 + .../EzrSharpCompatibilityFunction.cs | 71 + .../EzrSharpCompatibilityField.cs | 80 + .../EzrSharpCompatibilityProperty.cs | 92 + .../EzrSharpSourceExecutableWrapper.cs | 118 + .../EzrSharpSourceFieldWrapper.cs | 112 + .../EzrSharpSourceFunctionWrapper.cs | 82 + .../EzrSharpSourcePropertyWrapper.cs | 70 + .../EzrSharpSourceTypeWrapper.cs | 158 ++ src/Runtime/Types/Collections/EzrArray.cs | 488 ++++ .../Types/Collections/EzrDictionary.cs | 267 ++ src/Runtime/Types/Collections/EzrList.cs | 515 ++++ .../Collections/IEzrIndexedCollection.cs | 19 + src/Runtime/Types/Core/EzrBoolean.cs | 74 + src/Runtime/Types/Core/EzrConstants.cs | 22 + src/Runtime/Types/Core/EzrNothing.cs | 54 + src/Runtime/Types/Core/Numerics/EzrFloat.cs | 269 ++ src/Runtime/Types/Core/Numerics/EzrInteger.cs | 486 ++++ .../Core/RuntimeErrors/EzrAssertionError.cs | 35 + .../RuntimeErrors/EzrIllegalOperationError.cs | 38 + .../Core/RuntimeErrors/EzrKeyNotFoundError.cs | 38 + .../Types/Core/RuntimeErrors/EzrMathError.cs | 44 + .../EzrMissingRequiredArgumentError.cs | 38 + .../EzrPrivateMemberOperationError.cs | 38 + .../Core/RuntimeErrors/EzrRuntimeError.cs | 179 ++ .../RuntimeErrors/EzrUndefinedValueError.cs | 38 + .../EzrUnexpectedArgumentError.cs | 38 + .../RuntimeErrors/EzrUnexpectedTypeError.cs | 38 + .../EzrUnsupportedWrappingError.cs | 38 + .../RuntimeErrors/EzrValueOutOfRangeError.cs | 38 + .../RuntimeErrors/EzrWrapperExecutionError.cs | 38 + src/Runtime/Types/Core/Text/EzrCharacter.cs | 302 +++ .../Types/Core/Text/EzrCharacterList.cs | 491 ++++ src/Runtime/Types/Core/Text/EzrString.cs | 471 ++++ src/Runtime/Types/Executables/EzrClass.cs | 271 ++ .../Types/Executables/EzrClassInstance.cs | 577 +++++ src/Runtime/Types/Executables/EzrFunction.cs | 71 + .../Types/Executables/EzrRuntimeExecutable.cs | 244 ++ src/Runtime/Types/IEzrMutableObject.cs | 23 + src/Runtime/Types/IEzrObject.cs | 262 ++ .../WrapperAttributes/CsealAttribute.cs | 14 + .../SharpFieldWrapperAttribute.cs | 47 + .../SharpMethodParameters.cs | 65 + .../SharpMethodWrapperAttribute.cs | 67 + .../SharpTypeWrapperAttribute.cs | 31 + src/Shell/Directory.Build.props | 6 + src/Shell/EzrShell.cs | 154 ++ src/Shell/EzrShellConsoleHelper.cs | 131 + src/Shell/EzrShellEditor.cs | 110 + .../InstallerSrc}/environment.iss | 0 .../InstallerSrc}/ezrSquared 32-bit.iss | 19 +- .../InstallerSrc}/ezrSquared 64-bit.iss | 19 +- src/Shell/Shell.csproj | 53 + src/Syntax/Errors/StackedSyntaxError.cs | 18 + src/Syntax/Errors/SyntaxError.cs | 53 + src/Syntax/Lexer.cs | 657 +++++ src/Syntax/Parser/ParseResult.cs | 59 + src/Syntax/Parser/Parser.cs | 2234 +++++++++++++++++ src/Token.cs | 70 + src/TokenType.cs | 516 ++++ src/TokenTypeGroup.cs | 40 + src/Util/BigIntegerExtensions.cs | 43 + src/Util/Utils.cs | 121 + tests/calculator++.ezr2 | 609 +++++ tests/calculator.ezr2 | 95 + tests/full_test.ezr2 | 247 +- 131 files changed, 17667 insertions(+), 4522 deletions(-) create mode 100644 .editorconfig delete mode 100644 docs/CSAELs.markdown create mode 100644 docs/CSharp-and-ezrSquared.markdown create mode 100644 docs/Embedding-ezrSquared.markdown create mode 100644 docs/Get-started-with-CSAELs.markdown rename docs/{Introduction.markdown => Learn-ezrSquared.markdown} (89%) create mode 100644 docs/Multilingual-ezrSquared.markdown rename {src => graphics}/Icon.ico (100%) create mode 100644 src/AccessMod.cs delete mode 100644 src/AssemblyInfo.cs delete mode 100644 src/AutoGeneratedAssemblyInfo.cs create mode 100644 src/Executor/CodeExecutor.cs create mode 100644 src/Executor/ExecutionResult.cs delete mode 100644 src/EzrCommon.cs delete mode 100644 src/EzrErrors.cs delete mode 100644 src/EzrLexer.cs delete mode 100644 src/EzrNodes.cs delete mode 100644 src/EzrParser.cs delete mode 100644 src/EzrShell.cs create mode 100644 src/GlobalSuppressions.cs create mode 100644 src/Position.cs create mode 100644 src/Runtime/Collections/RuntimeEzrObjectDictionary.cs create mode 100644 src/Runtime/Collections/RuntimeEzrObjectList.cs create mode 100644 src/Runtime/Context.cs create mode 100644 src/Runtime/Interpreter.cs create mode 100644 src/Runtime/Nodes/BaseNodes.cs create mode 100644 src/Runtime/Nodes/CollectionNodes/ArrayLikeNode.cs create mode 100644 src/Runtime/Nodes/CollectionNodes/DictionaryNode.cs create mode 100644 src/Runtime/Nodes/ContextManipulationNodes/DefineBlockNode.cs create mode 100644 src/Runtime/Nodes/ContextManipulationNodes/VariableAccessNode.cs create mode 100644 src/Runtime/Nodes/ContextManipulationNodes/VariableAssignmentNode.cs create mode 100644 src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs create mode 100644 src/Runtime/Nodes/ControlFlowStructureNodes/IfNode.cs create mode 100644 src/Runtime/Nodes/ControlFlowStructureNodes/TryNode.cs create mode 100644 src/Runtime/Nodes/ControlFlowStructureNodes/WhileNode.cs create mode 100644 src/Runtime/Nodes/ExecutableNodes/CallNode.cs create mode 100644 src/Runtime/Nodes/ExecutableNodes/ClassDefinitionNode.cs create mode 100644 src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs create mode 100644 src/Runtime/Nodes/ExecutableNodes/IncludeNode.cs create mode 100644 src/Runtime/Nodes/ExecutableNodes/ReturnNode.cs create mode 100644 src/Runtime/Nodes/OperationNodes/BinaryOperationNode.cs create mode 100644 src/Runtime/Nodes/OperationNodes/UnaryOperationNode.cs create mode 100644 src/Runtime/Nodes/SimpleNodes/NoValueNode.cs create mode 100644 src/Runtime/Nodes/SimpleNodes/ValueNode.cs create mode 100644 src/Runtime/Reference.cs create mode 100644 src/Runtime/ReferencePool.cs create mode 100644 src/Runtime/RuntimeResult.cs create mode 100644 src/Runtime/Types/BaseTypes.cs create mode 100644 src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs create mode 100644 src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs create mode 100644 src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs create mode 100644 src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs create mode 100644 src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs create mode 100644 src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs create mode 100644 src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs create mode 100644 src/Runtime/Types/Collections/EzrArray.cs create mode 100644 src/Runtime/Types/Collections/EzrDictionary.cs create mode 100644 src/Runtime/Types/Collections/EzrList.cs create mode 100644 src/Runtime/Types/Collections/IEzrIndexedCollection.cs create mode 100644 src/Runtime/Types/Core/EzrBoolean.cs create mode 100644 src/Runtime/Types/Core/EzrConstants.cs create mode 100644 src/Runtime/Types/Core/EzrNothing.cs create mode 100644 src/Runtime/Types/Core/Numerics/EzrFloat.cs create mode 100644 src/Runtime/Types/Core/Numerics/EzrInteger.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs create mode 100644 src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs create mode 100644 src/Runtime/Types/Core/Text/EzrCharacter.cs create mode 100644 src/Runtime/Types/Core/Text/EzrCharacterList.cs create mode 100644 src/Runtime/Types/Core/Text/EzrString.cs create mode 100644 src/Runtime/Types/Executables/EzrClass.cs create mode 100644 src/Runtime/Types/Executables/EzrClassInstance.cs create mode 100644 src/Runtime/Types/Executables/EzrFunction.cs create mode 100644 src/Runtime/Types/Executables/EzrRuntimeExecutable.cs create mode 100644 src/Runtime/Types/IEzrMutableObject.cs create mode 100644 src/Runtime/Types/IEzrObject.cs create mode 100644 src/Runtime/WrapperAttributes/CsealAttribute.cs create mode 100644 src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs create mode 100644 src/Runtime/WrapperAttributes/SharpMethodParameters.cs create mode 100644 src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs create mode 100644 src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs create mode 100644 src/Shell/Directory.Build.props create mode 100644 src/Shell/EzrShell.cs create mode 100644 src/Shell/EzrShellConsoleHelper.cs create mode 100644 src/Shell/EzrShellEditor.cs rename src/{installer => Shell/InstallerSrc}/environment.iss (100%) rename src/{installer => Shell/InstallerSrc}/ezrSquared 32-bit.iss (84%) rename src/{installer => Shell/InstallerSrc}/ezrSquared 64-bit.iss (84%) create mode 100644 src/Shell/Shell.csproj create mode 100644 src/Syntax/Errors/StackedSyntaxError.cs create mode 100644 src/Syntax/Errors/SyntaxError.cs create mode 100644 src/Syntax/Lexer.cs create mode 100644 src/Syntax/Parser/ParseResult.cs create mode 100644 src/Syntax/Parser/Parser.cs create mode 100644 src/Token.cs create mode 100644 src/TokenType.cs create mode 100644 src/TokenTypeGroup.cs create mode 100644 src/Util/BigIntegerExtensions.cs create mode 100644 src/Util/Utils.cs create mode 100644 tests/calculator++.ezr2 create mode 100644 tests/calculator.ezr2 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4d85a4b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,267 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:warning +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false:warning +dotnet_style_qualification_for_property = false:warning + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:warning +dotnet_style_predefined_type_for_member_access = true:warning + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:warning +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_style_coalesce_expression = true:warning +dotnet_style_collection_initializer = true:warning +dotnet_style_explicit_tuple_names = true:warning +dotnet_style_namespace_match_folder = false +dotnet_style_null_propagation = true:warning +dotnet_style_object_initializer = true:warning +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:warning +dotnet_style_prefer_compound_assignment = true:warning +dotnet_style_prefer_conditional_expression_over_assignment = true:warning +dotnet_style_prefer_conditional_expression_over_return = true:warning +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning +dotnet_style_prefer_inferred_tuple_names = true:warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning +dotnet_style_prefer_simplified_boolean_expressions = true:warning +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true:warning + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:warning + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = false +dotnet_style_allow_statement_immediately_after_block_experimental = false + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false:warning +csharp_style_var_for_built_in_types = false:warning +csharp_style_var_when_type_is_apparent = false:warning + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:warning +csharp_style_expression_bodied_constructors = false:warning +csharp_style_expression_bodied_indexers = true:warning +csharp_style_expression_bodied_lambdas = true:warning +csharp_style_expression_bodied_local_functions = false:warning +csharp_style_expression_bodied_methods = false:warning +csharp_style_expression_bodied_operators = false:warning +csharp_style_expression_bodied_properties = true:warning + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:warning +csharp_style_pattern_matching_over_is_with_cast_check = true:warning +csharp_style_prefer_extended_property_pattern = true +csharp_style_prefer_not_pattern = true:warning +csharp_style_prefer_pattern_matching = true:warning +csharp_style_prefer_switch_expression = true:warning + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:warning + +# Modifier preferences +csharp_prefer_static_local_function = true:warning +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async +csharp_style_prefer_readonly_struct = true:warning +csharp_style_prefer_readonly_struct_member = true + +# Code-block preferences +csharp_prefer_braces = false:warning +csharp_prefer_simple_using_statement = true:warning +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_prefer_method_group_conversion = true:warning +csharp_style_prefer_primary_constructors = true +csharp_style_prefer_top_level_statements = true:warning + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:warning +csharp_style_deconstructed_variable_declaration = true:warning +csharp_style_implicit_object_creation_when_type_is_apparent = true:warning +csharp_style_inlined_variable_declaration = true:warning +csharp_style_prefer_index_operator = true:warning +csharp_style_prefer_local_over_anonymous_function = true:warning +csharp_style_prefer_null_check_over_type_check = true:warning +csharp_style_prefer_range_operator = true:warning +csharp_style_prefer_tuple_swap = true:warning +csharp_style_prefer_utf8_string_literals = true +csharp_style_throw_expression = true:warning +dotnet_diagnostic.IDE0059.severity = none # csharp_style_unused_value_assignment_preference = discard_variable +dotnet_diagnostic.IDE0058.severity = none # csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion + +# 'using' directive preferences +dotnet_diagnostic.IDE0065.severity = none # csharp_using_directive_placement = outside_namespace + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false +csharp_style_allow_embedded_statements_on_same_line_experimental = false:warning + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +# Other preferences +dotnet_style_prefer_collection_expression = true:warning + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = warning +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.constant_should_be_pascal_case.severity = warning +dotnet_naming_rule.constant_should_be_pascal_case.symbols = constant +dotnet_naming_rule.constant_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.private_or_internal_static_field_should_be_private_static_camel_case.severity = warning +dotnet_naming_rule.private_or_internal_static_field_should_be_private_static_camel_case.symbols = private_or_internal_static_field +dotnet_naming_rule.private_or_internal_static_field_should_be_private_static_camel_case.style = private_static_camel_case + +dotnet_naming_rule.private_or_internal_field_should_be_private_camel_case.severity = warning +dotnet_naming_rule.private_or_internal_field_should_be_private_camel_case.symbols = private_or_internal_field +dotnet_naming_rule.private_or_internal_field_should_be_private_camel_case.style = private_camel_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field +dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private, private_protected +dotnet_naming_symbols.private_or_internal_field.required_modifiers = + +dotnet_naming_symbols.private_or_internal_static_field.applicable_kinds = field +dotnet_naming_symbols.private_or_internal_static_field.applicable_accessibilities = internal, private, private_protected +dotnet_naming_symbols.private_or_internal_static_field.required_modifiers = static + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +dotnet_naming_symbols.constant.applicable_kinds = field +dotnet_naming_symbols.constant.applicable_accessibilities = * +dotnet_naming_symbols.constant.required_modifiers = const + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.private_static_camel_case.required_prefix = s_ +dotnet_naming_style.private_static_camel_case.required_suffix = +dotnet_naming_style.private_static_camel_case.word_separator = +dotnet_naming_style.private_static_camel_case.capitalization = camel_case + +dotnet_naming_style.private_camel_case.required_prefix = _ +dotnet_naming_style.private_camel_case.required_suffix = +dotnet_naming_style.private_camel_case.word_separator = +dotnet_naming_style.private_camel_case.capitalization = camel_case diff --git a/.gitignore b/.gitignore index 1ea2e1d..674d9c5 100644 --- a/.gitignore +++ b/.gitignore @@ -27,8 +27,8 @@ x86/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ -[Bb]in/ -[Oo]bj/ +[Bb]inaries/ +[Ii]ntermediates/ [Oo]ut/ [Ll]og/ [Ll]ogs/ @@ -365,5 +365,5 @@ FodyWeavers.xsd # -------------------------------------------------- [Ll]ibraries/ -docs/offline/_site/ -docs/offline/ezrSquared.Offline.Documentation.zip \ No newline at end of file +[Dd]ocs/offline/_site/ +[Dd]ocs/offline/ezrSquared.Offline.Documentation.zip \ No newline at end of file diff --git a/README.md b/README.md index dc2506a..3c9cb35 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ More information and documentation about ezr² is available at ***https://uralstech.github.io/ezrSquared***! ## What's the 'ezrSquared-re' branch? -ezrSquared is being rewritten from the ground up! Expect more features, better performance and better code documentation! +ezr² is being rewritten from the ground up! Expect more features, better performance and better code documentation! ## Update! I've finished the parser! Well, the important bits of it. Next what's left is (in no perticular order): diff --git a/docs/CSAELs.markdown b/docs/CSAELs.markdown deleted file mode 100644 index bc8b5a4..0000000 --- a/docs/CSAELs.markdown +++ /dev/null @@ -1,29 +0,0 @@ ---- -layout: default -title: C# in ezr² -nav_order: 3 ---- - -# C# in ezr² -{: .no_toc } - -
- - Table of contents - - {: .text-delta } -- TOC -{:toc} -
- -## Embedding ezr² to your application! -ezr² allows you to embed it to other programs and can also use C# variables and functions in ezr² code. -ezr² code is much simple and easier to understand than, for example, C# code. So, **embedding ezr² to your application -adds the ability to script events and/or high level game logic in the hand of your designers and end users**. - -## ezr² doesn't have [feature-ezr²-doesn't-have] built-in! -Now, this is where **CSAELs** step in. CSAELs or **CSharp Assisted Ezr² Libraries** are, to state the obvious, libraries or modules written in C# for ezr² scripting. -With CSAELs, anyone who knows C# can add any feature they want to ezr²! These features can also be built-in to ezr² in the future - it's a win-win situation! All you have to do -is wrap C# variables, functions and whatnot in classes the ezr² interpreter can understand. All these "wrapper" classes are part of the ezr² API. - -## API Documentation - TODO \ No newline at end of file diff --git a/docs/CSharp-and-ezrSquared.markdown b/docs/CSharp-and-ezrSquared.markdown new file mode 100644 index 0000000..7f2980a --- /dev/null +++ b/docs/CSharp-and-ezrSquared.markdown @@ -0,0 +1,23 @@ +--- +layout: default +title: C# and ezr² +nav_order: 4 +--- + +# C# and ezr² + +## Embedding ezr² to your application! + +ezr² can be embedded into other programs. This allows your users to write scripts in ezr² which can control various systems in your app. +ezr² code is much simple and easier to learn and understand than, for example, C# code. + +To learn more about embedding ezr² into your application, check the documentation [***here***](https://uralstech.github.io/ezrSquared/CSharp-and-ezrSquared/Embedding-ezrSquared) + +## ezr² doesn't have \[feature\] built-in! + +Now, this is where **CSAELs** step in. CSAELs, or, **CSharp Assisted ezr² Libraries** are libraries written in C# for ezr² scripting. + +With CSAELs, anyone who knows C# can add any feature they want to ezr². These features can also be built-in to ezr² - it's a win-win situation! +All you have to do is wrap C# variables, functions and whatnot with attributes the ezr² interpreter can identify. All these "wrapper" attributes are part of the ezr² API. + +To learn more about CSAELs, check the documentation [***here***](https://uralstech.github.io/ezrSquared/CSharp-and-ezrSquared/Get-started-with-CSAELs) diff --git a/docs/Embedding-ezrSquared.markdown b/docs/Embedding-ezrSquared.markdown new file mode 100644 index 0000000..55fdcfe --- /dev/null +++ b/docs/Embedding-ezrSquared.markdown @@ -0,0 +1,7 @@ +--- +layout: default +title: Embedding How-To +nav_order: 5 +--- + +# TODO \ No newline at end of file diff --git a/docs/Gemfile b/docs/Gemfile index c51d1c5..f5b42d1 100644 --- a/docs/Gemfile +++ b/docs/Gemfile @@ -14,4 +14,5 @@ platforms :mingw, :x64_mingw, :mswin, :jruby do end gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] -gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] \ No newline at end of file +gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] +gem "webrick", "~> 1.8" diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index e3c76a1..ea63b6a 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -255,6 +255,7 @@ GEM unf_ext (0.0.8.2) unicode-display_width (1.8.0) wdm (0.1.1) + webrick (1.8.1) PLATFORMS x64-mingw-ucrt @@ -269,6 +270,7 @@ DEPENDENCIES tzinfo (>= 1, < 3) tzinfo-data wdm (~> 0.1.1) + webrick (~> 1.8) BUNDLED WITH 2.4.8 diff --git a/docs/Get-started-with-CSAELs.markdown b/docs/Get-started-with-CSAELs.markdown new file mode 100644 index 0000000..305239d --- /dev/null +++ b/docs/Get-started-with-CSAELs.markdown @@ -0,0 +1,7 @@ +--- +layout: default +title: CSAELs How-To +nav_order: 6 +--- + +# TODO \ No newline at end of file diff --git a/docs/Introduction.markdown b/docs/Learn-ezrSquared.markdown similarity index 89% rename from docs/Introduction.markdown rename to docs/Learn-ezrSquared.markdown index 914ade0..824077a 100644 --- a/docs/Introduction.markdown +++ b/docs/Learn-ezrSquared.markdown @@ -1,10 +1,10 @@ --- layout: default -title: "Introduction and Documentation" +title: "Learn ezr²" nav_order: 2 --- -# An Introduction to ezr² +# Learn ezr² {: .no_toc }
@@ -17,6 +17,7 @@ nav_order: 2
## Why Learn ezr²? + ezr² is a programming language that's **easy to learn** and **practical to use**. ezr² can be learnt by anyone, **of any age**, in a few minutes. Anyone can extend the functionalities of ezr² with **libraries**. If you already know C#, you can even @@ -26,10 +27,12 @@ boilerplate syntax for the shorter **QuickSyntax**. The normal syntax satisfies as it is easy to use and QuickSyntax satisfies the expert, as it is very short. ## Documentation + Start coding with the help of ezr²'s official documentation! Read the text in **bold** for a TL;DR. (Heavily inspired by [***this Python tutorial***](https://python.land/python-tutorial)) ### Hello World, Displaying Text to The Screen and Strings + There's a tradition in which programming tutorials start with a so-called Hello World program. A **Hello World program** simply **prints the words "Hello world" to the screen**, and the **`show()` function lets you do that**. You will learn more about functions later. @@ -51,11 +54,13 @@ This way, a string is easy to recognize for ezr². Here are a few more examples ``` ### Nothing + After printing anything to the screen, the **`show()` function also displays "nothing"**. This means the **function `show()` returned no value, but printed the argument to the screen**. If you **write `"Example"` and run, only `"Example"` will be shown to the screen**. As in the expression **`"Example"` returned the string "Example"**. **`nothing` is a representation of a "lack of value"** - equivalent to null (C#, C, Java, etc) or None (Python). ### Numbers + Just like strings, you can ask ezr² to **print numbers using the `show()` function**. Unlike strings, **numbers don't need quotes around them**. So, the code to print the number 10 would be: @@ -76,6 +81,7 @@ Try some of these operators on numbers! | ^ | powered by | 4 ^ 2 | ### Floating-point Numbers + Try the **expression `3 / 2`**. **It returns `1` instead of the correct answer, `1.5`**. In computer programming, **there's a strong distinction between non-fractional numbers like 1, 3, and 42 and fractional numbers like 3.14 and 5.323**. **The former are called *integers* - *whole numbers*, while the latter are called *floats* - *floating-point numbers***. Now try this: @@ -88,13 +94,14 @@ This should display `1.5` to the screen, because you have specified that `2.0` i **An integer divided by another integer will always return an integer, but the same done with a float will always return a float**. **This rule is the same for all operators**. ### Variables + What if you want to store the result of a calculation, to be accessed later in the code? For this, you use *variables*. ***Variables* allow you to store items in memory for as long as the ezr² program runs**. It's like a reservation for an item, under the variable name, in the system memory. -The **syntax to assign a variable is so: `item NAME: VALUE`**. To assign the number 42 to a variable called age, you would write: +The **syntax to assign a variable is so: `NAME: VALUE`**. To assign the number 42 to a variable called age, you would write: ``` -item age: 42 +age: 42 ``` And just like numbers and strings, you can **print a variable with the `show()` function**. In the following example, you assign a few @@ -102,22 +109,23 @@ variables and then print them. Here you are also **adding strings together - thi You have to **convert the `age` variable to a string** to be able to add it to another string, so you **use the built-in `as_string` function in the integer**. ``` -item age: 42 -item name: "Joe" +age: 42 +name: "Joe" show("Hello, my name is " + name) show("My age is " + age.as_string()) ``` ### User Input + Let's make a simple adder - the user will enter two numbers, and the adder will return the result of adding them together. To do so you need to **get the user's input**. You can **use the `get()` function** for that. You have to **feed it the message to show to the user**. You can **enter `nothing` if you don't want any message with the input request**. The code should look something like this: ``` -item num1: get("Enter num 1: ") -item num2: get("Enter num 2: ") +num1: get("Enter num 1: ") +num2: get("Enter num 2: ") show(num1 + num2) ``` @@ -127,18 +135,19 @@ and `num2` respectively, the result will be `24`, not `6`. This is because the **`get()` function returns a string.** You need to **convert the string into an integer**. To do so you **use the built-in `as_integer()` function in the string**. You'll immediately convert the results of the `get()` functions to integers. Try the below code: ``` -item num1: get("Enter num 1: ").as_integer() -item num2: get("Enter num 2: ").as_integer() +num1: get("Enter num 1: ").as_integer() +num2: get("Enter num 2: ").as_integer() show(num1 + num2) ``` ### Conditions + Try entering normal text as the input for the above code - you'll get an error! This is because the **`as_integer()` function cannot convert normal text to integers**. To avoid the user seeing the messy error, you can **use the `try_as_integer()` function**. But, **this function returns `nothing` if it is unable to convert the string to an integer**! If you try to add `nothing` and a number together you'll get an error! You have to **make sure that `num1` and `num2` are integers** before you add them. You can **do this with *if expressions***. **The if expression has a body of code that only executes whenever the if statement's condition is met**. **The additional else statement, which also has a body of code, runs if the if condition is false**. **The else if statement is used when you wish to satisfy one statement while the other is false**. ``` -item num1: get("Enter num 1: ").try_as_integer() -item num2: get("Enter num 2: ").try_as_integer() +num1: get("Enter num 1: ").try_as_integer() +num2: get("Enter num 2: ").try_as_integer() if num1 = nothing do show("Num 1 is invalid!") @@ -165,21 +174,24 @@ Here are all the comparison operators: If you use **comparisons outside if expressions** they **will return a *boolean***. **Booleans are just two values - *true* or *false***. ### One-liners -You might have noticed that the if expression has the *end* keyword at the end. **All multi-line ezr² expressions *must* end with the *end* keyword**. But **you can write all multi-line expressions in one line - these are called *one-liners***. + +You might have noticed that the if expression has the *end* keyword at the end. **All multi-line ezr² expressions *must* end with the *end* keyword**. But **you can write most multi-line expressions in one line - these are called *one-liners***. They are the same as writing the multi-line version of an expression, but they must fit in a single line. For example - ``` -if get("Hello there! ") = "General Kenobi" do show("Nice") +if get("Hello there!\n") = "General Kenobi" do show("Nice") ``` Note that **new lines can be coded as the semicolon (`;`) symbol**. **Comments are signified by the at symbol (`@`) at the start**. Comments are just more information about the written code - like how the code works. They do not affect the execution of any code and are ignored by ezr². ### Loops + For the above scripts, you might have found it annoying to have to copy and paste the code again and again to try it out. What if you want the code to run forever? Or even a set number of times? Do you have to keep copying and pasting it? No! You'll use *loops* for that. **A loop keeps executing the given body of code till a condition is satisfied.** ezr² has two types of loops - *count loops* and *while loops*. ### Count Loops + ***Count loops* repeat the given code a *set number of times***. ``` count to 10 do @@ -215,11 +227,12 @@ end ``` ### While Loops + ***While loops* repeat the given code till the given condition turns false, and revaluate the condition every iteration**. ``` -item password: get("Enter password: ") +password: get("Enter password: ") while password ! "yeet" do - item password: get("Password is false! Try again: ") + password: get("Password is false! Try again: ") end ``` @@ -231,6 +244,7 @@ end ``` ### Iteration Control + What if you want to stop a loop while it's running or want to skip an iteration on a condition? You can **use the *stop* and *skip* keywords to control the iterations of loops**. **The *skip* keyword stops the current iteration and starts the next**. **The *stop* keyword just stops the loop**. Let's code a simple example. ``` count to 10 as i do @@ -250,26 +264,27 @@ In this example, the iteration is *skipped* when i = 5 and the loop is outright **The *skip* and *stop* keywords can also be used in while loops**. ### Arrays + If you try the one-liner version of the count loop, like - ``` count to 10 do show("Hi!") ``` -You'll see a whole lot of `nothing`s in parentheses, separated by commas! That's an *array*. +You'll see a whole lot of `nothing`-s in parentheses, separated by commas! That's an *array*. ***Arrays* are used to store multiple items of any type in a single variable**. **It is ordered and unchangeable, or *immutable***. When you say that **arrays are ordered**, it **means that the items have a defined order, and that order will not change**. An array is **created by putting items, seperated by commas, between parenthesis**. -**Array items are indexed**, the first item has index `0`, the second item has index `1` and so on. **Items of an array can be accessed with the `<=` operator** - +**Array items are indexed**, the first item has index `0`, the second item has index `1` and so on. **Items of an array can be accessed with the `<` operator** - ``` -item array_example: (1, "string", 3.54, nothing, false) -show(array_example <= 0) -show(array_example <= 1) -show(array_example <= 2) -show(array_example <= 3) -show(array_example <= 4) +array_example: (1, "string", 3.54, nothing, false) +show(array_example < 0) +show(array_example < 1) +show(array_example < 2) +show(array_example < 3) +show(array_example < 4) -show(array_example <= "sd") +show(array_example < "sd") ``` -That last line of code should show an error - the **item after the `<=` operator must be a valid index in the array**! +That last line of code should show an error - the **item after the `<` operator must be a valid index in the array**! Here are all the array operators: @@ -277,30 +292,31 @@ Here are all the array operators: |----------|:--------------:|--------------:| | * | duplication | (2,3) * 4 | | / | division | (6,2,3,4) / 2 | -| \<= | item access | (6,2) <= 1 | +| \< | item access | (6,2) < 1 | Now, what if you want to create an array with one item? Let's try it - ``` -item array_example: (3) +array_example: (3) show(array_example) ``` This won't work, as **ezr² thinks `(3)` is part of an operation - not an array**. So, you have to **have a comma after the first item**! ``` -item array_example: (3,) +array_example: (3,) show(array_example) ``` You can **access the length of the array with the built-in `length` variable in array** - ``` -item array_example: (1,2,3,4) +array_example: (1,2,3,4) show(array_example.length) ``` ### Lists + ***Lists* are like arrays, but they are changeable or *mutable***. They are **created with square brackets, instead of parentheses**. ``` -item list_example: [1,"string",1.45,nothing,true] +list_example: [1,"string",1.45,nothing,true] show(list_example) ``` @@ -308,11 +324,11 @@ Here are all the list operators: | Operator | Name | Example | |----------|:--------------:|-----------------------------:| -| + | append | item lst: [1,5]; lst + 4 | -| - | remove | item lst: [1,5]; lst - 1 | +| + | append | lst: [1,5]; lst + 4 | +| - | remove | lst: [1,5]; lst - 1 | | * | duplication | [2,3] * 4 | | / | division | [6,2,3,4] / 2 | -| \<= | item access | [6,2] <= 1 | +| \< | item access | [6,2] < 1 | You can **access the length of the list with the built-in `length` variable in the list**, just like with arrays. diff --git a/docs/Multilingual-ezrSquared.markdown b/docs/Multilingual-ezrSquared.markdown new file mode 100644 index 0000000..f0bbea2 --- /dev/null +++ b/docs/Multilingual-ezrSquared.markdown @@ -0,0 +1,59 @@ +--- +layout: default +title: "Multilingual ezr²" +nav_order: 3 +--- + +# Multilingual ezr² + +## Why? + +Most programming languages like C, C#, Python, and Java, just to name a few, are English-based. Of course, they do not follow the standard grammar for natural English, but, you would agree that it would be much easier to learn these languages if you knew English. This can be a huge barrier to those who have never spoken a single word of English. + +## How's it different from other multilingual (programming) languages? + +There are a few examples of programming languages which may not require you to know English: + +#### [***Scratch Jr.***](https://www.scratchjr.org/) + +This is a programming language that is based on symbols and pictures. How far can you go with pictures? + +Now, you can have language made up completely of symbols, Sign Language is a good example. But then, the user is forced learning a different language. Why not just learn English at that point and do conventional coding? + +#### [***Hedy***](https://www.hedy.org/) + +Hedy is a transpiler - something that converts Hedy code to Python code, and executes it. There is no method in which the Python code can be converted back to Hedy code in the way Hedy code is converted into Python code. Why is this important? + +Well, let's assume the role of Programmer A. They have made a project which is written in French Hedy code. They are satisfied with the project and publish it on GitHub. + +Here comes Programmer B, who likes A's project and downloads it, uses it and loves it. But, they have found a few bugs in the code! Sadly, they cannot fix the code as it is written in French Hedy, and they only know Hindi Hedy. + +As you can see, the language barrier has prevented the potential collaboration between two programmers. + +### So how *is* it different? + +Imagine a programming language, which: +- Can be written in one natural language syntax; +- Can be published in a natural-language-neutral intermediate syntax (QuickSyntax); +- Can be converted back to another natural language syntax; And, +- Can be converted to QuickSyntax again to publish! + +This means the natural language barrier is completely and utterly shattered! Yeah! + +## How? + +Well, this is still in a planning stage, but the structure should look like this: + +### The Syntax Checkers + +This includes the Lexer and Parser. There will be custom versions of these for each language, so that the translations are perfect. + +### The Converter + +This converts the Parsed nodes from/into QuickSyntax or serialized binaries. + +### The Interpreter + +The interpreter only interprets nodes that have been given to it. It does not know which language the source code is in. + +Of course, this is quite a high-level summary, and, again, this is only in the planning stage. diff --git a/docs/_config.yml b/docs/_config.yml index 09043a4..a39d559 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -5,6 +5,8 @@ markdown: kramdown encoding: UTF-8 author: Uralstech +exclude: ["offline/"] + remote_theme: just-the-docs/just-the-docs@v0.4.1 plugins: - jekyll-feed diff --git a/docs/index.markdown b/docs/index.markdown index 46e735b..3c1f5bc 100644 --- a/docs/index.markdown +++ b/docs/index.markdown @@ -1,14 +1,14 @@ --- layout: default title: The ezr² Programming Language -nav_order: 1 +nav_order: 2 --- # The `ezr²` Programming Language {: .no_toc } **ezr², or ezrSquared when you can't use the `²` symbol - is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#! -For more information check out the [*Introduction and Documentation page*](https://uralstech.github.io/ezrSquared/Introduction).** +For more information check out the [*Learn ezr²*](https://uralstech.github.io/ezrSquared/Learn-ezrSquared) page.**
@@ -21,61 +21,49 @@ For more information check out the [*Introduction and Documentation page*](https ## Advantages -- High-level -- Interpreted -- As close to "natural" language as possible while being practical +- As close to natural language as possible while being practical, with [***planned multilingual features***](https://uralstech.github.io/ezrSquared/Multilingual-ezrSquared) +- Easily extendible through C# Assisted ezr² Libraries - Easily embeddable -- Easily extensible through C# -- Free and open source -## Features (Existing and Planned) +## PC Installation -- Interactive shell -- Dynamic typing -- Object-oriented programming -- Error handling -- Rich set of operators -- Support for modules -- Support for C# through CSAELS -- Multiple paradigms -- Automatic memory management +To install ezr² on your PC, follow these steps: -## Installation +#### Windows (x86 and x64) -{: .warning } -**BEFORE YOU START CODING:** ezr² is still in **pre-release** status. That means **ezr² might get backwards-incompatible updates every now and then**. +* Download the appropriate installer from the [***GitHub Releases page***](https://github.com/uralstech/ezrSquared/releases), or, click on any of the download links. +* Run the installer and go through the installation. +

-Now, to install ezr² on your PC, follow these steps: +[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20(Windows%20x64)-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Installer.Windows.64-bit.exe) +[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20(Windows%20x86)-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Installer.Windows.32-bit.exe) -### Windows (32 and 64 bit) -{: .no_toc } +#### Linux (x64, ARM64 and ARM) -1. Download the latest release of ezr² (`ezrSquared.Installer.Windows.32-bit.exe` for 32-bit systems or `ezrSquared.Installer.Windows.64-bit.exe` for 64-bit systems) from [***GitHub***](https://github.com/Uralstech/ezrSquared/releases). -2. Run the installer and go through the installation. -3. Verify that ezr² is installed by running `ezrSquared` in a terminal - the ezr² biShell (built-in shell) should open (press Ctrl+C to exit). -4. Start coding! +* Download the appropriate `tar.xz` archive from the [***GitHub Releases page***](https://github.com/uralstech/ezrSquared/releases), or, click on any of the download links. +* Extract the `tar.xz` file to a folder of your choice. +* Optionally, add the folder to your PATH environment variable. +

-### Linux (64 bit) -{: .no_toc } +[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20(Linux%20x64)-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-x64.tar.gz) +[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20(Linux%20ARM64)-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-arm64.tar.gz) +[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20(Linux%20ARM)-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-arm.tar.gz) -1. Download the latest release of ezr² (`ezrSquared.Linux.tar.xz`) from [***GitHub***](https://github.com/Uralstech/ezrSquared/releases). -2. Extract the `tar.xz` file to a folder of your choice. -3. Add the folder to your PATH environment variable. -4. Verify that ezr² is installed by running `ezrSquared` in a terminal - the ezr² biShell (built-in shell) should open (press Ctrl+C to exit). -5. Start coding! +### Check the installation -### Android -{: .no_toc } +--- +* Run the `ezrSquared` command in a terminal (PowerShell, CMD, Bash, etc.) and the ezr² Shell should open. You can press Ctrl+C to exit. +* Start coding! -Check out [***ezr² Portable Interpreter on Google Play***](https://play.google.com/store/apps/details?id=com.Uralstech.ezrSquaredPortableInterpreter), an interpreter made with the help of -[***ezr² Net4.8***](https://github.com/Uralstech/ezrSquaredNet4.8) in [***Unity***](https://unity.com/)! +## Android Installation -### Other -{: .no_toc } +Download [***ezr² Portable Interpreter on Google Play***](https://play.google.com/store/apps/details?id=com.Uralstech.ezrSquaredPortableInterpreter). + +If you are interested in how ezr² was embedded to the portable interpreter (a Unity app), check out the [***C# and ezr² page***](https://uralstech.github.io/ezrSquared/CSharp-and-ezrSquared). -For other OSes you can clone the [***repository***](https://github.com/Uralstech/ezrSquared/), and compile your own build. If you're a contributor, feel free to add the build to the latest [***release***](https://github.com/Uralstech/ezrSquared/releases). +## Other Operating Systems -If you are interested in how ezr² was embedded to the portable interpreter, check out the [***C# in ezr² page***](https://uralstech.github.io/ezrSquared/CSAELs). +For other OSes you can clone the [***repository***](https://github.com/Uralstech/ezrSquared/), and compile your own build. If you're a contributor, feel free to add the build to the latest release. ## Usage @@ -83,45 +71,26 @@ An ezr² script has the extension `.ezr2`. To run an ezr² script, use the `ezrS ```cmd > ezrSquared hello.ezr2 -Use the "ezrSquared" command without any arguments to start the biShell: - -> ezrSquared -You can type any valid ezr² expression in the shell and see its result. ``` ## Documentation -The official documentation for ezr² is available in the [***Introduction and Documentation page***](https://uralstech.github.io/ezrSquared/Introduction), but is still **work in progress**. + +The official documentation for ezr² is available in the [***Learn ezr² page***](https://uralstech.github.io/ezrSquared/Learn-ezrSquared), but is still **work in progress**. Meanwhile, check out some example programs in [***GitHub***](https://github.com/Uralstech/ezrSquared/tree/master/Tests). The offline version of the ezrSquared website was made possible with [***Jekyll Offline***](https://github.com/dohliam/jekyll-offline). -The documentation is packaged with the Windows installer. For other OSes, download and extract `ezrSquared.Offline.Documentation.zip`, which is available for download with each release on GitHub. +The documentation is packaged with the Windows installer. For other OSes, download and extract the `zip` archive from [***GitHub Releases page***](https://github.com/uralstech/ezrSquared/releases), or, click on the link below: -## Latest Updates -**For those confused by the versioning: 1st place -> Major; 2nd place -> Feature; 3rd place -> Quality of Life; 4th place -> Library; 5th place -> Patch**. I plan to switch to [***Semantic Versioning 2.0.0***](https://semver.org/) for the first stable release. - -* **prerelease-1.5.1.3.0** - [03-05-23] - * Added new functions `get_window_size`, `set_window_size`, `get_window_position` and `set_window_position` - - to `Console` class in the IO library - * Function `set_buffer_size` in `Console` class in the IO library now uses the `SetBufferSize` C# function - -* **prerelease-1.5.1.2.0** - [01-04-23] - * Added new functions `get_buffer_size` and `set_buffer_size` to `Console` class in the IO library - * Unsupported functions in `Console` class in the IO library will now show new error if called - -* **prerelease-1.5.1.1.0** - [27-03-23] - * `Console.set_cursor_position` in the IO library now accepts two seperate integers +[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20Documentation-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Offline.Documentation.zip) -* **prerelease-1.5.1.0.1** - [25-03-23] - * Fixed bug in special function `equals` - -* **prerelease-1.5.1.0.0** - [23-03-23] - * "all" keyword and ',' symbol now interchangeable in normal and QuickSyntax `include` expressions +## Latest Updates -* **prerelease-1.5.0.0.0** - [21-03-23] - * More major changes to module/library system and `include` expression - * Context name of value-derived types now the name of the derived type +ezr² now uses [***Semantic Versioning 2.0.0***](https://semver.org/) for new releases. ezr² development updates will be posted on [***my blog***](https://uralstech.github.io/). ## Contributing + ezr² is an open source project and welcomes contributions from anyone who wants to improve it. If you want to contribute to ezr², please contact Uralstech at `info@uralstech.in`. + +The contribution requirements will be revamped for the full release. diff --git a/ezrSquared.sln b/ezrSquared.sln index abe7886..21f5bb8 100644 --- a/ezrSquared.sln +++ b/ezrSquared.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.4.33122.133 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EzrSquared", "src\EzrSquared.csproj", "{C2192D60-CF75-4781-B016-116E6709A76C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shell", "src\Shell\Shell.csproj", "{6F16EE16-DA61-47F9-9CAC-6E127A02DA2A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {C2192D60-CF75-4781-B016-116E6709A76C}.Debug|Any CPU.Build.0 = Debug|Any CPU {C2192D60-CF75-4781-B016-116E6709A76C}.Release|Any CPU.ActiveCfg = Release|Any CPU {C2192D60-CF75-4781-B016-116E6709A76C}.Release|Any CPU.Build.0 = Release|Any CPU + {6F16EE16-DA61-47F9-9CAC-6E127A02DA2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6F16EE16-DA61-47F9-9CAC-6E127A02DA2A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6F16EE16-DA61-47F9-9CAC-6E127A02DA2A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6F16EE16-DA61-47F9-9CAC-6E127A02DA2A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Icon.ico b/graphics/Icon.ico similarity index 100% rename from src/Icon.ico rename to graphics/Icon.ico diff --git a/samples/tic_tac_toe_demo.ezr2 b/samples/tic_tac_toe_demo.ezr2 index e45d01e..d6cc66c 100644 --- a/samples/tic_tac_toe_demo.ezr2 +++ b/samples/tic_tac_toe_demo.ezr2 @@ -1,42 +1,49 @@ -@ A demo for the ezr² programming language -@ https://github.com/Uralstech/ezrlang +@ A demo for the ezr² programming language +@ https://github.com/Uralstech/ezrSquared @ Main game matrix -item game: [["-", "-", "-"], - ["-", "-", "-"], - ["-", "-", "-"]] +game: [["-", "-", "-"], + ["-", "-", "-"], + ["-", "-", "-"]] @ Winning cases -item wins: [[["n", "n", "n"], - ["-", "-", "-"], - ["-", "-", "-"]], - [["-", "-", "-"], - ["n", "n", "n"], - ["-", "-", "-"]], - [["-", "-", "-"], - ["-", "-", "-"], - ["n", "n", "n"]], - [["n", "-", "-"], - ["n", "-", "-"], - ["n", "-", "-"]], - [["-", "n", "-"], - ["-", "n", "-"], - ["-", "n", "-"]], - [["-", "-", "n"], - ["-", "-", "n"], - ["-", "-", "n"]], - [["-", "-", "n"], - ["-", "n", "-"], - ["n", "-", "-"]], - [["n", "-", "-"], - ["-", "n", "-"], - ["-", "-", "n"]]] +wins: [[["n", "n", "n"], + ["-", "-", "-"], + ["-", "-", "-"]], + + [["-", "-", "-"], + ["n", "n", "n"], + ["-", "-", "-"]], + + [["-", "-", "-"], + ["-", "-", "-"], + ["n", "n", "n"]], + + [["n", "-", "-"], + ["n", "-", "-"], + ["n", "-", "-"]], + + [["-", "n", "-"], + ["-", "n", "-"], + ["-", "n", "-"]], + + [["-", "-", "n"], + ["-", "-", "n"], + ["-", "-", "n"]], + + [["-", "-", "n"], + ["-", "n", "-"], + ["n", "-", "-"]], + + [["n", "-", "-"], + ["-", "n", "-"], + ["-", "-", "n"]]] @ Function to show game matrix in more readable form function show_game do count to game.length as i do - item s: "" - count to (game <= i).length as j do item s: s + (game <= i <= j) + " " + s: "" + count to (game <= i).length as j do s: s + game <= i <= j + " " show(s) end @@ -44,18 +51,18 @@ end @ Function for checking if the game is over, and who has won function check_result do - item full: true + full: true count to wins.length as i do - item x_pts: 0 - item o_pts: 0 + x_pts: 0 + o_pts: 0 count to game.length as j do count to (game <= j).length as k do - if (((wins <= i) <= j) <= k) = "n" do - if ((game <= j) <= k) = "x" do item x_pts: x_pts + 1 - if ((game <= j) <= k) = "o" do item o_pts: o_pts + 1 + if wins <= i <= j <= k = "n" do + if game <= j <= k = "x" do x_pts: x_pts + 1 + if game <= j <= k = "o" do o_pts: o_pts + 1 end - if ((game <= j) <= k) = "-" do item full: false + if game <= j <= k = "-" do full: false end if x_pts >= 3 do @@ -71,12 +78,12 @@ end @ Function to register the players" current move function move_game with position, char do - item y: if position <= 3 do 0 else if position <= 6 do 1 else if position <= 9 do 2 else do -1 - item x: if position <= 3 do position - 1 else if position <= 6 do position - 4 else if position <= 9 do position - 7 else do -1 - if ((y < 0) or (x < 0)) or (position <= 0) do return "INVALID POSITION" - if ((game <= y) <= x) ! "-" do return "INVALID POSITION" + y: if position <= 3 do 0 else if position <= 6 do 1 else if position <= 9 do 2 else do -1 + x: if position <= 3 do position - 1 else if position <= 6 do position - 4 else if position <= 9 do position - 7 else do -1 + if (y < 0 or x < 0) or position <= 0 do return "INVALID POSITION" + if game <= y <= x ! "-" do return "INVALID POSITION" - item gamey : game <= y + gamey : game <= y gamey - x gamey.insert(x, char) @@ -92,27 +99,27 @@ show("\n") show_game() @ Main gameloop -item char: "x" +char: "x" while true do try do - item move: get(("Enter position (" + char) + ") ").as_integer() - error do + move: get(("Enter position (" + char) + ") ").as_integer() + catch do show("INVALID INPUT") skip end - item move: move_game(move, char) + move: move_game(move, char) if type_of(move) = "string" do show(move) skip else do - item game: move + game: move end show("\n") show_game() - item result: check_result() + result: check_result() if result = "1" do show("Draw!") stop @@ -124,5 +131,5 @@ while true do stop end - item char: if char = "x" do "o" else do "x" + char: if char = "x" do "o" else do "x" end \ No newline at end of file diff --git a/src/AccessMod.cs b/src/AccessMod.cs new file mode 100644 index 0000000..562687d --- /dev/null +++ b/src/AccessMod.cs @@ -0,0 +1,60 @@ +using System; + +namespace EzrSquared; + +/// +/// Accessibility modifiers for all defined scope. +/// +[Flags] +public enum AccessMod +{ + /// + /// Default value. + /// + None = 0, + + /// + /// Stand-in for a global scope. + /// + Global = 1, + + /// + /// Stand-in for a private scope. + /// + Private = 2, + + /// + /// Stand-in for a static scope. + /// + Static = 4, + + /// + /// Stand-in for a constant reference. + /// + Constant = 8, + + /// + /// Stand-in for a local-only scope. + /// + LocalScope = 16, + + /// + /// Stand-in for a global static scope. + /// + GlobalStatic = Global | Static, + + /// + /// Stand-in for a private constant scope. + /// + PrivateConstant = Private | Constant, + + /// + /// Stand-in for a private static constant scope. + /// + PrivateStaticConstant = Private | Static | Constant, + + /// + /// Stand-in for an INVALID global private scope. + /// + InvalidGlobalPrivate = Global | Private, +} diff --git a/src/AssemblyInfo.cs b/src/AssemblyInfo.cs deleted file mode 100644 index 26a4256..0000000 --- a/src/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyCompany("Uralstech")] -[assembly: AssemblyCopyright("Copyright 2022 - 2023 URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED.")] -[assembly: AssemblyProduct("ezrSquared")] - -[assembly: AssemblyVersion("0.1.0")] -[assembly: AssemblyFileVersion("0.1.0")] -[assembly: AssemblyInformationalVersion("0.1.0")] -[assembly: AssemblyTitle("ezrSquared")] -[assembly: AssemblyDescription("ezrSquared")] \ No newline at end of file diff --git a/src/AutoGeneratedAssemblyInfo.cs b/src/AutoGeneratedAssemblyInfo.cs deleted file mode 100644 index 8ae053f..0000000 --- a/src/AutoGeneratedAssemblyInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; -using System.Reflection; - -[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] - -// Generated by the MSBuild WriteCodeFragment class. - diff --git a/src/Directory.Build.props b/src/Directory.Build.props index bbc4966..71cef56 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,14 +1,6 @@ - true - false - false - false - false - false - false - false - false - D:\Code\csharp\ezrSquared\obj\ezrSquared\ + ..\Binaries\ezrSquared\ + ..\Intermediates\ezrSquared\ \ No newline at end of file diff --git a/src/Executor/CodeExecutor.cs b/src/Executor/CodeExecutor.cs new file mode 100644 index 0000000..16f0a8f --- /dev/null +++ b/src/Executor/CodeExecutor.cs @@ -0,0 +1,98 @@ +using EzrSquared.Runtime; +using EzrSquared.Runtime.Types.CSharpWrappers.Builtins; +using EzrSquared.Syntax; +using EzrSquared.Syntax.Errors; +using System; +using System.Collections.Generic; + +namespace EzrSquared.Executor; + +/// +/// Utility to execute ezr² code under one static interpreter. +/// +public static class CodeExecutor +{ + /// + /// The static interpreter. + /// + public static readonly Interpreter Interpreter = new(); + + /// + /// The runtime context, may be null. + /// + private static Context? s_runtimeContext; + + /// + /// Creates the runtime context. + /// + /// The file path to the code file this context will be used to execute. + public static void CreateRuntimeContext(string filePath) + { + s_runtimeContext = new Context($"<\"{filePath}\" context>", true, new Position(0, 0, filePath, string.Empty)); + } + + /// + /// Populates the runtime context with all built-ins. + /// + /// + /// Thrown if the runtime context is . + /// Use to initialize the runtime context. + /// + public static void PopulateRuntimeContext() + { + if (s_runtimeContext is null) + throw new NullReferenceException($"{nameof(s_runtimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); + + EzrBuiltinsUtility.AddBuiltinConstants(s_runtimeContext); + EzrBuiltinsUtility.AddBuiltinFunctions(s_runtimeContext); + EzrBuiltinsUtility.AddBuiltinTypes(s_runtimeContext); + } + + /// + /// Adds the given reference to the runtime context. + /// + /// + /// Thrown if the runtime context is . + /// Use to initialize the runtime context. + /// + /// The reference to add. + /// The name of the new symbol. + public static void AddToContext(Reference reference, string name) + { + if (s_runtimeContext is null) + throw new NullReferenceException($"{nameof(s_runtimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); + + s_runtimeContext.Set(null, name, reference); + } + + /// + /// Executes the given script. + /// + /// The script to execute. + /// + /// + /// Thrown if the runtime context is . + /// Use to initialize the runtime context. + /// + public static ExecutionResult Execute(string script) + { + if (s_runtimeContext is null) + throw new NullReferenceException($"{nameof(s_runtimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); + + // Tokenize the script. + SyntaxError? lexerError = new Lexer(s_runtimeContext.StartPosition.File, script).Tokenize(out List tokens); + if (lexerError is not null) // Check for errors. + return new ExecutionResult([.. tokens], lexerError); // Return tokens with lexing error. + + // Parse the tokens. + ParseResult parseResult = new Parser(tokens).Parse(); + if (parseResult.Error is not null) // Check for errors. + return new ExecutionResult([.. tokens], parseResult); // Return the tokens, with the parse error. + + // Interpret the Abstract Syntax Tree. + RuntimeResult result = Interpreter.Execute(parseResult.Node, s_runtimeContext); + + // Return result. + return new ExecutionResult([.. tokens], parseResult.Node, result); + } +} diff --git a/src/Executor/ExecutionResult.cs b/src/Executor/ExecutionResult.cs new file mode 100644 index 0000000..18f9ed4 --- /dev/null +++ b/src/Executor/ExecutionResult.cs @@ -0,0 +1,99 @@ +using EzrSquared.Runtime; +using EzrSquared.Runtime.Nodes; +using EzrSquared.Runtime.Types; +using EzrSquared.Syntax; +using EzrSquared.Syntax.Errors; + +namespace EzrSquared.Executor; + +/// +/// The result of a code execution operation. +/// +public class ExecutionResult +{ + /// + /// The tokens making up the executed script. + /// + public readonly Token[] Tokens; + + /// + /// Any error that occurred during lexing. + /// + public readonly SyntaxError? LexerError; + + /// + /// The Abstract Syntax Tree of the executed script. + /// + public readonly Node? Ast; + + /// + /// Any error that occurred during parsing. + /// + public readonly SyntaxError? ParseError; + + /// + /// The result of the execution. + /// + public readonly IEzrObject? Result; + + /// + /// Was the execution successful? + /// + public readonly bool Success; + + /// + /// Creates a new execution result, which failed at lexing. + /// + /// The tokens returned by the lexer. + /// The error. + public ExecutionResult(Token[] tokens, SyntaxError error) + { + Tokens = tokens; + LexerError = error; + + Success = false; + } + + /// + /// Creates a new execution result, which failed at parsing. + /// + /// The tokens returned by the lexer. + /// The parse result carrying the error. + public ExecutionResult(Token[] tokens, ParseResult result) + { + Tokens = tokens; + ParseError = result.Error; + + Success = false; + } + + /// + /// Creates a new execution result. + /// + /// The tokens returned by the lexer. + /// The executed AST node. + /// The runtime result carrying the result or error. + public ExecutionResult(Token[] tokens, Node ast, RuntimeResult result) + { + Tokens = tokens; + Ast = ast; + + Success = result.Error is null; + Result = Success ? result.Reference.Object : result.Error; + } + + /// + /// Returns the error message of the execution, be it a lexing, parsing or interpretation error. + /// + /// The error message. + public string GetErrorMessage() + { + return (Success, LexerError is not null, ParseError is not null) switch + { + (true, _, _) => string.Empty, + (false, true, _) => LexerError!.ToString(), + (false, false, true) => ParseError!.ToString(), + _ => Result!.ToPureString(CodeExecutor.Interpreter.RuntimeResult), + }; + } +} diff --git a/src/EzrCommon.cs b/src/EzrCommon.cs deleted file mode 100644 index 672bca5..0000000 --- a/src/EzrCommon.cs +++ /dev/null @@ -1,257 +0,0 @@ -namespace EzrSquared.EzrCommon -{ - /// - /// The representation of a position in the script. - /// - public class Position - { - /// - /// The index of the in the script. - /// - public int Index; - - /// - /// The line number of the in the script. - /// - public int Line; - - /// - /// The file name/path of the script. - /// - public readonly string File; - - /// - /// The script as text. - /// - public readonly string Script; - - /// - /// Creates a new object. - /// - /// The index of the in the script. - /// The line number of the in the script. - /// The file name/path of the script. - /// The script as text. - public Position(int index, int line, string file, string script) - { - Index = index; - Line = line; - File = file; - Script = script; - } - - /// - /// Advances the and increments by 1. If is a new-line character, is also incremented by 1. - /// - /// The character associated with the before advancing. - public void Advance(char currentChar) - { - Index++; - - if (currentChar == '\n') - Line++; - } - - - /// - /// Advances the and increments by 1. - /// - public void Advance() - { - Index++; - } - - /// - /// Creates a copy of the object. - /// - /// The copy. - public Position Copy() - { - return new Position(Index, Line, File, Script); - } - } - - /// - /// The type group of a . - /// - public enum TokenTypeGroup : ushort - { - Value, - Keyword, - Qeyword, - AssignmentSymbol, - Symbol, - Special - } - - /// - /// The identifying type of a . - /// - public enum TokenType : ushort - { - // Values - Integer, - FloatingPoint, - String, - Character, - CharacterList, - - // Keywords - KeywordAnd, - KeywordOr, - KeywordInvert, - KeywordNot, - KeywordIn, - KeywordGlobal, - KeywordItem, - KeywordIf, - KeywordElse, - KeywordCount, - KeywordFrom, - KeywordTo, - KeywordStep, - KeywordAs, - KeywordWhile, - KeywordSkip, - KeywordStop, - KeywordFunction, - KeywordSpecial, - KeywordObject, - KeywordWith, - KeywordReturn, - KeywordTry, - KeywordError, - KeywordDo, - KeywordEnd, - KeywordInclude, - KeywordAll, - - // Qeywords - QeywordF, - QeywordL, - QeywordE, - QeywordC, - QeywordT, - QeywordN, - QeywordW, - QeywordFD, - QeywordSD, - QeywordOD, - QeywordI, - QeywordS, - QeywordD, - QeywordG, - QeywordV, - - // Symbols - Plus, - HyphenMinus, - Asterisk, - Slash, - PercentSign, - Caret, - Ampersand, - VerticalBar, - Backslash, - Tilde, - LeftParenthesis, - RightParenthesis, - LeftSquareBracket, - RightSquareBracket, - LeftCurlyBracket, - RightCurlyBracket, - EqualSign, - ExclamationMark, - LessThanSign, - GreaterThanSign, - Comma, - Period, - BitwiseLeftShift, - BitwiseRightShift, - LessThanOrEqual, - GreaterThanOrEqual, - Arrow, - - // Assignment symbols - Colon, - AssignmentAddition, - AssignmentSubtraction, - AssignmentMultiplication, - AssignmentDivision, - AssignmentModulo, - AssignmentPower, - AssignmentBitwiseAnd, - AssignmentBitwiseOr, - AssignmentBitwiseXOr, - AssignmentBitwiseLeftShift, - AssignmentBitwiseRightShift, - - // Special - Identifier, - NewLine, - EndOfFile, - Invalid - } - - /// - /// The smallest component in the script identified by the , grouped together into objects to from source code constructs. - /// - public class Token - { - /// - /// The identifying of the . - /// - public readonly TokenType Type; - - /// - /// The of the . - /// - public readonly TokenTypeGroup TypeGroup; - - /// - /// The value of the ; may be empty. - /// - public readonly string Value; - - /// - /// The starting of the in the script. - /// - public readonly Position StartPosition; - - /// - /// The ending of the in the script. - /// - public readonly Position EndPosition; - - public static readonly Token Dummy = new Token(TokenType.Invalid, TokenTypeGroup.Special, string.Empty, new Position(int.MinValue, int.MinValue, string.Empty, string.Empty)); - - /// - /// Creates a new object. - /// - /// The identifying of the . - /// The of the . - /// The value of the ; may be empty. - /// The starting of the in the script. - /// The ending of the in the script. If not given, copies and advances it. - public Token(TokenType type, TokenTypeGroup typeGroup, string value, Position startPosition, Position? endPosition = null) - { - Type = type; - TypeGroup = typeGroup; - Value = value; - - StartPosition = startPosition; - if (endPosition is not null) - EndPosition = endPosition; - else - { - EndPosition = startPosition.Copy(); - EndPosition.Advance(); - } - } - - public override string ToString() - { - return $"Token({Type}, {TypeGroup}, \"{Value}\")"; - } - } -} \ No newline at end of file diff --git a/src/EzrErrors.cs b/src/EzrErrors.cs deleted file mode 100644 index 803a794..0000000 --- a/src/EzrErrors.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System.Text; - -namespace EzrSquared.EzrErrors -{ - using EzrCommon; - - /// - /// The base of all other, more specific, error classes. - /// - public abstract class Error - { - /// - /// The name of the . - /// - internal readonly string _title; - - /// - /// The reason why the occurred. - /// - internal readonly string _details; - - /// - /// The starting of the . - /// - internal readonly Position _startPosition; - - /// - /// The ending of the . - /// - internal readonly Position _endPosition; - - /// - /// Creates a new object. - /// - /// The title of the . - /// The reason why the occurred. - /// The starting of the . - /// The ending of the . - public Error(string title, string details, Position startPosition, Position endPosition) - { - _title = title; - _details = details; - _startPosition = startPosition; - _endPosition = endPosition; - } - - /// - /// Creates the formatted text representation of the . - /// - /// The formatted text. - public override string ToString() - { - return $"{_title} in {_startPosition.File}, line {_startPosition.Line}: {_details}\n{StringWithUnderline()}"; - } - - /// - /// Creates formatted text which contains the text between and , underlined with tilde symbols. - /// - /// The formatted text. - internal string StringWithUnderline() - { - string text = _startPosition.Script; - int start; - int end; - - int indexOfLastNewLine = text[0..((_startPosition.Index < text.Length) ? _startPosition.Index : text.Length)].LastIndexOf('\n'); - if (indexOfLastNewLine != -1) - start = indexOfLastNewLine; - else - start = 0; - - while (char.IsWhiteSpace(text[start]) && start < text.Length - 1) - start++; - - end = text.IndexOf('\n', start + 1); - if (end == -1) - end = text.Length; - - return new StringBuilder(" ") - .Append(text[start..end]) - .Append('\n') - .Append(' ', (_startPosition.Index - start) + 2) - .Append('~', _endPosition.Index - _startPosition.Index) - .ToString(); - } - } - - /// - /// The returned when an unknown character is identified in the script. - /// - internal class UnexpectedCharacterError : Error - { - /// - /// Creates a new object. - /// - /// The character that caused the . - /// The starting of the . - /// The ending of the . - public UnexpectedCharacterError(char character, Position startPosition, Position endPosition) : base("Unexpected character", $"{character}", startPosition, endPosition) { } - } - - /// - /// The returned when an invalid hexadecimal value is identified in the script. - /// - internal class InvalidHexValueError : Error - { - /// - /// Creates a new object. - /// - /// The reason why the occurred. - /// The starting of the . - /// The ending of the . - public InvalidHexValueError(string details, Position startPosition, Position endPosition) : base("Invalid hexadecimal value", details, startPosition, endPosition) { } - } - - /// - /// The returned when invalid code syntax is identified in the script. - /// - internal class InvalidGrammarError : Error - { - /// - /// Creates a new object. - /// - /// The reason why the occurred. - /// The starting of the . - /// The ending of the . - public InvalidGrammarError(string details, Position startPosition, Position endPosition) : base("Invalid grammar", details, startPosition, endPosition) { } - } - - /// - /// The returned when multiple objects need to be returned to the user. - /// - internal class StackedError : Error - { - /// - /// Creates a new object. - /// - /// The 'parent' error, or the error that occurred first. - /// The 'child' error, or the error that occurred because of the . - public StackedError(Error parent, Error child) : base("Multiple errors", string.Join("\n\nDue to the above error, another one occurred:\n", new Error[2] { parent, child }), parent._startPosition, parent._endPosition) { } - - /// - /// Creates the formatted text representation of the , which shows all child objects as the 'details'. - /// - /// The formatted text. - public override string ToString() - { - return _details; - } - } -} \ No newline at end of file diff --git a/src/EzrGrammar.txt b/src/EzrGrammar.txt index 6e46b53..c3927af 100644 --- a/src/EzrGrammar.txt +++ b/src/EzrGrammar.txt @@ -1,114 +1,126 @@ -ezrSquared syntax +ezr² syntax ================= Definitions ----------- -'\n' : new line or semicolon character -| : or -+ : can have more than one instance of -? : optional -'' : symbol(s) -"" : qeyword or keyword -[] : not structure -; : comment +'\n' : new line or semicolon character +| : or ++ : can have more than one instance of +? : optional +'' : symbol(s) +"" : qeyword or keyword +[] : not structure +@ : comment Structures ---------- -; 'statements' structures can contain multiple 'statement' structures +@ 'statements' structures can contain multiple 'statement' structures statements: statement - | (statement '\n')+ + | statement ('\n'+ statement?)+ -; 'statement' structures can contain return, skip or stop expressions or 'expression' structures +@ 'statement' structures can contain return, skip or stop expressions or 'expression' structures statement: - "return" expression? + "return" ("last"? expression)? | "skip" | "stop" | expression - -; 'expression' structures can contain item definition expressions or 'quick-expression' structures + +@ 'variable-identifier' structures contain the syntactic sugar required for the identifier of a variable in a variable definition expression +@ This is _not_ a structure defined in code and is only used for simplification _in this file_. +variable-identifier: + [identifier] + | [qeyword] + | junction @ Only if the structure starts with an [identifier] or [qeyword]. + +@ 'expression' structures can contain item definition expressions or 'quick-expression' structures expression: - "global"? "item"? (([identifier] | [qeyword]) | comparison) (':' | ':+' | ':-' | ':*' | ':/' | ':%' | ':^' | ':&' | ':|' | ':\' | ':<' | ':>') expression + ("global" | "private")? "static"? "constant"? "item"? (('(' variable-identifier (',' variable-identifier)+? ')') | variable-identifier) (':' | ':+' | ':-' | ':*' | ':/' | ':%' | ':^' | ':&' | ':|' | ':\' | ':<' | ':>') expression | quick-expression -; 'quick-expression' structures can contain QuickSyntax item definition expressions or 'junction' structures +@ 'quick-expression' structures can contain QuickSyntax item definition expressions or 'junction' structures quick-expression: - '!' "g"? "d"? (([identifier] | [qeyword]) | junction) (':' | ':+' | ':-' | ':*' | ':/' | ':%' | ':^' | ':&' | ':|' | ':\' | ':<' | ':>') expression + '!' ("g" | "p")? "c"? "d"? (('(' variable-identifier (',' variable-identifier)+? ')') | variable-identifier) (':' | ':+' | ':-' | ':*' | ':/' | ':%' | ':^' | ':&' | ':|' | ':\' | ':<' | ':>') expression | junction -; 'junction' structures can contain 'and' or 'or' comparison expressions or 'inversion' structures +@ 'junction' structures can contain 'and' or 'or' comparison expressions or 'inversion' structures junction: inversion ("and" | "or") inversion | inversion -; 'inversion' structures can contain inversion expressions or 'comparison' structures +@ 'inversion' structures can contain inversion expressions or 'contains-check' structures inversion: - '!' "v" expression - | "invert" expression + '!' "v" inversion + | ("invert" | "not") inversion + | contains-check + +@ 'contains-check' structures can contain is-contained-in, not-contained-in comparison expressions or 'comparison' structures +contains-check: + comparison (("not" "in" | "in") comparison)+ | comparison -; 'comparison' structures can contain equality, inequality, lesser than, greater than, lesser than or equality, greater than or equality, -; is-contained-in or not-contained-in comparison expressions or 'bitwise-or' structures +@ 'comparison' structures can contain equality, inequality, lesser than, greater than, lesser than or equality, +@ greater than or equality or 'bitwise-or' structures comparison: - bitwise-or ('=' | '!' | '<' | '>' | '<=' | '>=' | "not" "in" | "in") bitwise-or + bitwise-or (('=' | '!' | '<' | '>' | '<=' | '>=') bitwise-or)+ | bitwise-or -; 'bitwise-or' structures can contain bitwise-or expressions or 'bitwise-xor' structures +@ 'bitwise-or' structures can contain bitwise-or expressions or 'bitwise-xor' structures bitwise-or: - bitwise-xor '|' bitwise-xor + bitwise-xor ('|' bitwise-xor)+ | bitwise-xor -; 'bitwise-xor' structures can contain bitwise-xor expressions or 'bitwise-and' structures +@ 'bitwise-xor' structures can contain bitwise-xor expressions or 'bitwise-and' structures bitwise-xor: - bitwise-and '\' bitwise-and + bitwise-and ('\' bitwise-and)+ | bitwise-and -; 'bitwise-and' structures can contain bitwise-and expressions or 'bitwise-shift' structures +@ 'bitwise-and' structures can contain bitwise-and expressions or 'bitwise-shift' structures bitwise-and: - bitwise-shift '&' bitwise-shift + bitwise-shift ('&' bitwise-shift)+ | bitwise-shift -; 'bitwise-shift' structures can contain bitwise-left-shift or bitwise-right-shift expressions or 'arithmetic-expression' structures +@ 'bitwise-shift' structures can contain bitwise-left-shift or bitwise-right-shift expressions or 'arithmetic-expression' structures bitwise-shift: - arithmetic-expression ('<<' | '>>') arithmetic-expression + arithmetic-expression (('<<' | '>>') arithmetic-expression)+ | arithmetic-expression -; 'arithmetic-expression' structures can contain addition or subtraction expressions or 'term' structures +@ 'arithmetic-expression' structures can contain addition or subtraction expressions or 'term' structures arithmetic-expression: - term ('+' | '-') term + term (('+' | '-') term)+ | term -; 'term' structures can contain multiplication, division or modulus expressions or 'factor' structures +@ 'term' structures can contain multiplication, division or modulus expressions or 'factor' structures term: - factor ('*' | '/' | '%') factor + factor (('*' | '/' | '%') factor)+ | factor -; 'factor' structures can contain positive, negative or bitwise-inversion unary expressions or 'power' structures +@ 'factor' structures can contain positive, negative or bitwise-inversion unary expressions or 'power' structures factor: ('+' | '-' | '~') factor | power -; 'power' structures can contain power expression or 'object-attribute-access' structures +@ 'power' structures can contain power expression or 'object-attribute-access' structures power: - object-attribute-access '^' object-attribute-access + object-attribute-access ('^' object-attribute-access)+ | object-attribute-access - -; 'object-attribute-access' structures can contain object attribute access expressions or 'call' structures + +@ 'object-attribute-access' structures can contain object attribute access expressions or 'call' structures object-attribute-access: - call '.' object-attribute-access + call ('.' call)+ | call -; 'call' structures can contain function/object creation call expressions or 'atom' structures +@ 'call' structures can contain function/object instance creation call expressions or 'atom' structures call: atom '(' '\n'+? (expression '\n'+? (',' '\n'+? expression '\n'+?)+?)? ')' | atom -; 'atom' structures can contain literal value definition, variable access, parenthetical, array definition, list definition, dictionary definition expressions and 'if-expression' structures +@ 'atom' structures can contain literal value definition, variable access, parenthetical, array definition, list definition, dictionary definition expressions and 'if-expression' structures atom: ([integer] | [floating point] | [string] | [character] | [character list]) - | "global"? ([identifier] | [qeyword]) + | "global"? "static"? ([identifier] | [qeyword]) | '(' '\n'+? expression '\n'+? ')' | '(' '\n'+? (expression '\n'+? ',' '\n'+? (expression '\n'+? (',' '\n'+? expression '\n'+?)+?)?)? ')' | '[' '\n'+? (expression '\n'+? (',' '\n'+? expression '\n'+?)+?)? ']' @@ -118,40 +130,44 @@ atom: | while-expression | try-expression | function-definition-expression - | object-definition-expression + | class-definition-expression | include-expression + | define-block-expression -; 'if-expression' structures contain declarations of conditional if-else-if-else expressions. +@ 'if-expression' structures contain declarations of conditional if-else-if-else expressions. if-expression: "if" expression "do" statements ("else" "if" expression "do" statements)+? ("else" "do" statements)? "end" | "if" expression "do" statement ("else" "if" expression "do" statement)+? ("else" "do" statement)? -; 'count-expression' structures contain declarations of count loops, which are like for loops in C#. +@ 'count-expression' structures contain declarations of count loops, which are like for loops in C#. count-expression: "count" ("from" expression)? "to" expression ("step" expression)? ("as" expression)? "do" statements "end" | "count" ("from" expression)? "to" expression ("step" expression)? ("as" expression)? "do" statement -; 'while-expression' structures contain declarations of while loops. +@ 'while-expression' structures contain declarations of while loops. while-expression: - "while" expression "do" statements "end" - | "while" expression "do" statement + "while" expression "do" ((statements "end") | statement) -; 'try-expression' structures contain declarations of try-error blocks, which are like try-catch blocks in C#. +@ 'try-expression' structures contain declarations of try-catch blocks, which are like try-catch blocks in C#. try-expression: - "try" "do" statements ("error" expression ("as" expression)? "do" statements)+? ("error" ("as" expression)? "do" statements)? "end" - | "try" "do" statement ("error" expression ("as" expression)? "do" statement)+? ("error" ("as" expression)? "do" statement)? + "try" "do" statements ("catch" expression ("as" expression)? "do" statements)+? ("catch" ("as" expression)? "do" statements)? "end" + | "try" "do" statement ("catch" expression ("as" expression)? "do" statement)+? ("catch" ("as" expression)? "do" statement)? -; 'function-definition-expression' structures contain declarations of functions. +@ 'function-definition-expression' structures contain declarations of functions. function-definition-expression: - "function" expression? ("with" expression (',' expression)+?)? "do" statements "end" - | "function" expression? ("with" expression (',' expression)+?)? "do" statement + ("global" | "private")? "static"? "constant"? "function" expression? ("with" (expression (',' expression)+?)? ("more" "as" expression))? "do" ((statements "end") | statement) -; 'object-definition-expression' structures contain declarations of objects. -object-definition-expression: - "object" expression? ("with" expression (',' expression)+?)? ("from" expression (',' expression)+?)? "do" statements "end" - | "object" expression? ("with" expression (',' expression)+?)? ("from" expression (',' expression)+?)? "do" statement +@ 'class-definition-expression' structures contain declarations of classes. +class-definition-expression: + ("global" | "private")? "static"? "constant"? "readonly"? "object" expression? ("from" expression (',' expression)+?)? "do" ((statements "end") | statement) -; 'include-expression' structures contain declarations of include expressions, which are like using statements in C#. +@ 'include-expression' structures contain declarations of include expressions, which are like using statements in C#. include-expression: "include" expression ("as" expression)? - | "include" expression "from" expression ("as" expression)? \ No newline at end of file + | "include" expression "from" expression ("as" expression)? + +@ 'define-block-expression' structures contain declarations of define blocks, which allow the user to define multiple variables, functions, objects, etc. with the same accessibility modifiers. +define-block-expression: + "define" ("global" | "private") "static"? "constant"? statements "end" + | "define" "static" "constant"? statements "end" + | "define" "constant" statements "end" \ No newline at end of file diff --git a/src/EzrLexer.cs b/src/EzrLexer.cs deleted file mode 100644 index 5f40566..0000000 --- a/src/EzrLexer.cs +++ /dev/null @@ -1,602 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace EzrSquared.EzrLexer -{ - using EzrCommon; - using EzrErrors; - - /// - /// The ezrSquared Lexer or Tokenizer. The job of the Lexer is to convert the user input (code) into objects to be given as the input to the . - /// - public class Lexer - { - /// - /// The file name/path of the script. - /// - private readonly string _file; - - /// - /// The script to be tokenized. - /// - private readonly string _script; - - /// - /// The of the current lexing iteration in the script. - /// - private Position _position; - - /// - /// The character in the of the current lexing iteration in the script. - /// - private char _currentChar; - - /// - /// The value for checking if the has reached the end of the script. - /// - private bool _reachedEndFlag; - - /// - /// Creates a new object. - /// - /// The file name/path of the script. - /// The script to be tokenized. - public Lexer(string file, string script) - { - _file = file; - _script = script; - _position = new Position(-1, 1, _file, _script); - _currentChar = char.MinValue; - Advance(); - } - - /// - /// Advances the current in the script. - /// - private void Advance() - { - _position.Advance(_currentChar); - - if (_script.Length > _position.Index) - _currentChar = _script[_position.Index]; - else - _reachedEndFlag = true; - } - - /// - /// Creates a of objects from the given script. - /// - /// The created of objects. - /// Any that occurred in the lexing; if none occurred. - public Error? Tokenize(out List tokens) - { - Error? error; - tokens = new List(); - while (!_reachedEndFlag) - { - switch (_currentChar) - { - case '\r': - case '\t': - case ' ': - Advance(); - break; - case ';': - case '\n': - tokens.Add(CompileNewLines()); - break; - case '@': - do - { - Advance(); - } while (!_reachedEndFlag && _currentChar != '\n'); - break; - case '"': - tokens.Add(CompileStringLike(_currentChar, TokenType.String, out error)); - if (error is not null) - return error; - break; - case '`': - tokens.Add(CompileStringLike(_currentChar, TokenType.Character, out error)); - if (error is not null) - return error; - break; - case '\'': - tokens.Add(CompileStringLike(_currentChar, TokenType.CharacterList, out error)); - if (error is not null) - return error; - break; - case ':': - tokens.Add(CompileColon()); - break; - case '<': - Position lessThanTokenStartPosition = _position.Copy(); - Advance(); - - if (_currentChar == '=') - { - Advance(); - tokens.Add(new Token(TokenType.LessThanOrEqual, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); - } - else if (_currentChar == '<') - { - Advance(); - tokens.Add(new Token(TokenType.BitwiseLeftShift, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); - } - else - tokens.Add(new Token(TokenType.LessThanSign, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); - break; - case '>': - Position greaterThanTokenStartPosition = _position.Copy(); - Advance(); - - if (_currentChar == '=') - { - Advance(); - tokens.Add(new Token(TokenType.GreaterThanOrEqual, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); - } - else if (_currentChar == '>') - { - Advance(); - tokens.Add(new Token(TokenType.BitwiseRightShift, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); - } - else - tokens.Add(new Token(TokenType.GreaterThanSign, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); - break; - case '-': - Position minusTokenStartPosition = _position.Copy(); - Advance(); - - if (_currentChar == '>') - { - Advance(); - tokens.Add(new Token(TokenType.Arrow, TokenTypeGroup.Symbol, string.Empty, minusTokenStartPosition, _position.Copy())); - } - else - tokens.Add(new Token(TokenType.HyphenMinus, TokenTypeGroup.Symbol, string.Empty, minusTokenStartPosition, _position.Copy())); - break; - case '+': - tokens.Add(new Token(TokenType.Plus, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '*': - tokens.Add(new Token(TokenType.Asterisk, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '/': - tokens.Add(new Token(TokenType.Slash, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '%': - tokens.Add(new Token(TokenType.PercentSign, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '^': - tokens.Add(new Token(TokenType.Caret, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '=': - tokens.Add(new Token(TokenType.EqualSign, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '!': - tokens.Add(new Token(TokenType.ExclamationMark, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case ',': - tokens.Add(new Token(TokenType.Comma, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '.': - tokens.Add(new Token(TokenType.Period, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '(': - tokens.Add(new Token(TokenType.LeftParenthesis, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case ')': - tokens.Add(new Token(TokenType.RightParenthesis, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '[': - tokens.Add(new Token(TokenType.LeftSquareBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case ']': - tokens.Add(new Token(TokenType.RightSquareBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '{': - tokens.Add(new Token(TokenType.LeftCurlyBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '}': - tokens.Add(new Token(TokenType.RightCurlyBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '&': - tokens.Add(new Token(TokenType.Ampersand, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '|': - tokens.Add(new Token(TokenType.VerticalBar, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '\\': - tokens.Add(new Token(TokenType.Backslash, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - case '~': - tokens.Add(new Token(TokenType.Tilde, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); - Advance(); - break; - default: - if (char.IsLetter(_currentChar) || _currentChar == '_') - { - tokens.Add(CompileIdentifier()); - break; - } - else if (char.IsDigit(_currentChar)) - { - StringBuilder numberValue = new StringBuilder(); - Position numberTokenStartPosition = _position.Copy(); - bool hasPeriod = false; - - while (!_reachedEndFlag && (char.IsDigit(_currentChar) || _currentChar == '.')) - { - if (_currentChar == '.') - { - int peekIndex = _position.Index + 1; - char next = (peekIndex < _script.Length) ? _script[peekIndex] : '\0'; - - if (hasPeriod || !char.IsDigit(next)) - break; - hasPeriod = true; - } - - numberValue.Append(_currentChar); - Advance(); - } - - if (hasPeriod) - tokens.Add(new Token(TokenType.FloatingPoint, TokenTypeGroup.Value, numberValue.ToString(), numberTokenStartPosition, _position.Copy())); - else - tokens.Add(new Token(TokenType.Integer, TokenTypeGroup.Value, numberValue.ToString(), numberTokenStartPosition, _position.Copy())); - break; - } - else - { - Position errorStartPosition = _position.Copy(); - char unknownCharacter = _currentChar; - Advance(); - - return new UnexpectedCharacterError(unknownCharacter, errorStartPosition, _position); - } - } - } - - tokens.Add(new Token(TokenType.EndOfFile, TokenTypeGroup.Special, string.Empty, _position.Copy())); - return null; - } - - /// - /// Goes through newline characters and creates a single object with . - /// - /// The object. - private Token CompileNewLines() - { - Position startPosition = _position.Copy(); - while ((char.IsWhiteSpace(_currentChar) || _currentChar == '\r' || _currentChar == ';') && !_reachedEndFlag) - { - Advance(); - - if (_currentChar == '@') - { - do - { - Advance(); - } while (!_reachedEndFlag && _currentChar != '\n'); - } - } - - return new Token(TokenType.NewLine, TokenTypeGroup.Special, string.Empty, startPosition, _position.Copy()); - } - - /// - /// Creates a stringlike type (, , ) object. - /// - /// The value to enclose the stringlike. - /// The identifying of the . - /// Any that occurred in creating the stringlike; if none occurred. - /// The created . - private Token CompileStringLike(char enclosingChar, TokenType type, out Error? error) - { - error = null; - - StringBuilder toReturn = new StringBuilder(); - Position startPosition = _position.Copy(); - bool escapeChar = false; - bool countingUTF16 = false; - bool countingUTF32 = false; - int UTFCount = 0; - string hexValue = string.Empty; - Position hexStartPosition = startPosition; - Advance(); - - while (!_reachedEndFlag && (_currentChar != enclosingChar || escapeChar || countingUTF16 || countingUTF32)) - { - if (countingUTF16) - { - if ((_currentChar >= 'a' && _currentChar <= 'f') || (_currentChar >= 'A' && _currentChar <= 'F') || (_currentChar >= '0' && _currentChar <= '9')) - { - UTFCount++; - hexValue += _currentChar; - } - else - { - Position endPosition = _position.Copy(); - endPosition.Advance(); - - error = new InvalidHexValueError("UTF-16 hexadecimal values must be 4 characters long and only contain digits and/or the letters A to F", hexStartPosition, endPosition); - break; - } - - if (UTFCount >= 4) - { - toReturn.Append(Encoding.Unicode.GetChars(new byte[2] { Convert.ToByte(hexValue[2..4], 16), Convert.ToByte(hexValue[0..2], 16) })); - countingUTF16 = false; - } - } - else if (countingUTF32) - { - if ((_currentChar >= 'a' && _currentChar <= 'f') || (_currentChar >= 'A' && _currentChar <= 'F') || (_currentChar >= '0' && _currentChar <= '9')) - { - UTFCount++; - hexValue += _currentChar; - } - else - { - Position endPosition = _position.Copy(); - endPosition.Advance(); - - error = new InvalidHexValueError("UTF-32 hexadecimal values must be 6 characters long and only contain digits and/or the letters A to F", hexStartPosition, endPosition); - break; - } - - if (UTFCount >= 6) - { - if (Convert.ToInt32(hexValue, 16) > 1114111) - { - Position endPosition = _position.Copy(); - endPosition.Advance(); - - error = new InvalidHexValueError("UTF-32 hexadecimal values must be in range 000000 - 10FFFF", hexStartPosition, endPosition); - break; - } - else - toReturn.Append(Encoding.UTF32.GetChars(new byte[4] { Convert.ToByte(hexValue[4..6], 16), Convert.ToByte(hexValue[2..4], 16), Convert.ToByte(hexValue[0..2], 16), 0 })); - countingUTF32 = false; - } - } - else if (escapeChar) - { - switch (_currentChar) - { - case 'u': - hexValue = string.Empty; - countingUTF16 = true; - - hexStartPosition = _position.Copy(); - hexStartPosition.Advance(); - break; - case 'U': - hexValue = string.Empty; - countingUTF32 = true; - - hexStartPosition = _position.Copy(); - hexStartPosition.Advance(); - break; - case 'n': - toReturn.Append('\n'); - break; - case 't': - toReturn.Append('\t'); - break; - case 'b': - toReturn.Append('\b'); - break; - case 'r': - toReturn.Append('\r'); - break; - case '0': - toReturn.Append('\0'); - break; - case 'f': - toReturn.Append('\f'); - break; - case 'v': - toReturn.Append('\v'); - break; - default: - toReturn.Append(_currentChar); - break; - } - - escapeChar = false; - } - else if (_currentChar == '\\') - escapeChar = true; - else - toReturn.Append(_currentChar); - - Advance(); - } - - if (_reachedEndFlag || _currentChar != enclosingChar) - error = new InvalidGrammarError($"Expected '{enclosingChar}'", _position.Copy(), _position); - - Advance(); - return new Token(type, TokenTypeGroup.Value, toReturn.ToString(), startPosition, _position.Copy()); - } - - /// - /// Creates and assignment type (, , etc) objects. - /// - /// The created . - private Token CompileColon() - { - Position startPosition = _position.Copy(); - Advance(); - - switch (_currentChar) - { - case '+': - Advance(); - return new Token(TokenType.AssignmentAddition, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - case '-': - Advance(); - return new Token(TokenType.AssignmentSubtraction, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - case '*': - Advance(); - return new Token(TokenType.AssignmentMultiplication, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - case '/': - Advance(); - return new Token(TokenType.AssignmentDivision, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - case '%': - Advance(); - return new Token(TokenType.AssignmentModulo, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - case '^': - Advance(); - return new Token(TokenType.AssignmentPower, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - case '&': - Advance(); - return new Token(TokenType.AssignmentBitwiseAnd, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - case '|': - Advance(); - return new Token(TokenType.AssignmentBitwiseOr, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - case '\\': - Advance(); - return new Token(TokenType.AssignmentBitwiseXOr, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - case '<': - Advance(); - return new Token(TokenType.AssignmentBitwiseLeftShift, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - case '>': - Advance(); - return new Token(TokenType.AssignmentBitwiseRightShift, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - default: - return new Token(TokenType.Colon, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); - } - } - - /// - /// Creates , keyword type (, , etc) and qeyword type (, , etc) objects. - /// - /// The created . - private Token CompileIdentifier() - { - Position startPosition = _position.Copy(); - StringBuilder idValue = new StringBuilder(); - - while (!_reachedEndFlag && (char.IsLetterOrDigit(_currentChar) || _currentChar == '_')) - { - idValue.Append(_currentChar); - Advance(); - } - - string value = idValue.ToString(); - switch (value) - { - case "item": - return new Token(TokenType.KeywordItem, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "and": - return new Token(TokenType.KeywordAnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "or": - return new Token(TokenType.KeywordOr, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "invert": - return new Token(TokenType.KeywordInvert, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "if": - return new Token(TokenType.KeywordIf, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "else": - return new Token(TokenType.KeywordElse, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "do": - return new Token(TokenType.KeywordDo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "count": - return new Token(TokenType.KeywordCount, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "from": - return new Token(TokenType.KeywordFrom, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "as": - return new Token(TokenType.KeywordAs, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "to": - return new Token(TokenType.KeywordTo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "step": - return new Token(TokenType.KeywordStep, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "while": - return new Token(TokenType.KeywordWhile, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "function": - return new Token(TokenType.KeywordFunction, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "special": - return new Token(TokenType.KeywordSpecial, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "with": - return new Token(TokenType.KeywordWith, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "end": - return new Token(TokenType.KeywordEnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "return": - return new Token(TokenType.KeywordReturn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "skip": - return new Token(TokenType.KeywordSkip, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "stop": - return new Token(TokenType.KeywordStop, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "try": - return new Token(TokenType.KeywordTry, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "error": - return new Token(TokenType.KeywordError, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "not": - return new Token(TokenType.KeywordNot, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "in": - return new Token(TokenType.KeywordIn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "object": - return new Token(TokenType.KeywordObject, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "global": - return new Token(TokenType.KeywordGlobal, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "include": - return new Token(TokenType.KeywordInclude, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "all": - return new Token(TokenType.KeywordAll, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()); - case "f": - return new Token(TokenType.QeywordF, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "l": - return new Token(TokenType.QeywordL, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "e": - return new Token(TokenType.QeywordE, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "c": - return new Token(TokenType.QeywordC, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "t": - return new Token(TokenType.QeywordT, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "n": - return new Token(TokenType.QeywordN, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "w": - return new Token(TokenType.QeywordW, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "fd": - return new Token(TokenType.QeywordFD, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "sd": - return new Token(TokenType.QeywordSD, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "od": - return new Token(TokenType.QeywordOD, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "i": - return new Token(TokenType.QeywordI, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "s": - return new Token(TokenType.QeywordS, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "d": - return new Token(TokenType.QeywordD, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "g": - return new Token(TokenType.QeywordG, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - case "v": - return new Token(TokenType.QeywordV, TokenTypeGroup.Qeyword, value, startPosition, _position.Copy()); - default: - return new Token(TokenType.Identifier, TokenTypeGroup.Special, value, startPosition, _position.Copy()); - } - } - } -} \ No newline at end of file diff --git a/src/EzrNodes.cs b/src/EzrNodes.cs deleted file mode 100644 index 303589c..0000000 --- a/src/EzrNodes.cs +++ /dev/null @@ -1,726 +0,0 @@ -using System.Collections.Generic; - -namespace EzrSquared.EzrNodes -{ - using EzrCommon; - - /// - /// The representation of an ezrSquared source code construct. This is the base class of all nodes. Only for inheritance! - /// - public abstract class Node - { - /// - /// The starting of the . - /// - public Position StartPosition; - - /// - /// The ending of the . - /// - public Position EndPosition; - - /// - /// Creates a new object. - /// - /// The starting of the . - /// The ending of the . - public Node(Position startPosition, Position endPosition) - { - StartPosition = startPosition; - EndPosition = endPosition; - } - - public override string ToString() - { - return "Node()"; - } - } - - /// - /// The dummy invalid structure. For returning instead of if an occurs during parsing. - /// - public class InvalidNode : Node - { - /// - /// The static object. - /// - public static InvalidNode StaticInvalidNode = new InvalidNode(new Position(-1, -1, string.Empty, string.Empty), new Position(0, -1, string.Empty, string.Empty)); - - /// - /// Creates a new object. - /// - /// The starting of the . - /// The ending of the . - public InvalidNode(Position startPosition, Position endPosition) : base(startPosition, endPosition) { } - - public override string ToString() - { - return "InvalidNode()"; - } - } - - /// - /// The structure of a simple value like literals and variables. - /// - public class ValueNode : Node - { - /// - /// The value the represents. - /// - public Token Value; - - /// - /// Creates a new object. - /// - /// The value the represents, a object of the same type as must be used with the . - /// The starting of the . - /// The ending of the . - public ValueNode(Token value, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Value = value; - } - - public override string ToString() - { - return $"ValueNode({Value})"; - } - } - - /// - /// The structure for an arraylike (array or list). - /// - public class ArrayLikeNode : Node - { - /// - /// The elements of the arraylike. - /// - public List Elements; - - /// - /// The check for if the should create a list instead of an array. - /// - public bool CreateList; - - /// - /// Creates a new object. - /// - /// The elements of the arraylike. - /// The check for if the should create a list instead of an array. - /// The starting of the . - /// The ending of the . - public ArrayLikeNode(List elements, bool createList, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Elements = elements; - CreateList = createList; - } - - public override string ToString() - { - string[] elements = new string[Elements.Count]; - for (int i = 0; i < Elements.Count; i++) - elements[i] = Elements[i].ToString(); - - return $"ArrayLikeNode([{string.Join(", ", elements)}], {CreateList})"; - } - } - - /// - /// The structure for a dictionary. - /// - public class DictionaryNode : Node - { - /// - /// The key-value pairs of the dictionary. - /// - public List KeyValuePairs; - - /// - /// Creates a new object. - /// - /// The key-value pairs of the dictionary. - /// The starting of the . - /// The ending of the . - public DictionaryNode(List keyValuePairs, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - KeyValuePairs = keyValuePairs; - } - - public override string ToString() - { - string[] keyValuePairs = new string[KeyValuePairs.Count]; - for (int i = 0; i < KeyValuePairs.Count; i++) - keyValuePairs[i] = $"{KeyValuePairs[i][0]} : {KeyValuePairs[i][1]}"; - return $"DictionaryNode([{string.Join(", ", keyValuePairs)}])"; - } - } - - /// - /// The structure for a binary operation. - /// - public class BinaryOperationNode : Node - { - /// - /// The first operand of the binary operation. - /// - public Node Left; - - /// - /// The second operand of the binary operation. - /// - public Node Right; - - /// - /// The operator of the binary operation. - /// - public TokenType Operator; - - /// - /// Creates a new object. - /// - /// The first operand of the binary operation. - /// The second operand of the binary operation. - /// The operator of the binary operation. - /// The starting of the . - /// The ending of the . - public BinaryOperationNode(Node left, Node right, TokenType @operator, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Left = left; - Right = right; - Operator = @operator; - } - - public override string ToString() - { - return $"BinaryOperationNode({Left}, {Operator}, {Right})"; - } - } - - /// - /// The structure for a unary operation. - /// - public class UnaryOperationNode : Node - { - /// - /// The operand of the unary operation. - /// - public Node Operand; - - /// - /// The operator of the unary operation. - /// - public TokenType Operator; - - /// - /// Creates a new object. - /// - /// The operand of the unary operation. - /// The operator of the unary operation. - /// The starting of the . - /// The ending of the . - public UnaryOperationNode(Node operand, TokenType @operator, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Operand = operand; - Operator = @operator; - } - - public override string ToString() - { - return $"UnaryOperationNode({Operand}, {Operator})"; - } - } - - /// - /// The structure for accesing a variable from the context. - /// - public class VariableAccessNode : Node - { - /// - /// The name of the variable to access. - /// - public Token Name; - - /// - /// The check for if the variable access is from the global or local context. - /// - public bool GlobalAccess; - - /// - /// Creates a new object. - /// - /// The name of the variable, a object of type . - /// The check for if the variable access is from the global or local context. - /// The starting of the . - /// The ending of the . - public VariableAccessNode(Token name, bool globalAccess, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Name = name; - GlobalAccess = globalAccess; - } - - public override string ToString() - { - return $"VariableAccessNode({Name}, {GlobalAccess})"; - } - } - - /// - /// The structure for assigning a value to a variable in the context. - /// - public class VariableAssignmentNode : Node - { - /// - /// The variable to be assigned to. - /// - public Node Variable; - - /// - /// The operation , if not , between the existing value of and . The result of the operation will be assigned to . - /// - public TokenType AssignmentOperator; - - /// - /// The value to be assigned to . - /// - public Node Value; - - /// - /// The check for if the variable assignment is to the global or local context. Irrelevant if the variable to be assigned to is in a local context. - /// - public bool GlobalAssignment; - - /// - /// Creates a new object. - /// - /// The variable to be assigned to. - /// The operation , if not , between the existing value of and . The result of the operation will be assigned to . - /// The value to be assigned to . - /// The check for if the variable assignment is to the global or local context. Irrelevant if the variable to be assigned to is in a local context. - /// The starting of the . - /// The ending of the . - public VariableAssignmentNode(Node variable, TokenType assignmentOperator, Node value, bool globalAssignment, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Variable = variable; - AssignmentOperator = assignmentOperator; - Value = value; - GlobalAssignment = globalAssignment; - } - - public override string ToString() - { - return $"VariableAssignmentNode({Variable}, {AssignmentOperator}, {Value}, {GlobalAssignment})"; - } - } - - /// - /// The structure for a function call. - /// - public class CallNode : Node - { - /// - /// The function to be called. - /// - public Node FunctionToCall; - - /// - /// The array of arguments. - /// - public List Arguments; - - /// - /// Creates a new object. - /// - /// The function to be called. - /// The array of arguments. - /// The starting of the . - /// The ending of the . - public CallNode(Node functionToCall, List arguments, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - FunctionToCall = functionToCall; - Arguments = arguments; - } - - public override string ToString() - { - string[] arguments = new string[Arguments.Count]; - for (int i = 0; i < Arguments.Count; i++) - arguments[i] = Arguments[i].ToString(); - - return $"CallNode({FunctionToCall}, [{string.Join(", ", arguments)}])"; - } - } - - /// - /// The structure for an if expression. - /// - public class IfNode : Node - { - /// - /// The cases of the if expression. - /// - public List Cases; - - /// - /// The body of the else case. - /// - public Node? ElseCase; - - /// - /// Creates a new object. - /// - /// The cases of the if expression. - /// The body of the else case. - /// The starting of the . - /// The ending of the . - public IfNode(List cases, Node? elseCase, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Cases = cases; - ElseCase = elseCase; - } - - public override string ToString() - { - string?[] cases = new string[Cases.Count]; - for (int i = 0; i < Cases.Count; i++) - cases[i] = $"({Cases[i][0]}, {Cases[i][1]})"; - - return $"IfNode([{string.Join(", ", cases)}], {ElseCase})"; - } - } - - /// - /// The structure for a count expression. - /// - public class CountNode : Node - { - /// - /// The amount to count to. - /// - public Node To; - - /// - /// The amount to count from - optional. - /// - public Node? From; - - /// - /// The increment of each iteration - optional. - /// - public Node? Step; - - /// - /// The variable to store the iteration in - optional. - /// - public Node? As; - - /// - /// The body of the count loop. - /// - public Node Body; - - /// - /// Creates a new object. - /// - /// The amount to count to. - /// The amount to count from - optional. - /// The increment of each iteration - optional. - /// The variable to store the iteration in - optional. - /// The body of the count loop. - /// The starting of the . - /// The ending of the . - public CountNode(Node to, Node? from, Node? step, Node? @as, Node body, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - To = to; - From = from; - Step = step; - As = @as; - Body = body; - } - - public override string ToString() - { - return $"CountNode({To}, {From}, {Step}, {As}, {Body})"; - } - } - - /// - /// The structure for an while expression. - /// - public class WhileNode : Node - { - /// - /// The condition of the while loop. - /// - public Node Condition; - - /// - /// The body of the while loop. - /// - public Node Body; - - /// - /// Creates a new object. - /// - /// The condition of the while loop. - /// The body of the while loop. - /// The starting of the . - /// The ending of the . - public WhileNode(Node condition, Node body, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Condition = condition; - Body = body; - } - - public override string ToString() - { - return $"WhileNode({Condition}, {Body})"; - } - } - - /// - /// The structure for a try expression. - /// - public class TryNode : Node - { - /// - /// The try block. - /// - public Node Block; - - /// - /// The error cases of the try expression. - /// - public List Cases; - - /// - /// The (optional) where the error will be stored and the body of the empty else case. - /// - public Node?[]? EmptyCase; - - /// - /// Creates a new object. - /// - /// The try block. - /// The error cases of the try expression. - /// The (optional) where the error will be stored and the body of the empty else case. - /// The starting of the . - /// The ending of the . - public TryNode(Node block, List cases, Node?[]? emptyCase, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Block = block; - Cases = cases; - EmptyCase = emptyCase; - } - - public override string ToString() - { - string?[] cases = new string[Cases.Count]; - for (int i = 0; i < Cases.Count; i++) - cases[i] = $"({Cases[i][0]}, {Cases[i][1]}, {Cases[i][2]})"; - - return (EmptyCase is not null) ? $"TryNode({Block}, [{string.Join(", ", cases)}], ({EmptyCase[0]}, {EmptyCase[1]}))" : $"TryNode({Block}, [{string.Join(", ", cases)}], )"; - } - } - - /// - /// The structure for a function definition. - /// - public class FunctionDefinitionNode : Node - { - /// - /// The (optional) name of the function. - /// - public Node? Name; - - /// - /// The parameters of the function. - /// - public List Parameters; - - /// - /// The body of the function. - /// - public Node Body; - - /// - /// Creates a new object. - /// - /// The (optional) name of the function. - /// The parameters of the function. - /// The body of the function. - /// The starting of the . - /// The ending of the . - public FunctionDefinitionNode(Node? name, List parameters, Node body, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Name = name; - Parameters = parameters; - Body = body; - } - - public override string ToString() - { - string?[] parameters = new string[Parameters.Count]; - for (int i = 0; i < Parameters.Count; i++) - parameters[i] = Parameters[i].ToString(); - - return $"FunctionDefinitionNode({Name}, [{string.Join(", ", parameters)}], {Body})"; - } - } - - /// - /// The structure for an object definition. - /// - public class ObjectDefinitionNode : Node - { - /// - /// The (optional) name of the object. - /// - public Node? Name; - - /// - /// The creation parameters of the object. - /// - public List Parameters; - - /// - /// The parents of the object. - /// - public List Parents; - - /// - /// The body of the object. - /// - public Node Body; - - /// - /// Creates a new object. - /// - /// The (optional) name of the object. - /// The creation parameters of the object. - /// The parents of the object. - /// The body of the object. - /// The starting of the . - /// The ending of the . - public ObjectDefinitionNode(Node? name, List parameters, List parents, Node body, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Name = name; - Parameters = parameters; - Parents = parents; - Body = body; - } - - public override string ToString() - { - string?[] parameters = new string[Parameters.Count]; - for (int i = 0; i < Parameters.Count; i++) - parameters[i] = Parameters[i].ToString(); - - string?[] parents = new string[Parents.Count]; - for (int i = 0; i < Parents.Count; i++) - parents[i] = Parents[i].ToString(); - - return $"ObjectDefinitionNode({Name}, [{string.Join(", ", parameters)}], [{string.Join(", ", parents)}], {Body})"; - } - } - - /// - /// The structure for an include expression. - /// - public class IncludeNode : Node - { - /// - /// The script to include. - /// - Node Script; - - /// - /// The (optional) specific sub-structure or object to be included from the script. - /// - Node? SubStructure; - - /// - /// Specifies if all contents of the script need to be dumped into the current context. - /// - bool IsDumped; - - /// - /// The (optional) nickname of the object to be included. - /// - Node? Nickname; - - /// - /// Creates a new object. - /// - /// The script to include. - /// The (optional) specific sub-structure or object to be included from the script. - /// Specifies if all contents of the script need to be dumped into the current context. - /// The (optional) nickname of the object to be included. - /// The starting of the . - /// The ending of the . - public IncludeNode(Node script, Node? subStructure, bool isDumped, Node? nickname, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Script = script; - SubStructure = subStructure; - IsDumped = isDumped; - Nickname = nickname; - } - - public override string ToString() - { - return $"IncludeNode({Script}, {SubStructure}, {IsDumped}, {Nickname})"; - } - } - - /// - /// The structure for a return statement. - /// - public class ReturnNode : Node - { - /// - /// The optional value to be returned. - /// - public Node? Value; - - /// - /// Creates a new object. - /// - /// The optional value to be returned. - /// The starting of the . - /// The ending of the . - public ReturnNode(Node? value, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - Value = value; - } - - public override string ToString() - { - return $"ReturnNode({Value})"; - } - } - - /// - /// The structure for a statement or expression without any value (used as skip and stop statement nodes). - /// - public class NoValueNode : Node - { - /// - /// The identifying of the . - /// - public TokenType ValueType; - - /// - /// Creates a new object. - /// - /// The identifying of the . - /// The starting of the . - /// The ending of the . - public NoValueNode(TokenType valueType, Position startPosition, Position endPosition) : base(startPosition, endPosition) - { - ValueType = valueType; - } - - public override string ToString() - { - return $"NoValueNode({ValueType})"; - } - } -} diff --git a/src/EzrParser.cs b/src/EzrParser.cs deleted file mode 100644 index 9c236ad..0000000 --- a/src/EzrParser.cs +++ /dev/null @@ -1,2034 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace EzrSquared.EzrParser -{ - using EzrCommon; - using EzrErrors; - using EzrNodes; - - /// - /// The ezrSquared Parser. The job of the Parser is to convert the input objects from the into objects to be given as the input to the Interpreter (TODO). - /// - public class Parser - { - /// - /// The of objects to be parsed. - /// - private List _tokens; - - /// - /// The index of the object currently being parsed in the . - /// - private int _index; - - /// - /// The object currently being parsed at of . - /// - private Token _currentToken; - - /// - /// The boolean check for if normal syntax or QuickSyntax is being used. - /// - private bool _usingQuickSyntax; - - /// - /// The boolean check for if QuickSyntax was being used previously in parsing. - /// - private bool _wasUsingQuickSyntax; - - /// - /// The object that holds the result of the parsing. - /// - private ParseResult _result; - - /// - /// Creates a new object. - /// - /// The of objects to be parsed. - public Parser(List tokens) - { - _tokens = tokens; - _usingQuickSyntax = false; - _wasUsingQuickSyntax = false; - _result = new ParseResult(); - - _index = 0; - if (tokens.Count > _index) - _currentToken = _tokens[_index]; - else - _currentToken = Token.Dummy; - } - - /// - /// Advances to the next object in . - /// - private void Advance() - { - _index++; - _result.AdvanceCount++; - - if (_tokens.Count > _index) - _currentToken = _tokens[_index]; - } - - /// - /// Reverses back to the object at - in . - /// - /// The number of positions to reverse in . - private void Reverse(int reverseCount = 1) - { - _index -= reverseCount; - _result.AdvanceCount -= reverseCount; - _currentToken = _tokens[_index]; - } - - /// - /// Peeks at the previous object from in . - /// - /// The object. - private Token PeekPrevious() - { - int previousIndex = _index - 1; - if (previousIndex < 0) - return Token.Dummy; - - return _tokens[previousIndex]; - } - - /// - /// Registers the use of QuickSyntax. - /// - private void RegisterQuickSyntaxUse() - { - _wasUsingQuickSyntax = _usingQuickSyntax; - _usingQuickSyntax = true; - } - - /// - /// Unregisters the use of QuickSyntax. - /// - private void UnregisterQuickSyntaxUse() - { - _usingQuickSyntax = _wasUsingQuickSyntax; - } - - /// - /// Parses the objects in . - /// - public ParseResult Parse() - { - ParseStatements(); - if (_result.Error is null && _currentToken.Type != TokenType.EndOfFile) - _result.Failure(10, new InvalidGrammarError("Did not expect this!", _currentToken.StartPosition, _currentToken.EndPosition)); - return _result; - } - - /// - /// Tries creating a . - /// - /// The function to call for the first operand. - /// The function to call for the second operand. - /// The operator object(s). - private void BinaryOperation(Action left, Action right, params TokenType[] operators) - { - bool CurrentTokenInOperators() - { - int length = operators.Length; - for (int i = 0; i < length; i++) - { - if (_currentToken.Type == operators[i]) - return true; - } - - return false; - } - - Position startPosition = _currentToken.StartPosition; - - left(); - Node leftNode = _result.Node; - if (_result.Error is not null) - return; - - int toReverseTo = _result.AdvanceCount; - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - while (CurrentTokenInOperators()) - { - TokenType @operator = _currentToken.Type; - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - right(); - Node rightNode = _result.Node; - if (_result.Error is not null) - return; - - leftNode = new BinaryOperationNode(leftNode, rightNode, @operator, startPosition, _currentToken.EndPosition); - toReverseTo = _result.AdvanceCount; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - } - - - Reverse(_result.AdvanceCount - toReverseTo); - _result.Success(leftNode); - } - - /// - /// Tries parsing a 'statements' structure. - /// - private void ParseStatements() - { - List statements = new List(); - Position startPosition = _currentToken.StartPosition; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseStatement(); - Node statement = _result.Node; - if (_result.Error is not null) - return; - statements.Add(statement); - - while (true) - { - // NOTE: Qeyword 'l' for 'else if' is deprecated, use Qeyword 'e' instead in format: - // 'e [check]: [statement(s)]' - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - else - break; - - if (_currentToken.Type == TokenType.EndOfFile - || _currentToken.Type == TokenType.KeywordEnd - || _currentToken.Type == TokenType.KeywordElse - || _currentToken.Type == TokenType.KeywordError - || (_usingQuickSyntax - && (_currentToken.Type == TokenType.QeywordL - || _currentToken.Type == TokenType.QeywordE - || _currentToken.Type == TokenType.QeywordS))) - break; - - ParseStatement(); - statement = _result.Node; - if (_result.Error is not null) - return; - statements.Add(statement); - } - - _result.Success(new ArrayLikeNode(statements, false, startPosition, _currentToken.EndPosition)); - } - - /// - /// Tries parsing a 'statement' structure. - /// - private void ParseStatement() - { - Position startPosition = _currentToken.StartPosition; - - Node expression; - if (_currentToken.Type == TokenType.KeywordReturn) - { - Position possibleEndPosition = _currentToken.EndPosition; - Advance(); - - if (_currentToken.Type == TokenType.NewLine - || _currentToken.Type == TokenType.EndOfFile - || _currentToken.Type == TokenType.KeywordEnd - || _currentToken.Type == TokenType.KeywordElse - || _currentToken.Type == TokenType.KeywordError - || (_usingQuickSyntax - && (_currentToken.Type == TokenType.QeywordL - || _currentToken.Type == TokenType.QeywordE - || _currentToken.Type == TokenType.QeywordS))) - { - _result.Success(new ReturnNode(null, startPosition, possibleEndPosition)); - return; - } - - ParseExpression(); - expression = _result.Node; - if (_result.Error is not null) - return; - - _result.Success(new ReturnNode(expression, startPosition, _currentToken.EndPosition)); - return; - } - else if (_currentToken.Type == TokenType.KeywordSkip || _currentToken.Type == TokenType.KeywordStop) - { - Position endPosition = _currentToken.EndPosition; - TokenType currentTokenType = _currentToken.Type; - Advance(); - - _result.Success(new NoValueNode(currentTokenType, startPosition, endPosition)); - return; - } - - ParseExpression(); - expression = _result.Node; - if (_result.Error is not null) - _result.Failure(4, new InvalidGrammarError("Expected a statement!", _currentToken.StartPosition, _currentToken.EndPosition)); - else - _result.Success(expression); - } - - /// - /// Tries parsing an 'expression' structure. - /// - /// In cases where the variable assignment expression requires the 'item' keyword, set this to . - private void ParseExpression(bool itemKeywordRequired = false) - { - Position startPosition = _currentToken.StartPosition; - - bool globalAssignment = false; - bool usedItemKeyword = false; - int startingAdvanceCount = _result.AdvanceCount; - - if (_currentToken.Type == TokenType.KeywordGlobal) - { - globalAssignment = true; - Advance(); - } - - if (_currentToken.Type == TokenType.KeywordItem) - { - usedItemKeyword = true; - Advance(); - } - else if (itemKeywordRequired) - { - ParseQuickExpression(); - Node node_ = _result.Node; - if (_result.Error is not null) - _result.Failure(4, new InvalidGrammarError("Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); - else - _result.Success(node_); - return; - } - - if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) - { - ParseJunction(); - Node variable = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) - { - TokenType assignmentOperator = _currentToken.Type; - Advance(); - - ParseExpression(); - Node value = _result.Node; - if (_result.Error is not null) - return; - - _result.Success(new VariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); - return; - } - else if (usedItemKeyword) - { - _result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - Reverse(_result.AdvanceCount - startingAdvanceCount); - } - else if (usedItemKeyword) - { - _result.Failure(10, new InvalidGrammarError("Expected a variable name! The variable name is what will be assigned the value in a variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - Reverse(_result.AdvanceCount - startingAdvanceCount); - - ParseQuickExpression(); - Node node = _result.Node; - if (_result.Error is not null) - _result.Failure(4, new InvalidGrammarError("Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); - else - _result.Success(node); - } - - /// - /// Tries parsing a 'quick-expression' structure. - /// - private void ParseQuickExpression() - { - Position startPosition = _currentToken.StartPosition; - int startingAdvanceCount = _result.AdvanceCount; - - if (_currentToken.Type == TokenType.ExclamationMark) - { - Advance(); - - bool globalAssignment = false; - bool usedItemKeyword = false; - if (_currentToken.Type == TokenType.QeywordG) - { - globalAssignment = true; - Advance(); - } - - if (_currentToken.Type == TokenType.QeywordD) - { - usedItemKeyword = true; - Advance(); - } - - if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) - { - ParseJunction(); - Node variable = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) - { - TokenType assignmentOperator = _currentToken.Type; - Advance(); - - ParseExpression(); - Node value = _result.Node; - if (_result.Error is not null) - return; - - _result.Success(new VariableAssignmentNode(variable, assignmentOperator, value, globalAssignment, startPosition, _currentToken.EndPosition)); - return; - } - else if (usedItemKeyword) - { - _result.Failure(10, new InvalidGrammarError("Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - Reverse(_result.AdvanceCount - startingAdvanceCount); - } - else if (usedItemKeyword) - { - _result.Failure(10, new InvalidGrammarError("Expected a variable name! The variable name is what will be assigned the value in a variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - Reverse(_result.AdvanceCount - startingAdvanceCount); - } - - ParseJunction(); - Node node = _result.Node; - if (_result.Error is not null) - _result.Failure(4, new InvalidGrammarError("Expected a QuickSyntax expression!", _currentToken.StartPosition, _currentToken.EndPosition)); - else - _result.Success(node); - } - - /// - /// Tries parsing a 'junction' structure. - /// - private void ParseJunction() - { - BinaryOperation(ParseInversion, ParseInversion, TokenType.KeywordAnd, TokenType.KeywordOr); - } - - /// - /// Tries parsing an 'inversion' structure. - /// - private void ParseInversion() - { - Position startPosition = _currentToken.StartPosition; - int startingAdvanceCount = _result.AdvanceCount; - - if (_currentToken.Type == TokenType.KeywordInvert) - { - TokenType @operator = _currentToken.Type; - Advance(); - - ParseExpression(); - Node operand = _result.Node; - if (_result.Error is not null) - return; - - _result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); - return; - } - else if (_currentToken.Type == TokenType.ExclamationMark) - { - Advance(); - - if (_currentToken.Type == TokenType.QeywordV) - { - TokenType @operator = _currentToken.Type; - Advance(); - - ParseExpression(); - Node operand = _result.Node; - if (_result.Error is not null) - return; - - _result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); - return; - } - else - Reverse(_result.AdvanceCount - startingAdvanceCount); - } - - ParseComparison(); - Node node = _result.Node; - if (_result.Error is not null) - _result.Failure(4, new InvalidGrammarError("Expected an inversion expression!", _currentToken.StartPosition, _currentToken.EndPosition)); - else - _result.Success(node); - } - - /// - /// Tries parsing a 'comparison' structure. - /// - private void ParseComparison() - { - Position startPosition = _currentToken.StartPosition; - - ParseBitwiseOr(); - Node left = _result.Node; - if (_result.Error is not null) - return; - - int toReverseTo = _result.AdvanceCount; - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - while (_currentToken.Type == TokenType.EqualSign - || _currentToken.Type == TokenType.ExclamationMark - || _currentToken.Type == TokenType.LessThanSign - || _currentToken.Type == TokenType.GreaterThanSign - || _currentToken.Type == TokenType.LessThanOrEqual - || _currentToken.Type == TokenType.GreaterThanOrEqual - || _currentToken.Type == TokenType.KeywordNot - || _currentToken.Type == TokenType.KeywordIn) - { - TokenType @operator = _currentToken.Type; - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - if (@operator == TokenType.KeywordNot) - { - if (_currentToken.Type != TokenType.KeywordIn) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'in' keyword! The 'in' keyword is the second part of a check-not-in operation.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - Advance(); - } - - ParseBitwiseOr(); - Node right = _result.Node; - if (_result.Error is not null) - return; - - left = new BinaryOperationNode(left, right, @operator, startPosition, _currentToken.EndPosition); - toReverseTo = _result.AdvanceCount; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - } - - Reverse(_result.AdvanceCount - toReverseTo); - _result.Success(left); - } - - /// - /// Tries parsing a 'bitwise-or' structure. - /// - private void ParseBitwiseOr() - { - BinaryOperation(ParseBitwiseXOr, ParseBitwiseXOr, TokenType.VerticalBar); - } - - /// - /// Tries parsing a 'bitwise-xor' structure. - /// - private void ParseBitwiseXOr() - { - BinaryOperation(ParseBitwiseAnd, ParseBitwiseAnd, TokenType.Backslash); - } - - /// - /// Tries parsing a 'bitwise-and' structure. - /// - private void ParseBitwiseAnd() - { - BinaryOperation(ParseBitwiseShift, ParseBitwiseShift, TokenType.Ampersand); - } - - /// - /// Tries creating a 'bitwise-shift' structure. - /// - private void ParseBitwiseShift() - { - BinaryOperation(ParseArithmeticExpression, ParseArithmeticExpression, TokenType.BitwiseLeftShift, TokenType.BitwiseRightShift); - } - - /// - /// Tries parsing an 'arithmetic-expression' structure. - /// - private void ParseArithmeticExpression() - { - BinaryOperation(ParseTerm, ParseTerm, TokenType.Plus, TokenType.HyphenMinus); - } - - /// - /// Tries parsing a 'term' structure. - /// - private void ParseTerm() - { - BinaryOperation(ParseFactor, ParseFactor, TokenType.Asterisk, TokenType.Slash, TokenType.PercentSign); - } - - /// - /// Tries parsing a 'factor' structure. - /// - private void ParseFactor() - { - Position startPosition = _currentToken.StartPosition; - - TokenType @operator = _currentToken.Type; - if (@operator == TokenType.Plus || @operator == TokenType.HyphenMinus || @operator == TokenType.Tilde) - { - Advance(); - - ParseFactor(); - Node operand = _result.Node; - if (_result.Error is not null) - return; - - _result.Success(new UnaryOperationNode(operand, @operator, startPosition, _currentToken.EndPosition)); - return; - } - - ParsePower(); - } - - /// - /// Tries parsing a 'power' structure. - /// - private void ParsePower() - { - BinaryOperation(ParseObjectAttributeAccess, ParseObjectAttributeAccess, TokenType.Caret); - } - - /// - /// Tries parsing an 'object-attribute-access' structure. - /// - private void ParseObjectAttributeAccess() - { - BinaryOperation(ParseCall, ParseObjectAttributeAccess, TokenType.Period); - } - - /// - /// Tries parsing a 'call' structure. - /// - private void ParseCall() - { - Position startPosition = _currentToken.StartPosition; - - ParseAtom(); - Node node = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type == TokenType.LeftParenthesis) - { - Advance(); - - Position possibleErrorStartPosition = _currentToken.StartPosition; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - Position endPosition; - List arguments = new List(); - if (_currentToken.Type == TokenType.RightParenthesis) - { - endPosition = _currentToken.EndPosition; - Advance(); - } - else - { - ParseExpression(); - arguments.Add(_result.Node); - if (_result.Error is not null) - { - _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); - return; - } - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - while (_currentToken.Type == TokenType.Comma) - { - possibleErrorStartPosition = _currentToken.StartPosition; - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseExpression(); - arguments.Add(_result.Node); - if (_result.Error is not null) - { - _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); - return; - } - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - } - - if (_currentToken.Type != TokenType.RightParenthesis) - { - _result.Failure(10, new InvalidGrammarError("Expected a comma or right-parenthesis symbol! Commas are used to seperate the arguments of the function/object call expression, and the right-parenthesis is used to end it.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - endPosition = _currentToken.EndPosition; - Advance(); - } - - _result.Success(new CallNode(node, arguments, startPosition, endPosition)); - return; - } - - _result.Success(node); - } - - /// - /// Tries parsing a 'atom' structure. - /// - private void ParseAtom() - { - - Token startToken = _currentToken; - switch (startToken.Type) - { - case TokenType.KeywordGlobal: - Advance(); - - if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword) - { - Token variable = _currentToken; - Position endPosition = _currentToken.EndPosition; - Advance(); - - _result.Success(new VariableAccessNode(variable, true, startToken.StartPosition, endPosition)); - return; - } - _result.Failure(10, new InvalidGrammarError("Expected a variable name or the 'item' keyword! The variable name is used to access a global variable in a global variable access expression and the 'item' keyword is used to assign to a global variable in a global variable assignment expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - break; - case TokenType.LeftParenthesis: - ParseArrayOrParentheticalExpression(); - Node arrayNode = _result.Node; - if (_result.Error is not null) - return; - _result.Success(arrayNode); - break; - case TokenType.LeftSquareBracket: - ParseList(); - Node encapsulatedListNode = _result.Node; - if (_result.Error is not null) - return; - _result.Success(encapsulatedListNode); - break; - case TokenType.LeftCurlyBracket: - ParseDictionary(); - Node dictionaryNode = _result.Node; - if (_result.Error is not null) - return; - _result.Success(dictionaryNode); - break; - case TokenType.KeywordIf: - ParseIfExpression(); - Node ifNode = _result.Node; - if (_result.Error is not null) - return; - _result.Success(ifNode); - break; - case TokenType.KeywordCount: - ParseCountExpression(); - Node countNode = _result.Node; - if (_result.Error is not null) - return; - _result.Success(countNode); - break; - case TokenType.KeywordWhile: - ParseWhileExpression(); - Node whileNode = _result.Node; - if (_result.Error is not null) - return; - _result.Success(whileNode); - break; - case TokenType.KeywordTry: - ParseTryExpression(); - Node tryNode = _result.Node; - if (_result.Error is not null) - return; - _result.Success(tryNode); - break; - case TokenType.KeywordFunction: - ParseFunctionDefinitionExpression(); - Node functionDefinitionNode = _result.Node; - if (_result.Error is not null) - return; - _result.Success(functionDefinitionNode); - break; - case TokenType.KeywordObject: - ParseObjectDefinitionExpression(); - Node objectDefinitionNode = _result.Node; - if (_result.Error is not null) - return; - _result.Success(objectDefinitionNode); - break; - case TokenType.KeywordInclude: - ParseIncludeExpression(); - Node includeNode = _result.Node; - if (_result.Error is not null) - return; - _result.Success(includeNode); - break; - default: - if (startToken.TypeGroup == TokenTypeGroup.Value) - { - Advance(); - - _result.Success(new ValueNode(startToken, startToken.StartPosition, startToken.EndPosition)); - return; - } - else if (startToken.Type == TokenType.Identifier || startToken.TypeGroup == TokenTypeGroup.Qeyword) - { - Advance(); - - _result.Success(new VariableAccessNode(startToken, false, startToken.StartPosition, startToken.EndPosition)); - return; - } - - _result.Failure(4, new InvalidGrammarError("Expected an integer, float, string, character, character list, identifier, 'if' expression, 'count' expression, 'while' expression and so on.", _currentToken.StartPosition, _currentToken.EndPosition)); - break; - } - } - - /// - /// Tries parsing an array, an with set to OR a parenthetical expression. Starts from , which should be of . - /// - private void ParseArrayOrParentheticalExpression() - { - Position startPosition = _currentToken.StartPosition; - Advance(); - - Position possibleErrorStartPosition = _currentToken.StartPosition; - List elements = new List(); - bool isArray = false; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - Position endPosition; - if (_currentToken.Type == TokenType.RightParenthesis) - { - endPosition = _currentToken.EndPosition; - Advance(); - } - else - { - ParseExpression(); - elements.Add(_result.Node); - if (_result.Error is not null) - { - _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array/parenthetical expression must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); - return; - } - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - while (_currentToken.Type == TokenType.Comma) - { - isArray = true; - possibleErrorStartPosition = _currentToken.StartPosition; - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - if (_currentToken.Type == TokenType.RightParenthesis && elements.Count == 1) - break; - - ParseExpression(); - if (_result.Error is not null) - { - if (elements.Count > 1) - { - _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array must end with a right-parenthesis.", possibleErrorStartPosition, _currentToken.EndPosition))); - return; - } - - Position errorStartPosition = possibleErrorStartPosition.Copy(); - errorStartPosition.Advance(); - _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-parenthesis symbol! An array must end with a right-parenthesis.", errorStartPosition, _currentToken.EndPosition))); - } - - elements.Add(_result.Node); - if (_currentToken.Type == TokenType.NewLine) - Advance(); - } - - if (_currentToken.Type != TokenType.RightParenthesis) - { - if (isArray) - _result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! Commas seperate the elements of the array, while the right-parenthesis ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); - else - _result.Failure(10, new InvalidGrammarError("Expected a comma or a right-parenthesis symbol! The comma is used to create an array and seperate its elements, while the right-parenthesis declares the end of a parenthetical expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - endPosition = _currentToken.EndPosition; - Advance(); - } - - if (!isArray && elements.Count > 0) - _result.Success(elements[0]); - else - _result.Success(new ArrayLikeNode(elements, false, startPosition, endPosition)); - } - - /// - /// Tries parsing a list, an with set to . Starts from , which should be of . - /// - private void ParseList() - { - Position startPosition = _currentToken.StartPosition; - Advance(); - - Position possibleErrorStartPosition = _currentToken.StartPosition; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - Position endPosition; - List elements = new List(); - if (_currentToken.Type == TokenType.RightSquareBracket) - { - endPosition = _currentToken.EndPosition; - Advance(); - } - else - { - ParseExpression(); - elements.Add(_result.Node); - if (_result.Error is not null) - { - _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); - return; - } - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - while (_currentToken.Type == TokenType.Comma) - { - possibleErrorStartPosition = _currentToken.StartPosition; - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseExpression(); - elements.Add(_result.Node); - if (_result.Error is not null) - { - _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); - return; - } - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - } - - if (_currentToken.Type != TokenType.RightSquareBracket) - { - _result.Failure(10, new InvalidGrammarError("Expected a comma or a right-square-bracket symbol! Commas are used to seperate elements in the list, while the right-square-bracket ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - endPosition = _currentToken.EndPosition; - Advance(); - } - - _result.Success(new ArrayLikeNode(elements, true, startPosition, endPosition)); - } - - /// - /// Tries parsing a dictionary. Starts from , which should be of . - /// - private void ParseDictionary() - { - Position startPosition = _currentToken.StartPosition; - Advance(); - - Position possibleErrorStartPosition = _currentToken.StartPosition; - List pairs = new List(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - Position endPosition; - if (_currentToken.Type == TokenType.RightCurlyBracket) - { - endPosition = _currentToken.EndPosition; - Advance(); - } - else - { - ParseExpression(true); - Node left = _result.Node; - if (_result.Error is not null) - { - _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); - return; - } - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - if (_currentToken.Type != TokenType.Colon) - { - _result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseExpression(); - Node right = _result.Node; - if (_result.Error is not null) - return; - - pairs.Add(new Node[2] { left, right }); - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - while (_currentToken.Type == TokenType.Comma) - { - possibleErrorStartPosition = _currentToken.StartPosition; - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseExpression(true); - left = _result.Node; - if (_result.Error is not null) - { - _result.Failure(10, new StackedError(_result.Error, new InvalidGrammarError("Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorStartPosition, _currentToken.EndPosition))); - return; - } - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - if (_currentToken.Type != TokenType.Colon) - { - _result.Failure(10, new InvalidGrammarError("Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseExpression(); - right = _result.Node; - if (_result.Error is not null) - return; - - pairs.Add(new Node[2] { left, right }); - if (_currentToken.Type == TokenType.NewLine) - Advance(); - } - - if (_currentToken.Type != TokenType.RightCurlyBracket) - { - _result.Failure(10, new InvalidGrammarError("Expected a comma or right-curly-bracket symbol! Commas are used to seperate key-value pairs in the dictionary, and the right-curly-bracket declares its end.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - endPosition = _currentToken.EndPosition; - Advance(); - } - - _result.Success(new DictionaryNode(pairs, startPosition, endPosition)); - } - - /// - /// Tries parsing an if expression. Starts from , which should be of . - /// - private void ParseIfExpression() - { - Position startPosition = _currentToken.StartPosition; - Advance(); - - List cases = new List(); - Node? elseCase = null; - - ParseExpression(); - Node condition = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type != TokenType.KeywordDo) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - Advance(); - - Node body; - if (_currentToken.Type == TokenType.NewLine) - { - Advance(); - - ParseStatements(); - body = _result.Node; - if (_result.Error is not null) - return; - - Position endPosition; - cases.Add(new Node[2] { condition, body }); - if (_currentToken.Type == TokenType.KeywordEnd) - { - endPosition = _currentToken.EndPosition; - Advance(); - } - else if (_currentToken.Type == TokenType.KeywordElse) - { - while (_currentToken.Type == TokenType.KeywordElse) - { - Advance(); - - if (_currentToken.Type == TokenType.KeywordIf) - { - if (elseCase is not null) - { - _result.Failure(10, new InvalidGrammarError("The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); - return; - } - - Advance(); - - ParseExpression(); - condition = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type != TokenType.KeywordDo) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - Advance(); - - ParseStatements(); - body = _result.Node; - if (_result.Error is not null) - return; - - cases.Add(new Node[2] { condition, body }); - } - else if (_currentToken.Type != TokenType.KeywordDo) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - { - if (elseCase is not null) - { - _result.Failure(10, new InvalidGrammarError("There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); - return; - } - - Advance(); - - ParseStatements(); - elseCase = _result.Node; - if (_result.Error is not null) - return; - } - } - - if (_currentToken.Type != TokenType.KeywordEnd) - { - if (elseCase is null) - _result.Failure(10, new InvalidGrammarError("Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - else - _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - endPosition = _currentToken.EndPosition; - Advance(); - } - else - { - _result.Failure(10, new InvalidGrammarError("Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - _result.Success(new IfNode(cases, elseCase, startPosition, endPosition)); - return; - } - - ParseStatement(); - body = _result.Node; - if (_result.Error is not null) - return; - - cases.Add(new Node[2] { condition, body }); - while (_currentToken.Type == TokenType.KeywordElse) - { - Advance(); - - if (_currentToken.Type == TokenType.KeywordIf) - { - if (elseCase is not null) - { - _result.Failure(10, new InvalidGrammarError("The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); - return; - } - - Advance(); - - ParseExpression(); - condition = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type != TokenType.KeywordDo) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - Advance(); - - ParseStatement(); - body = _result.Node; - if (_result.Error is not null) - return; - - cases.Add(new Node[2] { condition, body }); - } - else if (_currentToken.Type != TokenType.KeywordDo) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - { - if (elseCase is not null) - { - _result.Failure(10, new InvalidGrammarError("There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); - return; - } - - Advance(); - - ParseStatement(); - elseCase = _result.Node; - if (_result.Error is not null) - return; - } - } - - _result.Success(new IfNode(cases, elseCase, startPosition, PeekPrevious().EndPosition)); - } - - /// - /// Tries parsing a count expression. Starts from , which should be of . - /// - private void ParseCountExpression() - { - Position startPosition = _currentToken.StartPosition; - Advance(); - - Node to = InvalidNode.StaticInvalidNode; - Node? from = null; - Node? step = null; - Node? @as = null; - - if (_currentToken.Type == TokenType.KeywordFrom) - { - Advance(); - - ParseExpression(); - from = _result.Node; - if (_result.Error is not null) - return; - } - - if (_currentToken.Type != TokenType.KeywordTo) - { - if (from is null) - _result.Failure(10, new InvalidGrammarError("Expected the 'to' or 'from' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop, and the optional 'from' keyword and the following expression is the amount to count from.", _currentToken.StartPosition, _currentToken.EndPosition)); - else - _result.Failure(10, new InvalidGrammarError("Expected the 'to' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - Advance(); - - ParseExpression(); - to = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type == TokenType.KeywordStep) - { - Advance(); - - ParseExpression(); - step = _result.Node; - if (_result.Error is not null) - return; - } - - if (_currentToken.Type == TokenType.KeywordAs) - { - Advance(); - - ParseExpression(); - @as = _result.Node; - if (_result.Error is not null) - return; - } - - if (_currentToken.Type != TokenType.KeywordDo) - { - if (step is null && @as is null) - _result.Failure(10, new InvalidGrammarError("Expected the 'do', 'step' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, the optional 'step' keyword and the following expression is the increment, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); - else if (@as is null) - _result.Failure(10, new InvalidGrammarError("Expected the 'do' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); - else - _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - Advance(); - - Node body; - Position endPosition; - if (_currentToken.Type == TokenType.NewLine) - { - Advance(); - - ParseStatements(); - body = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type != TokenType.KeywordEnd) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - endPosition = _currentToken.EndPosition; - Advance(); - } - else - { - ParseStatement(); - body = _result.Node; - if (_result.Error is not null) - return; - - endPosition = PeekPrevious().EndPosition; - } - - _result.Success(new CountNode(to, from, step, @as, body, startPosition, endPosition)); - } - - /// - /// Tries parsing a while expression. Starts from , which should be of . - /// - private void ParseWhileExpression() - { - Position startPosition = _currentToken.StartPosition; - Advance(); - - ParseExpression(); - Node condition = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type != TokenType.KeywordDo) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - Advance(); - - Node body; - Position endPosition; - if (_currentToken.Type == TokenType.NewLine) - { - Advance(); - - ParseStatements(); - body = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type != TokenType.KeywordEnd) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - endPosition = _currentToken.EndPosition; - Advance(); - } - else - { - ParseStatement(); - body = _result.Node; - if (_result.Error is not null) - return; - - endPosition = PeekPrevious().EndPosition; - } - - _result.Success(new WhileNode(condition, body, startPosition, endPosition)); - } - - /// - /// Tries parsing a try expression. Starts from , which should be of . - /// - private void ParseTryExpression() - { - Position startPosition = _currentToken.StartPosition; - Advance(); - - Node block; - List cases = new List(); - Node?[]? emptyCase = null; - - if (_currentToken.Type != TokenType.KeywordDo) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - Advance(); - - Node body; - if (_currentToken.Type == TokenType.NewLine) - { - Advance(); - - ParseStatements(); - block = _result.Node; - if (_result.Error is not null) - return; - - Position endPosition; - if (_currentToken.Type == TokenType.KeywordEnd) - { - endPosition = _currentToken.EndPosition; - Advance(); - } - else if (_currentToken.Type == TokenType.KeywordError) - { - while (_currentToken.Type == TokenType.KeywordError) - { - Advance(); - - Node? error = null; - bool isErrorNull = true; - - ErrorExpressionEvaluation: - bool isAsKeyword = _currentToken.Type == TokenType.KeywordAs; - if (_currentToken.Type == TokenType.KeywordDo || isAsKeyword) - { - if (emptyCase is not null) - { - _result.Failure(10, new InvalidGrammarError("There should only be one empty \"error\" expression! You cannot have multiple \"error\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); - return; - } - - Node? @as = null; - if (isAsKeyword) - { - Advance(); - - ParseExpression(); - @as = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type != TokenType.KeywordDo) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - } - - Advance(); - - ParseStatements(); - body = _result.Node; - if (_result.Error is not null) - return; - - if (error is not null) - cases.Add(new Node?[3] { error, @as, body }); - else - emptyCase = new Node?[2] { @as, body }; - } - else if (isErrorNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) - { - if (emptyCase is not null) - { - Token previous = PeekPrevious(); - _result.Failure(10, new InvalidGrammarError("There can't be any \"error\" expressions after an empty \"error\" expression!", previous.StartPosition, previous.EndPosition)); - return; - } - - ParseExpression(); - error = _result.Node; - if (_result.Error is not null) - return; - - isErrorNull = false; - goto ErrorExpressionEvaluation; - } - else if (isErrorNull) - { - _result.Failure(10, new InvalidGrammarError("Expected an expression or the 'as' or 'do' keywords! An expression after the 'error' keyword defines what error(s) will lead to the \"error\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - { - _result.Failure(10, new InvalidGrammarError("Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - } - - if (_currentToken.Type != TokenType.KeywordEnd) - { - if (emptyCase is null) - _result.Failure(10, new InvalidGrammarError("Expected the 'error' or 'end' keywords! The 'error' keyword defines the start of an \"error\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - else - _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - endPosition = _currentToken.EndPosition; - Advance(); - } - else - { - _result.Failure(10, new InvalidGrammarError("Expected the 'error' or 'end' keywords! The 'error' keyword defines the start of an \"error\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - _result.Success(new TryNode(block, cases, emptyCase, startPosition, endPosition)); - return; - } - - ParseStatement(); - block = _result.Node; - if (_result.Error is not null) - return; - - while (_currentToken.Type == TokenType.KeywordError) - { - Advance(); - - Node? error = null; - bool isErrorNull = true; - - ErrorExpressionEvaluation: - bool isAsKeyword = _currentToken.Type == TokenType.KeywordAs; - if (_currentToken.Type == TokenType.KeywordDo || isAsKeyword) - { - if (emptyCase is not null) - { - _result.Failure(10, new InvalidGrammarError("There should only be one empty \"error\" expression! You cannot have multiple \"error\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); - return; - } - - Node? @as = null; - if (isAsKeyword) - { - Advance(); - - ParseExpression(); - @as = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type != TokenType.KeywordDo) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - } - - Advance(); - - ParseStatement(); - body = _result.Node; - if (_result.Error is not null) - return; - - if (error is not null) - cases.Add(new Node?[3] { error, @as, body }); - else - emptyCase = new Node?[2] { @as, body }; - } - else if (isErrorNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) - { - if (emptyCase is not null) - { - Token previous = PeekPrevious(); - _result.Failure(10, new InvalidGrammarError("There can't be any \"error\" expressions after an empty \"error\" expression!", previous.StartPosition, previous.EndPosition)); - return; - } - - ParseExpression(); - error = _result.Node; - if (_result.Error is not null) - return; - - isErrorNull = false; - goto ErrorExpressionEvaluation; - } - else if (isErrorNull) - { - _result.Failure(10, new InvalidGrammarError("Expected an expression or the 'as' or 'do' keywords! An expression after the 'error' keyword defines what error(s) will lead to the \"error\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - { - _result.Failure(10, new InvalidGrammarError("Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"error\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - } - - _result.Success(new TryNode(block, cases, emptyCase, startPosition, PeekPrevious().EndPosition)); - } - - /// - /// Tries parsing a function definition expression. Starts from , which should be of . - /// - private void ParseFunctionDefinitionExpression() - { - Position startPosition = _currentToken.StartPosition; - Advance(); - - Node? name = null; - List parameters = new List(); - Node body; - - Position endPosition; - bool isNameNull = true; - - FunctionDefinitionEvaluation: - bool isWithKeyword = _currentToken.Type == TokenType.KeywordWith; - if (_currentToken.Type == TokenType.KeywordDo || isWithKeyword) - { - if (isWithKeyword) - { - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseExpression(); - parameters.Add(_result.Node); - if (_result.Error is not null) - return; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - while (_currentToken.Type == TokenType.Comma) - { - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseExpression(); - parameters.Add(_result.Node); - if (_result.Error is not null) - return; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - } - - if (_currentToken.Type != TokenType.KeywordDo) - { - _result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parameter and the 'do' keyword declares the start of the body of the \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - } - - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - { - Advance(); - - ParseStatements(); - body = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type != TokenType.KeywordEnd) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - endPosition = _currentToken.EndPosition; - Advance(); - } - else - { - ParseStatement(); - body = _result.Node; - if (_result.Error is not null) - return; - - endPosition = PeekPrevious().EndPosition; - } - } - else if (isNameNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) - { - ParseExpression(); - name = _result.Node; - if (_result.Error is not null) - return; - - isNameNull = false; - goto FunctionDefinitionEvaluation; - } - else if (isNameNull) - { - _result.Failure(10, new InvalidGrammarError("Expected an expression or the 'with' or 'do' keywords! An expression after the 'function' keyword defines the name, the 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - { - _result.Failure(10, new InvalidGrammarError("Expected the 'with' or 'do' keywords! The 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - _result.Success(new FunctionDefinitionNode(name, parameters, body, startPosition, endPosition)); - } - - // 'special' expressions are gone. - - /// - /// Tries parsing an object definition expression. Starts from , which should be of . - /// - private void ParseObjectDefinitionExpression() - { - // The parents of the object are now defined after the 'from' keyword like an array. The 'from' keyword must come before the 'do' keyword and after the 'with' keyword. - - Position startPosition = _currentToken.StartPosition; - Advance(); - - Node? name = null; - List parameters = new List(); - List parents = new List(); - Node body; - - Position endPosition; - bool isNameNull = true; - - ObjectDefinitionEvaluation: - bool isWithKeyword = _currentToken.Type == TokenType.KeywordWith; - bool isFromKeyword = _currentToken.Type == TokenType.KeywordFrom; - if (_currentToken.Type == TokenType.KeywordDo || isWithKeyword || isFromKeyword) - { - if (isWithKeyword) - { - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseExpression(); - parameters.Add(_result.Node); - if (_result.Error is not null) - return; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - while (_currentToken.Type == TokenType.Comma) - { - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseExpression(); - parameters.Add(_result.Node); - if (_result.Error is not null) - return; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - } - - isFromKeyword = _currentToken.Type == TokenType.KeywordFrom; - if (_currentToken.Type != TokenType.KeywordDo && !isFromKeyword) - { - _result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'from' or 'do' keywords! The comma symbol and the following expression defines another parameter, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - } - - if (isFromKeyword) - { - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseExpression(); - parents.Add(_result.Node); - if (_result.Error is not null) - return; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - while (_currentToken.Type == TokenType.Comma) - { - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - ParseExpression(); - parents.Add(_result.Node); - if (_result.Error is not null) - return; - - if (_currentToken.Type == TokenType.NewLine) - Advance(); - } - - if (_currentToken.Type != TokenType.KeywordDo) - { - _result.Failure(10, new InvalidGrammarError("Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parent and the 'do' keyword declares the start of the body of the \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - } - - Advance(); - - if (_currentToken.Type == TokenType.NewLine) - { - Advance(); - - ParseStatements(); - body = _result.Node; - if (_result.Error is not null) - return; - - if (_currentToken.Type != TokenType.KeywordEnd) - { - _result.Failure(10, new InvalidGrammarError("Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"object\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - endPosition = _currentToken.EndPosition; - Advance(); - } - else - { - ParseStatement(); - body = _result.Node; - if (_result.Error is not null) - return; - - endPosition = PeekPrevious().EndPosition; - } - } - else if (isNameNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) - { - ParseExpression(); - name = _result.Node; - if (_result.Error is not null) - return; - - isNameNull = false; - goto ObjectDefinitionEvaluation; - } - else if (isNameNull) - { - _result.Failure(10, new InvalidGrammarError("Expected an expression or the 'with', 'from' or 'do' keywords! An expression after the 'object' keyword defines the name, the 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\".", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - else - { - _result.Failure(10, new InvalidGrammarError("Expected the 'with', 'from' or 'do' keywords! The 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents of the \"object\" and the 'do' keyword declares the start of the body of the \"object\".", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - _result.Success(new ObjectDefinitionNode(name, parameters, parents, body, startPosition, endPosition)); - } - - /// - /// Tries parsing an include expression. Starts from , which should be of . - /// - private void ParseIncludeExpression() - { - Position startPosition = _currentToken.StartPosition; - Advance(); - - Node? subStructure = null; - Node? nickname = null; - bool isDumped = false; - Node script; - - if (_currentToken.Type != TokenType.KeywordAll && _currentToken.Type != TokenType.Comma) - { - ParseExpression(); - subStructure = _result.Node; - if (_result.Error is not null) - return; - } - else - { - isDumped = true; - Advance(); - } - - if (_currentToken.Type == TokenType.KeywordFrom) - { - Advance(); - - ParseExpression(); - script = _result.Node; - if (_result.Error is not null) - return; - } - else if (subStructure is not null) - { - script = subStructure; - subStructure = null; - } - else - { - _result.Failure(10, new InvalidGrammarError("Expected the 'from' keyword! If a specific object being included from a script (when the object's name is provided after the 'include' keyword) or if the whole script is added to the script (using the 'all' keyword or a comma symbol after the 'include' keyword), the 'from' keyword followed by an expression declaring the script's name or path must be provided.", _currentToken.StartPosition, _currentToken.EndPosition)); - return; - } - - if (_currentToken.Type == TokenType.KeywordAs) - { - Advance(); - - ParseExpression(); - nickname = _result.Node; - if (_result.Error is not null) - return; - } - - _result.Success(new IncludeNode(script, subStructure, isDumped, nickname, startPosition, PeekPrevious().EndPosition)); - } - } - - /// - /// The type of the object that is returned as the result of parsing done by the . - /// - public class ParseResult - { - /// - /// The that occurred while parsing, if any. - /// - public Error? Error; - - /// - /// The which is the result of the parsing. - /// - public Node Node; - - /// - /// The amount of times the advanced. - /// - public int AdvanceCount; - - /// - /// The priority of the error held in the . - /// - private int ErrorPriority; - - /// - /// Creates a new object. - /// - public ParseResult() - { - Error = null; - Node = InvalidNode.StaticInvalidNode; - AdvanceCount = 0; - ErrorPriority = 0; - } - - /// - /// Sets as the result of successful parsing. - /// - /// The result of the parsing. - /// The same object. - public void Success(Node node) - { - Node = node; - } - - /// - /// Sets as the result of failed parsing. - /// - /// - /// If the of is greater than or equal to the - /// of , then will override . - /// - /// The priority/fatality of the failure. - /// The that occurred in parsing. - /// The same object. - public void Failure(int priority, Error error) - { - if (Error is null || ErrorPriority <= priority || AdvanceCount == 0) - { - ErrorPriority = priority; - Error = error; - } - } - } -} diff --git a/src/EzrShell.cs b/src/EzrShell.cs deleted file mode 100644 index 5a5cc42..0000000 --- a/src/EzrShell.cs +++ /dev/null @@ -1,316 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace EzrSquared.EzrShell -{ - using EzrCommon; - using EzrErrors; - using EzrLexer; - using EzrParser; - - /// - /// The built-in shell for ezrSquared. - /// - internal class Shell - { - private const string Version = "0.1.0"; - - private const string ConsoleGraphicsInfo = $""" - | ezr² v{Version} - | Online documentation: - | https://uralstech.github.io/ezrSquared/Introduction.html - | Feature requests and bug reports: - | https://github.com/Uralstech/ezrSquared/issues - | GitHub repository: - __________________________| https://github.com/Uralstech/ezrSquared/ - """; - - private const string ConsoleGraphicsLetterE = """ - - - ___ - / _ \ - | __/ - \___| - """; - private const string ConsoleGraphicsLetterZ = """ - - - ____ - |_ / - / / - /___| - """; - private const string ConsoleGraphicsLetterR = """ - - - _ __ - | '__| - | | - |_| - """; - private const string ConsoleGraphicsSquaredSymbol = """ - ___ - |_ ) - / / - /___| - - - """; - - private struct Settings - { - public bool ShowLexerOutput; - public bool ShowParserOutput; - public string File; - - public Settings() - { - ShowLexerOutput = false; - ShowParserOutput = false; - File = string.Empty; - } - } - - private static ConsoleColor s_previousForegroundColor; - private static ConsoleColor s_previousBackgroundColor; - - private static void PrintSmallConsoleGraphics() - { - Console.Clear(); - Console.BackgroundColor = ConsoleColor.Black; - Console.SetCursorPosition(0, 0); - - Console.ForegroundColor = ConsoleColor.Green; - Console.Write('e'); - - Console.ForegroundColor = ConsoleColor.Red; - Console.Write('z'); - - Console.ForegroundColor = ConsoleColor.Blue; - Console.Write('r'); - - Console.ForegroundColor = ConsoleColor.Yellow; - Console.Write('²'); - - Console.ForegroundColor = ConsoleColor.White; - Console.WriteLine($" v{Version}"); - } - - private static void PrintBigConsoleGraphics() - { - Console.Clear(); - Console.BackgroundColor = ConsoleColor.Black; - - Console.SetCursorPosition(0, 0); - Console.ForegroundColor = ConsoleColor.White; - Console.Write(ConsoleGraphicsInfo); - - Console.ForegroundColor = ConsoleColor.Yellow; - Console.SetCursorPosition(0, 0); - Console.Write(ConsoleGraphicsSquaredSymbol); - - Console.ForegroundColor = ConsoleColor.Blue; - Console.SetCursorPosition(0, 0); - Console.Write(ConsoleGraphicsLetterR); - - Console.ForegroundColor = ConsoleColor.Red; - Console.SetCursorPosition(0, 0); - Console.Write(ConsoleGraphicsLetterZ); - - Console.ForegroundColor = ConsoleColor.Green; - Console.SetCursorPosition(0, 0); - Console.Write(ConsoleGraphicsLetterE); - Console.Write("\n\n"); - } - - private static void ShowError(string message) - { - Console.BackgroundColor = ConsoleColor.Black; - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(message); - } - - private static void ShowOutput(string message) - { - Console.BackgroundColor = ConsoleColor.Black; - Console.ForegroundColor = ConsoleColor.White; - Console.WriteLine(message); - } - - private static void ShowVerbose(string message) - { - Console.BackgroundColor = ConsoleColor.Black; - Console.ForegroundColor = ConsoleColor.DarkGray; - Console.WriteLine(message); - } - - private static string? GetShellInput() - { - Console.BackgroundColor = ConsoleColor.Black; - Console.ForegroundColor = ConsoleColor.Yellow; - - Console.Write(">>> "); - return Console.ReadLine(); - } - - private static bool ParseCommandLineArguments(string[] arguments, out Settings settings) - { - settings = new Settings(); - bool isFirstArgument = true; - - for (int i = 1; i < arguments.Length; i++) - { - if (arguments[i] == "-l" || string.Compare(arguments[1], "--lexer-output", true) == 0) - settings.ShowLexerOutput = true; - else if (arguments[i] == "-p" || string.Compare(arguments[1], "--parser-output", true) == 0) - settings.ShowLexerOutput = true; - else if (File.Exists(arguments[i])) - settings.File = arguments[i]; - else if (isFirstArgument && (arguments[i] == "-h" || string.Compare(arguments[1], "--help", true) == 0)) - { - ShowOutput(""" - Help for the `ezrSquared` command: - Intended use: - ezrSquared [file] [-h or --help] [-l or --lexer-output] [-p or --parser-output] - - file : File/script to execute. If not given, starts in interative mode. - -h or --help : Show this help screen. - -l or --lexer-output : Show the output of the Lexer. Only for debugging purposes. - -p or --parser-output : Show the output of the Parser. Only for debugging purposes. - """); - return false; - } - else - { - ShowError("Intended use:\n\tezrSquared [file] [-l | --lexer-output] [-p | --parser-output]"); - return false; - } - - isFirstArgument = false; - } - - return true; - } - - public static void Main() - { - s_previousBackgroundColor = Console.BackgroundColor; - s_previousForegroundColor = Console.ForegroundColor; - Console.OutputEncoding = Encoding.Unicode; - - string[] commandLineArguments = Environment.GetCommandLineArgs(); - if (!ParseCommandLineArguments(commandLineArguments, out Settings settings)) - return; - -#if DEBUG - settings.ShowLexerOutput = true; - settings.ShowParserOutput = true; - - Console.Write("File to read (press the 'enter' key to enter interactive mode): "); - string? filePath = Console.ReadLine(); - - - if (File.Exists(filePath)) - settings.File = filePath; - else if (!string.IsNullOrEmpty(filePath)) - { - ShowError($"File not found: \"{filePath}\""); - - Console.Write("Press any key to continue..."); - Console.ReadKey(); - - settings = new Settings(); - } -#endif - - if (!string.IsNullOrEmpty(settings.File)) - ExecuteFile(settings); - else - InteractiveMode(settings); - - Console.BackgroundColor = s_previousBackgroundColor; - Console.ForegroundColor = s_previousForegroundColor; - } - - private static void ExecuteFile(Settings settings) - { - Lexer lexer = new Lexer(Path.GetFileNameWithoutExtension(settings.File), File.ReadAllText(settings.File, Encoding.UTF8).ReplaceLineEndings("\n")); - Error? error = lexer.Tokenize(out List tokens); - if (settings.ShowLexerOutput) - { - ShowVerbose("Lexer output:"); - for (int i = 0; i < tokens.Count; i++) - ShowVerbose($" - {tokens[i]}"); - } - - if (error is not null) - { - ShowError(error.ToString()); - return; - } - - Parser parser = new Parser(tokens); - ParseResult result = parser.Parse(); - if (result.Error is not null) - { - ShowError(result.Error.ToString()); - return; - } - - if (settings.ShowParserOutput) - ShowVerbose($"Parser output:\n{result.Node}"); - - Console.Write("Press any key to continue..."); - Console.ReadKey(); - } - - private static void InteractiveMode(Settings settings) - { -#if PLATFORM_WINDOWS - if (Console.WindowWidth > 84) - PrintBigConsoleGraphics(); - else - PrintSmallConsoleGraphics(); -#else - PrintSmallConsoleGraphics(); -#endif - - while (true) - { - string? input = GetShellInput(); - - if (!string.IsNullOrEmpty(input)) - { - Lexer lexer = new Lexer("shell", input); - Error? error = lexer.Tokenize(out List tokens); - if (settings.ShowLexerOutput) - { - ShowVerbose("Lexer output:"); - for (int i = 0; i < tokens.Count; i++) - ShowVerbose($" - {tokens[i]}"); - } - - if (error is not null) - { - ShowError(error.ToString()); - continue; - } - - Parser parser = new Parser(tokens); - ParseResult result = parser.Parse(); - if (result.Error is not null) - { - ShowError(result.Error.ToString()); - continue; - } - - if (settings.ShowParserOutput) - ShowVerbose($"Parser output:\n{result.Node}"); - } - } - } - } -} \ No newline at end of file diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 1a8be45..fd644d0 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -1,28 +1,76 @@  - Exe - win-x64 - net7.0 - 7.0 - True + Library + win-x64;linux-x64;osx-x64 + AnyCPU;x64;arm64 + net8.0;netstandard2.1 + 12 + Disable + Enable + EzrSquared - EzrSquared.EzrShell.Shell - disable - enable - embedded - - Icon.ico - D:\Code\csharp\ezrSquared\src\AutoGeneratedAssemblyInfo.cs - D:\Code\csharp\ezrSquared\bin\ezrSquared\ - D:\Code\csharp\ezrSquared\obj\ezrSquared\ + Full - + True + + True True - True + + true - - - PLATFORM_WINDOWS + + + ezrSquared + ezrSquared + ezrSquared-lib + + ezr² Portable Library + The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! + + 0.1.0 + + Udayshankar Ravikumar + URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED + © 2022 - 2024 URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED + + en + + LICENSE.txt + README.md + https://uralstech.github.io/ezrSquared/ + programming language;portable;embeddable;compact;interpreted + ..\Binaries\ezrSquared\Package + + https://github.com/uralstech/ezrSquared + + Icon (256x256).png + + True + True + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + true + MULTI_TARGETING_SUPPORT_ATTRIBUTES diff --git a/src/GlobalSuppressions.cs b/src/GlobalSuppressions.cs new file mode 100644 index 0000000..3cb47e8 --- /dev/null +++ b/src/GlobalSuppressions.cs @@ -0,0 +1,12 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Collections.EzrArray.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] +[assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Numerics.EzrInteger.#ctor(System.Numerics.BigInteger,EzrSquared.Runtime.Context,EzrSquared.Position,EzrSquared.Position)")] +[assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrCharacterList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] +[assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Collections.EzrList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] +[assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrString.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] diff --git a/src/Position.cs b/src/Position.cs new file mode 100644 index 0000000..2edb486 --- /dev/null +++ b/src/Position.cs @@ -0,0 +1,76 @@ +namespace EzrSquared; + +/// +/// The representation of a position in the script. +/// +/// The index of the in the script. +/// The line number of the in the script. +/// The file name/path of the script. +/// The script as text. +public class Position(int index, int line, string file, string script) +{ + /// + /// A position that does not exist. + /// + public readonly static Position None = new(int.MinValue, int.MinValue, string.Empty, string.Empty); + + /// + /// The index of the in the script. + /// + public int Index = index; + + /// + /// The line number of the in the script. + /// + public int Line = line; + + /// + /// The file name/path of the script. + /// + public readonly string File = file; + + /// + /// The script as text. + /// + public readonly string Script = script; + + /// + /// Advances the and increments by 1. If is a new-line character, is also incremented by 1. + /// + /// The character associated with the before advancing. + public void Advance(char currentChar) + { + Index++; + + if (currentChar == '\n') + Line++; + } + + /// + /// Reverses to the given index. + /// + /// The index to reverse to. + /// The decrement for . + public void ReverseTo(int index, int lineDecrement) + { + Index = index; + Line -= lineDecrement; + } + + /// + /// Advances the and increments by 1. + /// + public void Advance() + { + Index++; + } + + /// + /// Creates a copy of the object. + /// + /// The copy. + public Position Copy() + { + return new Position(Index, Line, File, Script); + } +} diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs new file mode 100644 index 0000000..ee47e7f --- /dev/null +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -0,0 +1,278 @@ +using EzrSquared.Runtime.Types; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Collections; + +/// +/// A Dictionary for s. +/// +/// \bug If the keys can be access and are mutable objects, they can still be changed. +public class RuntimeEzrObjectDictionary : IMutable +{ + /// + /// The collection of s stored in the , in the format Dictionary<hashOfKey, KeyValuePair<key, valueReference>>. + /// + private readonly Dictionary> _items; + + /// + /// Creates a new . + /// + public RuntimeEzrObjectDictionary() + { + _items = []; + } + + /// + /// Creates a new from an existing . + /// + public RuntimeEzrObjectDictionary(Dictionary> items) + { + _items = items; + } + + /// + /// The number of s in the . + /// + public int Length => _items.Count; + + /// + /// Updates the with a new value. + /// + /// The key to update. + /// The value to assign to . + /// The object for returning errors. + public void Update(IEzrObject key, IEzrObject value, RuntimeResult result) + { + int hash = key.ComputeHashCode(result); + if (result.ShouldReturn) + return; + + if (_items.TryGetValue(hash, out KeyValuePair reference)) + reference.Value.UpdateObject(value); + else + { + if (key is IEzrMutableObject mutableElement) + { + IEzrObject? keyCopy = (IEzrObject?)mutableElement.DeepCopy(result); + if (result.ShouldReturn) + return; + + key = keyCopy!; + } + + Reference valueReference = ReferencePool.Get(value); + valueReference.UpdateRegister(true); + + _items.Add(hash, new KeyValuePair(key, valueReference)); + } + } + + /// + /// Removes a key, value pair from the . + /// + /// The key to be removed. + /// The object for returning errors. + /// if the operation was successful, if not. + public bool Remove(IEzrObject key, RuntimeResult result) + { + int hash = key.ComputeHashCode(result); + if (result.ShouldReturn) + return false; + + if (_items.TryGetValue(hash, out KeyValuePair pair)) + { + pair.Value.UpdateRegister(false); + ReferencePool.TryRelease(pair.Value); + + return _items.Remove(hash); + } + + return false; + } + + /// + /// Removes a key, value pair from the . + /// + /// + /// This method removes pairs using the hash of the keys, . + /// + /// The key (hash) to be removed. + /// if the operation was successful, if not. + public bool RemoveHash(int key) + { + return _items.Remove(key); + } + + /// + /// Merges a to the current . + /// + /// The other to be merged. + public void Merge(RuntimeEzrObjectDictionary other) + { + foreach (KeyValuePair> pair in other._items) + _items[pair.Key] = pair.Value; + } + + /// + /// Tries retrieving a value from the . + /// + /// The key of the value to be returned. + /// The object for returning errors. + /// The retrieved value or if it was not found. + public Reference Get(IEzrObject key, RuntimeResult result) + { + int hash = key.ComputeHashCode(result); + + return (!result.ShouldReturn && _items.TryGetValue(hash, out KeyValuePair pair)) ? pair.Value : Reference.Empty; + } + + /// + /// Checks if exists in the . + /// + /// The key to be checked. + /// The object for returning errors. + /// if the key was found, if any error occured or the key was not found. + public bool HasKey(IEzrObject key, RuntimeResult result) + { + int hash = key.ComputeHashCode(result); + return !result.ShouldReturn && _items.ContainsKey(hash); + } + + /// + /// Checks if the current dictionary is equal to the given dictionary. + /// + /// The other dictionary. + /// The object for returning errors. + /// The comparison result. + public bool IsEqual(RuntimeEzrObjectDictionary other, RuntimeResult result) + { + if (other._items.Count != _items.Count) + return false; + + foreach (KeyValuePair> pair in _items) + { + if (!other._items.TryGetValue(pair.Key, out KeyValuePair otherPair)) + return false; + + bool keyEquals = pair.Value.Key.StrictEquals(otherPair.Key, result); + if (result.ShouldReturn || !keyEquals) + return false; + + bool valueEquals = pair.Value.Value.Object.StrictEquals(otherPair.Value.Object, result); + if (result.ShouldReturn || !valueEquals) + return false; + } + + return true; + } + + /// + /// Retrieves all keys from the . + /// + /// The keys. + public IEzrObject[] GetKeys() + { + KeyValuePair[] pairs = [.. _items.Values]; + IEzrObject[] keys = new IEzrObject[pairs.Length]; + + for (int i = 0; i < pairs.Length; i++) + keys[i] = pairs[i].Key; + return keys; + } + + /// + /// Returns the actual integer (hash) keys from the . + /// + /// The integer hashes. + public int[] GetRealKeys() + { + return [.. _items.Keys]; + } + + /// + /// Retrieves all values from the . + /// + /// The values. + public IEzrObject[] GetValues() + { + KeyValuePair[] pairs = [.. _items.Values]; + IEzrObject[] values = new IEzrObject[pairs.Length]; + + for (int i = 0; i < pairs.Length; i++) + values[i] = pairs[i].Value.Object; + return values; + } + + /// + /// Retrieves all keys and values from the . + /// + /// The keys and values as an array of s. + public KeyValuePair[] GetPairs() + { + KeyValuePair[] pairs = [.. _items.Values]; + KeyValuePair[] purePairs = new KeyValuePair[pairs.Length]; + + for (int i = 0; i < pairs.Length; i++) + purePairs[i] = new KeyValuePair(pairs[i].Key, pairs[i].Value.Object); + return purePairs; + } + + /// + public IMutable? DeepCopy(RuntimeResult result) + { + KeyValuePair[] keyValuePairs = [.. _items.Values]; + Dictionary> copiedItems = new(_items.Count); + + for (int i = 0; i < keyValuePairs.Length; i++) + { + (IEzrObject key, Reference value) = (keyValuePairs[i].Key, keyValuePairs[i].Value); + if (key is IEzrMutableObject mutableKey) + { + IEzrObject? keyCopy = (IEzrObject?)mutableKey.DeepCopy(result); + if (result.ShouldReturn) + return null; + + key = keyCopy!; + } + + IEzrObject valueObject = value.Object; + if (valueObject is IEzrMutableObject mutableValue) + { + IEzrObject? valueObjectCopy = (IEzrObject?)mutableValue.DeepCopy(result); + if (result.ShouldReturn) + return null; + + valueObject = valueObjectCopy!; + } + + Reference valueCopy = ReferencePool.Get(valueObject); + valueCopy.UpdateRegister(true); + + int hash = key.ComputeHashCode(result); + if (result.ShouldReturn) + return null; + + copiedItems.Add(hash, new KeyValuePair(key, valueCopy)); + } + + return new RuntimeEzrObjectDictionary(copiedItems); + } + + /// + /// Releases the references associated with the dictionary, and clears it. + /// + public void Release() + { + foreach (KeyValuePair> item in _items) + { + item.Value.Value.UpdateRegister(false); + ReferencePool.TryRelease(item.Value.Value); + } + + _items.Clear(); + _items.TrimExcess(); + } + + /// Destructor. + ~RuntimeEzrObjectDictionary() => Release(); +} diff --git a/src/Runtime/Collections/RuntimeEzrObjectList.cs b/src/Runtime/Collections/RuntimeEzrObjectList.cs new file mode 100644 index 0000000..3d40c8d --- /dev/null +++ b/src/Runtime/Collections/RuntimeEzrObjectList.cs @@ -0,0 +1,110 @@ +using EzrSquared.Runtime.Types; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Collections; + +/// +/// A List for s. +/// +public class RuntimeEzrObjectList : List, IMutable +{ + /// + /// Creates a new . + /// + public RuntimeEzrObjectList() : base() { } + + /// + /// Creates a new with the specified capacity. + /// + /// The capacity of the list. + public RuntimeEzrObjectList(int capacity) : base(capacity) { } + + /// + /// Creates a new based on another . + /// + /// The base collection of s. + public RuntimeEzrObjectList(IEnumerable collection) : base(collection) { } + + /// + /// Removes an element in the list at the given index. + /// + /// The index. + public new void RemoveAt(int index) + { + Reference reference = this[index]; + + reference.UpdateRegister(false); + ReferencePool.TryRelease(reference); + + base.RemoveAt(index); + } + + /// + /// Removes a range of elements in the list. + /// + /// The index to start the range. + /// The length of the range. + public new void RemoveRange(int index, int length) + { + foreach (Reference reference in GetRange(index, length)) + { + reference.UpdateRegister(false); + ReferencePool.TryRelease(reference); + } + + base.RemoveRange(index, length); + } + + /// + /// Creates a shallow copy of a range of elements in the list. + /// + /// The index to start the range. + /// The length of the range. + /// The copy. + public new RuntimeEzrObjectList GetRange(int index, int length) + { + return new RuntimeEzrObjectList(base.GetRange(index, length)); + } + + /// + public IMutable? DeepCopy(RuntimeResult result) + { + RuntimeEzrObjectList copy = []; + for (int i = 0; i < Count; i++) + { + Reference newReference = ReferencePool.Get(this[i].Object, this[i].AccessibilityModifiers); + newReference.UpdateRegister(true); + + if (newReference.Object is IEzrMutableObject mutableElement) + { + IEzrObject? objectCopy = (IEzrObject?)mutableElement.DeepCopy(result); + if (result.ShouldReturn) + return null; + + newReference.UpdateObject(objectCopy!); + } + + copy.Add(newReference); + } + + return copy; + } + + /// + /// Releases the references associated with the list, and clears it. + /// + public void Release() + { + for (int i = 0; i < Count; i++) + { + this[i].UpdateRegister(false); + ReferencePool.TryRelease(this[i]); + } + + Clear(); + TrimExcess(); + } + + /// Destructor. + ~RuntimeEzrObjectList() => Release(); +} diff --git a/src/Runtime/Context.cs b/src/Runtime/Context.cs new file mode 100644 index 0000000..90d82d1 --- /dev/null +++ b/src/Runtime/Context.cs @@ -0,0 +1,478 @@ +using EzrSquared.Runtime.Types; +using EzrSquared.Util; +using System; +using System.Collections.Generic; + +namespace EzrSquared.Runtime; + +/// +/// Stores all user defined variables/constant references, called symbols. +/// +public class Context +{ + /// + /// Represents the status of a call. + /// + public enum GetStatus + { + /// + /// The operation was successful. + /// + Ok, + + /// + /// The requested symbol was not found. + /// + UndefinedSymbolAccessNotAllowed, + + /// + /// Accessing privates symbols from s without permission is not allowed. + /// + AccessToPrivateSymbolNotAllowed, + + /// + /// Cannot access static symbols without a known static . + /// + StaticAccessWithoutDefinedContextNotAllowed, + + /// + /// Cannot access symbols with both and accessibility modifiers. + /// + InvalidGlobalPrivateAccessNotAllowed, + } + + /// + /// Represents the status of a set call. + /// + /// + /// This includes both and . + /// + public enum SetStatus + { + /// + /// The operation was successful. + /// + Ok, + + /// + /// Assigning new values to a constant reference is not allowed. + /// + ConstantAssignmentNotAllowed, + + /// + /// Assigning privates symbols from s without permission is not allowed. + /// + PrivateSymbolAssignmentNotAllowed, + + /// + /// Changing the accessibility of an existing symbol in a parent is not allowed. + /// + SymbolAccessibilityChangeInParentNotAllowed, + + /// + /// Assigning a private symbol to a child is not allowed. + /// + PrivateSymbolAssignmentInChildNotAllowed, + + /// + /// Changing the accessibility of a symbol which has not been assigned to a is not allowed. + /// + UnregisteredSymbolScopeOrVariabilityChangeNotAllowed, + + /// + /// Assigning static symbols without a known static is not allowed. + /// + StaticAssignmentWithoutDefinedContextNotAllowed, + + /// + /// Cannot assign symbols with both and accessibility modifiers. + /// + InvalidGlobalPrivateAssignmentNotAllowed, + } + + /// + /// An empty context. + /// + public static readonly Context Empty = new(string.Empty, false, Position.None); + + /// + /// The number of symbols in the context. + /// + public int Count => _symbols.Count; + + /// + /// The name of the . + /// + public readonly string Name; + + /// + /// The unique identifier of the . + /// + public readonly long Id; + + /// + /// Is this a static ? + /// + public readonly bool IsStatic; + + /// + /// The starting of the . + /// + public Position StartPosition { get; private set; } + + /// + /// Other s which are linked to this. + /// + /// + /// This allowed the to access variables from multiple s while in a local scope. + /// + public Context[] LinkedContexts { get; private set; } + + /// + /// The parent of this . May be . + /// + public Context? Parent { get; private set; } + + /// + /// The static in relation to this . May be . + /// + public Context? StaticContext { get; private set; } + + /// + /// The symbols of this . + /// + private Dictionary _symbols; + + /// + /// Creates a new . + /// + /// The name of the . + /// Is this a static ? + /// The starting of the . + /// The parent of this . Can be . + /// The static in relation to this . Can be . + /// The number of other s which are linked to this. See . + /// Raised if is and a static as was provided at the same time. This is invalid as a can either be static or have a static related to it, but not both. + public Context(string name, bool isStatic, Position startPosition, Context? parent = null, Context? staticContext = null, int linkedContexts = 0) + { + Name = name; + Id = Utils.GetNextUniqueId(); + LinkedContexts = linkedContexts == 0 ? [] : new Context[linkedContexts]; + + if (isStatic && StaticContext != null) + throw new ArgumentException("A context cannot be static AND have a static context assigned to it.", nameof(staticContext)); + + IsStatic = isStatic; + StaticContext = staticContext ?? (IsStatic ? this : null); + + _symbols = []; + + StartPosition = startPosition; + Parent = parent; + } + + /// + /// Clears the existing and creates a new empty of s. + /// + /// The number of s to allocate the for. + public void SetNewLinkedContexts(int contexts) + { + LinkedContexts = contexts == 0 ? [] : new Context[contexts]; + } + + /// + /// Updates the to a new one. + /// + /// The new static . + public void UpdateStaticContext(Context? newStaticContext) + { + StaticContext = newStaticContext; + } + + /// + /// Updates the parent of this / + /// + /// The new parent . + public void UpdateParent(Context newParent) + { + if (newParent.Id != Id && !newParent.IsContextParent(this)) + Parent = newParent; + } + + /// + /// Updates the starting of this / + /// + /// The new starting . + public void UpdatePosition(Position startPosition) + { + StartPosition = startPosition; + } + + /// + /// Checks if the given is a parent of this . + /// + /// The to check. + /// if it is, otherwise. + private bool IsContextParent(Context context) + { + return Parent is not null && (Parent.Id == context.Id || Parent.IsContextParent(context)); + } + + /// + /// Retrieves the of the requested symbol. + /// + /// The from which the operation is being called. + /// The symbol to retrieve. + /// The resulting . + /// Accessibility modifiers of the operation, by default. + /// Should the ignore its linked contexts? (Used mainly for retrieving a reference before symbol assignment) + /// The , representing the result of the operation. + public GetStatus Get(Context? callingContext, string symbol, out Reference objectReference, AccessMod accessibilityModifiers = AccessMod.None, bool ignoreLinkedContexts = false) + { + callingContext ??= this; + if ((accessibilityModifiers & AccessMod.Global) == AccessMod.Global && Parent is not null) + return Parent.Get(callingContext, symbol, out objectReference, accessibilityModifiers, ignoreLinkedContexts); + + if ((accessibilityModifiers & AccessMod.InvalidGlobalPrivate) == AccessMod.InvalidGlobalPrivate) + { + objectReference = Reference.Empty; + return GetStatus.InvalidGlobalPrivateAccessNotAllowed; + } + + if ((accessibilityModifiers & AccessMod.Static) == AccessMod.Static) + if (StaticContext is not null && StaticContext.Id != Id) + return StaticContext.Get(callingContext, symbol, out objectReference, accessibilityModifiers, ignoreLinkedContexts); + else if (!IsStatic) + { + objectReference = Reference.Empty; + return GetStatus.StaticAccessWithoutDefinedContextNotAllowed; + } + + if (_symbols.TryGetValue(symbol, out Reference? reference)) + { + if ((reference.AccessibilityModifiers & AccessMod.Private) == AccessMod.Private + && callingContext.Id != Id && !callingContext.IsContextParent(this)) + { + objectReference = Reference.Empty; + return GetStatus.AccessToPrivateSymbolNotAllowed; + } + + objectReference = reference; + objectReference.UpdateRegisteredContext(this); + + return GetStatus.Ok; + } + + if ((accessibilityModifiers & AccessMod.Global) == AccessMod.Global) + { + objectReference = ReferencePool.Get(name: symbol); + objectReference.UpdateRegisteredContext(this); + + return GetStatus.UndefinedSymbolAccessNotAllowed; + } + + if (!ignoreLinkedContexts) + { + for (int i = 0; i < LinkedContexts.Length; i++) + { + Context linkedContext = LinkedContexts[i]; + if (linkedContext is null) + continue; + + GetStatus status = linkedContext.Get(callingContext, symbol, out objectReference, AccessMod.LocalScope); + if (status == GetStatus.Ok) + return status; + } + } + + if (Parent is not null && (accessibilityModifiers & AccessMod.LocalScope) != AccessMod.LocalScope) + { + GetStatus status = Parent.Get(callingContext, symbol, out objectReference, accessibilityModifiers, ignoreLinkedContexts); + if (status == GetStatus.Ok) + return status; + } + + objectReference = ReferencePool.Get(name: symbol); + objectReference.UpdateRegisteredContext(this); + return GetStatus.UndefinedSymbolAccessNotAllowed; + } + + /// + /// Sets a new to an existing . + /// + /// + /// If is , the operation is passed onto . + /// + /// The from which the operation is being called. + /// The new to be assigned and the name of the symbol, in the format ( Object, Name). + /// The old reference to assign to. + /// Accessibility modifiers of the operation, by default. + /// The , representing the result of the operation. + public (SetStatus, Reference) Set(Context? callingContext, (IEzrObject Object, string Name) newObject, Reference oldReference, AccessMod accessibilityModifiers = AccessMod.None) + { + if (oldReference.IsEmpty) + { + Reference newReference = ReferencePool.Get(newObject.Object, accessibilityModifiers, newObject.Name); + return (Set(callingContext, newObject.Name, newReference), newReference); + } + + if ((accessibilityModifiers & AccessMod.InvalidGlobalPrivate) == AccessMod.InvalidGlobalPrivate) + return (SetStatus.InvalidGlobalPrivateAssignmentNotAllowed, Reference.Empty); + + if ((oldReference.AccessibilityModifiers & AccessMod.Constant) == AccessMod.Constant) + return (SetStatus.ConstantAssignmentNotAllowed, Reference.Empty); + + if ((accessibilityModifiers & AccessMod.Static) == AccessMod.Static) + if (StaticContext is not null && StaticContext.Id != Id) + return StaticContext.Set(callingContext, newObject, oldReference, accessibilityModifiers); + else if (!IsStatic) + return (SetStatus.StaticAssignmentWithoutDefinedContextNotAllowed, Reference.Empty); + + callingContext ??= this; + if ((accessibilityModifiers & AccessMod.Private) == AccessMod.Private + && (oldReference.RegisteredContext?.IsContextParent(callingContext) ?? false)) + return (SetStatus.PrivateSymbolAssignmentInChildNotAllowed, Reference.Empty); + + bool areCallingAndReceivingContextsSame = callingContext.Id == oldReference.RegisteredContext?.Id; + bool isCallingContextRelatedToReceivingContext = areCallingAndReceivingContextsSame + || (oldReference.RegisteredContext is not null && callingContext.IsContextParent(oldReference.RegisteredContext)); + + if (oldReference.RegisteredContext is not null + && ((oldReference.AccessibilityModifiers | accessibilityModifiers) & AccessMod.Private) == AccessMod.Private + && !isCallingContextRelatedToReceivingContext) + return (SetStatus.PrivateSymbolAssignmentNotAllowed, Reference.Empty); + + if ((accessibilityModifiers & AccessMod.Private) == AccessMod.Private + || (accessibilityModifiers & AccessMod.Constant) == AccessMod.Constant) + if (isCallingContextRelatedToReceivingContext && !areCallingAndReceivingContextsSame) + return (SetStatus.SymbolAccessibilityChangeInParentNotAllowed, Reference.Empty); + else if (oldReference.RegisteredContext is null) + return (SetStatus.UnregisteredSymbolScopeOrVariabilityChangeNotAllowed, Reference.Empty); + + if (oldReference.RegisteredContext is null) + oldReference.UpdateObject(newObject.Object); + else + oldReference.UpdateObject(newObject.Object, accessibilityModifiers); + + return (SetStatus.Ok, oldReference); + } + + /// + /// Sets the to a new symbol. + /// + /// The from which the operation is being called. + /// The symbol to assign. + /// The reference to assign to the symbol. + /// The , representing the result of the operation. + public SetStatus Set(Context? callingContext, string symbol, Reference objectReference) + { + callingContext ??= this; + AccessMod accessibilityModifiers = objectReference.AccessibilityModifiers; + + if ((accessibilityModifiers & AccessMod.Global) == AccessMod.Global && Parent is not null) + return Parent.Set(callingContext, symbol, objectReference); + + if ((accessibilityModifiers & AccessMod.InvalidGlobalPrivate) == AccessMod.InvalidGlobalPrivate) + return SetStatus.InvalidGlobalPrivateAssignmentNotAllowed; + + if ((accessibilityModifiers & AccessMod.Static) == AccessMod.Static) + if (StaticContext is not null && StaticContext.Id != Id) + return StaticContext.Set(callingContext, symbol, objectReference); + else if (!IsStatic) + return SetStatus.StaticAssignmentWithoutDefinedContextNotAllowed; + + bool objectReferenceIsPrivate = (objectReference.AccessibilityModifiers & AccessMod.Private) == AccessMod.Private; + if (objectReferenceIsPrivate && IsContextParent(callingContext)) + return SetStatus.PrivateSymbolAssignmentInChildNotAllowed; + + bool areCallingAndReceivingContextsSame = callingContext.Id == Id; + bool isCallingContextRelatedToReceivingContext = areCallingAndReceivingContextsSame || callingContext.IsContextParent(this); + + if (_symbols.TryGetValue(symbol, out Reference? reference)) + { + if ((reference.AccessibilityModifiers & AccessMod.Constant) == AccessMod.Constant) + return SetStatus.ConstantAssignmentNotAllowed; + + if (((reference.AccessibilityModifiers & AccessMod.Private) == AccessMod.Private || objectReferenceIsPrivate) + && !isCallingContextRelatedToReceivingContext) + return SetStatus.PrivateSymbolAssignmentNotAllowed; + + _symbols[symbol] = objectReference; + objectReference.UpdateRegisteredContext(this); + return SetStatus.Ok; + } + + _symbols.Add(symbol, objectReference); + objectReference.UpdateRegisteredContext(this); + return SetStatus.Ok; + } + + /// + /// Checks if a symbol has been defined in this / + /// + /// The name of the symbol to check. + /// if it is, otherwise. + public bool IsDefined(string name) + { + return _symbols.ContainsKey(name); + } + + /// + /// Creates a deep copy of the context. + /// + /// + /// It is the caller's responsibility to handle linked contexts. + /// + /// Runtime result for raising errors/ + /// Symbols to exclude when copying. + /// The copy, or, if failed. + public Context? DeepCopy(RuntimeResult result, IEzrObject[] excludedSymbols) + { + Dictionary newSymbols = new(_symbols.Count); + + Context newContext = new(Name, IsStatic, StartPosition, Parent, StaticContext, LinkedContexts.Length); + foreach (KeyValuePair keyValuePair in _symbols) + { + if (Array.Exists(excludedSymbols, excludedSymbol => ReferenceEquals(excludedSymbol, keyValuePair.Value.Object))) + continue; + + Reference? copy = (Reference?)keyValuePair.Value.DeepCopy(result); + if (result.ShouldReturn) + return null; + + copy!.UpdateRegisteredContext(newContext); + + if (copy.Object is IEzrMutableObject mutable) + { + mutable.Context.UpdateParent(newContext); + (mutable as EzrObject)?.UpdateCreationContext(newContext); + } + + newSymbols[keyValuePair.Key] = copy; + } + + newContext._symbols = newSymbols; + return newContext; + } + + /// + /// Releases all references in the context and clears the symbols dictionary. + /// + public void Release() + { + foreach (KeyValuePair reference in _symbols) + { + reference.Value.UpdateRegisteredContext(null); + ReferencePool.TryRelease(reference.Value); + } + + _symbols.Clear(); + _symbols.TrimExcess(); + + for (int i = 0; i < LinkedContexts.Length; i++) + LinkedContexts[i]?.Release(); + } + + /// Destructor. + ~Context() => Release(); +} diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs new file mode 100644 index 0000000..e3576a4 --- /dev/null +++ b/src/Runtime/Interpreter.cs @@ -0,0 +1,1431 @@ +using EzrSquared.Runtime.Collections; +using EzrSquared.Runtime.Nodes; +using EzrSquared.Runtime.Types; +using EzrSquared.Runtime.Types.Collections; +using EzrSquared.Runtime.Types.Core; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.Core.Text; +using EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace EzrSquared.Runtime; + +/// +/// The ezr² Interpreter. The job of the Interpreter is to execute the Abstract Syntax Tree (AST) received from the (as a single object)! +/// +public class Interpreter +{ + /// + /// The result of the current execution. + /// + public readonly RuntimeResult RuntimeResult = new(); + + /// + /// Executes an AST under the given and returns the result. + /// + /// The AST, as a single object. + /// The run-time in which the AST will be executed. + /// The accessibility modifiers for objects that will be assigned from the executing . + /// The object. + public RuntimeResult Execute(Node ast, Context runtimeContext, AccessMod accessibilityModifiers = AccessMod.None) + { + RuntimeResult.Reset(); + + VisitNode(ast, runtimeContext, null, accessibilityModifiers); + return RuntimeResult; + } + + /// + /// Vists a and sends it to the appropriate execution function. + /// + /// The to execute. + /// The under which the execution will take place. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + /// Should the interpreter ignore undefined variables? + /// Raised if is of type . This should never happen as this means something has gone very wrong in the . + /// Raised if the method for executing has not been implemented. + internal void VisitNode(Node astNode, Context executionContext, Context? callingContext, AccessMod accessibilityModifiers, bool ignoreUndefinedVariable = false) + { + callingContext ??= executionContext; + switch (astNode) + { + case ValueNode node: + VisitValueNode(node, executionContext); + break; + case ArrayLikeNode node: + VisitArrayLikeNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case DictionaryNode node: + VisitDictionaryNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case VariableAccessNode node: + VisitVariableAccessNode(node, executionContext, callingContext, accessibilityModifiers, ignoreUndefinedVariable); + break; + case VariableAssignmentNode node: + VisitVariableAssignmentNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case DefineBlockNode node: + VisitDefineBlockNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case UnaryOperationNode node: + VisitUnaryOperationNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case BinaryOperationNode node: + VisitBinaryOperationNode(node, executionContext, callingContext, accessibilityModifiers, ignoreUndefinedVariable); + break; + case IfNode node: + VisitIfNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case CountNode node: + VisitCountNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case WhileNode node: + VisitWhileNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case TryNode node: + VisitTryNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case FunctionDefinitionNode node: + VisitFunctionDefinitionNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case ClassDefinitionNode node: + VisitClassDefinitionNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case CallNode node: + VisitCallNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case NoValueNode node: + VisitNoValueNode(node, executionContext); + break; + case ReturnNode node: + VisitReturnNode(node, executionContext, callingContext, accessibilityModifiers); + break; + case InvalidNode: + throw new ArgumentException("Interpreter received an InvalidNode object! Something has gone very wrong in the Parser.", nameof(astNode)); + default: + throw new NotImplementedException($"Visit{astNode.GetType().Name}() not defined!"); + } + } + + /// + /// Throws errors for returns. + /// + /// The set status. + /// The name of the set reference. + /// The node of the reference object. + /// The context of the reference. + /// Thrown if an unknown set status is encountered. + private void HandleSetStatus(Context.SetStatus status, string referenceName, Node referenceNode, Context referenceContext) + { + switch (status) + { + case Context.SetStatus.Ok: + break; + case Context.SetStatus.ConstantAssignmentNotAllowed: + RuntimeResult.Failure(new EzrIllegalOperationError($"Cannot change constant value \"{referenceName}\"!", referenceContext, referenceNode.StartPosition, referenceNode.EndPosition)); + break; + case Context.SetStatus.PrivateSymbolAssignmentNotAllowed: + RuntimeResult.Failure(new EzrPrivateMemberOperationError($"Cannot change or create private value \"{referenceName}\"!", referenceContext, referenceNode.StartPosition, referenceNode.EndPosition)); + break; + case Context.SetStatus.SymbolAccessibilityChangeInParentNotAllowed: + RuntimeResult.Failure(new EzrIllegalOperationError($"Cannot change \"{referenceName}\" to private or constant in a parent context!", referenceContext, referenceNode.StartPosition, referenceNode.EndPosition)); + break; + case Context.SetStatus.PrivateSymbolAssignmentInChildNotAllowed: + RuntimeResult.Failure(new EzrPrivateMemberOperationError($"Cannot change or create private value \"{referenceName}\" in child!", referenceContext, referenceNode.StartPosition, referenceNode.EndPosition)); + break; + case Context.SetStatus.UnregisteredSymbolScopeOrVariabilityChangeNotAllowed: + RuntimeResult.Failure(new EzrPrivateMemberOperationError("Cannot change reference to private or constant as it is not registered in a context!", referenceContext, referenceNode.StartPosition, referenceNode.EndPosition)); + break; + case Context.SetStatus.StaticAssignmentWithoutDefinedContextNotAllowed: + RuntimeResult.Failure(new EzrIllegalOperationError("Cannot assign static variable outside a static context!", referenceContext, referenceNode.StartPosition, referenceNode.EndPosition)); + break; + case Context.SetStatus.InvalidGlobalPrivateAssignmentNotAllowed: + RuntimeResult.Failure(new EzrIllegalOperationError("Cannot assign a variable with both 'global' and 'private' accessibility modifiers! Are you assigning it in a 'global' or 'private' define block?", referenceContext, referenceNode.StartPosition, referenceNode.EndPosition)); + break; + default: + throw new NotImplementedException($"Case for SetStatus {status} not implemented in {nameof(AssignValueToVariable)}!"); + } + } + + /// + /// Throws errors for returns. + /// + /// The set result. + /// The name of the set reference. + /// The node of the reference object. + /// The context of the reference. + /// The set reference. + private Reference HandleSetStatus((Context.SetStatus Status, Reference Reference) setResult, string referenceName, Node referenceNode, Context referenceContext) + { + HandleSetStatus(setResult.Status, referenceName, referenceNode, referenceContext); + return setResult.Reference; + } + + /// + /// Creates a "value" type object - i.e. , , , and , from a . + /// + /// The to execute. + /// The under which the value will be created. + /// Raised if an unimplemented or unexpected is encountered in . + private void VisitValueNode(ValueNode node, Context executionContext) + { + switch (node.Value.Type) + { + case TokenType.Integer: + RuntimeResult.Success(ReferencePool.Get(new EzrInteger(BigInteger.Parse(node.Value.Value), executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + break; + case TokenType.FloatingPoint: + RuntimeResult.Success(ReferencePool.Get(new EzrFloat(double.Parse(node.Value.Value), executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + break; + case TokenType.String: + RuntimeResult.Success(ReferencePool.Get(new EzrString(node.Value.Value, executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + break; + case TokenType.Character: + RuntimeResult.Success(ReferencePool.Get(new EzrCharacter(char.Parse(node.Value.Value), executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + break; + case TokenType.CharacterList: + RuntimeResult.Success(ReferencePool.Get(new EzrCharacterList(node.Value.Value, executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + break; + default: + throw new NotImplementedException($"Invalid TokenType \"{node.Value.Type}\" for {nameof(VisitValueNode)}!"); + } + } + + /// + /// Creates an array-like object, see , and for more information. + /// + /// The to execute. + /// The under which the array-like object will be created. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + #region private void VisitArrayLikeNode(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + private void VisitArrayLikeNode(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + if (node.CreateList) + CreateList(node, executionContext, callingContext, accessibilityModifiers); + else + CreateArray(node, executionContext, callingContext, accessibilityModifiers); + } + + /// + /// Creates a list of references to its elements. + /// + /// The to execute. + /// The under which the list will be created. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void CreateList(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + RuntimeEzrObjectList elementsReferences = new(node.Elements.Count); + for (int i = 0; i < node.Elements.Count; i++) + { + Node elementNode = node.Elements[i]; + VisitNode(elementNode, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + Reference reference = ReferencePool.Get(RuntimeResult.Reference.Object, AccessMod.None, string.Empty); + reference.UpdateRegister(true); + + elementsReferences.Add(reference); + } + + RuntimeResult.Success(ReferencePool.Get(new EzrList(elementsReferences, executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + } + + /// + /// Creates an array of objects. + /// + /// The to execute. + /// The under which the array will be created. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void CreateArray(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + IEzrObject[] elements = new IEzrObject[node.Elements.Count]; + for (int i = 0; i < node.Elements.Count; i++) + { + Node elementNode = node.Elements[i]; + VisitNode(elementNode, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + elements[i] = RuntimeResult.Reference.Object; + } + + RuntimeResult.Success(ReferencePool.Get(new EzrArray(elements, executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + } + #endregion + + /// + /// Creates a object from a . + /// + /// The to execute. + /// The under which the dictionary will be created. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void VisitDictionaryNode(DictionaryNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + RuntimeEzrObjectDictionary dictionary = new(); + List<(Node Key, Node Value)> pairs = node.KeyValuePairs; + + for (int i = 0; i < pairs.Count; i++) + { + // Get the key. + VisitNode(pairs[i].Key, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + IEzrObject key = RuntimeResult.Reference.Object; + + // Get the value. + VisitNode(pairs[i].Value, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + // Add it to the dictionary! + dictionary.Update(key, RuntimeResult.Reference.Object, RuntimeResult); + if (RuntimeResult.ShouldReturn) + return; + } + + RuntimeResult.Success(ReferencePool.Get(new EzrDictionary(dictionary, executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + } + + /// + /// Executes a and access a variable from the given . + /// + /// The to execute. + /// The from which the variable will be accessed. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + /// Should the interpreter ignore undefined variables? + /// Thrown if a case for the of the operation was not defined. + private void VisitVariableAccessNode(VariableAccessNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers, bool ignoreUndefinedVariable) + { + string name = node.Name.Value; + AccessMod operationAccessibilityModifiers = node.AccessibilityModifiers | accessibilityModifiers; + + // Get the reference. + Context.GetStatus status = executionContext.Get(callingContext, name, out Reference variable, operationAccessibilityModifiers, ignoreUndefinedVariable); + switch (status) + { + case Context.GetStatus.Ok: + case Context.GetStatus.UndefinedSymbolAccessNotAllowed when ignoreUndefinedVariable: + // If the reference is empty, break. + if (variable.IsEmpty) + { + RuntimeResult.Success(variable); + break; + } + + // Else, update the referenced object with the new context and position. + variable.Object.Update(executionContext, node.StartPosition, node.EndPosition); + + RuntimeResult.Success(variable); + break; + case Context.GetStatus.UndefinedSymbolAccessNotAllowed: + RuntimeResult.Failure(new EzrUndefinedValueError($"Variable \"{name}\" not defined!", executionContext, node.StartPosition, node.EndPosition)); + break; + case Context.GetStatus.AccessToPrivateSymbolNotAllowed: + RuntimeResult.Failure(new EzrPrivateMemberOperationError($"Cannot access private value \"{name}\"!", executionContext, node.StartPosition, node.EndPosition)); + break; + case Context.GetStatus.StaticAccessWithoutDefinedContextNotAllowed: + RuntimeResult.Failure(new EzrIllegalOperationError("Cannot access static variable outside a static context!", executionContext, node.StartPosition, node.EndPosition)); + break; + case Context.GetStatus.InvalidGlobalPrivateAccessNotAllowed: + RuntimeResult.Failure(new EzrIllegalOperationError("Cannot access a variable with both 'global' and 'private' accessibility modifiers! Are you accessing it in a 'global' or 'private' define block?", executionContext, node.StartPosition, node.EndPosition)); + break; + default: + throw new NotImplementedException($"Case for GetStatus {status} not implemented in {nameof(VisitVariableAccessNode)}!"); + } + } + + /// + /// Executes a and sets a variable/constant in the given . + /// + /// + /// A binary operation may also be executed depending on .
+ /// In the case a is provided as , multiple variables/constants will be assigned. + ///
+ /// The to execute. + /// The in which the variable will be assigned. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + #region VisitVariableAssignmentNode(VariableAssignmentNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + private void VisitVariableAssignmentNode(VariableAssignmentNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + AccessMod operationAccessibilityModifiers = node.AccessibilityModifiers | accessibilityModifiers; + + bool isSingleVariable = false; + Node[] variableNodes; + + // Check how many references are to be assigned. + if (node.Variable is ArrayLikeNode arrayLikeNode) + variableNodes = [.. arrayLikeNode.Elements]; + else + { + // Set flag if there is only one. + isSingleVariable = true; + + variableNodes = [node.Variable]; + } + + Reference[] variables = new Reference[variableNodes.Length]; + + // Get the references. + for (int i = 0; i < variableNodes.Length; i++) + { + Node elementNode = variableNodes[i]; + + // Set scope to local, if it is not global - to restrict it to the current execution context. + if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) + operationAccessibilityModifiers |= AccessMod.LocalScope; + + VisitNode(elementNode, executionContext, callingContext, operationAccessibilityModifiers, true); + if (RuntimeResult.ShouldReturn) + return; + + Reference reference = RuntimeResult.Reference; + if (!reference.IsRegistered) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for variable name, but got object of type \"{reference.Object.TypeName}\"!", executionContext, elementNode.StartPosition, elementNode.EndPosition)); + return; + } + + variables[i] = reference; + } + + VisitNode(node.Value, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + AssignValuesToVariables(node, variables, isSingleVariable, executionContext, callingContext, accessibilityModifiers); + } + + /// + /// Assigns the value(s) to the variable(s) defined in the . + /// + /// The being executed. + /// The array of variable references to be assigned to. + /// Is only one variable being assigned? + /// The in which the variable will be assigned. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void AssignValuesToVariables(VariableAssignmentNode node, Reference[] variables, bool isSingleVariable, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + IEzrObject value = RuntimeResult.Reference.Object; + if (isSingleVariable) + { + AssignValueToVariable(variables[0], value, node, executionContext, callingContext, accessibilityModifiers); + return; + } + + IEzrObject[] references; + IEzrObject[]? values; + + switch (value) + { + case IEzrIndexedCollection otherCollection when otherCollection.Length != variables.Length: + RuntimeResult.Failure(new EzrIllegalOperationError("Mismatched number of variables and values in assignment!", executionContext, node.StartPosition, node.EndPosition)); + return; + + case EzrArray otherArray: + values = otherArray.Value; break; + case EzrList otherList: + values = new IEzrObject[variables.Length]; + for (int i = 0; i < otherList.Value.Count; i++) + values[i] = otherList.Value[i].Object; + + break; + + default: + values = null; break; + } + + references = new IEzrObject[variables.Length]; + for (int i = 0; i < variables.Length; i++) + { + AssignValueToVariable(variables[i], values?[i] ?? value, node, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + references[i] = RuntimeResult.Reference.Object; + } + + RuntimeResult.Success(ReferencePool.Get(new EzrArray(references, executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + } + + /// + /// Assigns one of the values to one of the variables defined in the . + /// + /// The variable reference to assign to. + /// The value object to be assigned. + /// The being executed. + /// The in which the variable will be assigned. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void AssignValueToVariable(Reference variable, IEzrObject value, VariableAssignmentNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + Context assignmentContext = variable.RegisteredContext ?? executionContext; + if (node.AssignmentOperator != TokenType.Colon) + { + if (variable.IsEmpty) + { + RuntimeResult.Failure(new EzrUndefinedValueError($"Variable \"{variable.Name}\" does not exist for operation!", assignmentContext, node.Variable.StartPosition, node.Variable.EndPosition)); + return; + } + + ExecuteBinaryOperation(variable.Object, value, node, node.AssignmentOperator, assignmentContext); + if (RuntimeResult.ShouldReturn) + return; + + value = RuntimeResult.Reference.Object; + } + + (IEzrObject Object, string Name) newVariable = (value, variable.Name); + Reference variableReference = + HandleSetStatus( + assignmentContext.Set(callingContext, newVariable, variable, node.AccessibilityModifiers | accessibilityModifiers), + variable.Name, node.Variable, assignmentContext + ); + + if (RuntimeResult.ShouldReturn) + return; + + RuntimeResult.Success(variableReference); + } + #endregion + + /// + /// Executes a under its accessibility modifiers in the given . + /// + /// The to execute. + /// The in which the block will be executed. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void VisitDefineBlockNode(DefineBlockNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + AccessMod operationAccessibilityModifiers = node.AccessibilityModifiers | accessibilityModifiers; + VisitNode(node.Body, executionContext, callingContext, operationAccessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + } + + /// + /// Executes a and performs a unary operation. + /// + /// The to execute. + /// The under which the operation will be executed. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + /// Thrown if a case for the of the operand was not defined. + private void VisitUnaryOperationNode(UnaryOperationNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + VisitNode(node.Operand, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + IEzrObject operand = RuntimeResult.Reference.Object; + switch (node.Operator) + { + case TokenType.KeywordNot: + case TokenType.KeywordInvert: + operand.Inversion(RuntimeResult); + break; + + case TokenType.Tilde: + operand.BitwiseNegation(RuntimeResult); + break; + + case TokenType.HyphenMinus: + operand.Negation(RuntimeResult); + break; + case TokenType.Plus: + operand.Affirmation(RuntimeResult); + break; + + default: + throw new NotImplementedException($"Case for TokenType {node.Operator} not implemented in {nameof(VisitUnaryOperationNode)}()!"); + } + + if (RuntimeResult.ShouldReturn) + return; + + RuntimeResult.Reference.Object.Update(executionContext, node.StartPosition, node.EndPosition); + } + + /// + /// Executes a and performs a binary operation. + /// + /// The to execute. + /// The under which the operation will be executed. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + /// Should the interpreter ignore undefined variables? + private void VisitBinaryOperationNode(BinaryOperationNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers, bool ignoreUndefinedVariable) + { + switch (node.Operator) + { + case TokenType.Period: + ExecuteObjectAttributeAccess(node, executionContext, callingContext, accessibilityModifiers, ignoreUndefinedVariable); break; + + case TokenType.KeywordOr: + case TokenType.KeywordAnd: + ExecuteConjunctiveOperators(node, executionContext, callingContext, accessibilityModifiers); break; + + default: + VisitNode(node.Left, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + IEzrObject left = RuntimeResult.Reference.Object; + + VisitNode(node.Right, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + ExecuteBinaryOperation(left, RuntimeResult.Reference.Object, node, node.Operator, executionContext); break; + } + } + + /// + /// Executes an object attribute access operation. + /// + /// The operation's AST node. + /// The context under which the operation will take place. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + /// Should the interpreter ignore undefined variables? + private void ExecuteObjectAttributeAccess(BinaryOperationNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers, bool ignoreUndefinedVariable) + { + AccessMod operationAccessibilityModifiers = (node.Left as BinaryOperationNode)?.Operator != TokenType.Period + ? accessibilityModifiers & ~AccessMod.LocalScope + : accessibilityModifiers; + + VisitNode(node.Left, executionContext, callingContext, accessibilityModifiers & ~AccessMod.LocalScope); + if (RuntimeResult.ShouldReturn) + return; + + RuntimeResult.Reference.Object.Interpret(node.Right, callingContext, this, RuntimeResult, ignoreUndefinedVariable); + if (RuntimeResult.ShouldReturn) + return; + + Reference reference = RuntimeResult.Reference; + if (!reference.IsEmpty) + reference.Object.Update(executionContext, node.StartPosition, node.EndPosition); + } + + /// + /// Executes a boolean conjunctive operation. + /// + /// The operation's AST node. + /// The context under which the operation will take place. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void ExecuteConjunctiveOperators(BinaryOperationNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + VisitNode(node.Left, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + bool firstEvaluation = RuntimeResult.Reference.Object.EvaluateBoolean(RuntimeResult); + if (RuntimeResult.ShouldReturn) + return; + + EzrBoolean booleanValue; + if ((!firstEvaluation && node.Operator == TokenType.KeywordAnd) || (firstEvaluation && node.Operator == TokenType.KeywordOr)) + { + booleanValue = firstEvaluation ? EzrConstants.True : EzrConstants.False; + booleanValue.Update(executionContext, node.StartPosition, node.EndPosition); + + RuntimeResult.Success(ReferencePool.Get(booleanValue, AccessMod.PrivateConstant)); + return; + } + + VisitNode(node.Right, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + bool secondEvaluation = RuntimeResult.Reference.Object.EvaluateBoolean(RuntimeResult); + if (RuntimeResult.ShouldReturn) + return; + + booleanValue = secondEvaluation ? EzrConstants.True : EzrConstants.False; + booleanValue.Update(executionContext, node.StartPosition, node.EndPosition); + + RuntimeResult.Success(ReferencePool.Get(booleanValue, AccessMod.PrivateConstant)); + } + + /// + /// Executes a binary operation. + /// + /// The first value in the operation. + /// The second value in the operation. + /// The operation's AST node. + /// The operation to perform. + /// The context under which the operation will take place. + /// Thrown if a case for the of the operand was not defined. + private void ExecuteBinaryOperation(IEzrObject first, IEzrObject second, Node node, TokenType operation, Context executionContext) + { + switch (operation) + { + case TokenType.Plus: + case TokenType.AssignmentAddition: + first.Addition(second, RuntimeResult); + break; + + case TokenType.HyphenMinus: + case TokenType.AssignmentSubtraction: + first.Subtraction(second, RuntimeResult); + break; + + case TokenType.Asterisk: + case TokenType.AssignmentMultiplication: + first.Multiplication(second, RuntimeResult); + break; + + case TokenType.Slash: + case TokenType.AssignmentDivision: + first.Division(second, RuntimeResult); + break; + + case TokenType.Caret: + case TokenType.AssignmentPower: + first.Power(second, RuntimeResult); + break; + + case TokenType.PercentSign: + case TokenType.AssignmentModulo: + first.Modulo(second, RuntimeResult); + break; + + case TokenType.Ampersand: + case TokenType.AssignmentBitwiseAnd: + first.BitwiseAnd(second, RuntimeResult); + break; + + case TokenType.VerticalBar: + case TokenType.AssignmentBitwiseOr: + first.BitwiseOr(second, RuntimeResult); + break; + + case TokenType.Backslash: + case TokenType.AssignmentBitwiseXOr: + first.BitwiseXOr(second, RuntimeResult); + break; + + case TokenType.BitwiseLeftShift: + case TokenType.AssignmentBitwiseLeftShift: + first.BitwiseLeftShift(second, RuntimeResult); + break; + + case TokenType.BitwiseRightShift: + case TokenType.AssignmentBitwiseRightShift: + first.BitwiseRightShift(second, RuntimeResult); + break; + + case TokenType.EqualSign: + first.ComparisonEqual(second, RuntimeResult); + break; + + case TokenType.ExclamationMark: + first.ComparisonNotEqual(second, RuntimeResult); + break; + + case TokenType.LessThanSign: + first.ComparisonLessThan(second, RuntimeResult); + break; + + case TokenType.GreaterThanSign: + first.ComparisonGreaterThan(second, RuntimeResult); + break; + + case TokenType.LessThanOrEqual: + first.ComparisonLessThanOrEqual(second, RuntimeResult); + break; + + case TokenType.GreaterThanOrEqual: + first.ComparisonGreaterThanOrEqual(second, RuntimeResult); + break; + + case TokenType.KeywordIn: + second.HasValueContained(first, RuntimeResult); + break; + + case TokenType.KeywordNot: + second.NotHasValueContained(first, RuntimeResult); + break; + + default: + throw new NotImplementedException($"Case for TokenType {operation} not implemented in {nameof(ExecuteBinaryOperation)}()!"); + } + + if (RuntimeResult.ShouldReturn) + return; + + RuntimeResult.Reference.Object.Update(executionContext, node.StartPosition, node.EndPosition); + } + + /// + /// Executes an and performs a boolean expression. + /// + /// The to execute. + /// The under which the expression will be executed. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void VisitIfNode(IfNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + for (int i = 0; i < node.Cases.Count; i++) + { + VisitNode(node.Cases[i].Condition, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + bool condition = RuntimeResult.Reference.Object.EvaluateBoolean(RuntimeResult); + if (RuntimeResult.ShouldReturn) + return; + + if (condition) + { + VisitNode(node.Cases[i].Body, executionContext, callingContext, accessibilityModifiers); + return; + } + } + + if (node.ElseCase is not null) + { + VisitNode(node.ElseCase, executionContext, callingContext, accessibilityModifiers); + return; + } + + EzrConstants.Nothing.Update(executionContext, node.StartPosition, node.EndPosition); + RuntimeResult.Success(ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant)); + } + + /// + /// Executes a and creates a counting loop. + /// + /// The to execute. + /// The under which the loop will be executed. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void VisitCountNode(CountNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + VisitNode(node.To, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + List returns = []; + IEzrObject toParameter = RuntimeResult.Reference.Object; + + if (toParameter is not EzrInteger and not EzrFloat) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected types integer or float, but got object of type \"{toParameter.TypeName}\"!", executionContext, node.To.StartPosition, node.To.EndPosition)); + return; + } + + IEzrObject? fromParameter = null; + IEzrObject? stepParameter = null; + + Reference? iterationVariableReference = null; + string iterationVariableName = string.Empty; + Context iterationVariableRegisteredContext = executionContext; + + AccessMod operationAccessibilityModifiers = accessibilityModifiers; + if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) + operationAccessibilityModifiers |= AccessMod.LocalScope; + + if (node.From is not null) + { + VisitNode(node.From, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + fromParameter = RuntimeResult.Reference.Object; + if (fromParameter.HashTag != toParameter.HashTag) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"All parameters of the count loop must be of the same type! Expected type {toParameter.TypeName}, but got object of type \"{fromParameter.TypeName}\".", executionContext, node.From.StartPosition, node.From.EndPosition)); + return; + } + } + + if (node.Step is not null) + { + VisitNode(node.Step, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + stepParameter = RuntimeResult.Reference.Object; + if (stepParameter.HashTag != toParameter.HashTag) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"All parameters of the count loop must be of the same type! Expected type {toParameter.TypeName}, but got object of type \"{stepParameter.TypeName}\".", executionContext, node.Step.StartPosition, node.Step.EndPosition)); + return; + } + } + + if (node.IterationVariable is not null) + { + VisitNode(node.IterationVariable, executionContext, callingContext, operationAccessibilityModifiers, true); + if (RuntimeResult.ShouldReturn) + return; + + iterationVariableReference = RuntimeResult.Reference; + if (!iterationVariableReference.IsRegistered) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for iteration variable name, but got object of type \"{iterationVariableReference.Object.TypeName}\"!", executionContext, node.IterationVariable.StartPosition, node.IterationVariable.EndPosition)); + return; + } + + iterationVariableName = iterationVariableReference.Name; + iterationVariableRegisteredContext = iterationVariableReference.RegisteredContext ?? executionContext; + } + + if (toParameter is EzrInteger toParameterInteger) + { + BigInteger to = toParameterInteger.Value; + BigInteger from = (fromParameter as EzrInteger)?.Value ?? 0; + + BigInteger step; + Func condition; + + if (from < to) + (step, condition) = ((stepParameter as EzrInteger)?.Value ?? 1, i => i < to); + else + (step, condition) = ((stepParameter as EzrInteger)?.Value ?? -1, i => i > to); + + for (BigInteger i = from; condition(i); i += step) + { + int iterationResult = IterateLoop(i, null, returns, node, callingContext, + executionContext, accessibilityModifiers, operationAccessibilityModifiers, + iterationVariableReference, iterationVariableName, iterationVariableRegisteredContext); + + if (iterationResult == -1) + return; + else if (iterationResult == 1) + continue; + else if (iterationResult == 2) + break; + } + } + else + { + double to = ((EzrFloat)toParameter).Value; + double from = (fromParameter as EzrFloat)?.Value ?? 0; + + double step; + Func condition; + + if (from < to) + (step, condition) = ((stepParameter as EzrFloat)?.Value ?? 1, i => i <= to); + else + (step, condition) = ((stepParameter as EzrFloat)?.Value ?? -1, i => i >= to); + + for (double i = from; condition(i); i += step) + { + int iterationResult = IterateLoop(null, i, returns, node, callingContext, + executionContext, accessibilityModifiers, operationAccessibilityModifiers, + iterationVariableReference, iterationVariableName, iterationVariableRegisteredContext); + + if (iterationResult == -1) + return; + else if (iterationResult == 1) + continue; + else if (iterationResult == 2) + break; + } + } + + RuntimeResult.Success(ReferencePool.Get(new EzrArray([.. returns], executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + } + + /// + /// Code to run in an iteration of a count expression. + /// + /// The current iteration of the loop as a . + /// The current iteration of the loop as a . + /// The list of the returns of the loop. + /// The loop node. + /// The calling on the execution of the iteration. + /// The under which the iteration will be executed. + /// The accessibility modifiers for objects that will be assigned from the executing iteration. + /// The accessibility modifiers for the iteration variable. + /// The iteration variable reference. + /// The name of the iteration variable + /// The context under which the iteration variable is registered. + /// -1 for errors, 1 to skip the iteration, 2 for stopping the loop or 0 for continuation of the loop. + private int IterateLoop( + BigInteger? iBigInteger, + double? iDouble, + List returns, + CountNode node, + Context callingContext, + Context executionContext, + AccessMod accessibilityModifiers, + AccessMod operationAccessibilityModifiers, + Reference? iterationVariableReference, + string iterationVariableName, + Context iterationVariableRegisteredContext) + { + if (iterationVariableReference is not null && node.IterationVariable is not null) + { + (IEzrObject Object, string Name) newIterationVariable = ( + iBigInteger is not null + ? new EzrInteger(iBigInteger.Value, iterationVariableRegisteredContext, node.IterationVariable.StartPosition, node.IterationVariable.EndPosition) + : new EzrFloat(iDouble!.Value, iterationVariableRegisteredContext, node.IterationVariable.StartPosition, node.IterationVariable.EndPosition), + + iterationVariableName); + + HandleSetStatus( + iterationVariableRegisteredContext.Set(callingContext, newIterationVariable, iterationVariableReference, operationAccessibilityModifiers), + iterationVariableName, + node.IterationVariable, + iterationVariableRegisteredContext + ); + + if (RuntimeResult.ShouldReturn) + return -1; + } + + VisitNode(node.Body, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturnLoop) + return -1; + + if (RuntimeResult.SkipSet) + { + RuntimeResult.Reset(); + return 1; + } + if (RuntimeResult.StopSet) + { + RuntimeResult.Reset(); + return 2; + } + + returns.Add(RuntimeResult.Reference.Object); + return 0; + } + + /// + /// Executes a and creates a while (condition = true) loop. + /// + /// The to execute. + /// The under which the loop will be executed. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void VisitWhileNode(WhileNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + List returns = []; + + do + { + VisitNode(node.Condition, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + bool condition = RuntimeResult.Reference.Object.EvaluateBoolean(RuntimeResult); + if (RuntimeResult.ShouldReturn) + return; + + if (!condition) + break; + + VisitNode(node.Body, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturnLoop) + return; + + if (RuntimeResult.SkipSet) + { + RuntimeResult.Reset(); + continue; + } + if (RuntimeResult.StopSet) + { + RuntimeResult.Reset(); + break; + } + + returns.Add(RuntimeResult.Reference.Object); + } while (true); + + RuntimeResult.Success(ReferencePool.Get(new EzrArray([.. returns], executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + } + + /// + /// Executes a and creates a try-catch block. + /// + /// The to execute. + /// The under which the block will be executed. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void VisitTryNode(TryNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + VisitNode(node.Block, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturnTryCatch || RuntimeResult.Error is null) + return; + + EzrRuntimeError error = RuntimeResult.Error!; + RuntimeResult.Reset(); + + for (int i = 0; i < node.Cases.Count; i++) + { + (Node errorType, Node? errorVariableNode, Node body) = node.Cases[i]; + + VisitNode(errorType, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + IEzrObject targetObject = RuntimeResult.Reference.Object; + if (targetObject is not EzrSharpSourceTypeWrapper target || !typeof(EzrRuntimeError).IsAssignableFrom(target.SharpType)) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected error type, but got object of type \"{targetObject.TypeName}\"!", executionContext, errorType.StartPosition, errorType.EndPosition)); + return; + } + + if (target.SharpType.IsAssignableFrom(error.GetType())) + { + if (errorVariableNode is not null) + { + AccessMod operationAccessibilityModifiers = accessibilityModifiers; + if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) + operationAccessibilityModifiers |= AccessMod.LocalScope; + + VisitNode(errorVariableNode, executionContext, callingContext, operationAccessibilityModifiers, true); + if (RuntimeResult.ShouldReturn) + return; + + Reference reference = RuntimeResult.Reference; + if (!reference.IsRegistered) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for error variable name, but got object of type \"{reference.Object.TypeName}\"!", executionContext, errorVariableNode.StartPosition, errorVariableNode.EndPosition)); + return; + } + + Context assignmentContext = reference.RegisteredContext ?? executionContext; + error.Update(assignmentContext, errorVariableNode.StartPosition, errorVariableNode.EndPosition); + + (IEzrObject Object, string Name) newErrorVariable = (error, reference.Name); + HandleSetStatus(assignmentContext.Set(callingContext, newErrorVariable, reference, operationAccessibilityModifiers), reference.Name, errorVariableNode, assignmentContext); + if (RuntimeResult.ShouldReturn) + return; + } + + VisitNode(body, executionContext, callingContext, accessibilityModifiers); + return; + } + } + + if (node.EmptyCase.HasValue) + { + (Node? emptyCaseVariable, Node emptyCaseBody) = node.EmptyCase.Value; + if (emptyCaseVariable is not null) + { + AccessMod operationAccessibilityModifiers = accessibilityModifiers; + if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) + operationAccessibilityModifiers |= AccessMod.LocalScope; + + VisitNode(emptyCaseVariable, executionContext, callingContext, operationAccessibilityModifiers, true); + if (RuntimeResult.ShouldReturn) + return; + + Reference reference = RuntimeResult.Reference; + if (!reference.IsRegistered) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for error variable name, but got object of type \"{reference.Object.TypeName}\"!", executionContext, emptyCaseVariable.StartPosition, emptyCaseVariable.EndPosition)); + return; + } + + Context assignmentContext = reference.RegisteredContext ?? executionContext; + error.Update(assignmentContext, emptyCaseVariable.StartPosition, emptyCaseVariable.EndPosition); + + (IEzrObject Object, string Name) newErrorVariable = (error, reference.Name); + HandleSetStatus(assignmentContext.Set(callingContext, newErrorVariable, reference, operationAccessibilityModifiers), reference.Name, emptyCaseVariable, assignmentContext); + if (RuntimeResult.ShouldReturn) + return; + } + + VisitNode(emptyCaseBody, executionContext, callingContext, accessibilityModifiers); + return; + } + + EzrConstants.Nothing.Update(executionContext, node.StartPosition, node.EndPosition); + RuntimeResult.Success(ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant)); + } + + /// + /// Executes a and creates a function. + /// + /// The to execute. + /// The in which the function will be created. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void VisitFunctionDefinitionNode(FunctionDefinitionNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + Context newContext = new($"", false, node.StartPosition, executionContext, executionContext.StaticContext); + + (string Name, Node Node)[] parameters = new (string, Node)[node.Parameters.Count]; + for (int i = 0; i < parameters.Length; i++) + { + Node parameter = node.Parameters[i]; + VisitNode(parameter, newContext, callingContext, AccessMod.None, true); + if (RuntimeResult.ShouldReturn) + return; + + Reference reference = RuntimeResult.Reference; + if (string.IsNullOrEmpty(reference.Name)) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected an identifier or variable assignment to store arguments in, but received object of type \"{reference.Object.TypeName}\"!", executionContext, parameter.StartPosition, parameter.EndPosition)); + return; + } + + parameters[i] = (reference.Name, node.Parameters[i]); + } + + (Position StartPosition, Position EndPosition, string Name)? keywordArguments = null; + if (node.KeywordArguments is not null) + { + VisitNode(node.KeywordArguments, newContext, callingContext, AccessMod.None, true); + if (RuntimeResult.ShouldReturn) + return; + + Reference reference = RuntimeResult.Reference; + if (string.IsNullOrEmpty(reference.Name)) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected an identifier to store keyword arguments in, but received object of type \"{reference.Object.TypeName}\"!", executionContext, node.KeywordArguments.StartPosition, node.KeywordArguments.EndPosition)); + return; + } + + keywordArguments = (node.KeywordArguments.StartPosition, node.KeywordArguments.EndPosition, reference.Name); + } + + newContext.Release(); + + EzrFunction function; + if (node.Name is not null) + { + AccessMod operationAccessibilityModifiers = node.AccessibilityModifiers | accessibilityModifiers; + if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) + operationAccessibilityModifiers |= AccessMod.LocalScope; + + VisitNode(node.Name, executionContext, callingContext, operationAccessibilityModifiers, true); + if (RuntimeResult.ShouldReturn) + return; + + Reference reference = RuntimeResult.Reference; + if (!reference.IsRegistered) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for function name, but got object of type \"{reference.Object.TypeName}\"!", executionContext, node.Name.StartPosition, node.Name.EndPosition)); + return; + } + + Context assignmentContext = reference.RegisteredContext ?? executionContext; + function = new EzrFunction(reference.Name, node.Body, parameters, keywordArguments, node.ReturnLast, assignmentContext, node.StartPosition, node.EndPosition); + + (IEzrObject Object, string Name) newFunctionVariable = (function, reference.Name); + HandleSetStatus(assignmentContext.Set(callingContext, newFunctionVariable, reference, operationAccessibilityModifiers), reference.Name, node.Name, assignmentContext); + if (RuntimeResult.ShouldReturn) + return; + } + else + function = new EzrFunction(null, node.Body, parameters, keywordArguments, node.ReturnLast, executionContext, node.StartPosition, node.EndPosition); + + RuntimeResult.Success(ReferencePool.Get(function, AccessMod.PrivateConstant)); + } + + /// + /// Executes a and creates a class. + /// + /// The to execute. + /// The in which the class will be created. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void VisitClassDefinitionNode(ClassDefinitionNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + EzrClass[] parents = new EzrClass[node.Parents.Count]; + for (int i = 0; i < parents.Length; i++) + { + Node parentNode = node.Parents[i]; + VisitNode(parentNode, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + IEzrObject ezrObject = RuntimeResult.Reference.Object; + if (ezrObject is not EzrClass parent) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected a class, but received object of type \"{ezrObject.TypeName}\"!", executionContext, parentNode.StartPosition, parentNode.EndPosition)); + return; + } + + parents[i] = parent; + } + + EzrClass @class; + if (node.Name is not null) + { + AccessMod operationAccessibilityModifiers = node.AccessibilityModifiers | accessibilityModifiers; + if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) + operationAccessibilityModifiers |= AccessMod.LocalScope; + + VisitNode(node.Name, executionContext, callingContext, operationAccessibilityModifiers, true); + if (RuntimeResult.ShouldReturn) + return; + + Reference reference = RuntimeResult.Reference; + if (!reference.IsRegistered) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for class name, but got object of type \"{reference.Object.TypeName}\"!", executionContext, node.Name.StartPosition, node.Name.EndPosition)); + return; + } + + Context assignmentContext = reference.RegisteredContext ?? executionContext; + @class = new EzrClass(reference.Name, node.Body, parents, node.Readonly, + ((node.AccessibilityModifiers | accessibilityModifiers) & AccessMod.Static) == AccessMod.Static, this, + RuntimeResult, assignmentContext, node.StartPosition, node.EndPosition); + + if (RuntimeResult.ShouldReturn) + return; + + (IEzrObject Object, string Name) newClassVariable = (@class, reference.Name); + HandleSetStatus(assignmentContext.Set(callingContext, newClassVariable, reference, operationAccessibilityModifiers), reference.Name, node.Name, assignmentContext); + if (RuntimeResult.ShouldReturn) + return; + } + else + { + @class = new EzrClass(null, node.Body, parents, node.Readonly, + ((node.AccessibilityModifiers | accessibilityModifiers) & AccessMod.Static) == AccessMod.Static, this, + RuntimeResult, executionContext, node.StartPosition, node.EndPosition); + + if (RuntimeResult.ShouldReturn) + return; + } + + RuntimeResult.Success(ReferencePool.Get(@class, AccessMod.PrivateConstant)); + } + + /// + /// Executes a and calls the function in . + /// + /// The to execute. + /// The under which the call takes place. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void VisitCallNode(CallNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + VisitNode(node.Receiver, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + IEzrObject receiver = RuntimeResult.Reference.Object; + + Reference[] arguments = []; + if (node.Arguments.Count > 0) + { + Context argumentsContext = new($"<{receiver.TypeName} arguments>", false, receiver.StartPosition, callingContext, callingContext.StaticContext); + arguments = new Reference[node.Arguments.Count]; + + for (int i = 0; i < node.Arguments.Count; i++) + { + Node argument = node.Arguments[i]; + VisitNode(argument, argumentsContext, callingContext, accessibilityModifiers & ~AccessMod.LocalScope); + if (RuntimeResult.ShouldReturn) + return; + + Reference reference = RuntimeResult.GetReferenceCopyIfReleasable(); + if (reference.RegisteredContext?.Id == argumentsContext.Id) + { + Reference copy = reference.ShallowCopy(); + copy.UpdateName(reference.Name); + + reference = copy; + } + + arguments[i] = reference; + } + + argumentsContext.Release(); + } + + receiver.Execute(arguments, this, RuntimeResult); + if (RuntimeResult.ShouldReturn) + return; + + RuntimeResult.Reference.Object.Update(executionContext, node.StartPosition, node.EndPosition); + } + + /// + /// Executes a . + /// + /// + /// This is (currently) only used for executing loop skip (calling ) and loop stop (calling ) expressions. + /// + /// The to execute. + /// The under which the node is executed. + /// Thrown when an unimplemented or unexpected is encountered. + private void VisitNoValueNode(NoValueNode node, Context executionContext) + { + EzrConstants.Nothing.Update(executionContext, node.StartPosition, node.EndPosition); + Reference toReturn = ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant); + + switch (node.ValueType) + { + case TokenType.KeywordSkip: + RuntimeResult.SetSkipFlag(toReturn); break; + + case TokenType.KeywordStop: + RuntimeResult.SetStopFlag(toReturn); break; + + default: + throw new NotImplementedException($"Invalid {nameof(TokenType)} \"{node.ValueType}\" for {nameof(VisitNoValueNode)}()!"); + } + } + + /// + /// Executes a and sets the return flag in . + /// + /// The to execute. + /// The from which the arguments of the will be taken, if any. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void VisitReturnNode(ReturnNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + if (node.Value is null) + { + EzrConstants.Nothing.Update(executionContext, node.StartPosition, node.EndPosition); + + RuntimeResult.SetReturnFlag(ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant)); + return; + } + + VisitNode(node.Value, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + Reference toReturn = RuntimeResult.Reference; + if (node.ReturnLast) + { + switch (toReturn.Object) + { + case EzrArray otherArray when otherArray.Value.Length == 0: + case EzrList otherList when otherList.Value.Count == 0: + RuntimeResult.Failure(new EzrIllegalOperationError($"Cannot return the last element of an empty {toReturn.Object.TypeName}!", executionContext, node.Value.StartPosition, node.Value.EndPosition)); + return; + + case EzrArray otherArray: + toReturn = ReferencePool.Get(otherArray.Value[^1], AccessMod.PrivateConstant); break; + case EzrList otherList: + toReturn = otherList.Value[^1]; break; + + default: + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Can only return the last element of an array or list, but got object of type \"{toReturn.Object.TypeName}\"!", executionContext, node.Value.StartPosition, node.Value.EndPosition)); + return; + } + } + + RuntimeResult.SetReturnFlag(toReturn); + } +} diff --git a/src/Runtime/Nodes/BaseNodes.cs b/src/Runtime/Nodes/BaseNodes.cs new file mode 100644 index 0000000..6fe43b9 --- /dev/null +++ b/src/Runtime/Nodes/BaseNodes.cs @@ -0,0 +1,58 @@ +using EzrSquared.Syntax.Errors; +namespace EzrSquared.Runtime.Nodes; + +/// +/// The representation of an ezr² source code construct. This is the base class of all nodes. Only for inheritance! +/// +/// The starting of the . +/// The ending of the . +public abstract class Node(Position startPosition, Position endPosition) +{ + /// + /// The starting of the . + /// + public Position StartPosition = startPosition; + + /// + /// The ending of the . + /// + public Position EndPosition = endPosition; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(Node)}()"; + } +} + +/// +/// The dummy invalid structure. For returning instead of if an occurs during parsing. +/// +public class InvalidNode : Node +{ + /// + /// The static object. + /// + internal static readonly InvalidNode s_invalidNode = new(Position.None, Position.None); + + /// + /// Creates a new object. + /// + /// The starting of the . + /// The ending of the . + InvalidNode(Position startPosition, Position endPosition) : base(startPosition, endPosition) { } + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(InvalidNode)}()"; + } +} diff --git a/src/Runtime/Nodes/CollectionNodes/ArrayLikeNode.cs b/src/Runtime/Nodes/CollectionNodes/ArrayLikeNode.cs new file mode 100644 index 0000000..ae3d7f5 --- /dev/null +++ b/src/Runtime/Nodes/CollectionNodes/ArrayLikeNode.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for an arraylike (array or list). +/// +/// The elements of the arraylike. +/// The check for if the should create a list instead of an array. +/// The starting of the . +/// The ending of the . +public class ArrayLikeNode(List elements, bool createList, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The elements of the arraylike. + /// + public List Elements = elements; + + /// + /// The check for if the should create a list instead of an array. + /// + public bool CreateList = createList; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + string[] elements = new string[Elements.Count]; + for (int i = 0; i < Elements.Count; i++) + elements[i] = Elements[i].ToString(); + + return $"{nameof(ArrayLikeNode)}([{string.Join(", ", elements)}], {CreateList})"; + } +} diff --git a/src/Runtime/Nodes/CollectionNodes/DictionaryNode.cs b/src/Runtime/Nodes/CollectionNodes/DictionaryNode.cs new file mode 100644 index 0000000..7242980 --- /dev/null +++ b/src/Runtime/Nodes/CollectionNodes/DictionaryNode.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a dictionary. +/// +/// The key-value pairs of the dictionary. +/// The starting of the . +/// The ending of the . +public class DictionaryNode(List<(Node Key, Node Value)> keyValuePairs, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The key-value pairs of the dictionary. + /// + public List<(Node Key, Node Value)> KeyValuePairs = keyValuePairs; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + string[] keyValuePairs = new string[KeyValuePairs.Count]; + for (int i = 0; i < KeyValuePairs.Count; i++) + keyValuePairs[i] = $"{KeyValuePairs[i].Key} : {KeyValuePairs[i].Value}"; + + return $"{nameof(DictionaryNode)}([{string.Join(", ", keyValuePairs)}])"; + } +} diff --git a/src/Runtime/Nodes/ContextManipulationNodes/DefineBlockNode.cs b/src/Runtime/Nodes/ContextManipulationNodes/DefineBlockNode.cs new file mode 100644 index 0000000..e8ab996 --- /dev/null +++ b/src/Runtime/Nodes/ContextManipulationNodes/DefineBlockNode.cs @@ -0,0 +1,31 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a define block. +/// +/// The body of the block. +/// The accessibility modifiers for the define block. +/// The starting of the . +/// The ending of the . +public class DefineBlockNode(Node body, AccessMod accessibilityModifiers, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The body of the block. + /// + public Node Body = body; + + /// + /// The accessibility modifiers of the define block. + /// + public AccessMod AccessibilityModifiers = accessibilityModifiers; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(DefineBlockNode)}({Body}, {AccessibilityModifiers})"; + } +} diff --git a/src/Runtime/Nodes/ContextManipulationNodes/VariableAccessNode.cs b/src/Runtime/Nodes/ContextManipulationNodes/VariableAccessNode.cs new file mode 100644 index 0000000..0ebe1b5 --- /dev/null +++ b/src/Runtime/Nodes/ContextManipulationNodes/VariableAccessNode.cs @@ -0,0 +1,31 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for accesing a variable from the context. +/// +/// The name of the variable, a object of type . +/// The accessibility modifiers for the variable access operation. +/// The starting of the . +/// The ending of the . +public class VariableAccessNode(Token name, AccessMod accessibilityModifiers, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The name of the variable to access. + /// + public Token Name = name; + + /// + /// The accessibility modifiers for the variable access operation. + /// + public AccessMod AccessibilityModifiers = accessibilityModifiers; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(VariableAccessNode)}({Name}, {AccessibilityModifiers})"; + } +} diff --git a/src/Runtime/Nodes/ContextManipulationNodes/VariableAssignmentNode.cs b/src/Runtime/Nodes/ContextManipulationNodes/VariableAssignmentNode.cs new file mode 100644 index 0000000..abe0e5f --- /dev/null +++ b/src/Runtime/Nodes/ContextManipulationNodes/VariableAssignmentNode.cs @@ -0,0 +1,43 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for assigning a value to a variable in the context. +/// +/// The variable to be assigned to. +/// The operation , if not , between the existing value of and . The result of the operation will be assigned to . +/// The value to be assigned to . +/// The accessibility modifiers for the variable assignment operation. +/// The starting of the . +/// The ending of the . +public class VariableAssignmentNode(Node variable, TokenType assignmentOperator, Node value, AccessMod accessibilityModifiers, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The variable to be assigned to. + /// + public Node Variable = variable; + + /// + /// The operation , if not , between the existing value of and . The result of the operation will be assigned to . + /// + public TokenType AssignmentOperator = assignmentOperator; + + /// + /// The value to be assigned to . + /// + public Node Value = value; + + /// + /// The accessibility modifiers for the variable assignment operation. + /// + public AccessMod AccessibilityModifiers = accessibilityModifiers; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(VariableAssignmentNode)}({Variable}, {AssignmentOperator}, {Value}, {AccessibilityModifiers})"; + } +} diff --git a/src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs b/src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs new file mode 100644 index 0000000..5e2e1fe --- /dev/null +++ b/src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs @@ -0,0 +1,49 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a count expression. +/// +/// The amount to count to. +/// The amount to count from - optional. +/// The increment of each iteration - optional. +/// TThe variable to store the iteration number in - optional. +/// The body of the count loop. +/// The starting of the . +/// The ending of the . +public class CountNode(Node to, Node? from, Node? step, Node? iterationVariable, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The amount to count to. + /// + public Node To = to; + + /// + /// The amount to count from - optional. + /// + public Node? From = from; + + /// + /// The increment of each iteration - optional. + /// + public Node? Step = step; + + /// + /// The variable to store the iteration number in - optional. + /// + public Node? IterationVariable = iterationVariable; + + /// + /// The body of the count loop. + /// + public Node Body = body; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(CountNode)}({To}, {From?.ToString() ?? "null"}, {Step?.ToString() ?? "null"}, {IterationVariable?.ToString() ?? "null"}, {Body})"; + } +} diff --git a/src/Runtime/Nodes/ControlFlowStructureNodes/IfNode.cs b/src/Runtime/Nodes/ControlFlowStructureNodes/IfNode.cs new file mode 100644 index 0000000..ceb0de3 --- /dev/null +++ b/src/Runtime/Nodes/ControlFlowStructureNodes/IfNode.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for an if expression. +/// +/// The cases of the if expression. +/// The body of the else case. +/// The starting of the . +/// The ending of the . +public class IfNode(List<(Node Condition, Node Body)> cases, Node? elseCase, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The cases of the if expression. + /// + public List<(Node Condition, Node Body)> Cases = cases; + + /// + /// The body of the else case. + /// + public Node? ElseCase = elseCase; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + string?[] cases = new string[Cases.Count]; + for (int i = 0; i < Cases.Count; i++) + cases[i] = $"({Cases[i].Condition}, {Cases[i].Body})"; + + return $"{nameof(IfNode)}([{string.Join(", ", cases)}], {ElseCase?.ToString() ?? "null"})"; + } +} diff --git a/src/Runtime/Nodes/ControlFlowStructureNodes/TryNode.cs b/src/Runtime/Nodes/ControlFlowStructureNodes/TryNode.cs new file mode 100644 index 0000000..18bad2a --- /dev/null +++ b/src/Runtime/Nodes/ControlFlowStructureNodes/TryNode.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a try expression. +/// +/// The try block. +/// The error cases of the try expression. +/// The (optional) where the error will be stored and the body of the empty else case. +/// The starting of the . +/// The ending of the . +public class TryNode(Node block, List<(Node ErrorType, Node? Variable, Node Body)> cases, (Node? Variable, Node Body)? emptyCase, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The try block. + /// + public Node Block = block; + + /// + /// The error cases of the try expression. + /// + public List<(Node ErrorType, Node? Variable, Node Body)> Cases = cases; + + /// + /// The (optional) where the error will be stored and the body of the empty else case. + /// + public (Node? Variable, Node Body)? EmptyCase = emptyCase; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + string?[] cases = new string[Cases.Count]; + for (int i = 0; i < Cases.Count; i++) + cases[i] = $"({Cases[i].ErrorType}, {Cases[i].Variable?.ToString() ?? "null"}, {Cases[i].Body})"; + + return (EmptyCase is not null) + ? $"{nameof(TryNode)}({Block}, [{string.Join(", ", cases)}], ({EmptyCase?.Variable?.ToString() ?? "null"}, {EmptyCase?.Body}))" + : $"{nameof(TryNode)}({Block}, [{string.Join(", ", cases)}])"; + } +} diff --git a/src/Runtime/Nodes/ControlFlowStructureNodes/WhileNode.cs b/src/Runtime/Nodes/ControlFlowStructureNodes/WhileNode.cs new file mode 100644 index 0000000..4d6c9c3 --- /dev/null +++ b/src/Runtime/Nodes/ControlFlowStructureNodes/WhileNode.cs @@ -0,0 +1,31 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for an while expression. +/// +/// The condition of the while loop. +/// The body of the while loop. +/// The starting of the . +/// The ending of the . +public class WhileNode(Node condition, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The condition of the while loop. + /// + public Node Condition = condition; + + /// + /// The body of the while loop. + /// + public Node Body = body; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(WhileNode)}({Condition}, {Body})"; + } +} diff --git a/src/Runtime/Nodes/ExecutableNodes/CallNode.cs b/src/Runtime/Nodes/ExecutableNodes/CallNode.cs new file mode 100644 index 0000000..b63c43d --- /dev/null +++ b/src/Runtime/Nodes/ExecutableNodes/CallNode.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a function call. +/// +/// The function/object to be called. +/// The array of arguments. +/// The starting of the . +/// The ending of the . +public class CallNode(Node receiver, List arguments, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The function/object to be called. + /// + public Node Receiver = receiver; + + /// + /// The array of arguments. + /// + public List Arguments = arguments; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + string[] arguments = new string[Arguments.Count]; + for (int i = 0; i < Arguments.Count; i++) + arguments[i] = Arguments[i].ToString(); + + return $"{nameof(CallNode)}({Receiver}, [{string.Join(", ", arguments)}])"; + } +} diff --git a/src/Runtime/Nodes/ExecutableNodes/ClassDefinitionNode.cs b/src/Runtime/Nodes/ExecutableNodes/ClassDefinitionNode.cs new file mode 100644 index 0000000..e39e1fe --- /dev/null +++ b/src/Runtime/Nodes/ExecutableNodes/ClassDefinitionNode.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a class definition. +/// +/// The (optional) name of the class. +/// The accessibility modifiers for the class definition. +/// The check for if the class should be declared read-only. +/// The parents of the class. +/// The body of the class. +/// The starting of the . +/// The ending of the . +public class ClassDefinitionNode(Node? name, AccessMod accessibilityModifiers, bool @readonly, List parents, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The name of the class. May be . + /// + public Node? Name = name; + + /// + /// The accessibility modifiers for the class definition. + /// + public AccessMod AccessibilityModifiers = accessibilityModifiers; + + /// + /// The check for if the class should be declared read-only. + /// + public bool Readonly = @readonly; + + /// + /// The parents of the class. + /// + public List Parents = parents; + + /// + /// The body of the class. + /// + public Node Body = body; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + string?[] parents = new string[Parents.Count]; + for (int i = 0; i < Parents.Count; i++) + parents[i] = Parents[i].ToString(); + + return $"{nameof(ClassDefinitionNode)}({Name?.ToString() ?? "null"}, {AccessibilityModifiers}, {Readonly}, [{string.Join(", ", parents)}], {Body})"; + } +} diff --git a/src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs b/src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs new file mode 100644 index 0000000..01a1c50 --- /dev/null +++ b/src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a function definition. +/// +/// The (optional) name of the function. +/// The accessibility modifiers for the function definition. +/// The check for if the last expression of the function should be returned as its result. Only used in oneliners. +/// The parameters of the function. +/// The reference to store the extra keyword arguments in. +/// The body of the function. +/// The starting of the . +/// The ending of the . +public class FunctionDefinitionNode(Node? name, AccessMod accessibilityModifiers, bool returnLast, List parameters, Node? keywordArguments, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The (optional) name of the function. + /// + public Node? Name = name; + + /// + /// The accessibility modifiers for the function definition. + /// + public AccessMod AccessibilityModifiers = accessibilityModifiers; + + /// + /// The check for if the last expression of the function should be returned as its result. + /// Only used in oneliners. + /// + public bool ReturnLast = returnLast; + + /// + /// The parameters of the function. + /// + public List Parameters = parameters; + + /// + /// The reference to store the extra keyword arguments in. + /// + public Node? KeywordArguments = keywordArguments; + + /// + /// The body of the function. + /// + public Node Body = body; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + string?[] parameters = new string[Parameters.Count]; + for (int i = 0; i < Parameters.Count; i++) + parameters[i] = Parameters[i].ToString(); + + return $"{nameof(FunctionDefinitionNode)}({Name?.ToString() ?? "null"}, {AccessibilityModifiers}, {ReturnLast}, [{string.Join(", ", parameters)}], {KeywordArguments?.ToString() ?? "null"}, {Body})"; + } +} diff --git a/src/Runtime/Nodes/ExecutableNodes/IncludeNode.cs b/src/Runtime/Nodes/ExecutableNodes/IncludeNode.cs new file mode 100644 index 0000000..3d62f0c --- /dev/null +++ b/src/Runtime/Nodes/ExecutableNodes/IncludeNode.cs @@ -0,0 +1,43 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for an include expression. +/// +/// The script to include. +/// The (optional) specific sub-structure or object to be included from the script. +/// Specifies if all contents of the script need to be dumped into the current context. +/// The (optional) nickname of the object to be included. +/// The starting of the . +/// The ending of the . +public class IncludeNode(Node script, Node? subStructure, bool isDumped, Node? nickname, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The script to include. + /// + public readonly Node Script = script; + + /// + /// The (optional) specific sub-structure or object to be included from the script. + /// + public readonly Node? SubStructure = subStructure; + + /// + /// Specifies if all contents of the script need to be dumped into the current context. + /// + public readonly bool IsDumped = isDumped; + + /// + /// The (optional) nickname of the object to be included. + /// + public readonly Node? Nickname = nickname; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(IncludeNode)}({Script}, {SubStructure?.ToString() ?? "null"}, {IsDumped}, {Nickname?.ToString() ?? "null"})"; + } +} diff --git a/src/Runtime/Nodes/ExecutableNodes/ReturnNode.cs b/src/Runtime/Nodes/ExecutableNodes/ReturnNode.cs new file mode 100644 index 0000000..5e331db --- /dev/null +++ b/src/Runtime/Nodes/ExecutableNodes/ReturnNode.cs @@ -0,0 +1,31 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a return statement. +/// +/// The optional value to be returned. +/// Return the last element of , which should be a list or array. +/// The starting of the . +/// The ending of the . +public class ReturnNode(Node? value, bool returnLast, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The optional value to be returned. + /// + public Node? Value = value; + + /// + /// Return the last element of , which should be a list or array. + /// + public bool ReturnLast = returnLast; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(ReturnNode)}({Value?.ToString() ?? "null"})"; + } +} diff --git a/src/Runtime/Nodes/OperationNodes/BinaryOperationNode.cs b/src/Runtime/Nodes/OperationNodes/BinaryOperationNode.cs new file mode 100644 index 0000000..edbedfd --- /dev/null +++ b/src/Runtime/Nodes/OperationNodes/BinaryOperationNode.cs @@ -0,0 +1,37 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a binary operation. +/// +/// The first operand of the binary operation. +/// The second operand of the binary operation. +/// The operator of the binary operation. +/// The starting of the . +/// The ending of the . +public class BinaryOperationNode(Node left, Node right, TokenType @operator, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The first operand of the binary operation. + /// + public Node Left = left; + + /// + /// The second operand of the binary operation. + /// + public Node Right = right; + + /// + /// The operator of the binary operation. + /// + public TokenType Operator = @operator; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(BinaryOperationNode)}({Left}, {Operator}, {Right})"; + } +} diff --git a/src/Runtime/Nodes/OperationNodes/UnaryOperationNode.cs b/src/Runtime/Nodes/OperationNodes/UnaryOperationNode.cs new file mode 100644 index 0000000..4bedf6d --- /dev/null +++ b/src/Runtime/Nodes/OperationNodes/UnaryOperationNode.cs @@ -0,0 +1,31 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a unary operation. +/// +/// The operand of the unary operation. +/// The operator of the unary operation. +/// The starting of the . +/// The ending of the . +public class UnaryOperationNode(Node operand, TokenType @operator, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The operand of the unary operation. + /// + public Node Operand = operand; + + /// + /// The operator of the unary operation. + /// + public TokenType Operator = @operator; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(UnaryOperationNode)}({Operand}, {Operator})"; + } +} diff --git a/src/Runtime/Nodes/SimpleNodes/NoValueNode.cs b/src/Runtime/Nodes/SimpleNodes/NoValueNode.cs new file mode 100644 index 0000000..2cfa002 --- /dev/null +++ b/src/Runtime/Nodes/SimpleNodes/NoValueNode.cs @@ -0,0 +1,25 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a statement or expression without any value (used as skip and stop statement nodes). +/// +/// The identifying of the . +/// The starting of the . +/// The ending of the . +public class NoValueNode(TokenType valueType, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The identifying of the . + /// + public TokenType ValueType = valueType; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(NoValueNode)}({ValueType})"; + } +} diff --git a/src/Runtime/Nodes/SimpleNodes/ValueNode.cs b/src/Runtime/Nodes/SimpleNodes/ValueNode.cs new file mode 100644 index 0000000..bcf6634 --- /dev/null +++ b/src/Runtime/Nodes/SimpleNodes/ValueNode.cs @@ -0,0 +1,25 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure of a simple value like literals and variables. +/// +/// The value the represents. +/// The starting of the . +/// The ending of the . +public class ValueNode(Token value, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The value the represents. + /// + public Token Value = value; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(ValueNode)}({Value})"; + } +} diff --git a/src/Runtime/Reference.cs b/src/Runtime/Reference.cs new file mode 100644 index 0000000..16c7c81 --- /dev/null +++ b/src/Runtime/Reference.cs @@ -0,0 +1,166 @@ +using EzrSquared.Runtime.Types; + +namespace EzrSquared.Runtime; + +/// +/// A reference to an , with its scope, usable name and more metadata. +/// +/// +/// It is recommended to get references from the instead of creating them manually. +/// +/// The being referenced. +/// The accessibility modifiers of the reference. +/// The name of the reference. +public class Reference(IEzrObject? @object = null, AccessMod accessibilityModifiers = AccessMod.None, string name = "") : IMutable +{ + /// + /// The in which the reference is defined in. May be . + /// + public Context? RegisteredContext { get; private set; } + + /// + /// Is this reference registered in a ? + /// + public bool RegisteredInResult { get; private set; } + + /// + /// The number of other objects that have this reference registered. + /// + public int RegisteredIn { get; private set; } + + /// + /// The this references. + /// + public IEzrObject Object { get; private set; } = @object ?? EzrRuntimeInvalidObject.s_instance; + + /// + /// The name of the reference, may be . + /// + public string Name { get; private set; } = name; + + /// + /// The accessibility modifiers of the reference. See . + /// + public AccessMod AccessibilityModifiers = accessibilityModifiers; + + /// + /// Is this reference registered anywhere, including s? + /// + public bool IsRegisteredIncludingResult => IsRegistered || RegisteredInResult; + + /// + /// Is this reference registered anywhere, except s? + /// + public bool IsRegistered => RegisteredIn > 0 || RegisteredContext is not null; + + /// + /// Does this reference actually reference anything? + /// + public bool IsEmpty { get; private set; } = @object is null; + + /// + /// Static readonly empty reference. + /// + public static readonly Reference Empty = new(); + + /// + /// Resets the reference. + /// + /// The being referenced. + /// The accessibility modifiers of the reference. + /// The name of the reference. + public Reference Reset(IEzrObject? @object, AccessMod accessibilityModifiers, string name) + { + Object = @object ?? EzrRuntimeInvalidObject.s_instance; + AccessibilityModifiers = accessibilityModifiers; + + Name = name; + IsEmpty = @object is null; + + RegisteredContext = null; + RegisteredIn = 0; + + return this; + } + + /// + /// Updates the reference with new and values. + /// + /// The new object to reference. + /// The new accessibility modifiers. + public void UpdateObject(IEzrObject @object, AccessMod accessibilityModifiers = AccessMod.None) + { + Object = @object; + AccessibilityModifiers |= accessibilityModifiers; + } + + /// + /// Updates the reference with a new value. + /// + /// + /// This does not actually change the this reference is defined in, + /// but it changes the reference to the this is defined in.
+ ///
+ /// The new context. + public void UpdateRegisteredContext(Context? context) + { + RegisteredContext = context; + } + + /// + /// Updates the reference with a new value. + /// + /// Is it an unregister or register operation? + public void UpdateRegister(bool isRegistered) + { + RegisteredIn += isRegistered ? 1 : -1; + } + + /// + /// Updates the reference with a new value. + /// + /// The new value. + public void UpdateResultRegister(bool isRegistered) + { + RegisteredInResult = isRegistered; + } + + /// + /// Updates the reference with a new value. + /// + /// The new name. + public void UpdateName(string name) + { + Name = name; + } + + /// + /// Creates a very shallow copy of the reference. + /// + /// + /// This copy only includes the original's and . + /// + /// The copy. + public Reference ShallowCopy() + { + return ReferencePool.Get(Object, AccessibilityModifiers); + } + + /// + /// Creates a copy of the reference AND the referenced object, if it is mutable. + /// + /// + /// This copy only includes the original's , and . + /// + /// Runtime result to return errors in. + /// The copy, or, if failed. + public IMutable? DeepCopy(RuntimeResult result) + { + IEzrObject newObject = ((IEzrObject?)(Object as IEzrMutableObject)?.DeepCopy(result)) ?? Object; + if (result.ShouldReturn) + return null; + + Reference copy = ReferencePool.Get(newObject, AccessibilityModifiers, Name); + return copy; + } +} diff --git a/src/Runtime/ReferencePool.cs b/src/Runtime/ReferencePool.cs new file mode 100644 index 0000000..e593948 --- /dev/null +++ b/src/Runtime/ReferencePool.cs @@ -0,0 +1,42 @@ +using EzrSquared.Runtime.Types; +using System.Collections.Concurrent; + +namespace EzrSquared.Runtime; + +/// +/// A static pool for . +/// +public static class ReferencePool +{ + /// + /// The pool of references. + /// + private static readonly ConcurrentQueue s_ezrObjectReferencePool = new(); + + /// + /// Gets a freshly-reset reference from the pool or creates a new one. + /// + /// The being referenced. + /// The accessibility modifiers of the reference. + /// The name of the reference. + /// The reference. + public static Reference Get(IEzrObject? @object = null, AccessMod accessibilityModifiers = AccessMod.None, string name = "") + { + return s_ezrObjectReferencePool.TryDequeue(out Reference? ezrObjectReference) && ezrObjectReference is not null + ? ezrObjectReference.Reset(@object, accessibilityModifiers, name) + : new Reference(@object, accessibilityModifiers, name); + } + + /// + /// Releases a reference to the pool. + /// + /// The reference to release. + public static void TryRelease(Reference reference) + { + if (!reference.IsRegisteredIncludingResult) + { + reference.Reset(EzrRuntimeInvalidObject.s_instance, AccessMod.None, string.Empty); + s_ezrObjectReferencePool.Enqueue(reference); + } + } +} diff --git a/src/Runtime/RuntimeResult.cs b/src/Runtime/RuntimeResult.cs new file mode 100644 index 0000000..8f10396 --- /dev/null +++ b/src/Runtime/RuntimeResult.cs @@ -0,0 +1,181 @@ +using EzrSquared.Runtime.Types; +using EzrSquared.Runtime.Types.Core.Errors; + +namespace EzrSquared.Runtime; + +/// +/// The type of the object that is returned as the result of interpretation done by the . +/// +public class RuntimeResult +{ + /// + /// The reference to the resulting . + /// + public Reference Reference = Reference.Empty; + + /// + /// The error that occured in interpretation, if none occured, this is . + /// + public EzrRuntimeError? Error; + + /// + /// Should the interpreter return from the current execution? + /// + /// + /// This is when either of the below conditions are met:
+ /// - is not
+ /// - is set to
+ /// - is set to
+ /// - is set to
+ ///
+ public bool ShouldReturn => Error is not null || SkipSet || StopSet || ReturnSet; + + /// + /// Should the interpreter return from the current function execution? + /// + /// + /// This is when either of the below conditions are met:
+ /// - is not
+ ///
+ public bool ShouldReturnFunction => Error is not null; + + /// + /// Should the interpreter return from the current loop execution? + /// + /// + /// This is when either of the below conditions are met:
+ /// - is not
+ /// - is set to
+ ///
+ public bool ShouldReturnLoop => Error is not null || ReturnSet; + + /// + /// Should the interpreter return from the current try-catch block execution? + /// + /// + /// This is when either of the below conditions are met:
+ /// - is set to
+ /// - is set to
+ /// - is set to
+ ///
+ public bool ShouldReturnTryCatch => SkipSet || StopSet || ReturnSet; + + /// + /// The flag for when a loop skip is called. + /// + public bool SkipSet; + + /// + /// The flag for when a loop stop is called. + /// + public bool StopSet; + + /// + /// The flag for when a return call is called. + /// + public bool ReturnSet; + + /// + /// Creates a new . + /// + internal RuntimeResult() { } + + /// + /// Resets the current . + /// + /// + /// This:
+ /// - Sets , and to .
+ /// - Releases and sets to , unless specifically excluded. + ///
+ /// Reference to exclude from release. + public void Reset(Reference? exclude = null) + { + // Reset the flags and error. + SkipSet = StopSet = ReturnSet = false; + Error = null; + + // If the reference is not empty and not excluded, release it. + Reference.UpdateResultRegister(false); + if (!ReferenceEquals(Reference, Reference.Empty) && !ReferenceEquals(Reference, exclude)) + ReferencePool.TryRelease(Reference); + + // Set it to empty. + Reference = Reference.Empty; + } + + /// + /// Sets . + /// + /// The new value for . + private void SetReference(Reference reference) + { + reference.UpdateResultRegister(true); + Reference = reference; + } + + /// + /// Sets the flag, signifying a loop skip. + /// + /// The reference to return when the skip flag is used outside a loop. + public void SetSkipFlag(Reference reference) + { + Reset(reference); + + SetReference(reference); + SkipSet = true; + } + + /// + /// Sets the flag, signifying a loop stop. + /// + /// The reference to return when the stop flag is used outside a loop. + public void SetStopFlag(Reference reference) + { + Reset(reference); + + SetReference(reference); + StopSet = true; + } + + /// + /// Sets the flag, signifying a function return. + /// + /// The reference to the object returned by the function. + public void SetReturnFlag(Reference reference) + { + Reset(reference); + + SetReference(reference); + ReturnSet = true; + } + + /// + /// Sets a successful expression execution. + /// + /// The reference to the resulting . + public void Success(Reference reference) + { + Reset(reference); + SetReference(reference); + } + + /// + /// Sets a failed expression execution. + /// + /// The error that caused the failure. + public void Failure(EzrRuntimeError error) + { + Reset(); + Error = error; + } + + /// + /// Creates a shallow copy of the current if it is eligible for release by the pool. + /// + /// The copy of the reference, or the reference itself if not eligible for release. + public Reference GetReferenceCopyIfReleasable() + { + return Reference.IsRegistered ? Reference : Reference.ShallowCopy(); + } +} diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs new file mode 100644 index 0000000..53f6518 --- /dev/null +++ b/src/Runtime/Types/BaseTypes.cs @@ -0,0 +1,457 @@ +using EzrSquared.Runtime.Collections; +using EzrSquared.Runtime.Nodes; +using EzrSquared.Runtime.Types.Collections; +using EzrSquared.Runtime.Types.Core; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.Core.Text; +using System.Numerics; + +namespace EzrSquared.Runtime.Types; + +/// +/// An invalid, sort of "empty" object, to use instead of . +/// +internal class EzrRuntimeInvalidObject : EzrObject +{ + /// + /// The static instance of the invalid object. + /// + internal static EzrRuntimeInvalidObject s_instance = new(); + + /// + /// Creates a new . + /// + EzrRuntimeInvalidObject() : base(Context.Empty, Context.Empty, Position.None, Position.None) { } +} + +/// +/// The base root class of all built-in objects. Provides utility functions and bare-minimum operator handling. +/// +public abstract class EzrObject : IEzrObject +{ + /// + public virtual string TypeName { get; protected internal set; } = string.Empty; + + /// + public virtual string Tag { get; protected internal set; } = string.Empty; + + /// + /// The hash of . + /// + private int _hashTag = int.MinValue; + + /// + public int HashTag + { + get + { + if (_hashTag == int.MinValue) + _hashTag = Tag.GetHashCode(); + return _hashTag; + } + } + + /// + public Position StartPosition { get; private set; } + + /// + public Position EndPosition { get; private set; } + + /// + public Context Context { get; private set; } + + /// + /// Is the current object read-only? + /// + public bool IsReadOnly { get; protected internal set; } = true; + + /// + /// The current context in which the operation is being executed. + /// + protected internal Context _executionContext; + + /// + /// The context under which the object was created. + /// + protected internal Context _creationContext; + + /// + /// Creates a new object with the specified parent context and position. + /// + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrObject(Context parentContext, Position startPosition, Position endPosition) + { + StartPosition = startPosition; + EndPosition = endPosition; + + _executionContext = _creationContext = parentContext; + Context = new Context(TypeName, false, startPosition, _creationContext, _creationContext.StaticContext); + } + + /// + /// Creates a new object with the specified internal context, parent context and position. + /// + /// The internal context, if , creates a new one. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrObject(Context? context, Context parentContext, Position startPosition, Position endPosition) + { + StartPosition = startPosition; + EndPosition = endPosition; + + _executionContext = _creationContext = parentContext; + Context = context ?? new Context(TypeName, false, startPosition, _creationContext, _creationContext.StaticContext); + } + + /// + /// Changes and the parent of . Be careful when you use this function. + /// + /// The new creation context. + public void UpdateCreationContext(Context newCreationContext) + { + _creationContext = newCreationContext; + } + + /// + public void Update(Context context, Position startPosition, Position endPosition) + { + StartPosition = startPosition; + EndPosition = endPosition; + _executionContext = context; + + Context.UpdatePosition(StartPosition); + } + + /// + public virtual void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void ComparisonLessThan(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void ComparisonGreaterThan(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void ComparisonGreaterThanOrEqual(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void Addition(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void Subtraction(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void Multiplication(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void Division(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void Modulo(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void Power(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void Negation(RuntimeResult result) + { + result.Failure(IllegalOperation()); + } + + /// + public virtual void Affirmation(RuntimeResult result) + { + result.Failure(IllegalOperation()); + } + + /// + public virtual void BitwiseOr(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void BitwiseXOr(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void BitwiseAnd(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void BitwiseLeftShift(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void BitwiseRightShift(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other)); + } + + /// + public virtual void BitwiseNegation(RuntimeResult result) + { + result.Failure(IllegalOperation()); + } + + /// + public virtual void HasValueContained(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other, false)); + } + + /// + public virtual void NotHasValueContained(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation(other, false)); + } + + /// + public virtual void Inversion(RuntimeResult result) + { + result.Failure(IllegalOperation()); + } + + /// + public virtual bool EvaluateBoolean(RuntimeResult result) + { + result.Failure(IllegalOperation()); + return false; + } + + /// + public virtual void Interpret(Node code, Context callingContext, Interpreter interpreter, RuntimeResult result, bool ignoreUndefinedVariable = false) + { + interpreter.VisitNode(code, Context, callingContext, AccessMod.LocalScope, ignoreUndefinedVariable); + if (result.ShouldReturn) + return; + + Reference reference = result.Reference; + if (reference.IsEmpty && IsReadOnly) + { + result.Failure(new EzrUndefinedValueError($"You cannot create nor change members of a read-only object!", Context, StartPosition, EndPosition)); + return; + } + + if (IsReadOnly) + result.Success( + ReferencePool.Get( + reference.Object, + AccessMod.PrivateConstant, + reference.Name + ) + ); + } + + /// + public virtual void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + result.Failure(IllegalOperation()); + } + + /// + public virtual bool StrictEquals(IEzrObject other, RuntimeResult result) + { + result.Failure(IllegalOperation()); + return false; + } + + /// + public virtual int ComputeHashCode(RuntimeResult result) + { + result.Failure(IllegalOperation()); + return int.MinValue; + } + + /// + public virtual string ToString(RuntimeResult result) + { + return TypeName; + } + + /// + public virtual string ToPureString(RuntimeResult result) + { + return ToString(result); + } + + /// Destructor. + ~EzrObject() + { + Context.Release(); + } + + /// + /// Creates a new "nothing" constant. + /// + /// The constant. + protected internal Reference NewNothingConstant() + { + return ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant); + } + + /// + /// Creates a new boolean constant. + /// + /// The raw boolean value. + /// The constant. + protected internal Reference NewBooleanConstant(bool value) + { + return ReferencePool.Get(value + ? EzrConstants.True + : EzrConstants.False, AccessMod.PrivateConstant); + } + + /// + /// Creates a new integer constant. + /// + /// The raw integer value. + /// The constant. + protected internal Reference NewIntegerConstant(BigInteger value) + { + return ReferencePool.Get(new EzrInteger(value, _executionContext, StartPosition, EndPosition), AccessMod.PrivateConstant); + } + + /// + /// Creates a new float constant. + /// + /// The raw float value. + /// The constant. + protected internal Reference NewFloatConstant(double value) + { + return ReferencePool.Get(new EzrFloat(value, _executionContext, StartPosition, EndPosition), AccessMod.PrivateConstant); + } + + /// + /// Creates a new string constant. + /// + /// The raw string value. + /// The constant. + protected internal Reference NewStringConstant(string value) + { + return ReferencePool.Get(new EzrString(value, _executionContext, StartPosition, EndPosition), AccessMod.PrivateConstant); + } + + /// + /// Creates a new character list constant. + /// + /// The raw float value. + /// The constant. + protected internal Reference NewCharacterListConstant(string value) + { + return ReferencePool.Get(new EzrCharacterList(value, _executionContext, StartPosition, EndPosition), AccessMod.PrivateConstant); + } + + /// + /// Creates a new character constant. + /// + /// The raw character value. + /// The constant. + protected internal Reference NewCharacterConstant(char value) + { + return ReferencePool.Get(new EzrCharacter(value, _executionContext, StartPosition, EndPosition), AccessMod.PrivateConstant); + } + + /// + /// Creates a new array constant. + /// + /// The raw array value. + /// The constant. + protected internal Reference NewArrayConstant(IEzrObject[] elements) + { + return ReferencePool.Get(new EzrArray(elements, _executionContext, StartPosition, EndPosition), AccessMod.PrivateConstant); + } + + /// + /// Creates a new list constant. + /// + /// The raw list value. + /// The constant. + protected internal Reference NewListConstant(RuntimeEzrObjectList elements) + { + return ReferencePool.Get(new EzrList(elements, _executionContext, StartPosition, EndPosition), AccessMod.PrivateConstant); + } + + /// + /// Creates a new dictionary constant. + /// + /// The raw dictionary value. + /// The constant. + protected internal Reference NewDictionaryConstant(RuntimeEzrObjectDictionary dictionary) + { + return ReferencePool.Get(new EzrDictionary(dictionary, _executionContext, StartPosition, EndPosition), AccessMod.PrivateConstant); + } + + /// + /// Creates an illegal operation error based on the current context and position. + /// + /// The error. + protected internal EzrIllegalOperationError IllegalOperation() + { + return new($"Illegal operation for type \"{TypeName}\"!", _executionContext, StartPosition, EndPosition); + } + + /// + /// Creates an illegal operation error based on the current context and position and another object. + /// + /// The error. + protected internal EzrIllegalOperationError IllegalOperation(IEzrObject other, bool isRightHandSide = true) + { + return + isRightHandSide + ? new EzrIllegalOperationError($"Illegal operation for types \"{TypeName}\" and \"{other.TypeName}\"!", _executionContext, StartPosition, other.EndPosition) + : new EzrIllegalOperationError($"Illegal operation for types \"{other.TypeName}\" and \"{TypeName}\"!", _executionContext, other.StartPosition, EndPosition); + } +} diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs new file mode 100644 index 0000000..720b807 --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs @@ -0,0 +1,340 @@ +using EzrSquared.Runtime.Types.Core; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.Core.Text; +using EzrSquared.Runtime.WrapperAttributes; +using System; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.Builtins; + +/// +/// All built-in functions in ezr². +/// +public static class EzrBuiltinFunctions +{ + /// + /// Basic console print function. Implements . + /// + /// + /// ezr² parameters: + /// + /// + /// message + /// () The message to display on the console. + /// + /// + /// line_end + /// (Optional, , , ) Line end character(s) to use instead of \n. + /// + /// + /// + /// ezr² return type: + /// + ///
+ /// ezr² errors: + /// if "line_end" is not one of the specified types. + ///
+ /// The constructor arguments. + [SharpMethodWrapper("show", RequiredParameters = ["message"], OptionalParameters = ["line_end"])] + public static void Show(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference messageReference = arguments.ArgumentReferences["message"]; + + string message = messageReference.Object.ToPureString(result); + if (result.ShouldReturn) + return; + + string lineEnd = Environment.NewLine; + if (arguments.ArgumentReferences.TryGetValue("line_end", out Reference? lineEndReference)) + { + IEzrObject lineEndObject = lineEndReference.Object; + if (lineEndObject is EzrString lineEndString) + lineEnd = lineEndString.Value; + else if (lineEndObject is EzrCharacter lineEndCharacter) + lineEnd = lineEndCharacter.Value.ToString(); + else if (lineEndObject is EzrCharacterList lineEndCharacterList) + lineEnd = lineEndCharacterList.StringValue; + else + { + result.Failure(new EzrUnexpectedTypeError($"Expected line ending of type string, character or character list, but got object of type \"{lineEndObject.TypeName}\"", arguments.ExecutionContext, lineEndObject.StartPosition, lineEndObject.EndPosition)); + return; + } + } + + Console.Write($"{message}{lineEnd}"); + result.Success(ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant)); + } + + /// + /// Basic error throwing function. Implements . + /// + /// + /// ezr² parameters: + /// + /// + /// error + /// () The error to throw. + /// + /// + /// + /// ezr² errors: + /// + /// + /// + /// if "error" is not of the specified type. + /// + /// + /// error + /// the given error. + /// + /// + /// + /// The constructor arguments. + [SharpMethodWrapper("throw_error", RequiredParameters = ["error"])] + public static void ThrowError(SharpMethodParameters arguments) + { + Reference reference = arguments.ArgumentReferences["error"]; + + IEzrObject referenceObject = reference.Object; + if (referenceObject is not EzrRuntimeError error) + arguments.Result.Failure(new EzrUnexpectedTypeError($"Expected runtime error, but got object of type \"{referenceObject.TypeName}\"!", arguments.ExecutionContext, referenceObject.StartPosition, referenceObject.EndPosition)); + else + arguments.Result.Failure(error); + } + + /// + /// Basic console input function. Implements . + /// + /// + /// ezr² parameters: + /// + /// + /// message + /// () The message to display on the console before waiting for user input. + /// + /// + /// + /// ezr² return type: + /// + /// + /// The constructor arguments. + [SharpMethodWrapper("get", OptionalParameters = ["message"])] + public static void Get(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + if (arguments.ArgumentReferences.TryGetValue("message", out Reference? messageReference)) + { + string message = messageReference.Object.ToPureString(result); + if (result.ShouldReturn) + return; + + Console.Write(message); + } + + result.Success(ReferencePool.Get(new EzrString(Console.ReadLine() ?? string.Empty, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } + + /// + /// Basic console clear function. Implements . + /// + /// + /// ezr² return type: + /// + /// + /// The constructor arguments. + [SharpMethodWrapper("clear")] + public static void Clear(SharpMethodParameters arguments) + { + Console.Clear(); + arguments.Result.Success(ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant)); + } + + /// + /// Assertion function to assert conditions. + /// + /// + /// ezr² parameters: + /// + /// + /// condition + /// () The condition to assert. + /// + /// + /// + /// ezr² return type: + /// + ///
+ /// ezr² errors: + /// if the condition is not met. + ///
+ /// The constructor arguments. + [SharpMethodWrapper("assert", RequiredParameters = ["condition"])] + public static void Assert(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + IEzrObject condition = arguments.ArgumentReferences["condition"].Object; + + bool conditionResult = condition.EvaluateBoolean(result); + if (result.ShouldReturn) + return; + + if (!conditionResult) + { + result.Failure(new EzrAssertionError(arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition)); + return; + } + + result.Success(ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant)); + } + + /// + /// Basic hash function. Implements . + /// + /// + /// ezr² parameters: + /// + /// + /// to_hash + /// () The object to hash. + /// + /// + /// + /// ezr² return type: + /// + /// + /// The constructor arguments. + [SharpMethodWrapper("hash", RequiredParameters = ["to_hash"])] + public static void Hash(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference reference = arguments.ArgumentReferences["to_hash"]; + + int hash = reference.Object.ComputeHashCode(result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrInteger(hash, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } + + /// + /// Basic -like function. Uses . + /// + /// + /// ezr² parameters: + /// + /// + /// to_check + /// () The object to check the type of. + /// + /// + /// + /// ezr² return type: + /// + /// + /// The constructor arguments. + [SharpMethodWrapper("type_of", RequiredParameters = ["to_check"])] + public static void TypeOf(SharpMethodParameters arguments) + { + arguments.Result.Success(ReferencePool.Get( + new EzrString( + arguments.ArgumentReferences["to_check"].Object.Tag, + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition), + AccessMod.PrivateConstant)); + } + + /// + /// Gets the plain text name of the type of an object. Uses . + /// + /// + /// ezr² parameters: + /// + /// + /// to_check + /// () The object to check the type-name of. + /// + /// + /// + /// ezr² return type: + /// + /// + /// The constructor arguments. + [SharpMethodWrapper("type_name_of", RequiredParameters = ["to_check"])] + public static void TypeNameOf(SharpMethodParameters arguments) + { + arguments.Result.Success(ReferencePool.Get( + new EzrString( + arguments.ArgumentReferences["to_check"].Object.TypeName, + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition), + AccessMod.PrivateConstant)); + } + + /// + /// Gets the hash ID of the type of an object. Uses . + /// + /// + /// ezr² parameters: + /// + /// + /// to_check + /// () The object to check the type hash of. + /// + /// + /// + /// ezr² return type: + /// + /// + /// The constructor arguments. + [SharpMethodWrapper("type_hash_of", RequiredParameters = ["to_check"])] + public static void TypeHashOf(SharpMethodParameters arguments) + { + arguments.Result.Success(ReferencePool.Get( + new EzrInteger( + arguments.ArgumentReferences["to_check"].Object.HashTag, + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition), + AccessMod.PrivateConstant)); + } + + /// + /// Creates a copy of an . Uses . + /// + /// + /// ezr² parameters: + /// + /// + /// to_copy + /// () The object to copy. + /// + /// + /// + /// ezr² return type: + /// + /// + /// ezr² errors: + /// if "to_copy" is not of the expected type. + /// + /// The constructor arguments. + [SharpMethodWrapper("copy", RequiredParameters = ["to_copy"])] + public static void Copy(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + IEzrObject objectToCopy = arguments.ArgumentReferences["to_copy"].Object; + if (objectToCopy is not IEzrMutableObject mutableObject) + { + result.Failure(new EzrUnexpectedTypeError($"Cannot create copy of immutable object of type \"{objectToCopy.TypeName}\"!", arguments.ExecutionContext, objectToCopy.StartPosition, objectToCopy.EndPosition)); + return; + } + + IEzrObject? copy = (IEzrObject?)mutableObject.DeepCopy(result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(copy, AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs new file mode 100644 index 0000000..1a4a58f --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs @@ -0,0 +1,95 @@ +using EzrSquared.Runtime.Types.Core; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.Builtins; + +/// +/// Utility to add built-ins to contexts. +/// +public static class EzrBuiltinsUtility +{ + /// + /// Adds all built-in functions to the given context. + /// + /// The context to add to. + public static void AddBuiltinFunctions(Context context) + { + EzrSharpSourceFunctionWrapper show = new(EzrBuiltinFunctions.Show, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper throwError = new(EzrBuiltinFunctions.ThrowError, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper get = new(EzrBuiltinFunctions.Get, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper clear = new(EzrBuiltinFunctions.Clear, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper assert = new(EzrBuiltinFunctions.Assert, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper hash = new(EzrBuiltinFunctions.Hash, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper typeOf = new(EzrBuiltinFunctions.TypeOf, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper typeNameOf = new(EzrBuiltinFunctions.TypeNameOf, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper typeHashOf = new(EzrBuiltinFunctions.TypeHashOf, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper copy = new(EzrBuiltinFunctions.Copy, context, Position.None, Position.None); + + context.Set(null, show.SharpFunctionName, ReferencePool.Get(show, AccessMod.Constant)); + context.Set(null, throwError.SharpFunctionName, ReferencePool.Get(throwError, AccessMod.Constant)); + context.Set(null, get.SharpFunctionName, ReferencePool.Get(get, AccessMod.Constant)); + context.Set(null, clear.SharpFunctionName, ReferencePool.Get(clear, AccessMod.Constant)); + context.Set(null, assert.SharpFunctionName, ReferencePool.Get(assert, AccessMod.Constant)); + context.Set(null, hash.SharpFunctionName, ReferencePool.Get(hash, AccessMod.Constant)); + context.Set(null, typeOf.SharpFunctionName, ReferencePool.Get(typeOf, AccessMod.Constant)); + context.Set(null, typeNameOf.SharpFunctionName, ReferencePool.Get(typeNameOf, AccessMod.Constant)); + context.Set(null, typeHashOf.SharpFunctionName, ReferencePool.Get(typeHashOf, AccessMod.Constant)); + context.Set(null, copy.SharpFunctionName, ReferencePool.Get(copy, AccessMod.Constant)); + } + + /// + /// Adds all built-in types to the given context. + /// + /// The context to add to. + public static void AddBuiltinTypes(Context context) + { + EzrSharpSourceTypeWrapper runtimeError = new(typeof(EzrRuntimeError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper illegalOperationError = new(typeof(EzrIllegalOperationError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper undefinedValueError = new(typeof(EzrUndefinedValueError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper privateValueAccessError = new(typeof(EzrPrivateMemberOperationError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper mathError = new(typeof(EzrMathError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper valueOutOfRangeError = new(typeof(EzrValueOutOfRangeError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper unexpectedTypeError = new(typeof(EzrUnexpectedTypeError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper keyNotFoundError = new(typeof(EzrKeyNotFoundError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper missingRequiredArgumentError = new(typeof(EzrMissingRequiredArgumentError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper unexpectedArgumentError = new(typeof(EzrUnexpectedArgumentError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper unsupportedWrappingError = new(typeof(EzrUnsupportedWrappingError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper wrapperExecutionError = new(typeof(EzrWrapperExecutionError), context, Position.None, Position.None); + + context.Set(null, runtimeError.SharpTypeName, ReferencePool.Get(runtimeError, AccessMod.Constant)); + context.Set(null, illegalOperationError.SharpTypeName, ReferencePool.Get(illegalOperationError, AccessMod.Constant)); + context.Set(null, undefinedValueError.SharpTypeName, ReferencePool.Get(undefinedValueError, AccessMod.Constant)); + context.Set(null, privateValueAccessError.SharpTypeName, ReferencePool.Get(privateValueAccessError, AccessMod.Constant)); + context.Set(null, mathError.SharpTypeName, ReferencePool.Get(mathError, AccessMod.Constant)); + context.Set(null, valueOutOfRangeError.SharpTypeName, ReferencePool.Get(valueOutOfRangeError, AccessMod.Constant)); + context.Set(null, unexpectedTypeError.SharpTypeName, ReferencePool.Get(unexpectedTypeError, AccessMod.Constant)); + context.Set(null, keyNotFoundError.SharpTypeName, ReferencePool.Get(keyNotFoundError, AccessMod.Constant)); + context.Set(null, missingRequiredArgumentError.SharpTypeName, ReferencePool.Get(missingRequiredArgumentError, AccessMod.Constant)); + context.Set(null, unexpectedArgumentError.SharpTypeName, ReferencePool.Get(unexpectedArgumentError, AccessMod.Constant)); + context.Set(null, unsupportedWrappingError.SharpTypeName, ReferencePool.Get(unsupportedWrappingError, AccessMod.Constant)); + context.Set(null, wrapperExecutionError.SharpTypeName, ReferencePool.Get(wrapperExecutionError, AccessMod.Constant)); + } + + /// + /// Adds all built-in constants to the given context. + /// + /// The context to add to. + public static void AddBuiltinConstants(Context context) + { + context.Set( + null, + "true", + ReferencePool.Get(EzrConstants.True, AccessMod.Constant)); + + context.Set( + null, + "false", + ReferencePool.Get(EzrConstants.False, AccessMod.Constant)); + + context.Set( + null, + "nothing", + ReferencePool.Get(EzrConstants.Nothing, AccessMod.Constant)); + } +} diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs new file mode 100644 index 0000000..1249e7b --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -0,0 +1,93 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +using EzrSquared.Util; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; + +public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper +{ + /// + public override string TypeName { get; protected internal set; } = "csharp object instance"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpObjectInstance"; + + public readonly object Instance; + public readonly string InstanceTypeName; + + public EzrSharpCompatibilityObjectInstance(object instance, + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + Type instanceType, + + RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + Instance = instance; + InstanceTypeName = Utils.PascalToSnakeCase(instanceType.Name); + Tag = $"{Tag}.{InstanceTypeName}.{Utils.GetNextUniqueId()}"; + + MethodInfo[] publicMethods = instanceType.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + Dictionary duplicateNames = new(publicMethods.Length); + for (int i = 0; i < publicMethods.Length; i++) + { + MethodInfo method = publicMethods[i]; + if (method.ContainsGenericParameters || method.IsGenericMethod) + { + result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap CSharp method \"{method.Name}\" of instance \"{instanceType.Name}\"! Reasons can include the method being generic or containing generic parameters.", Context, StartPosition, EndPosition)); + return; + } + + if (method.IsAbstract) + continue; + + string methodObjectName = method.Name; + if (duplicateNames.TryGetValue(method.Name, out int duplicates)) + { + methodObjectName += $"_{duplicates}"; + duplicateNames[method.Name] += 1; + } + else + duplicateNames.Add(method.Name, 1); + + EzrSharpCompatibilityFunction methodObject = new(method, Instance, Context, StartPosition, EndPosition); + Context.Set(null, methodObjectName, ReferencePool.Get(methodObject, AccessMod.Constant)); + } + + PropertyInfo[] publicProperties = instanceType.GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + for (int i = 0; i < publicProperties.Length; i++) + { + EzrSharpCompatibilityProperty property = new(publicProperties[i], Instance, Context, StartPosition, EndPosition); + Context.Set(null, property.SharpPropertyName, ReferencePool.Get(property, AccessMod.Constant)); + } + + FieldInfo[] publicFields = instanceType.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + for (int i = 0; i < publicFields.Length; i++) + { + EzrSharpCompatibilityField field = new(publicFields[i], Instance, Context, StartPosition, EndPosition); + Context.Set(null, field.SharpFieldName, ReferencePool.Get(field, AccessMod.Constant)); + } + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, Instance); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrSharpCompatibilityObjectInstance)?.Instance.GetHashCode() == Instance.GetHashCode() && other.HashTag == HashTag; + } + + /// + public override string ToString(RuntimeResult result) + { + return $"<{TypeName} of type \"{InstanceTypeName}\">"; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs new file mode 100644 index 0000000..f74c106 --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -0,0 +1,110 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +using EzrSquared.Util; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; + +public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper +{ + /// + public override string TypeName { get; protected internal set; } = "csharp type"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpType"; + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + public readonly Type SharpType; + public readonly string SharpTypeName; + + public EzrSharpCompatibilityType( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + Type type, + + RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + SharpType = type; + SharpTypeName = Utils.PascalToSnakeCase(SharpType.Name); + Tag = $"{Tag}.{SharpTypeName}.{Utils.GetNextUniqueId()}"; + + if (SharpType.IsGenericType) + { + result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap generic CSharp type \"{SharpType.Name}\"!", Context, StartPosition, EndPosition)); + return; + } + + MethodInfo[] publicStaticMethods = SharpType.GetMethods(BindingFlags.Static | BindingFlags.Public); + Dictionary duplicateNames = new(publicStaticMethods.Length); + for (int i = 0; i < publicStaticMethods.Length; i++) + { + MethodInfo method = publicStaticMethods[i]; + if (method.ContainsGenericParameters || method.IsGenericMethod) + { + result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap CSharp static method \"{method.Name}\" of type \"{SharpType.Name}\"! Reasons can include the method being generic or containing generic parameters.", Context, StartPosition, EndPosition)); + return; + } + + if (method.IsAbstract) + continue; + + string methodObjectName = Utils.PascalToSnakeCase(method.Name); + if (duplicateNames.TryGetValue(method.Name, out int duplicates)) + { + methodObjectName += $"_{duplicates}"; + duplicateNames[method.Name] += 1; + } + else + duplicateNames.Add(method.Name, 1); + + EzrSharpCompatibilityFunction methodObject = new(method, null, Context, StartPosition, EndPosition); + Context.Set(null, methodObjectName, ReferencePool.Get(methodObject, AccessMod.Constant)); + } + + PropertyInfo[] publicStaticProperties = SharpType.GetProperties(BindingFlags.Static | BindingFlags.Public); + for (int i = 0; i < publicStaticProperties.Length; i++) + { + EzrSharpCompatibilityProperty property = new(publicStaticProperties[i], null, Context, StartPosition, EndPosition); + Context.Set(null, property.SharpPropertyName, ReferencePool.Get(property, AccessMod.Constant)); + } + + FieldInfo[] publicStaticFields = SharpType.GetFields(BindingFlags.Static | BindingFlags.Public); + for (int i = 0; i < publicStaticFields.Length; i++) + { + EzrSharpCompatibilityField field = new(publicStaticFields[i], null, Context, StartPosition, EndPosition); + Context.Set(null, field.SharpFieldName, ReferencePool.Get(field, AccessMod.Constant)); + } + + ConstructorInfo[] publicConstructors = SharpType.GetConstructors(); + for (int i = 0; i < publicConstructors.Length; i++) + { + ConstructorInfo constructor = publicConstructors[i]; + if (!constructor.IsPublic) + continue; + + IEzrObject constructorObject = new EzrSharpCompatibilityConstructor(constructor, SharpType, Context, StartPosition, EndPosition); + Context.Set(null, $"make_{i}", ReferencePool.Get(constructorObject, AccessMod.Constant)); + } + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, SharpType); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrSharpCompatibilityType)?.SharpType == SharpType && other.HashTag == HashTag; + } + + /// + public override string ToString(RuntimeResult result) + { + return $"<{TypeName} \"{SharpTypeName}\">"; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs new file mode 100644 index 0000000..d004c42 --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -0,0 +1,249 @@ +using EzrSquared.Runtime.Types.Core; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.Core.Text; +using System; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; + +public abstract class EzrSharpCompatibilityWrapper : EzrObject +{ + /// + public override string TypeName { get; protected internal set; } = "csharp wrapper"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpWrapper"; + + public EzrSharpCompatibilityWrapper(Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { } + + protected internal object? EzrObjectToPrimitive(IEzrObject value, TypeCode typeCode, RuntimeResult result) + { + switch (typeCode) + { + case TypeCode.Int16: + if (value is EzrInteger integer16Value) + if (integer16Value.TryGetIntRepresentation(out int output)) + if (output is < short.MinValue or > short.MaxValue) + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + return (short)output; + else + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.Int32: + if (value is EzrInteger integer32Value) + if (integer32Value.TryGetIntRepresentation(out int output)) + return output; + else + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.Int64: + if (value is EzrInteger integer64Value) + if (integer64Value.TryGetLongRepresentation(out long output)) + return output; + else + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.UInt16: + if (value is EzrInteger unsignedInteger16Value) + if (unsignedInteger16Value.TryGetIntRepresentation(out int output)) + if (output < 0) + result.Failure(new EzrValueOutOfRangeError($"Expected integer of value greater than or equal to 0, but got {output}!", Context, value.StartPosition, value.EndPosition)); + else if (output > ushort.MaxValue) + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + return (ushort)output; + else + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.UInt32: + if (value is EzrInteger unsignedInteger32Value) + if (unsignedInteger32Value.TryGetIntRepresentation(out int output)) + if (output < 0) + result.Failure(new EzrValueOutOfRangeError($"Expected integer of value greater than or equal to 0, but got {output}!", Context, value.StartPosition, value.EndPosition)); + else + return (uint)output; + else + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.UInt64: + if (value is EzrInteger unsignedInteger64Value) + if (unsignedInteger64Value.TryGetLongRepresentation(out long output)) + if (output < 0) + result.Failure(new EzrValueOutOfRangeError($"Expected integer of value greater than or equal to 0, but got {output}!", Context, value.StartPosition, value.EndPosition)); + else + return (ulong)output; + else + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.Byte: + if (value is EzrInteger byteValue) + if (byteValue.TryGetIntRepresentation(out int output)) + if (output < 0) + result.Failure(new EzrValueOutOfRangeError($"Expected integer of value greater than or equal to 0, but got {output}!", Context, value.StartPosition, value.EndPosition)); + else if (output > byte.MaxValue) + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + return (byte)output; + else + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.SByte: + if (value is EzrInteger signedByteValue) + if (signedByteValue.TryGetIntRepresentation(out int output)) + if (output is < sbyte.MinValue or > sbyte.MaxValue) + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + return (sbyte)output; + else + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.Single: + if (value is EzrFloat floatValue) + { + double output = floatValue.Value; + if (output is < float.MinValue or > float.MaxValue) + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + return (float)output; + } + else + result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.Double: + if (value is EzrFloat doubleValue) + return doubleValue.Value; + + result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.Boolean: + if (value is EzrBoolean booleanValue) + return booleanValue.Value; + + result.Failure(new EzrUnexpectedTypeError($"Expected boolean, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.Char: + if (value is EzrCharacter characterValue) + return characterValue.Value; + + result.Failure(new EzrUnexpectedTypeError($"Expected character, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.String: + if (value is EzrString stringValue) + return stringValue.Value; + else if (value is EzrCharacterList characterListValue) + return characterListValue.StringValue; + + result.Failure(new EzrUnexpectedTypeError($"Expected string or character list, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.Empty: + if (value is EzrNothing) + return null; + + result.Failure(new EzrUnexpectedTypeError($"Expected type nothing, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + default: + result.Failure(new EzrUnsupportedWrappingError($"Object of type \"{value.TypeName}\" cannot be converted from to CSharp type!", Context, value.StartPosition, value.EndPosition)); + break; + } + + return 0; + } + + protected internal void PrimitiveToEzrObject(object? value, TypeCode typeCode, RuntimeResult result) + { + if (value is null) + { + result.Success(NewNothingConstant()); + return; + } + + switch (typeCode) + { + case TypeCode.Int16: + result.Success(NewIntegerConstant((short)value)); + break; + case TypeCode.Int32: + result.Success(NewIntegerConstant((int)value)); + break; + case TypeCode.Int64: + result.Success(NewIntegerConstant((long)value)); + break; + case TypeCode.UInt16: + result.Success(NewIntegerConstant((ushort)value)); + break; + case TypeCode.UInt32: + result.Success(NewIntegerConstant((uint)value)); + break; + case TypeCode.UInt64: + result.Success(NewIntegerConstant((ulong)value)); + break; + case TypeCode.Byte: + result.Success(NewIntegerConstant((byte)value)); + break; + case TypeCode.SByte: + result.Success(NewIntegerConstant((sbyte)value)); + break; + case TypeCode.Single: + result.Success(NewFloatConstant((float)value)); + break; + case TypeCode.Double: + result.Success(NewFloatConstant((double)value)); + break; + case TypeCode.Boolean: + result.Success(NewBooleanConstant((bool)value)); + break; + case TypeCode.Char: + result.Success(NewCharacterConstant((char)value)); + break; + case TypeCode.String: + result.Success(NewStringConstant((string)value)); + break; + default: + result.Failure(new EzrUnsupportedWrappingError($"CSharp type \"{value.GetType().Name}\" cannot be converted to EzrSquared type!", Context, StartPosition, EndPosition)); + break; + } + } + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + bool equal = StrictEquals(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(equal)); + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + bool equal = StrictEquals(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(!equal)); + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return true; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs new file mode 100644 index 0000000..e15f8c2 --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -0,0 +1,80 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Util; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; + +public class EzrSharpCompatibilityConstructor : EzrSharpCompatibilityExecutable +{ + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + public readonly Type ConstructingType; + public readonly string ConstructingTypeName; + public readonly ConstructorInfo SharpConstructor; + + public EzrSharpCompatibilityConstructor(ConstructorInfo sharpConstructor, + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + Type constructType, + + Context context, Position startPosition, Position endPosition) : base(sharpConstructor, null, context, startPosition, endPosition) + { + SharpConstructor = sharpConstructor; + ConstructingType = constructType; + ConstructingTypeName = Utils.PascalToSnakeCase(ConstructingType.Name); + } + + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + Dictionary formattedArguments = ArgumentsArrayToDictionary(arguments, result); + if (result.ShouldReturn) + return; + + object?[] mappedArguments = CheckAndPopulateArguments(formattedArguments, result); + if (result.ShouldReturn) + return; + + try + { + object? output = SharpConstructor.Invoke(mappedArguments); + + if (output is null) + result.Success(NewNothingConstant()); + else + { + IEzrObject wrapper = new EzrSharpCompatibilityObjectInstance(output, ConstructingType, result, _executionContext, StartPosition, EndPosition); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(wrapper)); + } + } + catch (Exception error) + { + result.Failure(new EzrWrapperExecutionError(error.Message, Context, StartPosition, EndPosition)); + return; + } + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrSharpCompatibilityConstructor)?.SharpConstructor == SharpConstructor && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, SharpConstructor); + } + + /// + public override string ToString(RuntimeResult result) + { + return ParameterNames.Length > 0 + ? $"<{TypeName} for type \"{ConstructingTypeName}\", with \"{string.Join("\", \"", ParameterNames)}\">" + : $"<{TypeName} for \"{ConstructingTypeName}\">"; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs new file mode 100644 index 0000000..b82f4e1 --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -0,0 +1,126 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Util; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; + +public abstract class EzrSharpCompatibilityExecutable : EzrSharpCompatibilityWrapper +{ + /// + public override string TypeName { get; protected internal set; } = "csharp runtime executable"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpRuntimeExecutable"; + + public readonly ParameterInfo[] Parameters; + public readonly string[] ParameterNames; + public readonly object? Instance; + public readonly string SharpRuntimeExecutableName; + + public EzrSharpCompatibilityExecutable(MethodBase sharpMember, object? instance, Context context, Position startPosition, Position endPosition) : base(context, startPosition, endPosition) + { + SharpRuntimeExecutableName = Utils.PascalToSnakeCase(sharpMember.Name); + Tag = $"{Tag}.{SharpRuntimeExecutableName}.{Utils.GetNextUniqueId()}"; + + Parameters = sharpMember.GetParameters(); + ParameterNames = Array.ConvertAll(Parameters, p => Utils.PascalToSnakeCase(p.Name ?? string.Empty)); + Instance = instance; + } + + protected internal Dictionary ArgumentsArrayToDictionary(Reference[] arguments, RuntimeResult result) + { + Dictionary formattedArguments = new(arguments.Length); + + int index = 0; + int requiredKeywordArguments = 0; + for (int i = 0; i < arguments.Length; i++) + { + Reference reference = arguments[i]; + if (!string.IsNullOrEmpty(reference.Name) && !reference.IsRegistered) + { + if (formattedArguments.ContainsKey(reference.Name)) + { + result.Failure(new EzrIllegalOperationError($"Cannot override already defined argument \"{reference.Name}\"!", _executionContext, reference.Object.StartPosition, reference.Object.EndPosition)); + break; + } + + formattedArguments[reference.Name] = reference.Object; + if (Array.IndexOf(ParameterNames, reference.Name) >= 0) + requiredKeywordArguments++; + } + else + { + IndexCheck: + if (ParameterNames.Length <= index) + { + result.Failure(new EzrUnexpectedArgumentError( + requiredKeywordArguments > 0 + ? $"Only expected {ParameterNames.Length - requiredKeywordArguments} unnamed argument(s) as {requiredKeywordArguments} required argument(s) has/have been declared as (a) keyword argument(s)!" + : $"Only expected {ParameterNames.Length} unnamed argument(s)!", + _executionContext, StartPosition, EndPosition)); + break; + } + + string argumentName = ParameterNames[index]; + if (!formattedArguments.ContainsKey(argumentName)) + { + formattedArguments[argumentName] = reference.Object; + index++; + } + else + { + index++; + goto IndexCheck; + } + } + } + + return formattedArguments; + } + + protected internal object?[] CheckAndPopulateArguments(Dictionary arguments, RuntimeResult result) + { + object?[] formattedArguments = new object?[Parameters.Length]; + Array.Fill(formattedArguments, Type.Missing); + + for (int i = 0; i < Parameters.Length; i++) + { + ParameterInfo parameter = Parameters[i]; + if (!string.IsNullOrEmpty(parameter.Name) && arguments.TryGetValue(ParameterNames[i], out IEzrObject? argument)) + { + object? primitiveArgument = EzrObjectToPrimitive(argument, Type.GetTypeCode(parameter.ParameterType), result); + if (result.ShouldReturn) + return []; + + if (primitiveArgument?.GetType() != parameter.ParameterType) + { + result.Failure(new EzrUnexpectedTypeError($"CSharp argument \"{ParameterNames[i]}\" expected value of CSharp type \"{parameter.ParameterType.Name}\", but got object of type \"{argument.TypeName}\"!", Context, argument.StartPosition, argument.EndPosition)); + return []; + } + + formattedArguments[i] = primitiveArgument; + arguments.Remove(ParameterNames[i]); + } + else if (parameter.HasDefaultValue) + formattedArguments[i] = parameter.DefaultValue; + else + { + result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{ParameterNames[i]}\"!", _executionContext, StartPosition, EndPosition)); + return []; + } + } + + if (arguments.Count > 0) + { + Dictionary.Enumerator argumentsEnumerator = arguments.GetEnumerator(); + argumentsEnumerator.MoveNext(); + + KeyValuePair first = argumentsEnumerator.Current; + result.Failure(new EzrUnexpectedArgumentError($"Did not expect argument \"{first.Key}\"!", _executionContext, first.Value.StartPosition, first.Value.EndPosition)); + } + + return formattedArguments; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs new file mode 100644 index 0000000..4e2d2b1 --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs @@ -0,0 +1,71 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; + +public class EzrSharpCompatibilityFunction : EzrSharpCompatibilityExecutable +{ + /// + public override string TypeName { get; protected internal set; } = "csharp function"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpFunction"; + + public readonly MethodInfo SharpFunction; + + public EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context context, Position startPosition, Position endPosition) : base(sharpFunction, instance, context, startPosition, endPosition) + { + SharpFunction = sharpFunction; + } + + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + Dictionary formattedArguments = ArgumentsArrayToDictionary(arguments, result); + if (result.ShouldReturn) + return; + + object?[] mappedArguments = CheckAndPopulateArguments(formattedArguments, result); + if (result.ShouldReturn) + return; + + try + { + object? output = SharpFunction.Invoke(Instance, mappedArguments); + + if (output is null) + result.Success(NewNothingConstant()); + else + PrimitiveToEzrObject(output, Type.GetTypeCode(output.GetType()), result); + } + catch (Exception error) + { + result.Failure(new EzrWrapperExecutionError(error.Message, Context, StartPosition, EndPosition)); + return; + } + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, SharpFunction); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return other is EzrSharpCompatibilityFunction function + && function.SharpFunction == SharpFunction + && function.Instance?.GetHashCode() == Instance?.GetHashCode() + && other.HashTag == HashTag; + } + + /// + public override string ToString(RuntimeResult result) + { + return ParameterNames.Length > 0 + ? $"<{TypeName} \"{SharpRuntimeExecutableName}\", with \"{string.Join("\", \"", ParameterNames)}\">" + : $"<{TypeName} \"{SharpRuntimeExecutableName}\">"; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs new file mode 100644 index 0000000..19fe27f --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -0,0 +1,80 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Util; +using System; +using System.Reflection; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; + +public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper +{ + /// + public override string TypeName { get; protected internal set; } = "csharp field"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpField"; + + public readonly FieldInfo SharpField; + public readonly object? Instance; + public readonly string SharpFieldName; + + public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + SharpField = sharpField; + Instance = instance; + SharpFieldName = Utils.PascalToSnakeCase(SharpField.Name); + Tag = $"{Tag}.{SharpFieldName}.{Utils.GetNextUniqueId()}"; + } + + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + if (arguments.Length > 1) + { + result.Failure(new EzrUnexpectedArgumentError($"Only expected 0 (for getting the value) or 1 (for setting the value) argument(s) for CSharp field wrapper \"{SharpFieldName}\"!", Context, StartPosition, EndPosition)); + return; + } + + if (arguments.Length == 0) + { + object? value = SharpField.GetValue(Instance); + PrimitiveToEzrObject(value, Type.GetTypeCode(value?.GetType()), result); + } + else + { + object? value = EzrObjectToPrimitive(arguments[0].Object, Type.GetTypeCode(SharpField.FieldType), result); + if (result.ShouldReturn) + return; + + try + { + SharpField.SetValue(Instance, value); + result.Success(NewNothingConstant()); + } + catch (Exception error) + { + result.Failure(new EzrWrapperExecutionError(error.Message, Context, StartPosition, EndPosition)); + return; + } + } + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return other is EzrSharpCompatibilityField field + && field.SharpField == SharpField + && field.Instance?.GetHashCode() == Instance?.GetHashCode() + && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, SharpField); + } + + /// + public override string ToString(RuntimeResult result) + { + return $"<{TypeName} \"{SharpFieldName}\">"; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs new file mode 100644 index 0000000..cc900ff --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -0,0 +1,92 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Util; +using System; +using System.Reflection; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; + +public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper +{ + /// + public override string TypeName { get; protected internal set; } = "csharp property"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpProperty"; + + public readonly PropertyInfo SharpProperty; + public readonly object? Instance; + public readonly string SharpPropertyName; + + public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + SharpProperty = sharpProperty; + Instance = instance; + SharpPropertyName = Utils.PascalToSnakeCase(SharpProperty.Name); + Tag = $"{Tag}.{SharpPropertyName}.{Utils.GetNextUniqueId()}"; + } + + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + if (arguments.Length > 1) + { + result.Failure(new EzrUnexpectedArgumentError($"Only expected 0 (for getting the value) or 1 (for setting the value) argument(s) for CSharp property wrapper \"{SharpPropertyName}\"!", Context, StartPosition, EndPosition)); + return; + } + + if (arguments.Length == 0) + { + object? value = SharpProperty.GetValue(Instance); + PrimitiveToEzrObject(value, Type.GetTypeCode(value?.GetType()), result); + } + else + { + object? value = EzrObjectToPrimitive(arguments[0].Object, Type.GetTypeCode(SharpProperty.PropertyType), result); + if (result.ShouldReturn) + return; + + if (!SharpProperty.CanWrite || SharpProperty.SetMethod is null) + { + result.Failure(new EzrIllegalOperationError($"Cannot set value to CSharp property wrapper \"{SharpPropertyName}\" as it is read-only!", Context, StartPosition, EndPosition)); + return; + } + + if (!SharpProperty.SetMethod.IsPublic) + { + result.Failure(new EzrIllegalOperationError($"Cannot set value to CSharp property wrapper \"{SharpPropertyName}\" as it does not have a public setter method!", Context, StartPosition, EndPosition)); + return; + } + + try + { + SharpProperty.SetValue(Instance, value); + result.Success(NewNothingConstant()); + } + catch (Exception error) + { + result.Failure(new EzrWrapperExecutionError(error.Message, Context, StartPosition, EndPosition)); + return; + } + } + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, SharpProperty); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return other is EzrSharpCompatibilityProperty property + && property.SharpProperty == SharpProperty + && property.Instance?.GetHashCode() == Instance?.GetHashCode() + && other.HashTag == HashTag; + } + + /// + public override string ToString(RuntimeResult result) + { + return $"<{TypeName} \"{SharpPropertyName}\">"; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs new file mode 100644 index 0000000..015287e --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs @@ -0,0 +1,118 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; +using EzrSquared.Util; +using System; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; + +public abstract class EzrSharpSourceExecutableWrapper : EzrSharpCompatibilityWrapper +{ + /// + public override string TypeName { get; protected internal set; } = "csharp source executable wrapper"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceExecutableWrapper"; + + public (string Name, bool IsRequired)[] Parameters; + public bool HasKeywordArguments; + + public EzrSharpSourceExecutableWrapper(Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + Parameters = []; + } + + protected internal Dictionary CheckAndPopulateArguments(Reference[] arguments, RuntimeResult result) + { + int calculatedParameterIndex = 0; + int requiredKeywordArguments = 0; + int flaggedRequiredArguments = -1; + + Dictionary argumentReferences = new(arguments.Length); + + for (int i = 0; i < arguments.Length; i++) + { + string name; + int parameterIndex = 0; + Reference reference = arguments[i]; + + if (!string.IsNullOrEmpty(reference.Name) && !reference.IsRegistered && !reference.IsEmpty) + { + name = reference.Name; + if (argumentReferences.ContainsKey(name)) + { + result.Failure(new EzrIllegalOperationError($"Cannot override already defined argument \"{name}\"!", _executionContext, reference.Object.StartPosition, reference.Object.EndPosition)); + return argumentReferences; + } + + bool found = Array.Find(Parameters, (v) => + { + parameterIndex++; + return v.Name == name; + }) != default; + + if (found) + { + argumentReferences.Add(name, reference); + requiredKeywordArguments++; + } + else if (HasKeywordArguments) + { + argumentReferences.Add(name, reference); + parameterIndex = -1; + } + else + { + result.Failure(new EzrUnexpectedArgumentError($"Did not expect argument \"{name}\"!", _executionContext, reference.Object.StartPosition, reference.Object.EndPosition)); + return argumentReferences; + } + } + else + { + IndexCheck: + if (Parameters.Length <= calculatedParameterIndex) + { + result.Failure(new EzrUnexpectedArgumentError( + requiredKeywordArguments > 0 + ? $"Only expected {Parameters.Length - requiredKeywordArguments} unnamed argument(s) as {requiredKeywordArguments} required argument(s) has/have been declared as (a) keyword argument(s)!" + : $"Only expected {Parameters.Length} unnamed argument(s)!", + _executionContext, StartPosition, EndPosition)); + break; + } + + string argumentName = Parameters[calculatedParameterIndex].Name; + if (!argumentReferences.ContainsKey(argumentName)) + { + name = argumentName; + parameterIndex = calculatedParameterIndex; + + argumentReferences.Add(name, reference); + calculatedParameterIndex++; + } + else + { + calculatedParameterIndex++; + goto IndexCheck; + } + } + + if (parameterIndex > -1) + if (flaggedRequiredArguments < 0) + flaggedRequiredArguments = Utils.IndexToFlag(parameterIndex); + else + flaggedRequiredArguments |= Utils.IndexToFlag(parameterIndex); + } + + for (int i = 0; i < Parameters.Length; i++) + { + int parameterFlag = Utils.IndexToFlag(i); + if (Parameters[i].IsRequired && (flaggedRequiredArguments < 0 || (flaggedRequiredArguments & parameterFlag) != parameterFlag)) + { + result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{Parameters[i].Name}\"!", _executionContext, StartPosition, EndPosition)); + return argumentReferences; + } + } + + return argumentReferences; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs new file mode 100644 index 0000000..4aa481d --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs @@ -0,0 +1,112 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Util; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; + +public class EzrSharpSourceFieldWrapper : EzrSharpSourceExecutableWrapper +{ + /// + public override string TypeName { get; protected internal set; } = "csharp source field wrapper"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceFieldWrapper"; + + public readonly object? SharpInstance; + public readonly FieldInfo SharpField; + public readonly Type SharpFieldType; + public readonly string SharpFieldName; + public readonly bool IsReadOnlyField; + + public EzrSharpSourceFieldWrapper(FieldInfo fieldInfo, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + SharpInstance = instance; + SharpField = fieldInfo; + + SharpFieldWrapperAttribute attribute = SharpField.GetCustomAttribute(true) ?? throw new ArgumentException($"No \"{nameof(SharpFieldWrapperAttribute)}\" attribute found!", nameof(fieldInfo)); + + ArgumentException? fieldTypeException = SharpFieldWrapperAttribute.ValidateField(SharpField); + if (fieldTypeException is not null) + throw fieldTypeException; + + SharpFieldName = attribute.Name; + SharpFieldType = fieldInfo.FieldType; + IsReadOnlyField = attribute.IsReadOnly; + + if (!IsReadOnlyField && !SharpField.IsLiteral && !SharpField.IsInitOnly) + Parameters = [("value", false)]; + + Tag = $"{Tag}.{SharpFieldName}.{Utils.GetNextUniqueId()}"; + } + + /// + /// Converts a string from PascalCase to lowecase plain text, seperated by spaces. + /// + /// The text to convert in PascalCase. + /// The converted text in lowecase plain text. + private static string PascalCaseToLowerCasePlainText(string text) + { + StringBuilder result = new(); + result.Append(char.ToLowerInvariant(text[0])); + + for (int i = 1; i < text.Length; ++i) + { + char c = text[i]; + if (char.IsUpper(c)) + result.Append(' ').Append(char.ToLowerInvariant(c)); + else + result.Append(c); + } + + return result.ToString(); + } + + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); + if (result.ShouldReturn) + return; + + if (argumentReferences.TryGetValue("value", out Reference? newValue)) + { + if (!SharpFieldType.IsAssignableFrom(newValue.Object.GetType())) + { + string sharpFieldType = SharpFieldType.Name; + if (sharpFieldType.StartsWith("Ezr")) + sharpFieldType = sharpFieldType[3..]; + + result.Failure(new EzrUnexpectedTypeError($"Expected object of type \"{PascalCaseToLowerCasePlainText(sharpFieldType)}\", but got object of type \"{newValue.Object.TypeName}\"!", _executionContext, StartPosition, EndPosition)); + return; + } + + SharpField.SetValue(SharpInstance, newValue.Object); + } + + IEzrObject? fieldValue = (IEzrObject?)SharpField.GetValue(SharpInstance); + Reference fieldReference = fieldValue is null ? NewNothingConstant() : ReferencePool.Get(fieldValue, AccessMod.PrivateConstant); + + result.Success(fieldReference); + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, SharpField); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrSharpSourceFieldWrapper)?.SharpField == SharpField && other.HashTag == HashTag; + } + + /// + public override string ToString(RuntimeResult result) + { + return $"<{TypeName} \"{SharpFieldName}\">"; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs new file mode 100644 index 0000000..7d8e359 --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs @@ -0,0 +1,82 @@ +using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Util; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; + +public partial class EzrSharpSourceFunctionWrapper : EzrSharpSourceExecutableWrapper +{ + /// + public override string TypeName { get; protected internal set; } = "csharp source function wrapper"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceFunctionWrapper"; + + public readonly EzrSharpSourceWrappableMethod SharpFunction; + public readonly string SharpFunctionName; + + public EzrSharpSourceFunctionWrapper(EzrSharpSourceWrappableMethod function, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + SharpFunction = function; + SharpMethodWrapperAttribute attribute = SharpFunction.Method.GetCustomAttribute(true) ?? throw new ArgumentException($"No \"{nameof(SharpMethodWrapperAttribute)}\" attribute found!", nameof(function)); + + Exception? parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(SharpFunction.Method); + if (parameterException is not null) + throw parameterException; + + if (string.IsNullOrEmpty(attribute.Name)) + throw new ArgumentException($"ezrSquared compliant name not provided in {nameof(SharpMethodWrapperAttribute)} of function!", nameof(function)); + + int requiredParameters = attribute.RequiredParameters.Length; + Parameters = new (string Name, bool IsRequired)[attribute.RequiredParameters.Length + attribute.OptionalParameters.Length]; + + for (int j = 0; j < requiredParameters; j++) + Parameters[j] = new(attribute.RequiredParameters[j], true); + + for (int j = 0; j < attribute.OptionalParameters.Length; j++) + Parameters[j + requiredParameters] = new(attribute.OptionalParameters[j], false); + + HasKeywordArguments = attribute.HasKeywordArguments; + SharpFunctionName = attribute.Name; + Tag = $"{Tag}.{SharpFunctionName}.{Utils.GetNextUniqueId()}"; + } + + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); + if (result.ShouldReturn) + return; + + SharpFunction.Invoke(new SharpMethodParameters + ( + argumentReferences, + _executionContext, + _creationContext, + Context, + StartPosition, + EndPosition, + interpreter, + result + )); + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, SharpFunction); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrSharpSourceFunctionWrapper)?.SharpFunction == SharpFunction && other.HashTag == HashTag; + } + + /// + public override string ToString(RuntimeResult result) + { + return $"<{TypeName} \"{SharpFunctionName}\">"; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs new file mode 100644 index 0000000..7b14f5d --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs @@ -0,0 +1,70 @@ +using EzrSquared.Runtime.Types.Core; +using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Util; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; +public class EzrSharpSourcePropertyWrapper : EzrSharpSourceExecutableWrapper +{ + /// + public override string TypeName { get; protected internal set; } = "csharp source field wrapper"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceFieldWrapper"; + + public readonly object? SharpInstance; + public readonly PropertyInfo SharpProperty; + public readonly string SharpPropertyName; + + public EzrSharpSourcePropertyWrapper(PropertyInfo propertyInfo, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + SharpInstance = instance; + SharpProperty = propertyInfo; + + SharpFieldWrapperAttribute attribute = SharpProperty.GetCustomAttribute(true) ?? throw new ArgumentException($"No \"{nameof(SharpFieldWrapperAttribute)}\" attribute found!", nameof(propertyInfo)); + + Exception? propertyTypeException = SharpFieldWrapperAttribute.ValidateProperty(SharpProperty); + if (propertyTypeException is not null) + throw propertyTypeException; + + SharpPropertyName = attribute.Name; + + if (SharpProperty.CanWrite && !attribute.IsReadOnly) + Parameters = [("value", false)]; + + Tag = $"{Tag}.{SharpPropertyName}.{Utils.GetNextUniqueId()}"; + } + + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); + if (result.ShouldReturn) + return; + + if (argumentReferences.TryGetValue("value", out Reference? newValue)) + SharpProperty.SetValue(SharpInstance, newValue.Object); + + IEzrObject value = (IEzrObject?)SharpProperty.GetValue(SharpInstance) ?? EzrConstants.Nothing; + result.Success(ReferencePool.Get(value, AccessMod.PrivateConstant)); + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, SharpProperty); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrSharpSourceFieldWrapper)?.SharpField == SharpProperty && other.HashTag == HashTag; + } + + /// + public override string ToString(RuntimeResult result) + { + return $"<{TypeName} \"{SharpPropertyName}\">"; + } +} diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs new file mode 100644 index 0000000..0be83e7 --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -0,0 +1,158 @@ +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Util; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; + +public class EzrSharpSourceTypeWrapper : EzrSharpSourceExecutableWrapper +{ + /// + public override string TypeName { get; protected internal set; } = "csharp source type wrapper"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceTypeWrapper"; + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + public readonly Type SharpType; + + public readonly string SharpTypeName; + + public readonly EzrSharpSourceWrappableMethod Constructor; + + public EzrSharpSourceTypeWrapper( + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + Type type, + + Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + SharpType = type; + + // Check generics. + if (SharpType.IsGenericType) + throw new ArgumentException($"Cannot wrap generic CSharp type {SharpType.Name}!", nameof(type)); + + // Check for type attribute. + SharpTypeWrapperAttribute typeAttribute = SharpType.GetCustomAttribute(true) + ?? throw new ArgumentException($"No \"{nameof(SharpTypeWrapperAttribute)}\" attribute found for type \"{type.Name}\"!", nameof(type)); + + // Set name and tag. + SharpTypeName = typeAttribute.Name; + Tag = $"{Tag}.{SharpTypeName}.{Utils.GetNextUniqueId()}"; + + // Get constructor info. + MethodInfo constructor = SharpType.GetMethod(typeAttribute.Constructor, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreReturn) + ?? throw new NullReferenceException($"Could not find constructor method \"{typeAttribute.Constructor}\" in type \"{type.Name}\"!"); + + // Get constructor attribute. + SharpMethodWrapperAttribute constructorAttribute = constructor.GetCustomAttribute(true) + ?? throw new ArgumentException($"No \"{nameof(SharpMethodWrapperAttribute)}\" attribute found in constructor method \"{constructor.Name}\"!", nameof(type)); + + Exception? parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(constructor); + if (parameterException is not null) + throw parameterException; + + // Get constructor parameters. + int requiredParameters = constructorAttribute.RequiredParameters.Length; + Parameters = new (string Name, bool IsRequired)[constructorAttribute.RequiredParameters.Length + constructorAttribute.OptionalParameters.Length]; + + // Required parameters. + for (int j = 0; j < requiredParameters; j++) + Parameters[j] = new(constructorAttribute.RequiredParameters[j], true); + + // Optional parameters. + for (int j = 0; j < constructorAttribute.OptionalParameters.Length; j++) + Parameters[j + requiredParameters] = new(constructorAttribute.OptionalParameters[j], false); + + // Set variables. + HasKeywordArguments = constructorAttribute.HasKeywordArguments; + Constructor = (EzrSharpSourceWrappableMethod)constructor.CreateDelegate(typeof(EzrSharpSourceWrappableMethod)); + + // Get static methods to wrap. + MethodInfo[] staticMethods = SharpType.GetMethods(BindingFlags.Static); + for (int i = 0; i < staticMethods.Length; i++) + { + MethodInfo method = staticMethods[i]; + + // Check if abstract or same as constructor. + if (method.IsAbstract || method.Name == constructor.Name) + continue; + + // Check if method can be wrapped. + SharpMethodWrapperAttribute? methodAttribute = constructor.GetCustomAttribute(true); + if (methodAttribute is null) + continue; + + // Check if parameters of the method are valid. + parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(method); + if (parameterException is not null) + throw parameterException; + + // Set in context. + EzrSharpSourceFunctionWrapper methodObject = new((EzrSharpSourceWrappableMethod)method.CreateDelegate(typeof(EzrSharpSourceWrappableMethod)), Context, startPosition, endPosition); + + // Check if name already defined. + if (Context.IsDefined(methodObject.SharpFunctionName)) + throw new ArgumentException($"Cannot wrap CSharp static method \"{methodObject.SharpFunctionName}\" of type {SharpType.Name} as another method with the same name already exists!", nameof(type)); + + Context.Set(null, methodObject.SharpFunctionName, ReferencePool.Get(methodObject, AccessMod.Constant)); + } + + // Get public static properties. + PropertyInfo[] publicStaticProperties = SharpType.GetProperties(BindingFlags.Static | BindingFlags.Public); + for (int i = 0; i < publicStaticProperties.Length; i++) + { + EzrSharpCompatibilityProperty property = new(publicStaticProperties[i], null, Context, StartPosition, EndPosition); + Context.Set(null, property.SharpPropertyName, ReferencePool.Get(property, AccessMod.Constant)); + } + + // Get public static fields. + FieldInfo[] publicStaticFields = SharpType.GetFields(BindingFlags.Static | BindingFlags.Public); + for (int i = 0; i < publicStaticFields.Length; i++) + { + EzrSharpCompatibilityField field = new(publicStaticFields[i], null, Context, StartPosition, EndPosition); + Context.Set(null, field.SharpFieldName, ReferencePool.Get(field, AccessMod.Constant)); + } + } + + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); + if (result.ShouldReturn) + return; + + Constructor.Invoke(new SharpMethodParameters + ( + argumentReferences, + _executionContext, + _creationContext, + Context, + StartPosition, + EndPosition, + interpreter, + result + )); + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, SharpType); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrSharpSourceTypeWrapper)?.SharpType == SharpType && other.HashTag == HashTag; + } + + /// + public override string ToString(RuntimeResult result) + { + return $"<{TypeName} \"{SharpTypeName}\">"; + } +} diff --git a/src/Runtime/Types/Collections/EzrArray.cs b/src/Runtime/Types/Collections/EzrArray.cs new file mode 100644 index 0000000..3471fa8 --- /dev/null +++ b/src/Runtime/Types/Collections/EzrArray.cs @@ -0,0 +1,488 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Numerics; +using System; +using System.Numerics; + +namespace EzrSquared.Runtime.Types.Collections; + +/// +/// The immutable, array type object. +/// +/// The base value. +/// The parent context. +/// The starting position of the object. +/// The ending position of the object. +public class EzrArray(IEzrObject[] elements, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrIndexedCollection +{ + /// + public override string TypeName { get; protected internal set; } = "array"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.Array"; + + /// + /// The array value. + /// + public readonly IEzrObject[] Value = elements; + + /// + public int Length => Value.Length; + + /// + /// Compares the current array with another collection. + /// + /// The other collection. + /// Runtime result to carray any errors. + /// The result of the comparison. + private bool Compare(IEzrIndexedCollection other, RuntimeResult result) + { + if (Value.Length != other.Length) + return false; + + for (int i = 0; i < Value.Length; i++) + if (!Value[i].StrictEquals(other.At(i), result) || result.ShouldReturn) + return false; + + return true; + } + + /// + /// Checks if the specified object is contained in the current array. + /// + /// The object to check. + /// Runtime result to carray any errors. + /// The result of the check. + private bool Contains(IEzrObject ezrObject, RuntimeResult result) + { + for (int i = 0; i < Value.Length; i++) + { + bool isEqual = ezrObject.StrictEquals(Value[i], result); + if (isEqual || result.ShouldReturn) + return isEqual; + } + + return false; + } + + /// + public IEzrObject At(int index) + { + return Value[index]; + } + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + bool compareResult; + switch (other) + { + case IEzrIndexedCollection otherCollection: + compareResult = Compare(otherCollection, result); + if (result.ShouldReturn) + break; + + result.Success(NewBooleanConstant(compareResult)); break; + + default: + result.Success(NewBooleanConstant(false)); break; + } + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + bool compareResult; + switch (other) + { + case IEzrIndexedCollection otherCollection: + compareResult = Compare(otherCollection, result); + if (result.ShouldReturn) + break; + + result.Success(NewBooleanConstant(!compareResult)); break; + + default: + result.Success(NewBooleanConstant(true)); break; + } + } + + /// + /// Gets the object(s) at the specified index/indices. + /// + /// + public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger when Value.Length == 0: + case IEzrIndexedCollection when Value.Length == 0: + result.Failure(new EzrValueOutOfRangeError("The array is empty and cannot be indexed!", _executionContext, StartPosition, EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.Value < -Value.Length || otherInteger.Value >= Value.Length: + result.Failure(new EzrValueOutOfRangeError($"Index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int index): + result.Success(ReferencePool.Get(index >= 0 ? Value[index] : Value[^-index], AccessMod.PrivateConstant)); break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: < 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: > 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection otherCollection: + (IEzrObject index1, IEzrObject index2) = (otherCollection.At(0), otherCollection.At(1)); + if (index1 is not EzrInteger startIndex || index2 is not EzrInteger endIndex) + { + result.Failure(new EzrUnexpectedTypeError($"Both indices must be integers! Given indices were of types \"{index1.TypeName}\" (start) and \"{index2.TypeName}\" (end).", _executionContext, other.StartPosition, other.EndPosition)); + break; + } + + if (!startIndex.TryGetIntRepresentation(out int startIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (!endIndex.TryGetIntRepresentation(out int endIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + if (startIndexInt < -Value.Length || startIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Starting index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (startIndexInt < 0) + { + if (endIndexInt > startIndexInt || endIndexInt < -Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {-Value.Length}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + result.Success(NewArrayConstant(Value[^(-endIndexInt)..^(-startIndexInt - 1)])); + break; + } + + if (endIndexInt < startIndexInt || endIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {Value.Length - 1}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + result.Success(NewArrayConstant(Value[startIndexInt..(endIndexInt + 1)])); + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + /// Gets the object(s) at the specified index/indices. + /// + /// + public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult result) + { + ComparisonLessThan(other, result); + } + + /// + /// Creates a copy of the current object with the other object appended. If the other object is an array, appends its elements. + /// + /// + public override void Addition(IEzrObject other, RuntimeResult result) + { + IEzrObject[] newArray; + switch (other) + { + case EzrArray otherArray: + newArray = new IEzrObject[Value.Length + otherArray.Length]; + + Array.Copy(Value, newArray, Value.Length); + Array.Copy(otherArray.Value, 0, newArray, Value.Length, otherArray.Length); + + break; + + default: + newArray = new IEzrObject[Value.Length + 1]; + Array.Copy(Value, newArray, Value.Length); + + newArray[^1] = other; break; + } + + result.Success(NewArrayConstant(newArray)); + } + + /// + /// Creates a copy of the current object with the objects at the specified index/indices removed. + /// + /// + public override void Subtraction(IEzrObject other, RuntimeResult result) + { + IEzrObject[] newArray; + switch (other) + { + case EzrInteger when Value.Length == 0: + case IEzrIndexedCollection when Value.Length == 0: + result.Failure(new EzrValueOutOfRangeError("The array is empty and cannot be removed from!", _executionContext, StartPosition, EndPosition)); + break; + + case EzrInteger otherInteger when otherInteger.Value < -Value.Length || otherInteger.Value >= Value.Length: + result.Failure(new EzrValueOutOfRangeError($"Index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int index): + newArray = new IEzrObject[Value.Length - 1]; + if (index < 0) + index = Value.Length + index; + + Array.Copy(Value, newArray, index); + Array.Copy(Value, index + 1, newArray, index, Value.Length - (index + 1)); + + result.Success(NewArrayConstant(newArray)); + break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: < 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: > 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection otherCollection: + (IEzrObject index1, IEzrObject index2) = (otherCollection.At(0), otherCollection.At(1)); + if (index1 is not EzrInteger startIndex || index2 is not EzrInteger endIndex) + { + result.Failure(new EzrUnexpectedTypeError($"Both indices must be integers! Given indices were of types \"{index1.TypeName}\" (start) and \"{index2.TypeName}\" (end).", _executionContext, other.StartPosition, other.EndPosition)); + break; + } + + if (!startIndex.TryGetIntRepresentation(out int startIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (!endIndex.TryGetIntRepresentation(out int endIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + if (startIndexInt < -Value.Length || startIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Starting index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (startIndexInt < 0) + { + if (endIndexInt > startIndexInt || endIndexInt < -Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {-Value.Length}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + (startIndexInt, endIndexInt) = (Value.Length + endIndexInt, Value.Length + startIndexInt); + } + else if (endIndexInt < startIndexInt || endIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {Value.Length - 1}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + newArray = new IEzrObject[Value.Length - (endIndexInt - startIndexInt + 1)]; + + Array.Copy(Value, newArray, startIndexInt); + Array.Copy(Value, endIndexInt + 1, newArray, startIndexInt, Value.Length - (endIndexInt + 1)); + + result.Success(NewArrayConstant(newArray)); + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// Here, "multiply" means "duplicate/decrease the current value X times". + /// + public override void Multiplication(IEzrObject other, RuntimeResult result) + { + int newLength; + switch (other) + { + case EzrInteger otherInteger: + BigInteger newIntegerLength = Value.Length * otherInteger.Value; + if (newIntegerLength < int.MinValue || newIntegerLength > int.MaxValue) + { + result.Failure(new EzrValueOutOfRangeError("The multiplied length is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); + return; + } + + newLength = (int)newIntegerLength; + break; + + case EzrFloat otherFloat: + newLength = (int)(Value.Length * otherFloat.Value); + break; + + default: + result.Failure(IllegalOperation(other)); + return; + } + + IEzrObject[] newValue; + switch (newLength) + { + case int length when length < 0: + result.Failure(new EzrValueOutOfRangeError("The multiplied length of the array cannot be negative!", _executionContext, other.StartPosition, other.EndPosition)); + return; + + case int length when length == Value.Length: + newValue = Value; break; + + case int length when length == 0: + newValue = []; break; + + case int length when length < Value.Length: + newValue = Value[..newLength]; break; + + default: + newValue = new IEzrObject[newLength]; + int loops = newLength / Value.Length; + + int i; + for (i = 0; i < loops; i++) + Array.Copy(Value, 0, newValue, i * Value.Length, Value.Length); + + int currentEnd = i * Value.Length; + if (newLength > currentEnd) + Array.Copy(Value, 0, newValue, currentEnd, newLength - currentEnd); + + break; + } + + result.Success(NewArrayConstant(newValue)); + } + + /// Here, "divide" means "duplicate/decrease the current value X times". + /// + public override void Division(IEzrObject other, RuntimeResult result) + { + int newLength; + switch (other) + { + case EzrFloat { Value: <= 0 }: + case EzrInteger otherInteger when otherInteger.Value <= 0: + result.Failure(new EzrMathError("Division error", "Divisor cannot be less than or equal to zero in array division!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrFloat when Value.Length == 0: + case EzrInteger when Value.Length == 0: + result.Success(NewStringConstant(string.Empty)); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int divisor): + newLength = Value.Length / divisor; + result.Success(NewArrayConstant(Value[0..newLength])); + break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrFloat otherFloat: + newLength = (int)(Value.Length / otherFloat.Value); + + if (newLength < Value.Length) + result.Success(NewArrayConstant(Value[0..newLength])); + else + { + IEzrObject[] newValue = new IEzrObject[newLength]; + int loops = newLength / Value.Length; + + int i; + for (i = 0; i < loops; i++) + Array.Copy(Value, 0, newValue, i * Value.Length, Value.Length); + + int currentEnd = i * Value.Length; + if (newLength > currentEnd) + Array.Copy(Value, 0, newValue, currentEnd, newLength - currentEnd); + + result.Success(NewArrayConstant(newValue)); + break; + } + + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void HasValueContained(IEzrObject other, RuntimeResult result) + { + bool contains = Contains(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(contains)); + } + + /// + public override void NotHasValueContained(IEzrObject other, RuntimeResult result) + { + bool contains = Contains(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(!contains)); + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return Value.Length > 0; + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return other is EzrArray otherArray && Compare(otherArray, result) && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + int hash = HashTag; + for (int i = 0; i < Value.Length; i++) + { + hash = HashCode.Combine(hash, Value[i].ComputeHashCode(result)); + if (result.ShouldReturn) + return int.MinValue; + } + + return hash; + } + + /// + public override string ToString(RuntimeResult result) + { + string[] elements = new string[Value.Length]; + for (int i = 0; i < Value.Length; i++) + { + elements[i] = Value[i].ToString(result); + if (result.ShouldReturn) + return string.Empty; + } + + return $"({string.Join(", ", elements)})"; + } +} diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs new file mode 100644 index 0000000..95049a6 --- /dev/null +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -0,0 +1,267 @@ +using EzrSquared.Runtime.Collections; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Numerics; +using System; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Collections; + +/// +/// The mutable dictionary type object. +/// +/// The base value. +/// The parent context. +/// The starting position of the object. +/// The ending position of the object. +public class EzrDictionary(RuntimeEzrObjectDictionary value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrMutableObject +{ + /// + public override string TypeName { get; protected internal set; } = "dictionary"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.Dictionary"; + + /// + /// The dictionary value. + /// + public readonly RuntimeEzrObjectDictionary Value = value; + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrDictionary otherDictionary: + bool equal = Value.IsEqual(otherDictionary.Value, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(equal)); break; + + default: + result.Success(NewBooleanConstant(false)); break; + } + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrDictionary otherDictionary: + bool equal = Value.IsEqual(otherDictionary.Value, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(!equal)); break; + + default: + result.Success(NewBooleanConstant(true)); break; + } + } + + /// + /// Gets the object at the specified key. + /// + /// + public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) + { + Reference value = Value.Get(other, result); + if (value.IsEmpty) + result.Failure(new EzrKeyNotFoundError("The key was not found in the dictionary!", _executionContext, other.StartPosition, other.EndPosition)); + else + result.Success(value); + } + + /// + /// Gets the object at the specified key. + /// + /// + public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult result) + { + ComparisonLessThan(other, result); + } + + /// + /// Appends the current object with the other object and its key. If the other object is a dictionary, merges it with the current object. + /// + /// + public override void Addition(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case IEzrIndexedCollection { Length: < 2 }: + result.Failure(new EzrIllegalOperationError($"The {other.TypeName} must contain two values, the key and value!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: > 2 }: + result.Failure(new EzrIllegalOperationError($"The {other.TypeName} must only contain two values, the key and value!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection otherCollection: + Value.Update(otherCollection.At(0), otherCollection.At(1), result); + if (result.ShouldReturn) + return; + + result.Success(NewNothingConstant()); break; + + case EzrDictionary otherDictionary: + Value.Merge(otherDictionary.Value); + result.Success(NewNothingConstant()); + + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + /// Removes the object at the specified key. + /// + /// + public override void Subtraction(IEzrObject other, RuntimeResult result) + { + bool success = Value.Remove(other, result); + if (result.ShouldReturn) + return; + + if (!success) + result.Failure(new EzrKeyNotFoundError("The key not found in the dictionary and connot be removed!", _executionContext, other.StartPosition, other.EndPosition)); + else + result.Success(NewNothingConstant()); + } + + /// Here, "divide" means "decrease the number of pairs in the dictionary X times". + /// + public override void Division(IEzrObject other, RuntimeResult result) + { + int newLength; + switch (other) + { + case EzrFloat { Value: <= 0 }: + case EzrInteger otherInteger when otherInteger.Value <= 0: + result.Failure(new EzrMathError("Division error", "Divisor cannot be less than or equal to zero in dictionary division!", _executionContext, other.StartPosition, other.EndPosition)); return; + + case EzrFloat when Value.Length == 0: + case EzrInteger when Value.Length == 0: + result.Success(NewNothingConstant()); return; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int divisor): + newLength = Value.Length / divisor; break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); return; + + case EzrFloat otherFloat: + newLength = (int)(Value.Length / otherFloat.Value); + + if (newLength > Value.Length) + { + result.Failure(new EzrIllegalOperationError($"Divided length of dictionary is greater than its length ({Value.Length} / {otherFloat.Value} = {newLength})!", _executionContext, other.StartPosition, other.EndPosition)); + return; + } + + break; + + default: + result.Failure(IllegalOperation(other)); return; + } + + int[] keys = Value.GetRealKeys(); + for (int i = Value.Length - 1; i >= newLength; i--) + { + if (!Value.RemoveHash(keys[i])) + { + result.Failure(new EzrIllegalOperationError($"Key \"{keys[i]}\" was not found in the dictionary during deletion.", _executionContext, StartPosition, EndPosition)); + return; + } + } + + result.Success(NewNothingConstant()); + } + + /// + public override void HasValueContained(IEzrObject other, RuntimeResult result) + { + bool contains = Value.HasKey(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(contains)); + } + + /// + public override void NotHasValueContained(IEzrObject other, RuntimeResult result) + { + bool contains = Value.HasKey(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(!contains)); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return other is EzrDictionary otherDictionary && Value.IsEqual(otherDictionary.Value, result) && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + KeyValuePair[] pairs = Value.GetPairs(); + int hash = HashTag; + + for (int i = 0; i < pairs.Length; i++) + { + int hash1 = pairs[i].Key.ComputeHashCode(result); + if (result.ShouldReturn) + return int.MinValue; + + int hash2 = pairs[i].Value.ComputeHashCode(result); + if (result.ShouldReturn) + return int.MinValue; + + hash = HashCode.Combine(hash, hash1, hash2); + } + + return hash; + } + + /// + public override string ToString(RuntimeResult result) + { + KeyValuePair[] pairs = Value.GetPairs(); + string[] pairsAsString = new string[pairs.Length]; + + for (int i = 0; i < pairs.Length; i++) + { + string key = pairs[i].Key.ToString(result); + if (result.ShouldReturn) + return string.Empty; + + string value = pairs[i].Value.ToString(result); + if (result.ShouldReturn) + return string.Empty; + + pairsAsString[i] = $"{key} : {value}"; + } + + return $"{{{string.Join(", ", pairsAsString)}}}"; + } + + /// + public IMutable? DeepCopy(RuntimeResult result) + { + RuntimeEzrObjectDictionary? copy = (RuntimeEzrObjectDictionary?)Value.DeepCopy(result); + + return result.ShouldReturn ? null + : new EzrDictionary(copy!, Context, StartPosition, EndPosition); + } + + /// Destructor. + ~EzrDictionary() + { + Value.Release(); + Context.Release(); + } +} diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs new file mode 100644 index 0000000..30a4394 --- /dev/null +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -0,0 +1,515 @@ +using EzrSquared.Runtime.Collections; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Numerics; +using System; +using System.Numerics; + +namespace EzrSquared.Runtime.Types.Collections; + +/// +/// The mutable, list type object. +/// +/// The base value. +/// The parent context. +/// The starting position of the object. +/// The ending position of the object. +public class EzrList(RuntimeEzrObjectList elements, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrMutableObject, IEzrIndexedCollection +{ + /// + public override string TypeName { get; protected internal set; } = "list"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.List"; + + /// + /// The list value. + /// + public readonly RuntimeEzrObjectList Value = elements; + + /// + public int Length => Value.Count; + + /// + /// Compares the current list with another collection. + /// + /// The other collection. + /// Runtime result to carray any errors. + /// The result of the comparison. + private bool Compare(IEzrIndexedCollection other, RuntimeResult result) + { + if (Value.Count != other.Length) + return false; + + for (int i = 0; i < Value.Count; i++) + if (!Value[i].Object.StrictEquals(other.At(i), result) || result.ShouldReturn) + return false; + + return true; + } + + /// + /// Checks if the specified object is contained in the current list. + /// + /// The object to check. + /// Runtime result to carray any errors. + /// The result of the check. + private bool Contains(IEzrObject ezrObject, RuntimeResult result) + { + for (int i = 0; i < Value.Count; i++) + { + bool isEqual = ezrObject.StrictEquals(Value[i].Object, result); + if (isEqual || result.ShouldReturn) + return isEqual; + } + + return false; + } + + /// + public IEzrObject At(int index) + { + return Value[index].Object; + } + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + bool compareResult; + switch (other) + { + case IEzrIndexedCollection otherCollection: + compareResult = Compare(otherCollection, result); + if (result.ShouldReturn) + break; + + result.Success(NewBooleanConstant(compareResult)); break; + + default: + result.Success(NewBooleanConstant(false)); break; + } + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + bool compareResult; + switch (other) + { + case IEzrIndexedCollection otherCollection: + compareResult = Compare(otherCollection, result); + if (result.ShouldReturn) + break; + + result.Success(NewBooleanConstant(!compareResult)); break; + + default: + result.Success(NewBooleanConstant(true)); break; + } + } + + /// + /// Gets the object(s) at the specified index/indices. + /// + /// + public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger when Value.Count == 0: + case IEzrIndexedCollection when Value.Count == 0: + result.Failure(new EzrValueOutOfRangeError("The list is empty and cannot be indexed!", _executionContext, StartPosition, EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.Value < -Value.Count || otherInteger.Value >= Value.Count: + result.Failure(new EzrValueOutOfRangeError($"Index must be in range 0 to {Value.Count - 1} or -1 to {-Value.Count}!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int index): + result.Success(index >= 0 ? Value[index] : Value[^-index]); break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: < 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: > 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection otherCollection: + (IEzrObject index1, IEzrObject index2) = (otherCollection.At(0), otherCollection.At(1)); + if (index1 is not EzrInteger startIndex || index2 is not EzrInteger endIndex) + { + result.Failure(new EzrUnexpectedTypeError($"Both indices must be integers! Given indices were of types \"{index1.TypeName}\" (start) and \"{index2.TypeName}\" (end).", _executionContext, other.StartPosition, other.EndPosition)); + break; + } + + if (!startIndex.TryGetIntRepresentation(out int startIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (!endIndex.TryGetIntRepresentation(out int endIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + if (startIndexInt < -Value.Count || startIndexInt >= Value.Count) + { + result.Failure(new EzrValueOutOfRangeError($"Starting index must be in range 0 to {Value.Count - 1} or -1 to {-Value.Count}!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (startIndexInt < 0) + { + if (endIndexInt > startIndexInt || endIndexInt < -Value.Count) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {-Value.Count}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + result.Success(NewListConstant(Value.GetRange(Value.Count + endIndexInt, -(endIndexInt - startIndexInt) + 1))); + break; + } + + if (endIndexInt < startIndexInt || endIndexInt >= Value.Count) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {Value.Count - 1}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + result.Success(NewListConstant(Value.GetRange(startIndexInt, endIndexInt - startIndexInt + 1))); + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + /// Gets the object(s) at the specified index/indices. + /// + /// + public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult result) + { + ComparisonLessThan(other, result); + } + + /// + /// Appends the current object with the other object. If the other object is a list, appends its elements. + /// + /// + public override void Addition(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrList otherList: + Value.AddRange(otherList.Value); break; + + default: + Reference reference = ReferencePool.Get(other); + reference.UpdateRegister(true); + + Value.Add(reference); break; + } + + result.Success(NewNothingConstant()); + } + + /// + /// Removes the object(s) at the specified index/indices. + /// + /// + public override void Subtraction(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger when Value.Count == 0: + case IEzrIndexedCollection when Value.Count == 0: + result.Failure(new EzrValueOutOfRangeError("The list is empty and cannot be removed from!", _executionContext, StartPosition, EndPosition)); + break; + + case EzrInteger otherInteger when otherInteger.Value < -Value.Count || otherInteger.Value >= Value.Count: + result.Failure(new EzrValueOutOfRangeError($"Index must be in range 0 to {Value.Count - 1} or -1 to {-Value.Count}!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int index): + Value.RemoveAt(index >= 0 ? index : Value.Count + index); + result.Success(NewNothingConstant()); + + break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: < 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: > 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection otherCollection: + (IEzrObject index1, IEzrObject index2) = (otherCollection.At(0), otherCollection.At(1)); + if (index1 is not EzrInteger startIndex || index2 is not EzrInteger endIndex) + { + result.Failure(new EzrUnexpectedTypeError($"Both indices must be integers! Given indices were of types \"{index1.TypeName}\" (start) and \"{index2.TypeName}\" (end).", _executionContext, other.StartPosition, other.EndPosition)); + break; + } + + if (!startIndex.TryGetIntRepresentation(out int startIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (!endIndex.TryGetIntRepresentation(out int endIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + if (startIndexInt < -Value.Count || startIndexInt >= Value.Count) + { + result.Failure(new EzrValueOutOfRangeError($"Starting index must be in range 0 to {Value.Count - 1} or -1 to {-Value.Count}!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (startIndexInt < 0) + { + if (endIndexInt > startIndexInt || endIndexInt < -Value.Count) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {-Value.Count}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + Value.RemoveRange(Value.Count + endIndexInt, -(endIndexInt - startIndexInt) + 1); + result.Success(NewNothingConstant()); + break; + } + + if (endIndexInt < startIndexInt || endIndexInt >= Value.Count) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {Value.Count - 1}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + Value.RemoveRange(startIndexInt, endIndexInt - startIndexInt + 1); + result.Success(NewNothingConstant()); + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// Here, "multiply" means "duplicate/decrease the current value X times". + /// + public override void Multiplication(IEzrObject other, RuntimeResult result) + { + int newLength; + switch (other) + { + case EzrInteger otherInteger: + BigInteger newIntegerLength = Value.Count * otherInteger.Value; + if (newIntegerLength < int.MinValue || newIntegerLength > int.MaxValue) + { + result.Failure(new EzrValueOutOfRangeError("The multiplied length is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); + return; + } + + newLength = (int)newIntegerLength; + break; + + case EzrFloat otherFloat: + newLength = (int)(Value.Count * otherFloat.Value); + break; + + default: + result.Failure(IllegalOperation(other)); + return; + } + + switch (newLength) + { + case int length when length < 0: + result.Failure(new EzrValueOutOfRangeError("The multiplied length of the list cannot be negative!", _executionContext, other.StartPosition, other.EndPosition)); + return; + + case int length when length == Value.Count: break; + case int length when length == 0: Value.Clear(); break; + + case int length when length < Value.Count: + Value.RemoveRange(newLength, Value.Count - newLength); break; + + default: + Reference[] original = new Reference[Value.Count]; + Value.CopyTo(original); + + int loops = (newLength / Value.Count) - 1; + + int i; + for (i = 0; i < loops; i++) + Value.AddRange(Array.ConvertAll(original, element => + { + Reference copy = element.ShallowCopy(); + copy.UpdateRegister(true); + + return copy; + })); + + int currentEnd = (loops == 0 ? 1 : i + 1) * original.Length; + if (newLength > currentEnd) + Value.AddRange(Array.ConvertAll(original[..(newLength - currentEnd)], element => + { + Reference copy = element.ShallowCopy(); + copy.UpdateRegister(true); + + return copy; + })); + + break; + } + + result.Success(NewNothingConstant()); + } + + /// Here, "divide" means "duplicate/decrease the current value X times". + /// + public override void Division(IEzrObject other, RuntimeResult result) + { + int newLength; + switch (other) + { + case EzrFloat { Value: <= 0 }: + case EzrInteger otherInteger when otherInteger.Value <= 0: + result.Failure(new EzrMathError("Division error", "Divisor cannot be less than or equal to zero in list division!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrFloat when Value.Count == 0: + case EzrInteger when Value.Count == 0: + result.Success(NewNothingConstant()); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int divisor): + newLength = Value.Count / divisor; + Value.RemoveRange(newLength, Value.Count - newLength); + + result.Success(NewNothingConstant()); + break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrFloat otherFloat: + newLength = (int)(Value.Count / otherFloat.Value); + + if (newLength < Value.Count) + Value.RemoveRange(newLength, Value.Count - newLength); + else + { + Reference[] original = new Reference[Value.Count]; + Value.CopyTo(original); + + int loops = (newLength / Value.Count) - 1; + + int i; + for (i = 0; i < loops; i++) + Value.AddRange(Array.ConvertAll(original, element => + { + Reference copy = element.ShallowCopy(); + copy.UpdateRegister(true); + + return copy; + })); + + int currentEnd = (loops == 0 ? 1 : i + 1) * original.Length; + if (newLength > currentEnd) + Value.AddRange(Array.ConvertAll(original[..(newLength - currentEnd)], element => + { + Reference copy = element.ShallowCopy(); + copy.UpdateRegister(true); + + return copy; + })); + } + + result.Success(NewNothingConstant()); + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void HasValueContained(IEzrObject other, RuntimeResult result) + { + bool contains = Contains(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(contains)); + } + + /// + public override void NotHasValueContained(IEzrObject other, RuntimeResult result) + { + bool contains = Contains(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(!contains)); + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return Value.Count > 0; + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return other is EzrList otherList && Compare(otherList, result) && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + int hash = HashTag; + for (int i = 0; i < Value.Count; i++) + { + hash = HashCode.Combine(hash, Value[i].Object.ComputeHashCode(result)); + if (result.ShouldReturn) + return int.MinValue; + } + + return hash; + } + + /// + public override string ToString(RuntimeResult result) + { + string[] elements = new string[Value.Count]; + for (int i = 0; i < Value.Count; i++) + { + elements[i] = Value[i].Object.ToString(result); + if (result.ShouldReturn) + return string.Empty; + } + + return $"[{string.Join(", ", elements)}]"; + } + + /// + public IMutable? DeepCopy(RuntimeResult result) + { + RuntimeEzrObjectList? copy = Value.DeepCopy(result) as RuntimeEzrObjectList; + return result.ShouldReturn ? null + : new EzrList(copy!, Context, StartPosition, EndPosition); + } + + /// Destructor. + ~EzrList() + { + Value.Release(); + Context.Release(); + } +} diff --git a/src/Runtime/Types/Collections/IEzrIndexedCollection.cs b/src/Runtime/Types/Collections/IEzrIndexedCollection.cs new file mode 100644 index 0000000..6d6d823 --- /dev/null +++ b/src/Runtime/Types/Collections/IEzrIndexedCollection.cs @@ -0,0 +1,19 @@ +namespace EzrSquared.Runtime.Types.Collections; + +/// +/// Interface for an indexed collection of ezr² objects. +/// +internal interface IEzrIndexedCollection : IEzrObject +{ + /// + /// The length of the collection. + /// + public int Length { get; } + + /// + /// Gets the object at the specified index/ + /// + /// The index. + /// The object at the index. + public IEzrObject At(int index); +} diff --git a/src/Runtime/Types/Core/EzrBoolean.cs b/src/Runtime/Types/Core/EzrBoolean.cs new file mode 100644 index 0000000..93a4c39 --- /dev/null +++ b/src/Runtime/Types/Core/EzrBoolean.cs @@ -0,0 +1,74 @@ +using System; + +namespace EzrSquared.Runtime.Types.Core; + +/// +/// The boolean type object. +/// +/// The base value. +/// The parent context. +/// The starting position of the object. +/// The ending position of the object. +public class EzrBoolean(bool value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "boolean"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.Boolean"; + + /// + /// The boolean value of the object. + /// + public readonly bool Value = value; + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + bool otherEvaluation = other.EvaluateBoolean(result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(otherEvaluation == Value)); + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + bool otherEvaluation = other.EvaluateBoolean(result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(otherEvaluation != Value)); + } + + /// + public override void Inversion(RuntimeResult result) + { + result.Success(NewBooleanConstant(!Value)); + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return Value; + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrBoolean)?.Value == Value && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, Value); + } + + /// + public override string ToString(RuntimeResult result) + { + return Value ? "true" : "false"; + } +} diff --git a/src/Runtime/Types/Core/EzrConstants.cs b/src/Runtime/Types/Core/EzrConstants.cs new file mode 100644 index 0000000..5d3b4f1 --- /dev/null +++ b/src/Runtime/Types/Core/EzrConstants.cs @@ -0,0 +1,22 @@ +namespace EzrSquared.Runtime.Types.Core; + +/// +/// Static constants for objects that won't change. +/// +public static class EzrConstants +{ + /// + /// Constant boolean true value. + /// + public static readonly EzrBoolean True = new(true, Context.Empty, Position.None, Position.None); + + /// + /// Constant boolean false value. + /// + public static readonly EzrBoolean False = new(false, Context.Empty, Position.None, Position.None); + + /// + /// Constant "nothing" value. + /// + public static readonly EzrNothing Nothing = new(Context.Empty, Position.None, Position.None); +} diff --git a/src/Runtime/Types/Core/EzrNothing.cs b/src/Runtime/Types/Core/EzrNothing.cs new file mode 100644 index 0000000..90eb1b7 --- /dev/null +++ b/src/Runtime/Types/Core/EzrNothing.cs @@ -0,0 +1,54 @@ +using System; + +namespace EzrSquared.Runtime.Types.Core; + +/// +/// The -equivalent type. +/// +/// The parent context. +/// The starting position of the object. +/// The ending position of the object. +public class EzrNothing(Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "nothing"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.Nothing"; + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + result.Success(NewBooleanConstant(other is EzrNothing)); + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + result.Success(NewBooleanConstant(other is not EzrNothing)); + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return false; + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, 0); + } + + /// + public override string ToString(RuntimeResult result) + { + return "nothing"; + } +} diff --git a/src/Runtime/Types/Core/Numerics/EzrFloat.cs b/src/Runtime/Types/Core/Numerics/EzrFloat.cs new file mode 100644 index 0000000..937b53f --- /dev/null +++ b/src/Runtime/Types/Core/Numerics/EzrFloat.cs @@ -0,0 +1,269 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Text; +using System; +using System.Numerics; + +namespace EzrSquared.Runtime.Types.Core.Numerics; + +/// +/// The float (actually double) type object. +/// +/// The base value. +/// The parent context. +/// The starting position of the object. +/// The ending position of the object. +public class EzrFloat(double value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "float"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.Float"; + + /// + /// The double value. + /// + public readonly double Value = value; + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value == otherInteger.GetDoubleRepresentation())); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value == otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value == otherCharacter.Value)); break; + default: + result.Success(NewBooleanConstant(false)); break; + } + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value != otherInteger.GetDoubleRepresentation())); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value != otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value != otherCharacter.Value)); break; + default: + result.Success(NewBooleanConstant(true)); break; + } + } + + /// + public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value < otherInteger.GetDoubleRepresentation())); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value < otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value < otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonGreaterThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value > otherInteger.GetDoubleRepresentation())); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value > otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value > otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value <= otherInteger.GetDoubleRepresentation())); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value <= otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value <= otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonGreaterThanOrEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value >= otherInteger.GetDoubleRepresentation())); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value >= otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value >= otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Addition(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewFloatConstant(Value + otherInteger.GetDoubleRepresentation())); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(Value + otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewFloatConstant(Value + otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Subtraction(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewFloatConstant(Value - otherInteger.GetDoubleRepresentation())); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(Value - otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewFloatConstant(Value - otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Multiplication(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewFloatConstant(Value * otherInteger.GetDoubleRepresentation())); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(Value * otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewFloatConstant(Value * otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Division(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger { Value: BigInteger value } when value == 0: + case EzrFloat { Value: 0 }: + case EzrCharacter { Value: '\0' }: + result.Failure(new EzrMathError("Division error", "Divisor cannot be zero!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger: + result.Success(NewFloatConstant(Value / otherInteger.GetDoubleRepresentation())); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(Value / otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewFloatConstant(Value / otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Modulo(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger { Value: BigInteger value } when value == 0: + case EzrFloat { Value: 0 }: + case EzrCharacter { Value: '\0' }: + result.Failure(new EzrMathError("Division error", "Divisor cannot be zero!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger: + result.Success(NewFloatConstant(Value % otherInteger.GetDoubleRepresentation())); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(Value % otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewFloatConstant(Value % otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Power(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewFloatConstant(Math.Pow(Value, otherInteger.GetDoubleRepresentation()))); break; + case EzrCharacter otherCharacter: + result.Success(NewFloatConstant(Math.Pow(Value, otherCharacter.Value))); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Negation(RuntimeResult result) + { + result.Success(NewFloatConstant(-Value)); + } + + /// + public override void Affirmation(RuntimeResult result) + { + result.Success(NewFloatConstant(Math.Abs(Value))); + } + + /// + public override void Inversion(RuntimeResult result) + { + result.Success(NewFloatConstant(Value > 0 ? 0 : 1)); + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return Value > 0f; + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrFloat)?.Value == Value && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, Value); + } + + /// + public override string ToString(RuntimeResult result) + { + return $"{Value}"; + } +} diff --git a/src/Runtime/Types/Core/Numerics/EzrInteger.cs b/src/Runtime/Types/Core/Numerics/EzrInteger.cs new file mode 100644 index 0000000..e4ae81f --- /dev/null +++ b/src/Runtime/Types/Core/Numerics/EzrInteger.cs @@ -0,0 +1,486 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Text; +using EzrSquared.Util.Extensions; +using System; +using System.Numerics; + +namespace EzrSquared.Runtime.Types.Core.Numerics; + +/// +/// The integer type object. +/// +/// The value. +/// The parent context. +/// The starting position of the object. +/// The ending position of the object. +public class EzrInteger(BigInteger value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) +{ + /// + /// Represents the size of the integer value stored in an object. + /// + public enum Size + { + /// + /// Same as . + /// + Int32, + + /// + /// Same as . + /// + Int64, + + /// + /// Large, unknown. See also . + /// + Big + } + + /// + public override string TypeName { get; protected internal set; } = "integer"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.Integer"; + + /// + /// The integer value. + /// + public readonly BigInteger Value = value; + + /// + /// The size of the . + /// + public readonly Size ValueSize = value switch + { + BigInteger bigInteger when bigInteger > int.MinValue && bigInteger < int.MaxValue => Size.Int32, + BigInteger bigInteger when bigInteger > long.MinValue && bigInteger < long.MaxValue => Size.Int64, + _ => Size.Big, + }; + + /// + /// The double representation of . May be . + /// + private double? _doubleRepresentation; + + /// + /// The long representation of . May be . + /// + private long? _longRepresentation; + + /// + /// The int representation of . May be . + /// + private int? _intRepresentation; + + /// + /// Gets a double representation of the current object. + /// + /// The double representation. + public double GetDoubleRepresentation() + { + return _doubleRepresentation is not null + ? (double)_doubleRepresentation + : (double)(_doubleRepresentation = (double)Value); + } + + /// + /// Tries to get a long representation of the current object. + /// + /// The long representation. + /// if successful, otherwise. + public bool TryGetLongRepresentation(out long value) + { + if (_longRepresentation is not null) + { + value = (long)_longRepresentation; + return true; + } + + switch (ValueSize) + { + case Size.Int32: + case Size.Int64: + _longRepresentation = value = (long)Value; + return true; + default: + value = 0; + return false; + } + } + + /// + /// Tries to get an int representation of the current object. + /// + /// The int representation. + /// if successful, otherwise. + public bool TryGetIntRepresentation(out int value) + { + if (_intRepresentation is not null) + { + value = (int)_intRepresentation; + return true; + } + + if (ValueSize == Size.Int32) + { + _intRepresentation = value = (int)Value; + return true; + } + + value = 0; + return false; + } + + /// + /// Gets an int representation of the current object. Use only if you know the value of the current object will fit in an int value. + /// + /// The int representation. + public int GetIntRepresentation() + { + return _intRepresentation is not null + ? (int)_intRepresentation + : (int)(_intRepresentation = (int)Value); + } + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value == otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(GetDoubleRepresentation() == otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value == otherCharacter.Value)); break; + default: + result.Success(NewBooleanConstant(false)); break; + } + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value != otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(GetDoubleRepresentation() != otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value != otherCharacter.Value)); break; + default: + result.Success(NewBooleanConstant(true)); break; + } + } + + /// + public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value < otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(GetDoubleRepresentation() < otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value < otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonGreaterThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value > otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(GetDoubleRepresentation() > otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value > otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value <= otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(GetDoubleRepresentation() <= otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value <= otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonGreaterThanOrEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value >= otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(GetDoubleRepresentation() >= otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value >= otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Addition(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value + otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(GetDoubleRepresentation() + otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value + otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Subtraction(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value - otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(GetDoubleRepresentation() - otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value - otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Multiplication(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value * otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(GetDoubleRepresentation() * otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value * otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Division(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger { Value: BigInteger value } when value == 0: + case EzrFloat { Value: 0 }: + case EzrCharacter { Value: '\0' }: + result.Failure(new EzrMathError("Division error", "Divisor cannot be zero!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value / otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(GetDoubleRepresentation() / otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value / otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Modulo(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger { Value: BigInteger value } when value == 0: + case EzrFloat { Value: 0 }: + case EzrCharacter { Value: '\0' }: + result.Failure(new EzrMathError("Division error", "Divisor cannot be zero!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value % otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(GetDoubleRepresentation() % otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value % otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Power(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int otherInteger32): + result.Success(NewIntegerConstant(BigInteger.Pow(Value, otherInteger32))); break; + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value.Power(otherInteger.Value))); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(BigInteger.Pow(Value, otherCharacter.Value))); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Negation(RuntimeResult result) + { + result.Success(NewIntegerConstant(-Value)); + } + + /// + public override void Affirmation(RuntimeResult result) + { + result.Success(NewIntegerConstant(BigInteger.Abs(Value))); + } + + /// + public override void BitwiseOr(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value | otherInteger.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value | otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void BitwiseXOr(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value ^ otherInteger.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value ^ otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void BitwiseAnd(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value & otherInteger.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value & otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void BitwiseLeftShift(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger when ValueSize != Size.Int32: + case EzrCharacter when ValueSize != Size.Int32: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, StartPosition, EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.ValueSize != Size.Int32: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(GetIntRepresentation() << otherInteger.GetIntRepresentation())); + break; + + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(GetIntRepresentation() << otherCharacter.Value)); + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void BitwiseRightShift(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger when ValueSize != Size.Int32: + case EzrCharacter when ValueSize != Size.Int32: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, StartPosition, EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.ValueSize != Size.Int32: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(GetIntRepresentation() >> otherInteger.GetIntRepresentation())); + break; + + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(GetIntRepresentation() >> otherCharacter.Value)); + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void BitwiseNegation(RuntimeResult result) + { + result.Success(NewIntegerConstant(~Value)); + } + + /// + public override void Inversion(RuntimeResult result) + { + result.Success(NewIntegerConstant(Value > 0 ? 0 : 1)); + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return Value > 0; + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrInteger)?.Value == Value && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, Value); + } + + /// + public override string ToString(RuntimeResult result) + { + return $"{Value}"; + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs new file mode 100644 index 0000000..88bd11e --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs @@ -0,0 +1,35 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when an assertion fails. +/// +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("assertion_error", nameof(WrapperConstructor))] +public class EzrAssertionError(Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Assertion failed", "The assertion conditions were not met!", context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "assertion error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.AssertionError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper()] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + arguments.Result.Success(ReferencePool.Get( + new EzrAssertionError( + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition), + AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs new file mode 100644 index 0000000..de047ff --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs @@ -0,0 +1,38 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when a generic illegal operation occurs. +/// +/// Details on why the error happened. +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("illegal_operation_error", nameof(WrapperConstructor))] +public class EzrIllegalOperationError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Illegal operation", details, context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "illegal operation error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.IllegalOperationError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["details"])] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrIllegalOperationError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs new file mode 100644 index 0000000..f3d41bc --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs @@ -0,0 +1,38 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when a key-not-found error occurs. +/// +/// Details on why the error happened. +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("key_not_found_error", nameof(WrapperConstructor))] +public class EzrKeyNotFoundError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Key not found", details, context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "key not found error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.KeyNotFoundError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["details"])] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrKeyNotFoundError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs new file mode 100644 index 0000000..658a761 --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs @@ -0,0 +1,44 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when a generic mathematical error occurs. +/// +/// The title of the error. +/// Details on why the error happened. +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("math_error", nameof(WrapperConstructor))] +public class EzrMathError(string title, string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError(title, details, context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "math error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.MathError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["title", "details"])] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference titleReference = arguments.ArgumentReferences["title"]; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string title = GetStringArgument("title", titleReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrMathError(title, details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs new file mode 100644 index 0000000..ddc21e8 --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs @@ -0,0 +1,38 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when an argument is missing. +/// +/// Details on why the error happened. +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("missing_required_argument_error", nameof(WrapperConstructor))] +public class EzrMissingRequiredArgumentError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Missing required argument", details, context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "missing required argument error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.MissingRequiredArgumentError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["details"])] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrMissingRequiredArgumentError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs new file mode 100644 index 0000000..4f4c32a --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs @@ -0,0 +1,38 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when an illegal operation is performed on a private member. +/// +/// Details on why the error happened. +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("private_member_operation_error", nameof(WrapperConstructor))] +public class EzrPrivateMemberOperationError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Private member operation", details, context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "Private member operation error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.PrivateMemberOperationError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["details"])] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrPrivateMemberOperationError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs new file mode 100644 index 0000000..cc96122 --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs @@ -0,0 +1,179 @@ +using EzrSquared.Runtime.Types.Core.Text; +using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Util; +using System; +using System.Collections.Generic; +using System.Text; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Base of all error type objects. +/// +[SharpTypeWrapper("runtime_error", nameof(WrapperConstructor))] +public class EzrRuntimeError : EzrObject +{ + /// + public override string TypeName { get; protected internal set; } = "runtime error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.RuntimeError"; + + /// + /// The name of the . + /// + public readonly string Title; + + /// + /// The reason why the occurred. + /// + public readonly string Details; + + /// + /// The context where the error occurred. + /// + public readonly Context ErrorContext; + + /// + /// The starting position of the error. + /// + public readonly Position ErrorStartPosition; + + /// + /// The ending position of the error. + /// + public readonly Position ErrorEndPosition; + + /// + /// Creates a new runtime error object. + /// + /// The title of the error. + /// Details on why the error happened. + /// The context in which the error occurred. + /// The starting position of the error. + /// The ending position of the error. + public EzrRuntimeError(string title, string details, Context context, Position startPosition, Position endPosition) : base(context, startPosition, endPosition) + { + Title = title; + Details = details; + ErrorContext = context; + ErrorStartPosition = startPosition; + ErrorEndPosition = endPosition; + + Context.Set(null, "title", ReferencePool.Get(new EzrString(Title, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "details", ReferencePool.Get(new EzrString(Details, Context, StartPosition, EndPosition), AccessMod.Constant)); + } + + /// + /// Converts the given argument to a string. + /// + /// The name of the argument. + /// The argument object. + /// The context of the argument. + /// Runtime result for carrying errors. + /// The string, or if failed. + protected internal static string GetStringArgument(string argumentName, IEzrObject ezrObject, Context context, RuntimeResult result) + { + switch (ezrObject) + { + case EzrString ezrString: + return ezrString.Value; + + case EzrCharacter ezrCharacter: + return ezrCharacter.Value.ToString(); + + case EzrCharacterList ezrCharacterList: + return ezrCharacterList.StringValue; + + default: + result.Failure(new EzrUnexpectedTypeError($"Expected {argumentName} of type string, character or character list, but got object of type \"{ezrObject.TypeName}\"!", context, ezrObject.StartPosition, ezrObject.EndPosition)); + return string.Empty; + } + } + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["title", "details"])] + public static void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference titleReference = arguments.ArgumentReferences["title"]; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string title = GetStringArgument("title", titleReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrRuntimeError(title, details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } + + /// + /// Generates the trace back to the error. + /// + /// The trace. + protected internal string GenerateTraceback(int correctedLineNumber) + { + StringBuilder result = new(); + Context? context = ErrorContext; + + while (context is not null) + { + result.Insert(0, $" File '{ErrorContext.StartPosition.File}', line {correctedLineNumber} - In '{context.Name}'\n"); + context = context.Parent; + } + + return result.Insert(0, "Traceback - most recent call last:\n").ToString(); + } + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + bool equal = StrictEquals(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(equal)); + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + bool equal = StrictEquals(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(!equal)); + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, Title, Details); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return other is EzrRuntimeError otherError && otherError.Title == Title && otherError.Details == Details && other.HashTag == HashTag; + } + + /// + public override string ToString(RuntimeResult result) + { + return $"<{TypeName} \"{Title}\">"; + } + + /// + public override string ToPureString(RuntimeResult result) + { + (int adjustedLineNumber, string sourceWithUnderline) = Utils.SourceWithUnderline(ErrorStartPosition, ErrorEndPosition); + + return $"{GenerateTraceback(adjustedLineNumber)}\n{Title}: {Details}\n{sourceWithUnderline}"; + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs new file mode 100644 index 0000000..30e681a --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs @@ -0,0 +1,38 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when an undefined value is encountered. +/// +/// Details on why the error happened. +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("undefined_value_error", nameof(WrapperConstructor))] +public class EzrUndefinedValueError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Undefined value", details, context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "undefined value error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.UndefinedValueError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["details"])] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrUndefinedValueError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs new file mode 100644 index 0000000..799b01b --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs @@ -0,0 +1,38 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when an unexpected argument is encountered. +/// +/// Details on why the error happened. +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("unexpected_argument_error", nameof(WrapperConstructor))] +public class EzrUnexpectedArgumentError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unexpected argument(s)", details, context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "unexpected argument error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.UnexpectedArgumentError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["details"])] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrUnexpectedArgumentError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs new file mode 100644 index 0000000..f26ecce --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs @@ -0,0 +1,38 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when an unexpected type is encountered. +/// +/// Details on why the error happened. +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("unexpected_type_error", nameof(WrapperConstructor))] +public class EzrUnexpectedTypeError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unexpected type", details, context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "unexpected type error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.UnexpectedTypeError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["details"])] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrUnexpectedTypeError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs new file mode 100644 index 0000000..4934f74 --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs @@ -0,0 +1,38 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when wrapping an unsupported type is attempted. +/// +/// Details on why the error happened. +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("unsupported_wrapping_error", nameof(WrapperConstructor))] +public class EzrUnsupportedWrappingError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unsupported wrapping", details, context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "unsupported csharp wrapping error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.UnsupportedCSharpWrappingError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["details"])] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrUnsupportedWrappingError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs new file mode 100644 index 0000000..d89408d --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs @@ -0,0 +1,38 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when a value is out of a range. +/// +/// Details on why the error happened. +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("value_out_of_range_error", nameof(WrapperConstructor))] +public class EzrValueOutOfRangeError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Value out of range", details, context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "value out of range error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.ValueOutOfRangeError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["details"])] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrValueOutOfRangeError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs new file mode 100644 index 0000000..2944e33 --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs @@ -0,0 +1,38 @@ +using EzrSquared.Runtime.WrapperAttributes; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Error type for when an error related to the execution of C# wrappers occurs. +/// +/// Details on why the error happened. +/// The context in which the error occurred. +/// The starting position of the error. +/// The ending position of the error. +[SharpTypeWrapper("wrapper_execution_error", nameof(WrapperConstructor))] +public class EzrWrapperExecutionError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Wrapper execution error", details, context, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "csharp wrapper execution error"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CSharpWrapperExecutionError"; + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["details"])] + public static new void WrapperConstructor(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + Reference detailsReference = arguments.ArgumentReferences["details"]; + + string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(new EzrWrapperExecutionError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + } +} diff --git a/src/Runtime/Types/Core/Text/EzrCharacter.cs b/src/Runtime/Types/Core/Text/EzrCharacter.cs new file mode 100644 index 0000000..2a040d0 --- /dev/null +++ b/src/Runtime/Types/Core/Text/EzrCharacter.cs @@ -0,0 +1,302 @@ +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Util.Extensions; +using System; +using System.Numerics; + +namespace EzrSquared.Runtime.Types.Core.Text; + +/// +/// The character type object. +/// +/// The base value. +/// The parent context. +/// The starting position of the object. +/// The ending position of the object. +public class EzrCharacter(char value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "character"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.Character"; + + /// + /// The character value. + /// + public readonly char Value = value; + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value == otherCharacter.Value)); break; + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value == otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value == otherFloat.Value)); break; + case EzrString otherString: + result.Success(NewBooleanConstant(Value.ToString() == otherString.Value)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(Value.ToString() == otherCharacterList.StringValue)); break; + default: + result.Success(NewBooleanConstant(false)); break; + } + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value != otherCharacter.Value)); break; + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value != otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value != otherFloat.Value)); break; + case EzrString otherString: + result.Success(NewBooleanConstant(Value.ToString() != otherString.Value)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(Value.ToString() != otherCharacterList.StringValue)); break; + default: + result.Success(NewBooleanConstant(true)); break; + } + } + + /// + public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value < otherCharacter.Value)); break; + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value < otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value < otherFloat.Value)); break; + case EzrString otherString: + result.Success(NewBooleanConstant(Value.CompareTo(otherString.Value) < 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(Value.CompareTo(otherCharacterList.StringValue) < 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonGreaterThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value > otherCharacter.Value)); break; + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value > otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value > otherFloat.Value)); break; + case EzrString otherString: + result.Success(NewBooleanConstant(Value.CompareTo(otherString.Value) > 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(Value.CompareTo(otherCharacterList.StringValue) > 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value <= otherCharacter.Value)); break; + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value <= otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value <= otherFloat.Value)); break; + case EzrString otherString: + result.Success(NewBooleanConstant(Value.CompareTo(otherString.Value) <= 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(Value.CompareTo(otherCharacterList.StringValue) <= 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonGreaterThanOrEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value >= otherCharacter.Value)); break; + case EzrInteger otherInteger: + result.Success(NewBooleanConstant(Value >= otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewBooleanConstant(Value >= otherFloat.Value)); break; + case EzrString otherString: + result.Success(NewBooleanConstant(Value.CompareTo(otherString.Value) >= 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(Value.CompareTo(otherCharacterList.StringValue) >= 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Addition(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value + otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(Value + otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value + otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Subtraction(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value - otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(Value - otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value - otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Multiplication(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value * otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(Value * otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value * otherCharacter.Value)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Division(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger { Value: BigInteger value } when value == 0: + case EzrFloat { Value: 0 }: + case EzrCharacter { Value: '\0' }: + result.Failure(new EzrMathError("Division error", "Divisor cannot be zero!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value / otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(Value / otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value / otherCharacter.Value)); break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Modulo(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger { Value: BigInteger value } when value == 0: + case EzrFloat { Value: 0 }: + case EzrCharacter { Value: '\0' }: + result.Failure(new EzrMathError("Division error", "Divisor cannot be zero!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value % otherInteger.Value)); break; + case EzrFloat otherFloat: + result.Success(NewFloatConstant(Value % otherFloat.Value)); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(Value % otherCharacter.Value)); break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Power(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger otherInteger: + result.Success(NewIntegerConstant(Value.Power(otherInteger.Value))); break; + case EzrCharacter otherCharacter: + result.Success(NewIntegerConstant(BigInteger.Pow(Value, otherCharacter.Value))); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void Negation(RuntimeResult result) + { + result.Success(NewIntegerConstant(-Value)); + } + + /// + public override void Affirmation(RuntimeResult result) + { + result.Success(NewIntegerConstant(Math.Abs(Value))); + } + + /// + public override void Inversion(RuntimeResult result) + { + result.Success(NewIntegerConstant(Value > 0 ? 0 : 1)); + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return Value > 0; + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrCharacter)?.Value == Value && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, Value); + } + + /// + public override string ToString(RuntimeResult result) + { + return $"`{Value}`"; + } + + /// + public override string ToPureString(RuntimeResult result) + { + return $"{Value}"; + } +} diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs new file mode 100644 index 0000000..1c63ade --- /dev/null +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -0,0 +1,491 @@ +using EzrSquared.Runtime.Types.Collections; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Numerics; +using System; +using System.Numerics; +using System.Text; + +namespace EzrSquared.Runtime.Types.Core.Text; + +/// +/// The type object. +/// +/// The base string value. +/// The parent context. +/// The starting position of the object. +/// The ending position of the object. +public class EzrCharacterList(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrMutableObject +{ + /// + public override string TypeName { get; protected internal set; } = "character list"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.CharacterList"; + + /// + /// The value. + /// + public readonly StringBuilder Value = new(value); + + /// + /// Calls and returns the value converted to a . + /// + public string StringValue => Value.ToString(); + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(StringValue == otherString.Value)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(StringValue == otherCharacterList.StringValue)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(StringValue == otherCharacter.Value.ToString())); break; + default: + result.Success(NewBooleanConstant(false)); break; + } + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(StringValue != otherString.Value)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(StringValue != otherCharacterList.StringValue)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(StringValue != otherCharacter.Value.ToString())); break; + default: + result.Success(NewBooleanConstant(true)); break; + } + } + + /// + /// Gets the character(s) at the specified index/indices OR compares the current object to other stringlike objects, checks if this is less than the other. + /// + /// + public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger when Value.Length == 0: + case IEzrIndexedCollection when Value.Length == 0: + result.Failure(new EzrValueOutOfRangeError("The character list is empty and cannot be indexed!", _executionContext, StartPosition, EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.Value < -Value.Length || otherInteger.Value >= Value.Length: + result.Failure(new EzrValueOutOfRangeError($"Index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int index): + result.Success(NewCharacterConstant(index >= 0 ? Value[index] : Value[^-index])); break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: < 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: > 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection otherCollection: + (IEzrObject index1, IEzrObject index2) = (otherCollection.At(0), otherCollection.At(1)); + if (index1 is not EzrInteger startIndex || index2 is not EzrInteger endIndex) + { + result.Failure(new EzrUnexpectedTypeError($"Both indices must be integers! Given indices were of types \"{index1.TypeName}\" (start) and \"{index2.TypeName}\" (end).", _executionContext, other.StartPosition, other.EndPosition)); + break; + } + + if (!startIndex.TryGetIntRepresentation(out int startIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (!endIndex.TryGetIntRepresentation(out int endIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + if (startIndexInt < -Value.Length || startIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Starting index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (startIndexInt < 0) + { + if (endIndexInt > startIndexInt || endIndexInt < -Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {-Value.Length}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + result.Success(NewCharacterListConstant(StringValue[(Value.Length + endIndexInt)..(Value.Length + startIndexInt + 1)])); + break; + } + + if (endIndexInt < startIndexInt || endIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {Value.Length - 1}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + result.Success(NewCharacterListConstant(StringValue[startIndexInt..(endIndexInt + 1)])); + break; + + case EzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.Value) < 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacterList.StringValue) < 0)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacter.Value.ToString()) < 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonGreaterThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.Value) > 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacterList.StringValue) > 0)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacter.Value.ToString()) > 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + /// Gets the character(s) at the specified index/indices OR compares the current object to other stringlike objects, checks if this is less than or equal to the other. + /// + /// + public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger: + case IEzrIndexedCollection: + ComparisonLessThan(other, result); + break; + + case EzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.Value) <= 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacterList.StringValue) <= 0)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacter.Value.ToString()) <= 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonGreaterThanOrEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.Value) >= 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacterList.StringValue) >= 0)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacter.Value.ToString()) >= 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + /// Appends the string representation of the other object to the current object. + /// + /// + public override void Addition(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrCharacterList otherCharacterList: + Value.Append(otherCharacterList.Value); break; + case EzrString otherString: + Value.Append(otherString.Value); break; + case EzrCharacter otherCharacter: + Value.Append(otherCharacter.Value); break; + default: + string otherStringValue = other.ToPureString(result); + if (result.ShouldReturn) + return; + + Value.Append(otherStringValue); + break; + } + + result.Success(NewNothingConstant()); + } + + /// + /// Removes the character(s) at the specified index/indices. + /// + /// + public override void Subtraction(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger when Value.Length == 0: + case IEzrIndexedCollection when Value.Length == 0: + result.Failure(new EzrValueOutOfRangeError("The character list is empty and cannot be removed from!", _executionContext, StartPosition, EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.Value < -Value.Length || otherInteger.Value >= Value.Length: + result.Failure(new EzrValueOutOfRangeError($"Index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int index): + Value.Remove(index >= 0 ? index : Value.Length + index, 1); + result.Success(NewNothingConstant()); + break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: < 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: > 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection otherCollection: + (IEzrObject index1, IEzrObject index2) = (otherCollection.At(0), otherCollection.At(1)); + if (index1 is not EzrInteger startIndex || index2 is not EzrInteger endIndex) + { + result.Failure(new EzrUnexpectedTypeError($"Both indices must be integers! Given indices were of types \"{index1.TypeName}\" (start) and \"{index2.TypeName}\" (end).", _executionContext, other.StartPosition, other.EndPosition)); + break; + } + + if (!startIndex.TryGetIntRepresentation(out int startIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (!endIndex.TryGetIntRepresentation(out int endIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + if (startIndexInt < -Value.Length || startIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Starting index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (startIndexInt < 0) + { + if (endIndexInt > startIndexInt || endIndexInt < -Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {-Value.Length}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + Value.Remove(Value.Length + endIndexInt, startIndexInt - endIndexInt + 1); + result.Success(NewNothingConstant()); + break; + } + + if (endIndexInt < startIndexInt || endIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {Value.Length - 1}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + Value.Remove(startIndexInt, endIndexInt - startIndexInt + 1); + result.Success(NewNothingConstant()); + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// Here, "multiply" means "duplicate/decrease the current value X times". + /// + public override void Multiplication(IEzrObject other, RuntimeResult result) + { + int newLength; + string originalValue; + switch (other) + { + case EzrInteger otherInteger: + BigInteger newIntegerLength = Value.Length * otherInteger.Value; + if (newIntegerLength < int.MinValue || newIntegerLength > int.MaxValue) + { + result.Failure(new EzrValueOutOfRangeError("The multiplied length is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); + return; + } + + newLength = (int)newIntegerLength; + break; + + case EzrFloat otherFloat: + newLength = (int)(Value.Length * otherFloat.Value); + break; + + default: + result.Failure(IllegalOperation(other)); + return; + } + + switch (newLength) + { + case int length when length < 0: + result.Failure(new EzrValueOutOfRangeError("The multiplied length of the character list cannot be negative!", _executionContext, other.StartPosition, other.EndPosition)); + break; + + case int length when length == Value.Length: break; + case 0: Value.Clear(); break; + + case int length when length < Value.Length: + originalValue = StringValue; + + Value.Clear(); + Value.Append(originalValue[..newLength]); + break; + + default: + originalValue = StringValue; + int loops = (newLength / originalValue.Length) - 1; + + int i; + for (i = 0; i < loops; i++) + Value.Append(originalValue); + + int currentEnd = (loops == 0 ? 1 : i + 1) * originalValue.Length; + if (newLength > currentEnd) + Value.Append(originalValue[..(newLength - currentEnd)]); + + break; + } + + result.Success(NewNothingConstant()); + } + + /// Here, "divide" means "duplicate/decrease the current value X times". + /// + public override void Division(IEzrObject other, RuntimeResult result) + { + int newLength; + switch (other) + { + case EzrFloat { Value: <= 0 }: + case EzrInteger otherInteger when otherInteger.Value <= 0: + result.Failure(new EzrMathError("Division error", "Divisor cannot be less than or equal to zero in character list division!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrFloat when Value.Length == 0: + case EzrInteger when Value.Length == 0: + result.Success(NewNothingConstant()); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int divisor): + newLength = Value.Length / divisor; + Value.Remove(newLength, Value.Length - newLength); + + result.Success(NewNothingConstant()); + break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrFloat otherFloat: + newLength = (int)(Value.Length / otherFloat.Value); + + if (newLength < Value.Length) + Value.Remove(newLength, Value.Length - newLength); + else + { + string originalValue = StringValue; + while (Value.Length < newLength) + Value.Append(originalValue[..Math.Clamp(newLength - originalValue.Length, 0, originalValue.Length)]); + } + + result.Success(NewNothingConstant()); + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void HasValueContained(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(StringValue.Contains(otherString.Value))); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(StringValue.Contains(otherCharacterList.StringValue))); break; + default: + result.Failure(IllegalOperation(other, false)); break; + } + } + + /// + public override void NotHasValueContained(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(!StringValue.Contains(otherString.Value))); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(!StringValue.Contains(otherCharacterList.StringValue))); break; + default: + result.Failure(IllegalOperation(other, false)); break; + } + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return Value.Length > 0; + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrCharacterList)?.StringValue == StringValue && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + int hash = HashTag; + for (int i = 0; i < Value.Length; i++) + hash = HashCode.Combine(hash, Value[i]); + + return hash; + } + + /// + public override string ToString(RuntimeResult result) + { + return $"'{StringValue}'"; + } + + /// + public override string ToPureString(RuntimeResult result) + { + return StringValue; + } + + /// + public IMutable? DeepCopy(RuntimeResult result) + { + return new EzrCharacterList(StringValue, _executionContext, StartPosition, EndPosition); + } +} diff --git a/src/Runtime/Types/Core/Text/EzrString.cs b/src/Runtime/Types/Core/Text/EzrString.cs new file mode 100644 index 0000000..1e3c130 --- /dev/null +++ b/src/Runtime/Types/Core/Text/EzrString.cs @@ -0,0 +1,471 @@ +using EzrSquared.Runtime.Types.Collections; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Numerics; +using System; +using System.Numerics; +using System.Text; + +namespace EzrSquared.Runtime.Types.Core.Text; + +/// +/// The string type object. +/// +/// The base value. +/// The parent context. +/// The starting position of the object. +/// The ending position of the object. +public class EzrString(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) +{ + /// + public override string TypeName { get; protected internal set; } = "string"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.String"; + + /// + /// The string value. + /// + public readonly string Value = value; + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(Value == otherString.Value)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(Value == otherCharacterList.StringValue)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value == otherCharacter.Value.ToString())); break; + default: + result.Success(NewBooleanConstant(false)); break; + } + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(Value != otherString.Value)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(Value != otherCharacterList.StringValue)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(Value != otherCharacter.Value.ToString())); break; + default: + result.Success(NewBooleanConstant(true)); break; + } + } + + /// + /// Gets the character(s) at the specified index/indices OR compares the current object to other stringlike objects, checks if this is less than the other. + /// + /// + public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger when Value.Length == 0: + case IEzrIndexedCollection when Value.Length == 0: + result.Failure(new EzrValueOutOfRangeError("The string is empty and cannot be indexed!", _executionContext, StartPosition, EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.Value < -Value.Length || otherInteger.Value >= Value.Length: + result.Failure(new EzrValueOutOfRangeError($"Index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int index): + result.Success(NewCharacterConstant(index >= 0 ? Value[index] : Value[^-index])); break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: < 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: > 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection otherCollection: + (IEzrObject index1, IEzrObject index2) = (otherCollection.At(0), otherCollection.At(1)); + if (index1 is not EzrInteger startIndex || index2 is not EzrInteger endIndex) + { + result.Failure(new EzrUnexpectedTypeError($"Both indices must be integers! Given indices were of types \"{index1.TypeName}\" (start) and \"{index2.TypeName}\" (end).", _executionContext, other.StartPosition, other.EndPosition)); + break; + } + + if (!startIndex.TryGetIntRepresentation(out int startIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (!endIndex.TryGetIntRepresentation(out int endIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + if (startIndexInt < -Value.Length || startIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Starting index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (startIndexInt < 0) + { + if (endIndexInt > startIndexInt || endIndexInt < -Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {-Value.Length}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + result.Success(NewStringConstant(Value[^(-endIndexInt)..^(-startIndexInt - 1)])); + break; + } + + if (endIndexInt < startIndexInt || endIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {Value.Length - 1}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + result.Success(NewStringConstant(Value[startIndexInt..(endIndexInt + 1)])); + break; + + case EzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.Value) < 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacterList.StringValue) < 0)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacter.Value.ToString()) < 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonGreaterThan(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.Value) > 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacterList.StringValue) > 0)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacter.Value.ToString()) > 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + /// Gets the character(s) at the specified index/indices OR compares the current object to other stringlike objects, checks if this is less than the other. + /// + /// + public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger: + case IEzrIndexedCollection: + ComparisonLessThan(other, result); + break; + + case EzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.Value) <= 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacterList.StringValue) <= 0)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacter.Value.ToString()) <= 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void ComparisonGreaterThanOrEqual(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.Value) >= 0)); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacterList.StringValue) >= 0)); break; + case EzrCharacter otherCharacter: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacter.Value.ToString()) >= 0)); break; + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + /// Creates a copy of the current object with the string representation of the other object appended. + /// + /// + public override void Addition(IEzrObject other, RuntimeResult result) + { + string newValue = Value; + switch (other) + { + case EzrCharacterList otherCharacterList: + newValue += otherCharacterList.StringValue; break; + case EzrString otherString: + newValue += otherString.Value; break; + case EzrCharacter otherCharacter: + newValue += otherCharacter.Value; break; + default: + newValue += other.ToPureString(result); + if (result.ShouldReturn) + return; + break; + } + + result.Success(NewStringConstant(newValue)); + } + + /// + /// Creates a copy of the current object with the character(s) at the specified index/indices removed. + /// + /// + public override void Subtraction(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrInteger when Value.Length == 0: + case IEzrIndexedCollection when Value.Length == 0: + result.Failure(new EzrValueOutOfRangeError("The string is empty and cannot be removed from!", _executionContext, StartPosition, EndPosition)); + break; + + case EzrInteger otherInteger when otherInteger.Value < -Value.Length || otherInteger.Value >= Value.Length: + result.Failure(new EzrValueOutOfRangeError($"Index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int index): + result.Success(NewStringConstant(index >= 0 ? Value.Remove(index, 1) : Value.Remove(Value.Length + index, 1))); break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: < 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection { Length: > 2 }: + result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case IEzrIndexedCollection otherCollection: + (IEzrObject index1, IEzrObject index2) = (otherCollection.At(0), otherCollection.At(1)); + if (index1 is not EzrInteger startIndex || index2 is not EzrInteger endIndex) + { + result.Failure(new EzrUnexpectedTypeError($"Both indices must be integers! Given indices were of types \"{index1.TypeName}\" (start) and \"{index2.TypeName}\" (end).", _executionContext, other.StartPosition, other.EndPosition)); + break; + } + + if (!startIndex.TryGetIntRepresentation(out int startIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (!endIndex.TryGetIntRepresentation(out int endIndexInt)) + { + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + if (startIndexInt < -Value.Length || startIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Starting index must be in range 0 to {Value.Length - 1} or -1 to {-Value.Length}!", _executionContext, startIndex.StartPosition, startIndex.EndPosition)); + break; + } + + if (startIndexInt < 0) + { + if (endIndexInt > startIndexInt || endIndexInt < -Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {-Value.Length}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + result.Success(NewStringConstant(Value.Remove(Value.Length + endIndexInt, startIndexInt - endIndexInt + 1))); + break; + } + + if (endIndexInt < startIndexInt || endIndexInt >= Value.Length) + { + result.Failure(new EzrValueOutOfRangeError($"Ending index must be in range {startIndexInt} to {Value.Length - 1}!", _executionContext, endIndex.StartPosition, endIndex.EndPosition)); + break; + } + + result.Success(NewStringConstant(Value.Remove(startIndexInt, endIndexInt - startIndexInt + 1))); + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// Here, "multiply" means "duplicate/decrease the current value X times". + /// + public override void Multiplication(IEzrObject other, RuntimeResult result) + { + int newLength; + switch (other) + { + case EzrInteger otherInteger: + BigInteger newIntegerLength = Value.Length * otherInteger.Value; + if (newIntegerLength < int.MinValue || newIntegerLength > int.MaxValue) + { + result.Failure(new EzrValueOutOfRangeError("The multiplied length is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); + return; + } + + newLength = (int)newIntegerLength; + break; + + case EzrFloat otherFloat: + newLength = (int)(Value.Length * otherFloat.Value); + break; + + default: + result.Failure(IllegalOperation(other)); + return; + } + + string newValue; + switch (newLength) + { + case int length when length < 0: + result.Failure(new EzrValueOutOfRangeError("The multiplied length of the string cannot be negative!", _executionContext, other.StartPosition, other.EndPosition)); + return; + + case int length when length == Value.Length: + newValue = Value; break; + + case int length when length == 0: + newValue = string.Empty; break; + + case int length when length < Value.Length: + newValue = Value[..newLength]; break; + + default: + StringBuilder builder = new(); + int loops = newLength / Value.Length; + + int i; + for (i = 0; i < loops; i++) + builder.Append(Value); + + int currentEnd = i * Value.Length; + if (newLength > currentEnd) + builder.Append(Value[..(newLength - currentEnd)]); + + newValue = builder.ToString(); + break; + } + + result.Success(NewStringConstant(newValue)); + } + + /// Here, "divide" means "duplicate/decrease the current value X times". + /// + public override void Division(IEzrObject other, RuntimeResult result) + { + int newLength; + switch (other) + { + case EzrFloat { Value: <= 0 }: + case EzrInteger otherInteger when otherInteger.Value <= 0: + result.Failure(new EzrMathError("Division error", "Divisor cannot be less than or equal to zero in string division!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrFloat when Value.Length == 0: + case EzrInteger when Value.Length == 0: + result.Success(NewStringConstant(string.Empty)); break; + + case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int divisor): + newLength = Value.Length / divisor; + result.Success(NewStringConstant(Value[0..newLength])); + break; + + case EzrInteger: + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; + + case EzrFloat otherFloat: + newLength = (int)(Value.Length / otherFloat.Value); + + if (newLength < Value.Length) + result.Success(NewStringConstant(Value[0..newLength])); + else + { + StringBuilder builder = new(Value); + while (builder.Length < newLength) + builder.Append(Value[..Math.Clamp(newLength - Value.Length, 0, Value.Length)]); + + result.Success(NewStringConstant(builder.ToString())); + } + + break; + + default: + result.Failure(IllegalOperation(other)); break; + } + } + + /// + public override void HasValueContained(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(Value.Contains(otherString.Value))); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(Value.Contains(otherCharacterList.StringValue))); break; + default: + result.Failure(IllegalOperation(other, false)); break; + } + } + + /// + public override void NotHasValueContained(IEzrObject other, RuntimeResult result) + { + switch (other) + { + case EzrString otherString: + result.Success(NewBooleanConstant(!Value.Contains(otherString.Value))); break; + case EzrCharacterList otherCharacterList: + result.Success(NewBooleanConstant(!Value.Contains(otherCharacterList.StringValue))); break; + default: + result.Failure(IllegalOperation(other, false)); break; + } + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return !string.IsNullOrEmpty(Value); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return (other as EzrString)?.Value == Value && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, Value); + } + + /// + public override string ToString(RuntimeResult result) + { + return $"\"{Value}\""; + } + + /// + public override string ToPureString(RuntimeResult result) + { + return Value; + } +} diff --git a/src/Runtime/Types/Executables/EzrClass.cs b/src/Runtime/Types/Executables/EzrClass.cs new file mode 100644 index 0000000..ce7a914 --- /dev/null +++ b/src/Runtime/Types/Executables/EzrClass.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; +using EzrSquared.Runtime.Nodes; +using EzrSquared.Runtime.Types.Core.Errors; + +namespace EzrSquared.Runtime.Types; + +/// +/// The "type" type object? You know. +/// +public class EzrClass : EzrRuntimeExecutable, IEzrMutableObject +{ + /// + public override string TypeName { get; protected internal set; } = "class"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.Class"; + + /// + /// The parents of the class. + /// + public readonly EzrClass[] Parents; + + /// + /// Is the class static? + /// + public readonly bool IsStatic; + + /// + /// The references to the class's static parents. + /// + public readonly Reference[] StaticParentReferences; + + /// + /// Creates a new class. + /// + /// The name of the executable. + /// The source code body of the executable. + /// The parents of the class. + /// Is this a read-only class? + /// Is this a static class? + /// Interpreter for executing the static body of the class. + /// Runtime result for carrying errors. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrClass(string? name, Node body, EzrClass[] parents, bool isReadOnly, bool isStatic, Interpreter interpreter, RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(name, body, [], null, parentContext, startPosition, endPosition, new Context($"<{$"\"{name}\"" ?? ""} static context>", true, startPosition, parentContext)) + { + IsReadOnly = isReadOnly; + IsStatic = isStatic; + Parents = parents; + StaticParentReferences = new Reference[Parents.Length]; + + Context newContext = new($"<{ExecutableName} static initialization context>", false, StartPosition, Context, Context); + + AddStaticParents(result); + if (result.ShouldReturn) + { + newContext.Release(); + return; + } + + interpreter.VisitNode(body, newContext, null, IsStatic ? AccessMod.Static : AccessMod.None); + + if (IsStatic || result.ShouldReturn) + { + newContext.Release(); + return; + } + + Context.GetStatus status = newContext.Get(null, EzrClassInstance.InitializationFunction, out Reference functionReference, AccessMod.LocalScope); + if ((status != Context.GetStatus.Ok && status != Context.GetStatus.UndefinedSymbolAccessNotAllowed) + || (!functionReference.IsEmpty && functionReference.Object is not EzrFunction)) + { + result.Failure(new EzrUndefinedValueError("Cannot have any object defined in class with reserved name \"initialize\", unless it is a function!", _executionContext, StartPosition, EndPosition)); + newContext.Release(); + + return; + } + else if (functionReference.IsEmpty) + { + newContext.Release(); + return; + } + + if ((functionReference.AccessibilityModifiers & AccessMod.Constant) != AccessMod.Constant || (functionReference.AccessibilityModifiers & AccessMod.Private) == AccessMod.Private) + { + result.Failure(new EzrIllegalOperationError($"Initialization function for class \"{ExecutableName}\" must be a non-private constant!", _executionContext, StartPosition, EndPosition)); + newContext.Release(); + + return; + } + + EzrFunction initializationFunction = (EzrFunction)functionReference.Object; + Parameters = initializationFunction.Parameters; + KeywordArguments = initializationFunction.KeywordArguments; + + newContext.Release(); + } + + /// + /// Creates a new class from the innards of an existing one. + /// + /// The name of the executable. + /// The source code body of the executable. + /// The source code of the class's parameters and their default values. + /// The position in source code and name of the variable for the class's extra keyword arguments. + /// The parents of the class. + /// The references to the class's static parents. + /// Is this a read-only class? + /// Is this a static class? + /// The internal static context. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + /// + /// \bug The name given to the parents is problematic, as two parents could have the same executable name. + public EzrClass(string? name, Node body, (string Name, Node Node)[] parameters, (Position StartPosition, Position EndPosition, string Name)? keywordArguments, EzrClass[] parents, Reference[] staticParentReferences, bool isReadOnly, bool isStatic, Context staticContext, Context parentContext, Position startPosition, Position endPosition) : base(name, body, parameters, keywordArguments, parentContext, startPosition, endPosition, staticContext) + { + Parents = parents; + IsReadOnly = isReadOnly; + IsStatic = isStatic; + StaticParentReferences = staticParentReferences; + } + + private void AddStaticParents(RuntimeResult result) + { + Context.SetNewLinkedContexts(Parents.Length); + + int anonymousParents = 0; + for (int i = 0; i < Parents.Length; i++) + { + EzrClass parent = Parents[i]; + if (IsStatic && !parent.IsStatic) + { + result.Failure(new EzrIllegalOperationError("A static class can only inherit from other static classes!", _executionContext, StartPosition, EndPosition)); + return; + } + + parent.Update(Context, StartPosition, EndPosition); + Reference reference = ReferencePool.Get(parent, AccessMod.PrivateStaticConstant); + + if (Array.Exists(StaticParentReferences, existingParent => existingParent?.Object?.HashTag == parent.HashTag)) + { + result.Failure(new EzrIllegalOperationError($"Cannot inherit from the same class \"{parent.ExecutableName}\" more than once!", _executionContext, StartPosition, EndPosition)); + return; + } + + string name; + if (parent.IsAnonymous) + { + name = i == 0 ? "parent" : $"parent_anonymous_{anonymousParents}"; + anonymousParents++; + } + else + name = i == 0 ? "parent" : $"parent_{parent.ExecutableName}"; + + reference.UpdateName(name); + Context.Set(null, name, reference); + + StaticParentReferences[i] = reference; + Context.LinkedContexts[i] = reference.Object.Context; + } + } + + /// \bug The name given to the parents is problematic, as two parents could have the same executable name. + private Reference[] AddParents(Reference[] arguments, Context context, Interpreter interpreter, RuntimeResult result) + { + List parentReferences = []; + int anonymousParents = 0; + + for (int i = 0; i < Parents.Length; i++) + { + EzrClass parent = Parents[i]; + if (parent.IsStatic) + continue; + + parent.Execute(arguments, interpreter, result, true); + if (result.ShouldReturn) + return []; + + Reference reference = ReferencePool.Get(result.Reference.Object, AccessMod.PrivateConstant); + reference.Object.Update(context, StartPosition, EndPosition); + + if (parentReferences.Exists(existingParent => (existingParent.Object as EzrClassInstance)?.Class?.HashTag == parent.HashTag)) + { + result.Failure(new EzrIllegalOperationError($"Cannot inherit from the same class \"{parent.ExecutableName}\" more than once!", _executionContext, StartPosition, EndPosition)); + return []; + } + + string name; + if (parent.IsAnonymous) + { + name = i == 0 ? "parent" : $"parent_anonymous_{anonymousParents}"; + anonymousParents++; + } + else + name = i == 0 ? "parent" : $"parent_{parent.ExecutableName}"; + + reference.UpdateName(name); + context.Set(null, name, reference); + + parentReferences.Add(reference); + context.LinkedContexts[i] = reference.Object.Context; + } + + return [.. parentReferences]; + } + + /// + /// Creates a new instance of the class. + /// + /// The arguments of the execution. + /// The interpreter to be used in execution. + /// Runtime result for carrying any errors. + /// Should the arguments checker ignore extra parameters? + private void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result, bool ignoreExtraArguments) + { + if (IsStatic) + { + result.Failure(new EzrIllegalOperationError("Cannot create instance of a static class!", Context, StartPosition, EndPosition)); + return; + } + + Context newContext = new($"<{TypeName} \"{ExecutableName}\" instance>", false, StartPosition, Context, Context, Parents.Length); + Reference[] instanceParentReferences = AddParents(arguments, newContext, interpreter, result); + if (result.ShouldReturn) + return; + + IEzrObject instance = new EzrClassInstance(this, instanceParentReferences, arguments, ignoreExtraArguments, newContext, Body, IsReadOnly, interpreter, result, _executionContext, StartPosition, EndPosition); + if (result.ShouldReturn) + return; + + result.Success(ReferencePool.Get(instance, AccessMod.PrivateConstant)); + } + + /// + /// Creates a new instance of the class. + /// + /// + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + Execute(arguments, interpreter, result, false); + } + + /// + public IMutable? DeepCopy(RuntimeResult result) + { + Context? copy = Context.DeepCopy(result, []); + if (result.ShouldReturn) + return null; + + Reference[] staticParentReferences = new Reference[StaticParentReferences.Length]; + for (int i = 0; i < StaticParentReferences.Length; i++) + { + string name = StaticParentReferences[i].Name; + Context.GetStatus status = copy!.Get(null, name, out Reference reference); + + if (status != Context.GetStatus.Ok) + { + result.Failure(new EzrUndefinedValueError($"Could not access static parent \"{name}\" for copy! (Something's really gone wrong)", Context, StartPosition, EndPosition)); + return null; + } + + staticParentReferences[i] = reference; + copy.LinkedContexts[i] = reference.Object.Context; + } + + return new EzrClass(IsAnonymous ? null : ExecutableName, Body, Parameters, KeywordArguments, Parents, staticParentReferences, IsReadOnly, IsStatic, copy!, _creationContext, StartPosition, EndPosition); + } +} diff --git a/src/Runtime/Types/Executables/EzrClassInstance.cs b/src/Runtime/Types/Executables/EzrClassInstance.cs new file mode 100644 index 0000000..bd2912d --- /dev/null +++ b/src/Runtime/Types/Executables/EzrClassInstance.cs @@ -0,0 +1,577 @@ +using System; +using EzrSquared.Runtime.Nodes; +using EzrSquared.Runtime.Types.Core; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.Core.Text; + +namespace EzrSquared.Runtime.Types; + +/// +/// The "instance of a class" type object? +/// +public class EzrClassInstance : EzrObject, IEzrMutableObject +{ + /// Special function name for initializer (constructor). + public const string InitializationFunction = "initialize"; + + /// Special function name for 'this = other' operator. + public const string IsEqualFunction = "is_equal"; + + /// Special function name for 'this ! other' operator. + public const string IsNotEqualFunction = "is_inequal"; + + /// Special function name for 'this < other' operator. + public const string IsLessThanFunction = "is_less_than"; + + /// Special function name for 'this > other' operator. + public const string IsGreaterThanFunction = "is_greater_than"; + + /// Special function name for 'this <= other' operator. + public const string IsLessThanOrEqualFunction = "is_less_than_or_equal"; + + /// Special function name for 'this >= other' operator. + public const string IsGreaterThanOrEqualFunction = "is_greater_than_or_equal"; + + /// Special function name for 'this + other' operator. + public const string AdditionFunction = "addition"; + + /// Special function name for 'this - other' operator. + public const string SubtractionFunction = "subtraction"; + + /// Special function name for 'this * other' operator. + public const string MultiplicationFunction = "multiplication"; + + /// Special function name for 'this / other' operator. + public const string DivisionFunction = "division"; + + /// Special function name for 'this % other' operator. + public const string ModuloFunction = "modulo"; + + /// Special function name for 'this ^ other' operator. + public const string PowerFunction = "power"; + + /// Special function name for '-this' operator. + public const string NegationFunction = "negation"; + + /// Special function name for '+this' operator. + public const string AffirmationFunction = "affirmation"; + + /// Special function name for 'this | other' operator. + public const string BitwiseOrFunction = "bitwise_or"; + + /// Special function name for 'this \ other' operator. + public const string BitwiseXOrFunction = "bitwise_xor"; + + /// Special function name for 'this & other' operator. + public const string BitwiseAndFunction = "bitwise_and"; + + /// Special function name for 'this << other' operator. + public const string BitwiseLeftShiftunction = "bitwise_left_shift"; + + /// Special function name for 'this >> other' operator. + public const string BitwiseRightShiftFunction = "bitwise_right_shift"; + + /// Special function name for '~this' operator. + public const string BitwiseNegationFunction = "bitwise_negation"; + + /// Special function name for 'other in this' operator. + public const string ContainsFunction = "contains"; + + /// Special function name for 'other not in this' operator. + public const string DoesNotContainFunction = "does_not_contain"; + + /// Special function name for 'invert this' operator. + public const string InversionFunction = "inversion"; + + /// Special function name for evaluation of the 'this' into a boolean. + public const string EvaluateBooleanFunction = "evaluate_boolean"; + + /// Special function name for 'this(arguments)' operator. + public const string CalledFunction = "call_received"; + + /// Special function name for strict equality checking of 'this' and 'other'. + public const string StrictComparisonFunction = "strict_equals"; + + /// Special function name for hashing 'this'. + public const string GetHashCodeFunction = "get_hash_code"; + + /// Special function name for the string representation of 'this'. + public const string ToStringFunction = "to_string"; + + /// Special function name for the "pure" string representation of 'this'. + public const string ToPureStringFunction = "to_real_string"; + + /// + /// The interpreter for executing parts of the class instance. + /// + public readonly Interpreter Interpreter; + + /// + /// The parent class of the class instance. + /// + public readonly EzrClass Class; + + /// + /// The references to the class instance's parents. + /// + public readonly Reference[] ParentReferences; + + /// + /// Creates a new instance of the class . + /// + /// The parent class of the current object. + /// The references to the class instance's parents. + /// The arguments for the creation of the object. + /// Should the arguments checker ignore extra arguments? + /// The internal context of the object. + /// The source code body of the object. + /// Is the object read-only? + /// The interpreter for executing parts of the object. + /// Runtime result for carrying errors. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrClassInstance(EzrClass @class, Reference[] parentReferences, Reference[] arguments, bool ignoreExtraArguments, Context context, Node body, bool readOnly, Interpreter interpreter, RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(context, parentContext, startPosition, endPosition) + { + Class = @class; + TypeName = Class.ExecutableName; + Tag = $"{Class.Tag}.Instance"; + + Interpreter = interpreter; + IsReadOnly = readOnly; + + ParentReferences = parentReferences; + Context.Set(null, "this", ReferencePool.Get(this, AccessMod.PrivateConstant)); + + Context tempStaticContext = new($"<{TypeName} instance initialization context>", true, StartPosition, Context.StaticContext); + Context? trueStaticContext = Context.StaticContext; + + Context.UpdateStaticContext(tempStaticContext); + Interpreter.VisitNode(body, Context, null, AccessMod.None); + Context.UpdateStaticContext(trueStaticContext); + + tempStaticContext.Release(); + if (result.ShouldReturn) + return; + + bool hasInitializationFunction = Context.Get(null, InitializationFunction, out Reference functionReference, AccessMod.LocalScope, true) == Context.GetStatus.Ok + && functionReference.Object is EzrFunction function; + + if (hasInitializationFunction) + (functionReference.Object as EzrFunction)!.Execute(arguments, interpreter, result, ignoreExtraArguments); + else if (arguments.Length > 0 && !ignoreExtraArguments) + result.Failure(new EzrUnexpectedArgumentError("Did not expected any arguments!", context, StartPosition, EndPosition)); + } + + /// + /// Creates a new instance of the class . + /// + /// The parent class of the current object. + /// The references to the class instance's parents. + /// The internal context of the object. + /// Is the object read-only? + /// The interpreter for executing parts of the object. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrClassInstance(EzrClass @class, Reference[] parentReferences, bool readOnly, Interpreter interpreter, Context context, Context parentContext, Position startPosition, Position endPosition) : base(context, parentContext, startPosition, endPosition) + { + Class = @class; + TypeName = Class.ExecutableName; + Tag = $"{Class.Tag}.Instance"; + + Interpreter = interpreter; + IsReadOnly = readOnly; + + ParentReferences = parentReferences; + Context.Set(null, "this", ReferencePool.Get(this, AccessMod.PrivateConstant)); + } + + #region Operator overrides + /// + /// Gets a function based on the name and number of parameters. + /// + /// The name of the function. + /// The number of parameters required for the function. + /// The resulting reference to the function. + /// if successful, otherwise. + private bool GetFunction(string name, int parameters, out Reference functionReference) + { + return Context.Get(null, name, out functionReference, AccessMod.LocalScope) == Context.GetStatus.Ok + && functionReference.Object is EzrFunction function + && (parameters == -1 || function.Parameters.Length == parameters); + } + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + if (GetFunction(IsEqualFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Success(NewBooleanConstant(false)); + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + if (GetFunction(IsNotEqualFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Success(NewBooleanConstant(true)); + } + + /// + public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) + { + if (GetFunction(IsLessThanFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void ComparisonGreaterThan(IEzrObject other, RuntimeResult result) + { + if (GetFunction(IsGreaterThanFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult result) + { + if (GetFunction(IsLessThanOrEqualFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void ComparisonGreaterThanOrEqual(IEzrObject other, RuntimeResult result) + { + if (GetFunction(IsGreaterThanOrEqualFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void Addition(IEzrObject other, RuntimeResult result) + { + if (GetFunction(AdditionFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void Subtraction(IEzrObject other, RuntimeResult result) + { + if (GetFunction(SubtractionFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void Multiplication(IEzrObject other, RuntimeResult result) + { + if (GetFunction(MultiplicationFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void Division(IEzrObject other, RuntimeResult result) + { + if (GetFunction(DivisionFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void Modulo(IEzrObject other, RuntimeResult result) + { + if (GetFunction(ModuloFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void Power(IEzrObject other, RuntimeResult result) + { + if (GetFunction(PowerFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void Negation(RuntimeResult result) + { + if (GetFunction(NegationFunction, 0, out Reference objectReference)) + objectReference.Object.Execute([], Interpreter, result); + else + result.Failure(IllegalOperation()); + } + + /// + public override void Affirmation(RuntimeResult result) + { + if (GetFunction(AffirmationFunction, 0, out Reference objectReference)) + objectReference.Object.Execute([], Interpreter, result); + else + result.Failure(IllegalOperation()); + } + + /// + public override void BitwiseOr(IEzrObject other, RuntimeResult result) + { + if (GetFunction(BitwiseOrFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void BitwiseXOr(IEzrObject other, RuntimeResult result) + { + if (GetFunction(BitwiseXOrFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void BitwiseAnd(IEzrObject other, RuntimeResult result) + { + if (GetFunction(BitwiseAndFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void BitwiseLeftShift(IEzrObject other, RuntimeResult result) + { + if (GetFunction(BitwiseLeftShiftunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void BitwiseRightShift(IEzrObject other, RuntimeResult result) + { + if (GetFunction(BitwiseRightShiftFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other)); + } + + /// + public override void BitwiseNegation(RuntimeResult result) + { + if (GetFunction(BitwiseNegationFunction, 0, out Reference objectReference)) + objectReference.Object.Execute([], Interpreter, result); + else + result.Failure(IllegalOperation()); + } + + /// + public override void HasValueContained(IEzrObject other, RuntimeResult result) + { + if (GetFunction(ContainsFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other, false)); + } + + /// + public override void NotHasValueContained(IEzrObject other, RuntimeResult result) + { + if (GetFunction(DoesNotContainFunction, 1, out Reference objectReference)) + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + else + result.Failure(IllegalOperation(other, false)); + } + + /// + public override void Inversion(RuntimeResult result) + { + if (GetFunction(InversionFunction, 0, out Reference objectReference)) + objectReference.Object.Execute([], Interpreter, result); + else + result.Failure(IllegalOperation()); + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + if (GetFunction(EvaluateBooleanFunction, 0, out Reference objectReference)) + { + objectReference.Object.Execute([], Interpreter, result); + if (result.ShouldReturn) + return false; + + IEzrObject ezrObject = result.Reference.Object; + if (ezrObject is not EzrBoolean evaluation) + { + result.Failure(new EzrUnexpectedTypeError($"Expected output of function \"{EvaluateBooleanFunction}\" to be of type boolean but got object of type \"{ezrObject.TypeName}\"!", Context, ezrObject.StartPosition, ezrObject.EndPosition)); + return false; + } + + return evaluation.Value; + } + + result.Failure(IllegalOperation()); + return false; + } + + /// + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + if (GetFunction(CalledFunction, -1, out Reference objectReference)) + objectReference.Object.Execute(arguments, Interpreter, result); + else + result.Failure(IllegalOperation()); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + if (GetFunction(StrictComparisonFunction, 1, out Reference objectReference)) + { + objectReference.Object.Execute([ReferencePool.Get(other, AccessMod.Private)], Interpreter, result); + if (result.ShouldReturn) + return false; + + IEzrObject ezrObject = result.Reference.Object; + if (ezrObject is not EzrBoolean evaluation) + { + result.Failure(new EzrUnexpectedTypeError($"Expected output of function \"{StrictComparisonFunction}\" to be of type boolean but got object of type \"{ezrObject.TypeName}\"!", Context, ezrObject.StartPosition, ezrObject.EndPosition)); + return false; + } + + return evaluation.Value; + } + + result.Failure(IllegalOperation()); + return false; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + if (GetFunction(GetHashCodeFunction, 0, out Reference objectReference)) + { + objectReference.Object.Execute([], Interpreter, result); + if (result.ShouldReturn) + return 0; + + IEzrObject ezrObject = result.Reference.Object; + if (ezrObject is not EzrInteger evaluation) + { + result.Failure(new EzrUnexpectedTypeError($"Expected output of function \"{GetHashCodeFunction}\" to be of type integer but got object of type \"{ezrObject.TypeName}\"!", Context, ezrObject.StartPosition, ezrObject.EndPosition)); + return 0; + } + + if (evaluation.TryGetIntRepresentation(out int hashCode)) + return HashCode.Combine(HashTag, hashCode); + + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, evaluation.StartPosition, evaluation.EndPosition)); + return 0; + } + + result.Failure(IllegalOperation()); + return 0; + } + + /// + public override string ToString(RuntimeResult result) + { + if (GetFunction(ToStringFunction, 0, out Reference objectReference)) + { + objectReference.Object.Execute([], Interpreter, result); + if (result.ShouldReturn) + return string.Empty; + + IEzrObject ezrObject = result.Reference.Object; + if (ezrObject is not EzrString and not EzrCharacterList and not EzrCharacter) + { + result.Failure(new EzrUnexpectedTypeError($"Expected output of function \"{ToStringFunction}\" to be of types string, character list or character but got object of type \"{ezrObject.TypeName}\"!", Context, ezrObject.StartPosition, ezrObject.EndPosition)); + return string.Empty; + } + + return ezrObject switch + { + EzrString stringValue => stringValue.Value, + EzrCharacterList characterListValue => characterListValue.StringValue, + EzrCharacter characterValue => characterValue.Value.ToString(), + _ => throw new ArgumentException($"Unexpected type {ezrObject.GetType().Name} for string conversion!") + }; + } + + return $""; + } + + /// + public override string ToPureString(RuntimeResult result) + { + if (GetFunction(ToPureStringFunction, 0, out Reference objectReference)) + { + objectReference.Object.Execute([], Interpreter, result); + if (result.ShouldReturn) + return string.Empty; + + IEzrObject ezrObject = result.Reference.Object; + if (ezrObject is not EzrString and not EzrCharacterList and not EzrCharacter) + { + result.Failure(new EzrUnexpectedTypeError($"Expected output of function \"{ToPureStringFunction}\" to be of types string, character list or character but got object of type \"{ezrObject.TypeName}\"!", Context, ezrObject.StartPosition, ezrObject.EndPosition)); + return string.Empty; + } + + return ezrObject switch + { + EzrString stringValue => stringValue.Value, + EzrCharacterList characterListValue => characterListValue.StringValue, + EzrCharacter characterValue => characterValue.Value.ToString(), + _ => throw new ArgumentException($"Unexpected type {ezrObject.GetType().Name} for string conversion!") + }; + } + + return ToString(result); + } + #endregion + + /// + public IMutable? DeepCopy(RuntimeResult result) + { + Context? copy = Context.DeepCopy(result, [this]); + if (result.ShouldReturn) + return null; + + Reference[] parentReferences = new Reference[ParentReferences.Length]; + for (int i = 0; i < ParentReferences.Length; i++) + { + string name = ParentReferences[i].Name; + Context.GetStatus status = copy!.Get(null, name, out Reference reference); + + if (status != Context.GetStatus.Ok) + { + result.Failure(new EzrUndefinedValueError($"Could not access parent \"{name}\" for copy! (Something's really gone wrong)", Context, StartPosition, EndPosition)); + return null; + } + + parentReferences[i] = reference; + copy.LinkedContexts[i] = reference.Object.Context; + } + + return new EzrClassInstance(Class, parentReferences, IsReadOnly, Interpreter, copy!, _creationContext, StartPosition, EndPosition); + } +} diff --git a/src/Runtime/Types/Executables/EzrFunction.cs b/src/Runtime/Types/Executables/EzrFunction.cs new file mode 100644 index 0000000..61079c2 --- /dev/null +++ b/src/Runtime/Types/Executables/EzrFunction.cs @@ -0,0 +1,71 @@ +using EzrSquared.Runtime.Nodes; + +namespace EzrSquared.Runtime.Types; + +/// +/// The function type object. +/// +/// The name of the executable. +/// The source code body of the executable. +/// The source code of the executable's parameters and their default values. +/// The position in source code and name of the variable for the executable's extra keyword arguments. +/// Should the function return its last expression as the result? +/// The parent context. +/// The starting position of the object. +/// The ending position of the object. +public class EzrFunction(string? name, Node body, (string Name, Node Node)[] parameters, (Position StartPosition, Position EndPosition, string Name)? keywordArguments, bool returnLast, Context parentContext, Position startPosition, Position endPosition) : EzrRuntimeExecutable(name, body, parameters, keywordArguments, parentContext, startPosition, endPosition), IEzrMutableObject +{ + /// + public override string TypeName { get; protected internal set; } = "function"; + + /// + public override string Tag { get; protected internal set; } = "ezrSquared.RuntimeDefinedFunction"; + + /// + /// Should the function return its last expression as the result? + /// + public readonly bool ReturnLast = returnLast; + + /// + /// Executes the current function. + /// + /// The arguments of the execution. + /// The interpreter to be used in execution. + /// Runtime result for carrying any errors. + /// Should the function ignore extra arguments? + public void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result, bool ignoreExtraArguments) + { + Context newContext = new($"<{TypeName} \"{ExecutableName}\">", false, StartPosition, _creationContext, _creationContext.StaticContext); + CheckAndPopulateArguments(arguments, newContext, interpreter, result, ignoreExtraArguments); + if (result.ShouldReturn) + return; + + interpreter.VisitNode(Body, newContext, null, AccessMod.None); + if (result.ShouldReturnFunction) + { + Context.Release(); + return; + } + + if (result.Reference.IsEmpty) + result.Success(NewNothingConstant()); + else if (result.Reference.RegisteredContext?.Id == newContext.Id) + result.Success(ReferencePool.Get(result.Reference.Object, AccessMod.PrivateConstant)); + else + result.Success(result.Reference); + + newContext.Release(); + } + + /// + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + Execute(arguments, interpreter, result, false); + } + + /// + public IMutable? DeepCopy(RuntimeResult result) + { + return new EzrFunction(IsAnonymous ? null : ExecutableName, Body, Parameters, KeywordArguments, ReturnLast, _creationContext, StartPosition, EndPosition); + } +} diff --git a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs new file mode 100644 index 0000000..d9720e3 --- /dev/null +++ b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs @@ -0,0 +1,244 @@ +using EzrSquared.Runtime.Types.Collections; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Core.Text; +using EzrSquared.Runtime.Collections; +using EzrSquared.Runtime.Nodes; +using EzrSquared.Util; +using System; + +namespace EzrSquared.Runtime.Types; + +/// +/// The base root class of all runtime executables. +/// +public abstract class EzrRuntimeExecutable : EzrObject +{ + /// + /// The name of the executable. + /// + public readonly string ExecutableName; + + /// + /// Is the executable anonymous? + /// + public readonly bool IsAnonymous; + + /// + /// The source code body of the executable. + /// + public readonly Node Body; + + /// + /// The name and source code of the executable's parameters and their default values. + /// + public (string Name, Node Node)[] Parameters { get; internal protected set; } + + /// + /// The position in source code and name of the variable for the executable's extra keyword arguments. + /// + public (Position StartPosition, Position EndPosition, string Name)? KeywordArguments { get; internal protected set; } + + /// + /// Creates a new executable object. + /// + /// The name of the executable. + /// The source code body of the executable. + /// The source code of the executable's parameters and their default values. + /// The position in source code and name of the variable for the executable's extra keyword arguments. + /// The internal context, if , creates a new one. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrRuntimeExecutable(string? name, Node body, (string Name, Node Node)[] parameters, (Position StartPosition, Position EndPosition, string Name)? keywordArguments, Context parentContext, Position startPosition, Position endPosition, Context? initializationContext = null) : base(initializationContext, parentContext, startPosition, endPosition) + { + Tag = name is not null + ? $"{Tag}.{name}.{Utils.GetNextUniqueId()}" + : $"{Tag}.{Utils.GetNextUniqueId()}"; + ExecutableName = name ?? $""; + + Body = body; + Parameters = parameters; + KeywordArguments = keywordArguments; + + IsAnonymous = string.IsNullOrEmpty(name); + } + + /// + /// Checks if the given array of arguments conform to the executables parameters, and populates them in the given context. + /// + /// The arguments to check. + /// The context to populate + /// The interpreter for executing parameter default values. + /// Runtime result for carrying errors. + /// Should the checker ignore extra arguments? + protected internal void CheckAndPopulateArguments(Reference[] arguments, Context context, Interpreter interpreter, RuntimeResult result, bool ignoreExtraArguments) + { + // Create dictionary to store extra keyword arguments, if allowed. + RuntimeEzrObjectDictionary? keywordArguments = KeywordArguments.HasValue ? new() : null; + + // Index for iterating through the ParameterNames array. + int parameterIndex = 0; + + // Index for iterating through the arguments. + int argumentIndex = 0; + + while (argumentIndex < arguments.Length) + { + // Get the argument. Reference and object. + Reference argument = arguments[argumentIndex]; + IEzrObject argumentObject = argument.Object; + + // Is the parameterIndex in the bounds of the dictionary? + bool isValidIndex = parameterIndex < Parameters.Length; + + // Is this a keyword argument? As in, provided like name: value. + bool isKeywordArgument = !string.IsNullOrEmpty(argument.Name) && !argument.IsRegistered; + + // The name of the argument as in Parameters or the given name. + string key = isValidIndex ? Parameters[parameterIndex].Name : string.Empty; + + if (isKeywordArgument) + { + // If it is a keyword argument, and it exists in Parameters: + if (Array.FindIndex(Parameters, paramter => paramter.Name == argument.Name) != -1) + key = argument.Name; // Choose that as the key. + else if (keywordArguments is not null) // If it doesn't, and extra keyword arguments are allowed: + { + // Add the argument to the dictionary, and continue onto the next argument. + keywordArguments.Update(new EzrString(argument.Name, context, argumentObject.StartPosition, argumentObject.EndPosition), argumentObject, result); + + argumentIndex++; + continue; + } + else if (!ignoreExtraArguments) // If extra arguments are not allowed, and ignoreExtraArguments is not set: + { + // Return an error. + result.Failure(new EzrUnexpectedArgumentError($"Did not expect argument \"{argument.Name}\"!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); + return; + } + else // Otherwise, if ignoreExtraArguments is set, continue onto the next argument. + { + argumentIndex++; + continue; + } + } + + // Is the key already exist? + bool hasKey = isValidIndex && context.IsDefined(key); + + // If parameterIndex is out of bounds, or the key is already defined and the argument is a keyword argument, or if all the arguments have already been set: + if (!isValidIndex || (hasKey && (isKeywordArgument || parameterIndex + 1 >= Parameters.Length))) + { + // Return an error. + result.Failure(new EzrUnexpectedArgumentError( + isKeywordArgument + ? $"Did not expect argument \"{key}\", as it is already specified!" + : "Did not expect any more arguments!", + _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); + return; + } + + // Otherwise, if it is not a keyword argument: + if (!isKeywordArgument) + parameterIndex++; // Add to parameterIndex. + + // If the argument is already defined, and it's not a keyword argument, then go to the next iteration while staying on the same argument. + // The parameterIndex will be added to again, and get onto the next required parameter. + if (hasKey) + continue; + + // After all that, update the argument, and set it to the context. + argumentObject.Update(context, argumentObject.StartPosition, argumentObject.EndPosition); + context.Set(null, key, ReferencePool.Get(argumentObject, AccessMod.Private)); + + // Add to the argument index. + argumentIndex++; + } + + // Go through all the parameters. + for (int i = parameterIndex; i < Parameters.Length; i++) + { + (string parameter, Node parameterNode) = Parameters[i]; + + // Check if it is defined: + if (context.IsDefined(parameter)) + continue; // If so, continue to the next. + + // The accessibility modifiers for the execution; if it is a simple access node, the modifiers should be local-only. + AccessMod operationAccessibilityModifiers = parameterNode is VariableAccessNode ? AccessMod.LocalScope : AccessMod.None; + + // Otherwise, execute the parameter source code. + interpreter.VisitNode(parameterNode, context, null, operationAccessibilityModifiers, true); + if (result.ShouldReturn) // Check for errors and return if necessary. + return; + + // If the result is empty, i.e. there is no default value: + if (result.Reference.IsEmpty) + { + // Return an error. + result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{parameter}\"!", _executionContext, StartPosition, EndPosition)); + return; + } + + // Otherwise, if it is still not defined due to strange assignment practises by the programmer: + if (!context.IsDefined(parameter)) + context.Set(null, parameter, ReferencePool.Get(result.Reference.Object, AccessMod.Private)); // Set it. + } + + // If the extra keyword arguments dictionary should be set: + if (KeywordArguments.HasValue) + context.Set(null, KeywordArguments.Value.Name, ReferencePool.Get(new EzrDictionary(keywordArguments!, context, KeywordArguments.Value.StartPosition, KeywordArguments.Value.EndPosition), AccessMod.Private)); // Set it. + } + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + bool equal = StrictEquals(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(equal)); + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + bool equal = StrictEquals(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(!equal)); + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return true; + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashTag; + } + + /// + public override string ToString(RuntimeResult result) + { + string[] paramterNames = Array.ConvertAll(Parameters, parameter => parameter.Name); + return (Parameters.Length > 0, IsAnonymous) switch + { + (true, true) => $"<{TypeName} {ExecutableName}, with \"{string.Join("\", \"", paramterNames)}\">", + (true, false) => $"<{TypeName} \"{ExecutableName}\", with \"{string.Join("\", \"", paramterNames)}\">", + + (false, true) => $"<{TypeName} {ExecutableName}>", + (false, false) => $"<{TypeName} \"{ExecutableName}\">", + }; + } +} diff --git a/src/Runtime/Types/IEzrMutableObject.cs b/src/Runtime/Types/IEzrMutableObject.cs new file mode 100644 index 0000000..1802ebc --- /dev/null +++ b/src/Runtime/Types/IEzrMutableObject.cs @@ -0,0 +1,23 @@ +namespace EzrSquared.Runtime.Types; + +/// +/// A mutable object. +/// +/// The type inheriting this interface. +public interface IMutable +{ + /// + /// Creates a deep copy of the . + /// + /// + /// The deep copy here means that all properties and fields in the object are also copied. + /// + /// Runtime result for raising errors./ + /// The copy, or, if failed. + public IMutable? DeepCopy(RuntimeResult result); +} + +/// +/// A mutable . +/// +public interface IEzrMutableObject : IMutable, IEzrObject { } diff --git a/src/Runtime/Types/IEzrObject.cs b/src/Runtime/Types/IEzrObject.cs new file mode 100644 index 0000000..c5dbfd3 --- /dev/null +++ b/src/Runtime/Types/IEzrObject.cs @@ -0,0 +1,262 @@ +using EzrSquared.Runtime.Nodes; +using EzrSquared.Runtime.Types.Core.Text; + +namespace EzrSquared.Runtime.Types; + +/// +/// An object in the ezr² language. +/// +public interface IEzrObject +{ + /// + /// The name of the type of this object, in plain text, all lowercase. Spaces are allowed. + /// + public string TypeName { get; } + + /// + /// The tag of the type of this object, similar to C# namespace naming conventions. + /// + public string Tag { get; } + + /// + /// The hash of . + /// + public int HashTag { get; } + + /// + /// The starting position of the object in source code. + /// + public Position StartPosition { get; } + + /// + /// The ending position of the object in source code. + /// + public Position EndPosition { get; } + + /// + /// The of the object. + /// + public Context Context { get; } + + /// + /// Updates the context and position of the object. + /// + /// The new context of the object. + /// The new starting position of the object. + /// The new ending position of the object. + public void Update(Context context, Position startPosition, Position endPosition); + + /// + /// Compares the object to another, checks equality. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void ComparisonEqual(IEzrObject other, RuntimeResult result); + + /// + /// Compares the object to another, checks unequality. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void ComparisonNotEqual(IEzrObject other, RuntimeResult result); + + /// + /// Compares the object to another, checks if the current object is less than the other. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void ComparisonLessThan(IEzrObject other, RuntimeResult result); + + /// + /// Compares the object to another, checks if the current object is greater than the other. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void ComparisonGreaterThan(IEzrObject other, RuntimeResult result); + + /// + /// Compares the object to another, checks if the current object is less than or equal to the other. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult result); + + /// + /// Compares the object to another, checks if the current object is greater than or equal to the other. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void ComparisonGreaterThanOrEqual(IEzrObject other, RuntimeResult result); + + /// + /// Performs the addition operation between the current object and another. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void Addition(IEzrObject other, RuntimeResult result); + + /// + /// Performs the subtraction operation between the current object and another. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void Subtraction(IEzrObject other, RuntimeResult result); + + /// + /// Performs the multiplication operation between the current object and another. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void Multiplication(IEzrObject other, RuntimeResult result); + + /// + /// Performs the division operation between the current object and another. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void Division(IEzrObject other, RuntimeResult result); + + /// + /// Performs the modulo operation between the current object and another. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void Modulo(IEzrObject other, RuntimeResult result); + + /// + /// Performs the power or exponent operation between the current object and another. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void Power(IEzrObject other, RuntimeResult result); + + /// + /// Negates the current object. + /// + /// Runtime result for carrying the result and any errors. + public void Negation(RuntimeResult result); + + /// + /// Affirms the current object. + /// + /// Runtime result for carrying the result and any errors. + public void Affirmation(RuntimeResult result); + + /// + /// Performs the bit-wise OR operation between the current object and another. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void BitwiseOr(IEzrObject other, RuntimeResult result); + + /// + /// Performs the bit-wise X-OR operation between the current object and another. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void BitwiseXOr(IEzrObject other, RuntimeResult result); + + /// + /// Performs the bit-wise AND operation between the current object and another. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void BitwiseAnd(IEzrObject other, RuntimeResult result); + + /// + /// Performs the bit-wise left-shift operation between the current object and another. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void BitwiseLeftShift(IEzrObject other, RuntimeResult result); + + /// + /// Performs the bit-wise right-shift operation between the current object and another. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void BitwiseRightShift(IEzrObject other, RuntimeResult result); + + /// + /// Bit-wise negates the current object. + /// + /// Runtime result for carrying the result and any errors. + public void BitwiseNegation(RuntimeResult result); + + /// + /// Checks if the other object is contained in the current object. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void HasValueContained(IEzrObject other, RuntimeResult result); + + /// + /// Checks if the other object is NOT contained in the current object. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public void NotHasValueContained(IEzrObject other, RuntimeResult result); + + /// + /// Inverts the current object, like, for example, true to false. + /// + /// Runtime result for carrying the result and any errors. + public void Inversion(RuntimeResult result); + + /// + /// Evaluates the current object as a boolean value. + /// + /// Runtime result for carrying any errors. + /// The evaluated value. + public bool EvaluateBoolean(RuntimeResult result); + + /// + /// Interprets an AST node in context of the current object. + /// + /// The node to interpret. + /// The context calling on this action. + /// The interpreter to use. + /// Runtime result for carrying any errors. + /// Should the interpretation ignore undefined variables? Useful in getting empty variable references. + public void Interpret(Node code, Context callingContext, Interpreter interpreter, RuntimeResult result, bool ignoreUndefinedVariable = false); + + /// + /// Executes the current object, like a function. + /// + /// The arguments of the execution. + /// The interpreter to be used in execution. + /// Runtime result for carrying any errors. + public void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result); + + /// + /// Strictly compares the current object to another, taking into account inheritance. + /// + /// The other object in the operation. + /// Runtime result for carrying the result and any errors. + public bool StrictEquals(IEzrObject other, RuntimeResult result); + + /// + /// Evaluates the current object as its hash. + /// + /// Runtime result for carrying any errors. + /// The evaluated value. + public int ComputeHashCode(RuntimeResult result); + + /// + /// Evaluates the current object as a string value. + /// + /// Runtime result for carrying any errors. + /// The evaluated value. + public string ToString(RuntimeResult result); + + /// + /// Evaluates the current object as a string value. + /// + /// + /// This is used to show the 'real' string representation of the object. Like, for example, will
+ /// return "example" when called on an object with value "example", but this function will return example (without quotes). + ///
+ /// Runtime result for carrying any errors. + /// The evaluated value. + public string ToPureString(RuntimeResult result); +} diff --git a/src/Runtime/WrapperAttributes/CsealAttribute.cs b/src/Runtime/WrapperAttributes/CsealAttribute.cs new file mode 100644 index 0000000..7096644 --- /dev/null +++ b/src/Runtime/WrapperAttributes/CsealAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace EzrSquared.Runtime.WrapperAttributes; + +/// +/// Attribute for identifying CSAELs (C# Assisted ezr² Libraries). +/// +/// +/// This has not been implemented. It doesn't do anything right now. +/// +[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = true)] +public class CsealAttribute : Attribute +{ +} diff --git a/src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs new file mode 100644 index 0000000..0fd1c89 --- /dev/null +++ b/src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs @@ -0,0 +1,47 @@ +using EzrSquared.Runtime.Types; +using System; +using System.Reflection; + +namespace EzrSquared.Runtime.WrapperAttributes; + +/// +/// Attribute for C# fields and properties which will be wrapped into ezr². +/// +/// The ezr² name for the property or field. +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] +public class SharpFieldWrapperAttribute(string name) : Attribute +{ + /// + /// The ezr² name for the property or field. + /// + public string Name = name; + + /// + /// Is the property or field read-only? + /// + public bool IsReadOnly; + + /// + /// Checks if the given field is of type . + /// + /// The field. + /// if the check was successful, an otherwise. + public static ArgumentException? ValidateField(FieldInfo fieldInfo) + { + return !typeof(IEzrObject).IsAssignableFrom(fieldInfo.FieldType) + ? new($"Expected field \"{fieldInfo.Name}\" to be of type {nameof(IEzrObject)}, as it uses the attribute \"{nameof(SharpFieldWrapperAttribute)}\"", fieldInfo.Name) + : null; + } + + /// + /// Checks if the given property is of type . + /// + /// The property. + /// if the check was successful, an otherwise. + public static ArgumentException? ValidateProperty(PropertyInfo propertyInfo) + { + return !typeof(IEzrObject).IsAssignableFrom(propertyInfo.PropertyType) + ? new($"Expected property \"{propertyInfo.Name}\" to be of type {nameof(IEzrObject)}, as it uses the attribute \"{nameof(SharpFieldWrapperAttribute)}\"", propertyInfo.Name) + : null; + } +} diff --git a/src/Runtime/WrapperAttributes/SharpMethodParameters.cs b/src/Runtime/WrapperAttributes/SharpMethodParameters.cs new file mode 100644 index 0000000..0d2e28d --- /dev/null +++ b/src/Runtime/WrapperAttributes/SharpMethodParameters.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; + +namespace EzrSquared.Runtime.WrapperAttributes; + +/// +/// Class for the paramters of a wrapped C# method. +/// +/// See . +/// See . +/// See . +/// See . +/// See . +/// See . +/// See . +/// See . +public class SharpMethodParameters( + Dictionary argumentReferences, + Context executionContext, + Context creationContext, + Context methodContext, + Position startPosition, + Position endPosition, + Interpreter interpreter, + RuntimeResult result) +{ + /// + /// The references to the actual ezr² arguments. + /// + public Dictionary ArgumentReferences = argumentReferences; + + /// + /// The context under which the method is being executed. + /// + public Context ExecutionContext = executionContext; + + /// + /// The context under which the method wrapper was created. + /// + public Context CreationContext = creationContext; + + /// + /// The context of the method wrapper itself. + /// + public Context MethodContext = methodContext; + + /// + /// The starting position of the method wrapper object. + /// + public Position StartPosition = startPosition; + + /// + /// The ending position of the method wrapper object. + /// + public Position EndPosition = endPosition; + + /// + /// The interpreter executing the method. + /// + public Interpreter Interpreter = interpreter; + + /// + /// The runtime result to return values or to throw errors. + /// + public RuntimeResult Result = result; +} diff --git a/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs new file mode 100644 index 0000000..fc06c43 --- /dev/null +++ b/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs @@ -0,0 +1,67 @@ +global using EzrSharpSourceWrappableMethod = System.Action; + +using System; +using System.Reflection; + +namespace EzrSquared.Runtime.WrapperAttributes; + +/// +/// Attribute for C# methods which will be wrapped into ezr². +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] +public class SharpMethodWrapperAttribute : Attribute +{ + /// + /// The ezr² name for the method. + /// + public readonly string Name = string.Empty; + + /// + /// The ezr² names of the required parameters of the method. + /// + public string[] RequiredParameters = []; + + /// + /// The ezr² names of the optional parameters of the method. + /// + public string[] OptionalParameters = []; + + /// + /// Does this method support additional keyword arguments (kwargs)? + /// + public bool HasKeywordArguments; + + /// + /// Creates a new instance of with a name. + /// + /// The ezr² name for the method. + public SharpMethodWrapperAttribute(string name) + { + Name = name; + } + + /// + /// Creates a new instance of . + /// + public SharpMethodWrapperAttribute() { } + + /// + /// Checks if the given method has all the required parameter. + /// + /// The method. + /// if the check was successful, an otherwise. + public static Exception? ValidateMethodParameters(MethodInfo methodInfo) + { + // Get the parameter types of the method + Type[] parameterTypes = Array.ConvertAll(methodInfo.GetParameters(), p => p.ParameterType); + + // Check if the number of parameters matches + if (parameterTypes.Length != 1) + return new TargetParameterCountException($"\"{methodInfo.Name}\": Method must have exactly one parameter, as it uses the {nameof(SharpMethodWrapperAttribute)} attribute."); + + // Check if the required parameter types match + return parameterTypes[0] != typeof(SharpMethodParameters) + ? new FormatException($"\"{methodInfo.Name}\": Parameter 1 must be of type {nameof(SharpMethodParameters)}, as it uses the {nameof(SharpMethodWrapperAttribute)} attribute.") + : null; + } +} diff --git a/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs new file mode 100644 index 0000000..6c134d7 --- /dev/null +++ b/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs @@ -0,0 +1,31 @@ +using System; + +namespace EzrSquared.Runtime.WrapperAttributes; + +/// +/// Attribute for C# classes which will be wrapped into ezr². +/// +/// The ezr² name for the type. +/// The name of the static constructor method. See for more details. +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] +public class SharpTypeWrapperAttribute(string name, string constructor) : Attribute +{ + /// + /// The ezr² name for the type. + /// + public readonly string Name = name; + + /// + /// The name of the static constructor method. + /// + /// + /// The static constructor method should have the following arguments: + ///
Context context, + ///
Position startPosition, + ///
Position endPosition, + ///
Dictionary<, EzrObjectReference> arguments, + ///
interpreter, + ///
result + ///
+ public readonly string Constructor = constructor; +} \ No newline at end of file diff --git a/src/Shell/Directory.Build.props b/src/Shell/Directory.Build.props new file mode 100644 index 0000000..bfde4f7 --- /dev/null +++ b/src/Shell/Directory.Build.props @@ -0,0 +1,6 @@ + + + ..\..\Binaries\Shell\ + ..\..\Intermediates\Shell\ + + \ No newline at end of file diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs new file mode 100644 index 0000000..26136c1 --- /dev/null +++ b/src/Shell/EzrShell.cs @@ -0,0 +1,154 @@ +using EzrSquared; +using EzrSquared.Executor; +using EzrSquared.Runtime.Types.Collections; +using System; +using System.IO; +using System.Text; + +namespace EzrSquaredCli; + +/// +/// The built-in shell for ezrSquared. +/// +internal class Shell +{ + private const string Version = "0.1.0"; + + private static bool s_showLexerOutput; + private static bool s_showParserOutput; + private static string s_filePath = string.Empty; + + public static void Main() + { + Console.OutputEncoding = Encoding.Unicode; + + string[] commandLineArguments = Environment.GetCommandLineArgs(); + if (!ParseCommandLineArguments(commandLineArguments)) + return; + +#if DEBUG + Console.Write("File to read (press the 'enter' key to enter interactive mode): "); + string? filePath = Console.ReadLine(); + + if (File.Exists(filePath)) + s_filePath = filePath; + else if (!string.IsNullOrEmpty(filePath)) + { + EzrShellConsoleHelper.ShowError($"File not found: \"{filePath}\""); + Console.Write("Press any key to enter interactive mode..."); + Console.ReadKey(); + } +#endif + + if (!string.IsNullOrEmpty(s_filePath)) + ExecuteFile(); + else + InteractiveMode(); + + Console.ResetColor(); + } + + private static bool ParseCommandLineArguments(string[] arguments) + { + for (int i = 1; i < arguments.Length; i++) + { + switch (arguments[i]) + { + case "-l": + case "--lexer-output": + s_showLexerOutput = true; + break; + case "-p": + case "--parser-output": + s_showParserOutput = true; + break; + case "-h": + case "--help": + ShowHelp(); + Console.ResetColor(); + return false; + default: + if (!string.IsNullOrEmpty(s_filePath) && File.Exists(arguments[i])) + s_filePath = arguments[i]; + else + { + EzrShellConsoleHelper.ShowError("Invalid argument or file not found."); + return false; + } + break; + } + } + + return true; + } + + private static void ShowHelp() + { + EzrShellConsoleHelper.ShowOutput(""" + Help for the `ezrSquared` command: + Intended use: + ezrSquared [file] [-h or --help] [-l or --lexer-output] [-p or --parser-output] + + file : File/script to execute. If not given, starts in interactive mode. + -h or --help : Show this help screen. + -l or --lexer-output : Show the output of the Lexer. Only for debugging purposes. + -p or --parser-output : Show the output of the Parser. Only for debugging purposes. + """); + } + + private static void ExecuteFile() + { + CodeExecutor.CreateRuntimeContext(s_filePath); + CodeExecutor.PopulateRuntimeContext(); + + ExecuteCode(File.ReadAllText(s_filePath, Encoding.UTF8)); + EzrShellConsoleHelper.WaitForUser(); + } + + private static void InteractiveMode() + { + if (Console.WindowWidth > 100) + EzrShellConsoleHelper.PrintBigConsoleGraphics(Version); + else + EzrShellConsoleHelper.PrintSmallConsoleGraphics(Version); + + CodeExecutor.CreateRuntimeContext("shell"); + CodeExecutor.PopulateRuntimeContext(); + + while (true) + { + string? input = EzrShellConsoleHelper.GetShellInput(); + if (input?.Trim()?.Equals("\\editor", StringComparison.OrdinalIgnoreCase) == true) + input = EzrShellEditor.StartShellEditor(); + + if (!string.IsNullOrEmpty(input)) + ExecuteCode(input); + } + } + + private static bool ExecuteCode(string script) + { + ExecutionResult result = CodeExecutor.Execute(script); + if (s_showLexerOutput) + EzrShellConsoleHelper.ShowVerbose($"Lexer output:\n - {string.Join("\n - ", result.Tokens)}"); + + if (s_showParserOutput) + EzrShellConsoleHelper.ShowVerbose($"Parser output:\n{result.Ast}"); + + if (!result.Success) + { + EzrShellConsoleHelper.ShowError(result.GetErrorMessage()); + return false; + } + + string outputText = result.Result is EzrArray array && array.Value.Length == 1 + ? array.Value[0].ToString(CodeExecutor.Interpreter.RuntimeResult) + : result.Result!.ToString(CodeExecutor.Interpreter.RuntimeResult); + + if (CodeExecutor.Interpreter.RuntimeResult.Error is not null) + EzrShellConsoleHelper.ShowError(CodeExecutor.Interpreter.RuntimeResult.Error.ToPureString(CodeExecutor.Interpreter.RuntimeResult)); + else + EzrShellConsoleHelper.ShowOutput(outputText); + return true; + } +} \ No newline at end of file diff --git a/src/Shell/EzrShellConsoleHelper.cs b/src/Shell/EzrShellConsoleHelper.cs new file mode 100644 index 0000000..e272d86 --- /dev/null +++ b/src/Shell/EzrShellConsoleHelper.cs @@ -0,0 +1,131 @@ +using System; + +namespace EzrSquaredCli; + +internal static class EzrShellConsoleHelper +{ + private const string ConsoleGraphicsInfo = """ + â–‹ ezr² v{0} + â–‹ Online documentation: + â–‹ https://uralstech.github.io/ezrSquared/Introduction.html + â–‹ Feature requests and bug reports: + â–‹ https://github.com/Uralstech/ezrSquared/issues + â–‹ GitHub repository: + â–‹ https://github.com/Uralstech/ezrSquared/ + â–‹ + â–‹ + â–‹ + â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‚â–‹ + """; + + private const string ConsoleGraphicsLetterE = """ + + ▟███████▙ + ██ ██ + ██ ██ + ████████▛ + ██ + ██ + ██ + ██ + ▜████████ + """; + private const string ConsoleGraphicsLetterZ = """ + + █████████ + ▟█▛ + ▟█▛ + ▟█▛ + ▟█▛ + ▟█▛ + ▟█▛ + ▟█▛ + █████████ + """; + private const string ConsoleGraphicsLetterR = """ + + ██▟█████▙ + ██▛ ▜█ + ██ + ██ + ██ + ██ + ██ + ██ + ██ + """; + private const string ConsoleGraphicsSquaredSymbol = """ + ████▙ + ██ + ▟███▛ + ██ + ▜████ + + + + + """; + + internal static void PrintSmallConsoleGraphics(string version) + { + Console.Clear(); + + ShowMessage("e", ConsoleColor.Green, true); + ShowMessage("z", ConsoleColor.Red); + ShowMessage("r", ConsoleColor.Blue); + ShowMessage("²", ConsoleColor.Yellow); + ShowMessage($" v{version}", ConsoleColor.White); + } + + internal static void PrintBigConsoleGraphics(string version) + { + Console.Clear(); + + ShowMessage(string.Format(ConsoleGraphicsInfo, version), ConsoleColor.White, true); + ShowMessage(ConsoleGraphicsSquaredSymbol, ConsoleColor.Yellow, true); + ShowMessage(ConsoleGraphicsLetterR, ConsoleColor.Blue, true); + ShowMessage(ConsoleGraphicsLetterZ, ConsoleColor.Red, true); + ShowMessage($"{ConsoleGraphicsLetterE}\n", ConsoleColor.Green, true); + } + + internal static void ShowError(string message) + { + ShowMessage(message, ConsoleColor.Red); + } + + internal static void ShowOutput(string message) + { + ShowMessage(message, ConsoleColor.White); + } + + internal static void ShowVerbose(string message) + { + ShowMessage(message, ConsoleColor.DarkGray); + } + + internal static string? GetShellInput(string? prompt = null, int? line = null) + { + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = ConsoleColor.Yellow; + Console.Write(line.HasValue ? $"{line} >>> {prompt}" : $">>> {prompt}"); + return Console.ReadLine(); + } + + internal static void WaitForUser() + { + Console.ResetColor(); + + Console.Write("Press any key to continue..."); + Console.ReadKey(); + } + + private static void ShowMessage(string message, ConsoleColor color, bool resetPosition = false) + { + if (resetPosition) + Console.SetCursorPosition(0, 0); + + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = color; + Console.WriteLine(message); + } +} diff --git a/src/Shell/EzrShellEditor.cs b/src/Shell/EzrShellEditor.cs new file mode 100644 index 0000000..df5dd8a --- /dev/null +++ b/src/Shell/EzrShellEditor.cs @@ -0,0 +1,110 @@ +using System.IO; +using System.Text; +using System; + +namespace EzrSquaredCli; + +internal class EzrShellEditor +{ + internal static string? StartShellEditor() + { + StringBuilder scriptBuilder = new(); + int line = 1; + string filepath = string.Empty; + + bool running = true; + while (running) + { + string? input = EzrShellConsoleHelper.GetShellInput(line: line); + if (input is null) + continue; + + switch (input.Trim()) + { + case "\\run": + return scriptBuilder.ToString(); + case "\\clear": + ConfirmAndClearScript(scriptBuilder); + break; + case "\\save": + SaveScriptToFile(scriptBuilder, ref filepath); + break; + case "\\quit": + running = !ConfirmAndQuitEditor(); + break; + + default: + scriptBuilder.AppendLine(input); + line++; + + AppendScriptToFile(input, filepath); + break; + } + } + + return null; + } + + private static void ConfirmAndClearScript(StringBuilder scriptBuilder) + { + string? confirmation = EzrShellConsoleHelper.GetShellInput("Are you sure? You will lose this script forever. (y/N) "); + if (confirmation?.Equals("y", StringComparison.OrdinalIgnoreCase) == true) + scriptBuilder.Clear(); + } + + private static bool ConfirmAndQuitEditor() + { + string? confirmation = EzrShellConsoleHelper.GetShellInput("Are you sure? You will lose this script forever. (y/N) "); + return confirmation?.Equals("y", StringComparison.OrdinalIgnoreCase) == true; + } + + private static void SaveScriptToFile(StringBuilder scriptBuilder, ref string filepath) + { + string? userFilePath = EzrShellConsoleHelper.GetShellInput("Save filepath: "); + if (string.IsNullOrEmpty(userFilePath) || !IsValidPath(userFilePath)) + { + EzrShellConsoleHelper.ShowError("Invalid file path!"); + return; + } + + userFilePath = Path.GetFullPath(userFilePath); + if (File.Exists(userFilePath)) + { + string? confirmation = EzrShellConsoleHelper.GetShellInput($"There is already a file at \"{userFilePath}\". If you continue with the operation, ezr² will erase the file. Do you want to continue? (y/N) "); + if (confirmation?.Equals("y", StringComparison.OrdinalIgnoreCase) != true) + return; + } + + string? directory = Path.GetDirectoryName(userFilePath); + if (string.IsNullOrEmpty(directory)) + { + EzrShellConsoleHelper.ShowError("Could not get directory path!"); + return; + } + + if (!Directory.Exists(directory)) + Directory.CreateDirectory(directory); + + filepath = userFilePath; + File.WriteAllText(filepath, scriptBuilder.ToString()); + } + + private static void AppendScriptToFile(string input, string filepath) + { + if (!string.IsNullOrEmpty(filepath)) + File.AppendAllText(filepath, $"\n{input}"); + } + + private static bool IsValidPath(string path, bool allowRelativePaths = false) + { + try + { + string fullPath = Path.GetFullPath(path); + return allowRelativePaths || Path.IsPathRooted(fullPath); + } + catch + { + return false; + } + } +} diff --git a/src/installer/environment.iss b/src/Shell/InstallerSrc/environment.iss similarity index 100% rename from src/installer/environment.iss rename to src/Shell/InstallerSrc/environment.iss diff --git a/src/installer/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss similarity index 84% rename from src/installer/ezrSquared 32-bit.iss rename to src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 19f0480..5eaaad6 100644 --- a/src/installer/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "1.0.0" +#define MyAppVersion "0.1.0" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" @@ -34,8 +34,8 @@ InfoAfterFile=D:\Code\csharp\ezrSquared\Changelog.txt ; Remove the following line to run in administrative install mode (install for all users.) PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog -OutputDir=D:\Code\csharp\ezrSquared\bin\Installer\ -OutputBaseFilename=ezrSquared Installer (Windows 32-bit) +OutputDir=D:\Code\csharp\ezrSquared\Binaries\Installer\ +OutputBaseFilename=ezr² Installer (Windows 32-bit) SetupIconFile=D:\Code\csharp\ezrSquared\src\Icon.ico Compression=lzma SolidCompression=yes @@ -53,13 +53,14 @@ LocalDocumentation=%1 Offline Documentation [Types] Name: "full"; Description: "Full installation" -Name: "compact"; Description: "Compact installation" +Name: "compact"; Description: "Compact installation - Without documentation" +Name: "bareMinimum"; Description: "The bare minimum - Excludes the standard libraries" Name: "custom"; Description: "Custom installation"; Flags: iscustom [Components] -Name: "main"; Description: "ezr² Interpreter"; Types: full compact custom; Flags: fixed -Name: "libs"; Description: "Standard Libraries"; Types: full compact -Name: "docs"; Description: "Documentation"; Types: full +Name: "main"; Description: "ezr² Code Executor"; Types: full compact bareMinimum custom; Flags: fixed +Name: "libs"; Description: "ezr² Standard Libraries"; Types: full compact +Name: "docs"; Description: "ezr² Documentation"; Types: full [Tasks] Name: "addtopath"; Description: "Add ezr² to PATH environment variable"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce @@ -70,8 +71,8 @@ Name: "{app}\Libraries" [Files] Source: "D:\Code\csharp\ezrSquared\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion -Source: "D:\Code\csharp\ezrSquared\bin\ezrSquared\Release\net7.0-windows10.0.22621.0\win-x86\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion -Source: "D:\Code\csharp\ezrSquared\bin\ezrSquared\Release\net7.0-windows10.0.22621.0\win-x86\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x86\publish\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion +Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x86\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "D:\Code\csharp\ezrSquared\docs\offline\_site\*"; DestDir: "{app}\Documentation"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: docs Source: "D:\Code\csharp\ezrSquared\bin\Libraries\IO\Release\net7.0-windows10.0.22621.0\win-x86\IO.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs Source: "D:\Code\csharp\ezrSquared\bin\Libraries\STD\Release\net7.0-windows10.0.22621.0\win-x86\STD.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs diff --git a/src/installer/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss similarity index 84% rename from src/installer/ezrSquared 64-bit.iss rename to src/Shell/InstallerSrc/ezrSquared 64-bit.iss index d7863a7..44af479 100644 --- a/src/installer/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "1.0.0" +#define MyAppVersion "0.1.0" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" @@ -35,8 +35,8 @@ InfoAfterFile=D:\Code\csharp\ezrSquared\Changelog.txt ; Remove the following line to run in administrative install mode (install for all users.) PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog -OutputDir=D:\Code\csharp\ezrSquared\bin\Installer\ -OutputBaseFilename=ezrSquared Installer (Windows 64-bit) +OutputDir=D:\Code\csharp\ezrSquared\Binaries\Installer\ +OutputBaseFilename=ezr² Installer (Windows 64-bit) SetupIconFile=D:\Code\csharp\ezrSquared\src\Icon.ico Compression=lzma SolidCompression=yes @@ -54,13 +54,14 @@ LocalDocumentation=%1 Offline Documentation [Types] Name: "full"; Description: "Full installation" -Name: "compact"; Description: "Compact installation" +Name: "compact"; Description: "Compact installation - Without documentation" +Name: "bareMinimum"; Description: "The bare minimum - Excludes the standard libraries" Name: "custom"; Description: "Custom installation"; Flags: iscustom [Components] -Name: "main"; Description: "ezr² Interpreter"; Types: full compact custom; Flags: fixed -Name: "libs"; Description: "Standard Libraries"; Types: full compact -Name: "docs"; Description: "Documentation"; Types: full +Name: "main"; Description: "ezr² Code Executor"; Types: full compact bareMinimum custom; Flags: fixed +Name: "libs"; Description: "ezr² Standard Libraries"; Types: full compact +Name: "docs"; Description: "ezr² Documentation"; Types: full [Tasks] Name: "addtopath"; Description: "Add ezr² to PATH environment variable"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce @@ -71,8 +72,8 @@ Name: "{app}\Libraries" [Files] Source: "D:\Code\csharp\ezrSquared\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion -Source: "D:\Code\csharp\ezrSquared\bin\ezrSquared\Release\net7.0-windows10.0.22621.0\win-x64\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion -Source: "D:\Code\csharp\ezrSquared\bin\ezrSquared\Release\net7.0-windows10.0.22621.0\win-x64\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x64\publish\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion +Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x64\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "D:\Code\csharp\ezrSquared\docs\offline\_site\*"; DestDir: "{app}\Documentation"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: docs Source: "D:\Code\csharp\ezrSquared\bin\Libraries\IO\Release\net7.0-windows10.0.22621.0\win-x64\IO.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs Source: "D:\Code\csharp\ezrSquared\bin\Libraries\STD\Release\net7.0-windows10.0.22621.0\win-x64\STD.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj new file mode 100644 index 0000000..b8282a0 --- /dev/null +++ b/src/Shell/Shell.csproj @@ -0,0 +1,53 @@ + + + Exe + win-x64;linux-x64;osx-x64 + AnyCPU;x64;arm64 + net8.0 + 12 + + Disable + Enable + + EzrSquaredCli.Shell + + True + + True + True + + + + ezrSquaredShell + ezrSquared + + The ezrSquared Command Line Interface + The Command Line Interface for the ezrSquared programming language. + + 0.1.0 + + Udayshankar Ravikumar + URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED + © 2022 - 2024 URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED + + en + + ..\..\Graphics\Icon.ico + + https://github.com/uralstech/ezrSquared + + + + True + + + + + ..\..\Binaries\ezrSquared\Release\net8.0\ezrSquared-lib.dll + + + + + + + diff --git a/src/Syntax/Errors/StackedSyntaxError.cs b/src/Syntax/Errors/StackedSyntaxError.cs new file mode 100644 index 0000000..4d3d0a9 --- /dev/null +++ b/src/Syntax/Errors/StackedSyntaxError.cs @@ -0,0 +1,18 @@ +namespace EzrSquared.Syntax.Errors; + +/// +/// The returned when multiple objects need to be returned to the user. +/// +/// The 'parent' error, or the error that occurred first. +/// The 'child' error, or the error that occurred because of the . +internal class StackedSyntaxError(SyntaxError parent, SyntaxError child) : SyntaxError("Multiple errors", $"{parent}\n\nDue to the above error, another one occurred:\n{child}", parent._startPosition, parent._endPosition) +{ + /// + /// Creates the formatted text representation of the , which shows all child objects as the 'details'. + /// + /// The formatted text. + public override string ToString() + { + return _details; + } +} diff --git a/src/Syntax/Errors/SyntaxError.cs b/src/Syntax/Errors/SyntaxError.cs new file mode 100644 index 0000000..d61a249 --- /dev/null +++ b/src/Syntax/Errors/SyntaxError.cs @@ -0,0 +1,53 @@ +using EzrSquared.Util; + +namespace EzrSquared.Syntax.Errors; + +/// +/// Error class for all syntax error. +/// +/// The title of the . +/// The reason why the occurred. +/// The starting of the . +/// The ending of the . +public class SyntaxError(string title, string details, Position startPosition, Position endPosition) +{ + /// An unexpected character was encountered. + public const string UnexpectedCharacter = "Unexpected character"; + + /// An invalid hexadecimal value was encountered. + public const string InvalidHexValue = "Invalid hexadecimal value"; + + /// Invalid grammar was encountered. + public const string InvalidGrammar = "Invalid grammar"; + + /// + /// The name of the . + /// + protected internal readonly string _title = title; + + /// + /// The reason why the occurred. + /// + protected internal readonly string _details = details; + + /// + /// The starting of the . + /// + protected internal readonly Position _startPosition = startPosition; + + /// + /// The ending of the . + /// + protected internal readonly Position _endPosition = endPosition; + + /// + /// Creates the formatted text representation of the . + /// + /// The formatted text. + public override string ToString() + { + (int adjustedLineNumber, string sourceWithUnderline) = Utils.SourceWithUnderline(_startPosition, _endPosition); + + return $"{_title} in {_startPosition.File}, line {adjustedLineNumber}: {_details}\n{sourceWithUnderline}"; + } +} diff --git a/src/Syntax/Lexer.cs b/src/Syntax/Lexer.cs new file mode 100644 index 0000000..1e7fe36 --- /dev/null +++ b/src/Syntax/Lexer.cs @@ -0,0 +1,657 @@ +using EzrSquared.Syntax.Errors; +using System; +using System.Collections.Generic; +using System.Text; + +namespace EzrSquared.Syntax; + +/// +/// The ezr² Lexer or Tokenizer. The job of the Lexer is to convert the user input (code) into objects to be given as the input to the . +/// +public class Lexer +{ + /// + /// The file name/path of the script. + /// + private readonly string _file; + + /// + /// The script to be tokenized. + /// + private readonly string _script; + + /// + /// The of the current lexing iteration in the script. + /// + private readonly Position _position; + + /// + /// The character in the of the current lexing iteration in the script. + /// + private char _currentChar; + + /// + /// The value for checking if the has reached the end of the script. + /// + private bool _reachedEnd; + + /// + /// Creates a new object. + /// + /// The file name/path of the script. + /// The script to be tokenized. + public Lexer(string file, string script) + { + _file = file; + _script = script; + _position = new Position(-1, 1, _file, _script); + _currentChar = char.MinValue; + Advance(); + } + + /// + /// Advances the current in the script. + /// + private void Advance() + { + if (_reachedEnd) + return; + + _position.Advance(_currentChar); + + if (_script.Length > _position.Index) + _currentChar = _script[_position.Index]; + else + { + _reachedEnd = true; + _currentChar = '\0'; + } + } + + /// + /// Reverses to the given index. + /// + /// + /// Warning: The decrement is hard set to one if the character at is a newline, and zero otherwise. + /// + /// The index to reverse to. + private void ReverseTo(int index) + { + _position.ReverseTo(index, _script[index] == '\n' ? 1 : 0); + _currentChar = _script[_position.Index]; + } + +/// +/// Creates a of objects from the given script. +/// +/// The created of objects. +/// Any that occurred in the lexing; if none occurred. +public SyntaxError? Tokenize(out List tokens) + { + SyntaxError? error; + tokens = []; + while (!_reachedEnd) + { + switch (_currentChar) + { + case '\r': + case '\t': + case ' ': + Advance(); + break; + case ';': + case '\n': + tokens.Add(CompileNewLines()); + break; + case '@': + SkipComment(); + break; + case '"': + case '`': + case '\'': + tokens.Add(CompileStringLike(out error)); + if (error is not null) + return error; + break; + case ':': + tokens.Add(CompileColon()); + break; + case '<': + Position lessThanTokenStartPosition = _position.Copy(); + Advance(); + + switch (_currentChar) + { + case '=': + Advance(); + tokens.Add(new Token(TokenType.LessThanOrEqual, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); + break; + + case '<': + Advance(); + tokens.Add(new Token(TokenType.BitwiseLeftShift, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); + break; + + default: + tokens.Add(new Token(TokenType.LessThanSign, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); + break; + } + break; + case '>': + Position greaterThanTokenStartPosition = _position.Copy(); + Advance(); + + switch (_currentChar) + { + case '=': + Advance(); + tokens.Add(new Token(TokenType.GreaterThanOrEqual, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + break; + + case '>': + Advance(); + tokens.Add(new Token(TokenType.BitwiseRightShift, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + break; + + default: + tokens.Add(new Token(TokenType.GreaterThanSign, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + break; + } + break; + case '-': + tokens.Add(new Token(TokenType.HyphenMinus, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '+': + tokens.Add(new Token(TokenType.Plus, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '*': + tokens.Add(new Token(TokenType.Asterisk, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '/': + tokens.Add(new Token(TokenType.Slash, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '%': + tokens.Add(new Token(TokenType.PercentSign, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '^': + tokens.Add(new Token(TokenType.Caret, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '=': + tokens.Add(new Token(TokenType.EqualSign, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '!': + tokens.Add(new Token(TokenType.ExclamationMark, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case ',': + tokens.Add(new Token(TokenType.Comma, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '.': + tokens.Add(new Token(TokenType.Period, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '(': + tokens.Add(new Token(TokenType.LeftParenthesis, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case ')': + tokens.Add(new Token(TokenType.RightParenthesis, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '[': + tokens.Add(new Token(TokenType.LeftSquareBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case ']': + tokens.Add(new Token(TokenType.RightSquareBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '{': + tokens.Add(new Token(TokenType.LeftCurlyBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '}': + tokens.Add(new Token(TokenType.RightCurlyBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '&': + tokens.Add(new Token(TokenType.Ampersand, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '|': + tokens.Add(new Token(TokenType.VerticalBar, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '\\': + tokens.Add(new Token(TokenType.Backslash, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '~': + tokens.Add(new Token(TokenType.Tilde, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + Advance(); + break; + case '_': + case char current when char.IsLetter(current): + tokens.Add(CompileIdentifier()); + break; + case char current when char.IsDigit(current): + tokens.Add(CompileNumber()); + break; + + default: + Position errorStartPosition = _position.Copy(); + char unknownCharacter = _currentChar; + Advance(); + + return new SyntaxError(SyntaxError.UnexpectedCharacter, unknownCharacter.ToString(), errorStartPosition, _position); + } + } + + tokens.Add(new Token(TokenType.EndOfFile, TokenTypeGroup.Special, string.Empty, _position.Copy())); + return null; + } + + private void SkipComment() + { + do + { + Advance(); + } while (!_reachedEnd && _currentChar != '\n'); + } + + /// + /// Goes through digit and period characters and creates a single object with or . + /// + /// The object. + private Token CompileNumber() + { + StringBuilder numberValue = new(); + Position numberTokenStartPosition = _position.Copy(); + bool hasPeriod = false; + + while (!_reachedEnd && (char.IsDigit(_currentChar) || _currentChar == '.')) + { + if (_currentChar == '.') + { + int peekIndex = _position.Index + 1; + char next = peekIndex < _script.Length ? _script[peekIndex] : '\0'; + + if (hasPeriod || !char.IsDigit(next)) + break; + + hasPeriod = true; + } + + numberValue.Append(_currentChar); + Advance(); + } + + return new Token( + hasPeriod ? TokenType.FloatingPoint : TokenType.Integer, + TokenTypeGroup.Value, + numberValue.ToString(), + numberTokenStartPosition, + _position.Copy() + ); + } + + /// + /// Goes through newline characters and creates a single object with . + /// + /// The object. + private Token CompileNewLines() + { + int lastNewLineIndex = _position.Index; + while (!_reachedEnd && (char.IsWhiteSpace(_currentChar) || _currentChar == ';')) + { + Advance(); + if (_currentChar is '\n' or ';' or '@') + { + if (_currentChar == '@') + { + SkipComment(); + if (_reachedEnd) + break; + } + + lastNewLineIndex = _position.Index; + } + } + + ReverseTo(lastNewLineIndex); + Position startPosition = _position.Copy(); + + Advance(); + return new Token(TokenType.NewLine, TokenTypeGroup.Special, string.Empty, startPosition, _position.Copy()); + } + + /// + /// Creates a of types , or , depending on the enclosing character. + /// + /// Any that occurred in creating the stringlike; if none occurred. + /// The created . + private Token CompileStringLike(out SyntaxError? error) + { + char enclosingChar = _currentChar; + + StringBuilder toReturn = new(); + Position startPosition = _position.Copy(); + error = null; + + Advance(); + + while (!_reachedEnd && _currentChar != enclosingChar) + { + if (_currentChar == '\\') + { + ProcessEscapeSequence(toReturn, ref error); + if (error is not null) + return Token.Empty; + } + else + { + toReturn.Append(_currentChar); + Advance(); + } + } + + if (_currentChar != enclosingChar) + { + Position errorStartPosition = _position.Copy(); + _position.Advance(); + + error = new SyntaxError(SyntaxError.InvalidGrammar, $"Expected '{enclosingChar}'!", errorStartPosition, _position); + return Token.Empty; + } + + Advance(); + if (enclosingChar == '`' && ((toReturn.Length > 1 is bool tooLong && tooLong) || toReturn.Length == 0)) + { + error = new SyntaxError(SyntaxError.InvalidGrammar, + tooLong + ? "Value too long to be a character!" + : "A character cannot be empty!", startPosition, _position); + + return Token.Empty; + } + + return new Token( + enclosingChar switch + { + '`' => TokenType.Character, + '\'' => TokenType.CharacterList, + _ => TokenType.String + }, + TokenTypeGroup.Value, + toReturn.ToString(), + startPosition, + _position.Copy()); + } + + /// + /// Processes an escape sequence in a stringlike. + /// + /// The to append the special character to. + /// Any that occurred in the process; if none occurred. + private void ProcessEscapeSequence(StringBuilder builder, ref SyntaxError? error) + { + Position startPosition = _position.Copy(); + Advance(); + + switch (_currentChar) + { + case 'u': + builder.Append(ProcessUtf16Sequence(ref error)); + break; + case 'U': + builder.Append(ProcessUtf32Sequence(ref error)); + break; + case 'n': + builder.Append('\n'); + Advance(); + break; + case 't': + builder.Append('\t'); + Advance(); + break; + case 'b': + builder.Append('\b'); + Advance(); + break; + case 'r': + builder.Append('\r'); + Advance(); + break; + case '0': + builder.Append('\0'); + Advance(); + break; + case 'f': + builder.Append('\f'); + Advance(); + break; + case 'v': + builder.Append('\v'); + Advance(); + break; + case '"': + case '\'': + case '`': + case '\\': + builder.Append(_currentChar); + Advance(); + break; + default: + error = new SyntaxError(SyntaxError.UnexpectedCharacter, $"Unknown escape sequence '\\{_currentChar}'.", startPosition, _position); + break; + } + } + + /// + /// Processes a UTF-16 escaped sequence in a stringlike. + /// + /// Any that occurred in the process; if none occurred. + /// The UTF-16 character. + private char[] ProcessUtf16Sequence(ref SyntaxError? error) + { + int characterCount = 0; + string hexValue = string.Empty; + Position startPosition = _position.Copy(); + + Advance(); + while (characterCount < 4) + { + if (_currentChar is (>= 'a' and <= 'f') or (>= 'A' and <= 'F') or (>= '0' and <= '9')) + { + characterCount++; + hexValue += _currentChar; + Advance(); + } + else + { + Position endPosition = _position.Copy(); + endPosition.Advance(); + + error = new SyntaxError(SyntaxError.InvalidHexValue, "UTF-16 hexadecimal values must be 4 characters long and only contain digits and the letters A to F!", startPosition, endPosition); + return []; + } + } + + return Encoding.Unicode.GetChars([Convert.ToByte(hexValue[2..4], 16), Convert.ToByte(hexValue[0..2], 16)]); + } + + /// + /// Processes a UTF-32 escaped sequence in a stringlike. + /// + /// Any that occurred in the process; if none occurred. + /// The UTF-32 character. + private string ProcessUtf32Sequence(ref SyntaxError? error) + { + int characterCount = 0; + string hexValue = string.Empty; + Position startPosition = _position.Copy(); + + Advance(); + while (characterCount < 6) + { + if (_currentChar is (>= 'a' and <= 'f') or (>= 'A' and <= 'F') or (>= '0' and <= '9')) + { + characterCount++; + hexValue += _currentChar; + Advance(); + } + else + { + Position endPosition = _position.Copy(); + endPosition.Advance(); + + error = new SyntaxError(SyntaxError.InvalidHexValue, "UTF-32 hexadecimal values must be 6 characters long and only contain digits and the letters A to F!", startPosition, endPosition); + return string.Empty; + } + } + + int unicodePoint = Convert.ToInt32(hexValue, 16); + if (unicodePoint > 0x10FFFF) + { + error = new SyntaxError(SyntaxError.InvalidHexValue, "UTF-32 hexadecimal values must be in range 000000 - 10FFFF!", startPosition, _position); + return string.Empty; + } + + return char.ConvertFromUtf32(unicodePoint); + } + + /// + /// Creates and assignment type (, , etc) objects. + /// + /// The created . + private Token CompileColon() + { + Position startPosition = _position.Copy(); + Advance(); + + switch (_currentChar) + { + case '+': + Advance(); + return new Token(TokenType.AssignmentAddition, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + case '-': + Advance(); + return new Token(TokenType.AssignmentSubtraction, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + case '*': + Advance(); + return new Token(TokenType.AssignmentMultiplication, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + case '/': + Advance(); + return new Token(TokenType.AssignmentDivision, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + case '%': + Advance(); + return new Token(TokenType.AssignmentModulo, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + case '^': + Advance(); + return new Token(TokenType.AssignmentPower, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + case '&': + Advance(); + return new Token(TokenType.AssignmentBitwiseAnd, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + case '|': + Advance(); + return new Token(TokenType.AssignmentBitwiseOr, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + case '\\': + Advance(); + return new Token(TokenType.AssignmentBitwiseXOr, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + case '<': + Advance(); + return new Token(TokenType.AssignmentBitwiseLeftShift, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + case '>': + Advance(); + return new Token(TokenType.AssignmentBitwiseRightShift, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + default: + return new Token(TokenType.Colon, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + } + } + + /// + /// Creates , keyword type (, , etc) and qeyword type (, , etc) objects. + /// + /// The created . + private Token CompileIdentifier() + { + Position startPosition = _position.Copy(); + StringBuilder idValue = new(); + + while (!_reachedEnd && (char.IsLetterOrDigit(_currentChar) || _currentChar == '_')) + { + idValue.Append(_currentChar); + Advance(); + } + + string original = idValue.ToString(); + return original.ToLower() switch + { + "private" => new Token(TokenType.KeywordPrivate, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "constant" => new Token(TokenType.KeywordConstant, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "readonly" => new Token(TokenType.KeywordReadonly, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "item" => new Token(TokenType.KeywordItem, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "and" => new Token(TokenType.KeywordAnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "or" => new Token(TokenType.KeywordOr, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "invert" => new Token(TokenType.KeywordInvert, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "if" => new Token(TokenType.KeywordIf, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "else" => new Token(TokenType.KeywordElse, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "do" => new Token(TokenType.KeywordDo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "count" => new Token(TokenType.KeywordCount, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "from" => new Token(TokenType.KeywordFrom, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "as" => new Token(TokenType.KeywordAs, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "to" => new Token(TokenType.KeywordTo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "step" => new Token(TokenType.KeywordStep, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "while" => new Token(TokenType.KeywordWhile, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "function" => new Token(TokenType.KeywordFunction, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + +#pragma warning disable CS0618 + "special" => new Token(TokenType.KeywordSpecial, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), +#pragma warning restore CS0618 + + "with" => new Token(TokenType.KeywordWith, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "more" => new Token(TokenType.KeywordMore, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "end" => new Token(TokenType.KeywordEnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "return" => new Token(TokenType.KeywordReturn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "last" => new Token(TokenType.KeywordLast, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "skip" => new Token(TokenType.KeywordSkip, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "stop" => new Token(TokenType.KeywordStop, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "try" => new Token(TokenType.KeywordTry, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "catch" => new Token(TokenType.KeywordCatch, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "not" => new Token(TokenType.KeywordNot, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "in" => new Token(TokenType.KeywordIn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "object" => new Token(TokenType.KeywordObject, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "global" => new Token(TokenType.KeywordGlobal, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "include" => new Token(TokenType.KeywordInclude, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "all" => new Token(TokenType.KeywordAll, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "static" => new Token(TokenType.KeywordStatic, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "define" => new Token(TokenType.KeywordDefine, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "f" => new Token(TokenType.QeywordF, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "l" => new Token(TokenType.QeywordL, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "e" => new Token(TokenType.QeywordE, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "c" => new Token(TokenType.QeywordC, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "p" => new Token(TokenType.QeywordP, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "t" => new Token(TokenType.QeywordT, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "n" => new Token(TokenType.QeywordN, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "w" => new Token(TokenType.QeywordW, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "fd" => new Token(TokenType.QeywordFd, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "sd" => new Token(TokenType.QeywordSd, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "sb" => new Token(TokenType.QeywordSb, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "od" => new Token(TokenType.QeywordOd, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "i" => new Token(TokenType.QeywordI, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "s" => new Token(TokenType.QeywordS, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "d" => new Token(TokenType.QeywordD, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "g" => new Token(TokenType.QeywordG, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + "v" => new Token(TokenType.QeywordV, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), + _ => new Token(TokenType.Identifier, TokenTypeGroup.Special, original, startPosition, _position.Copy()), + }; + } +} \ No newline at end of file diff --git a/src/Syntax/Parser/ParseResult.cs b/src/Syntax/Parser/ParseResult.cs new file mode 100644 index 0000000..ff74adb --- /dev/null +++ b/src/Syntax/Parser/ParseResult.cs @@ -0,0 +1,59 @@ +using EzrSquared.Runtime.Nodes; +using EzrSquared.Syntax.Errors; + +namespace EzrSquared.Syntax; + +/// +/// The type of the object that is returned as the result of parsing done by the . +/// +public class ParseResult +{ + /// + /// The that occurred while parsing, if any. + /// + public SyntaxError? Error = null; + + /// + /// The which is the result of the parsing. + /// + public Node Node = InvalidNode.s_invalidNode; + + /// + /// The amount of times the advanced. + /// + public int AdvanceCount = 0; + + /// + /// The priority of the error held in the . + /// + private int _errorPriority = 0; + + /// + /// Sets as the result of successful parsing. + /// + /// The result of the parsing. + /// The same object. + public void Success(Node node) + { + Node = node; + } + + /// + /// Sets as the result of failed parsing. + /// + /// + /// If is greater than or equal to the + /// then will override . + /// + /// The priority/fatality of the failure. + /// The that occurred in parsing. + /// The same object. + public void Failure(int priority, SyntaxError error) + { + if (Error is null || _errorPriority < priority) + { + _errorPriority = priority; + Error = error; + } + } +} diff --git a/src/Syntax/Parser/Parser.cs b/src/Syntax/Parser/Parser.cs new file mode 100644 index 0000000..7c53dd4 --- /dev/null +++ b/src/Syntax/Parser/Parser.cs @@ -0,0 +1,2234 @@ +using EzrSquared.Runtime.Nodes; +using EzrSquared.Syntax.Errors; +using System; +using System.Collections.Generic; + +namespace EzrSquared.Syntax; + +/// +/// The ezr² Parser. The job of the Parser is to convert the input objects from the into objects to be given as the input to the . +/// +public class Parser +{ + /// + /// The of objects to be parsed. + /// + private readonly List _tokens; + + /// + /// The object that holds the result of the parsing. + /// + private readonly ParseResult _result; + + /// + /// The index of the object currently being parsed in the . + /// + private int _index; + + /// + /// The object currently being parsed at of . + /// + private Token _currentToken; + + // /// + // /// The boolean check for if normal syntax or QuickSyntax is being used. + // /// + // private bool _usingQuickSyntax; + + // /// + // /// The boolean check for if QuickSyntax was being used previously in parsing. + // /// + // private bool _wasUsingQuickSyntax; + + /// + /// Creates a new object. + /// + /// The of objects to be parsed. + public Parser(List tokens) + { + _tokens = tokens; + // _usingQuickSyntax = false; + // _wasUsingQuickSyntax = false; + _result = new ParseResult(); + + _index = 0; + _currentToken = tokens.Count > _index ? _tokens[_index] : Token.Empty; + } + + /// + /// Advances to the next object in . + /// + private void Advance(int advanceCount = 1) + { + _index += advanceCount; + _result.AdvanceCount += advanceCount; + + if (_tokens.Count > _index) + _currentToken = _tokens[_index]; + } + + /// + /// Reverses back to the object at - in . + /// + /// The number of positions to reverse in . + private void Reverse(int reverseCount = 1) + { + _index -= reverseCount; + _result.AdvanceCount -= reverseCount; + _currentToken = _tokens[_index]; + } + + /// + /// Peeks at the previous object from in . + /// + /// The object. + private Token PeekPrevious() + { + int previousIndex = _index - 1; + return previousIndex < 0 ? Token.Empty : _tokens[previousIndex]; + } + + /// + /// Peeks at the next object from in . + /// + /// The numbers of places to advance in . + /// The object. + private Token PeekNext(int advanceCount = 1) + { + int nextIndex = _index + advanceCount; + return _tokens.Count < nextIndex ? Token.Empty : _tokens[nextIndex]; + } + + // /// + // /// Registers the use of QuickSyntax. + // /// + // private void RegisterQuickSyntaxUse() + // { + // _wasUsingQuickSyntax = _usingQuickSyntax; + // _usingQuickSyntax = true; + // } + + // /// + // /// Unregisters the use of QuickSyntax. + // /// + // private void UnregisterQuickSyntaxUse() + // { + // _usingQuickSyntax = _wasUsingQuickSyntax; + // } + + /// + /// Parses the objects in . + /// + public ParseResult Parse() + { + ParseStatements(); + if (_result.Error is null && _currentToken.Type != TokenType.EndOfFile) + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Did not expect this!", _currentToken.StartPosition, _currentToken.EndPosition)); + return _result; + } + + /// + /// Tries creating a . + /// + /// The function to call for the first operand. + /// The function to call for the second operand. + /// The operator object(s). + /// + /// Any special case that needs to be uniquely handled by the "OnCase" . + ///

+ /// "OnCase" is called after the token of type "Type" and any new lines have been parsed, and before has been called. + ///
+ /// Note that "Type" must be included in . + /// + private void BinaryOperation(Action left, Action right, TokenType[] operators, (TokenType Type, Action OnCase)? specialCase = null) + { + Position startPosition = _currentToken.StartPosition; + + left(); + if (_result.Error is not null) + return; + Node leftNode = _result.Node; + + int toReverseTo = _result.AdvanceCount; + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + while (Array.Exists(operators, @operator => @operator == _currentToken.Type)) + { + TokenType @operator = _currentToken.Type; + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + if (specialCase?.Type == @operator) + { + specialCase.Value.OnCase(); + if (_result.Error is not null) + return; + } + + right(); + if (_result.Error is not null) + return; + Node rightNode = _result.Node; + + leftNode = new BinaryOperationNode(leftNode, rightNode, @operator, startPosition, rightNode.EndPosition); + toReverseTo = _result.AdvanceCount; + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + } + + Reverse(_result.AdvanceCount - toReverseTo); + _result.Success(leftNode); + } + + /// + /// Tries parsing a 'statements' structure. + /// + private void ParseStatements() + { + List statements = []; + Position startPosition = _currentToken.StartPosition; + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + ParseStatement(); + if (_result.Error is not null) + return; + + statements.Add(_result.Node); + while (true) + { + // NOTE: Qeyword 'l' for 'else if' is deprecated, use Qeyword 'e' instead in format: + // 'e [check]: [statement(s)]' + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + else + break; + + if (_currentToken.Type is TokenType.EndOfFile + or TokenType.KeywordEnd + or TokenType.KeywordElse + or TokenType.KeywordCatch) + // || (_usingQuickSyntax + // && (_currentToken.Type == TokenType.QeywordL + // || _currentToken.Type == TokenType.QeywordE + // || _currentToken.Type == TokenType.QeywordS))) + break; + + ParseStatement(); + if (_result.Error is not null) + return; + + statements.Add(_result.Node); + } + + _result.Success(new ArrayLikeNode(statements, false, startPosition, statements[^1].EndPosition)); + } + + /// + /// Tries parsing a 'statement' structure. + /// + private void ParseStatement() + { + Position startPosition = _currentToken.StartPosition; + if (_currentToken.Type == TokenType.KeywordReturn) + { + Position possibleEndPosition = _currentToken.EndPosition; + Advance(); + + if (_currentToken.Type is TokenType.NewLine + or TokenType.EndOfFile + or TokenType.KeywordEnd + or TokenType.KeywordElse + or TokenType.KeywordCatch) + // || (_usingQuickSyntax + // && (_currentToken.Type == TokenType.QeywordL + // || _currentToken.Type == TokenType.QeywordE + // || _currentToken.Type == TokenType.QeywordS))) + { + _result.Success(new ReturnNode(null, false, startPosition, possibleEndPosition)); + return; + } + + bool returnLast = false; + if (_currentToken.Type == TokenType.KeywordLast) + { + Advance(); + returnLast = true; + } + + ParseExpression(); + if (_result.Error is not null) + return; + + Node expression = _result.Node; + _result.Success(new ReturnNode(expression, returnLast, startPosition, expression.EndPosition)); + return; + } + else if (_currentToken.Type is TokenType.KeywordSkip or TokenType.KeywordStop) + { + Position endPosition = _currentToken.EndPosition; + TokenType currentTokenType = _currentToken.Type; + Advance(); + + _result.Success(new NoValueNode(currentTokenType, startPosition, endPosition)); + return; + } + + ParseExpression(); + if (_result.Error is not null) + _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a statement!", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + /// + /// Tries parsing an 'expression' structure. + /// + /// In cases where the variable assignment expression requires the 'item' keyword, set this to . + private void ParseExpression(bool itemKeywordRequired = false) + { + Position startPosition = _currentToken.StartPosition; + + AccessMod accessibilityModifiers = AccessMod.None; + bool usedItemKeyword = false; + int startingAdvanceCount = _result.AdvanceCount; + + if (_currentToken.Type == TokenType.KeywordGlobal) + { + accessibilityModifiers |= AccessMod.Global; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordPrivate) + { + if ((accessibilityModifiers & AccessMod.Global) == AccessMod.Global) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "A variable, function or class cannot be declared 'global' and 'private' at the same time! It must be either 'global' , which means it is accessible to any code, or 'private' , which means it is only accessible to the current context.", startPosition, _currentToken.EndPosition)); + return; + } + + accessibilityModifiers |= AccessMod.Private; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordStatic) + { + accessibilityModifiers |= AccessMod.Static; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordConstant) + { + accessibilityModifiers |= AccessMod.Constant; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordItem) + { + usedItemKeyword = true; + Advance(); + } + else if (itemKeywordRequired) + { + ParseQuickExpression(true); + if (_result.Error is not null) + _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword || _currentToken.Type == TokenType.LeftParenthesis) + { + ParseJunction(); + if (_result.Error is not null) + return; + + Node variable = _result.Node; + if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) + { + TokenType assignmentOperator = _currentToken.Type; + Advance(); + + ParseExpression(); + if (_result.Error is not null) + return; + + Node value = _result.Node; + _result.Success(new VariableAssignmentNode(variable, assignmentOperator, value, accessibilityModifiers, startPosition, value.EndPosition)); + return; + } + else if (usedItemKeyword || ((accessibilityModifiers & AccessMod.PrivateConstant) != 0)) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + else + Reverse(_result.AdvanceCount - startingAdvanceCount); + } + else if (usedItemKeyword) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a variable name! The variable name is where the value will be assigned.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + else + Reverse(_result.AdvanceCount - startingAdvanceCount); + + ParseQuickExpression(); + if (_result.Error is not null) + _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + /// + /// Tries parsing a 'quick-expression' structure. + /// + private void ParseQuickExpression(bool itemKeywordRequired = false) + { + Position startPosition = _currentToken.StartPosition; + int startingAdvanceCount = _result.AdvanceCount; + + if (_currentToken.Type == TokenType.ExclamationMark) + { + Advance(); + + AccessMod accessibilityModifiers = AccessMod.None; + bool usedItemKeyword = false; + if (_currentToken.Type == TokenType.QeywordG) + { + accessibilityModifiers |= AccessMod.Global; + Advance(); + } + + if (_currentToken.Type == TokenType.QeywordP) + { + if ((accessibilityModifiers & AccessMod.Global) == AccessMod.Global) + { + Position errorStartPosition = startPosition.Copy(); + errorStartPosition.Advance(); + + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "A variable, function or class cannot be declared 'global' and 'private' at the same time! It must be either 'global' , which means it is accessible to any code, or 'private' , which means it is only accessible to the current context.", errorStartPosition, _currentToken.EndPosition)); + return; + } + + accessibilityModifiers |= AccessMod.Private; + Advance(); + } + + if (_currentToken.Type == TokenType.QeywordSb) + { + accessibilityModifiers |= AccessMod.Static; + Advance(); + } + + if (_currentToken.Type == TokenType.QeywordC) + { + accessibilityModifiers |= AccessMod.Constant; + Advance(); + } + + if (_currentToken.Type == TokenType.QeywordD) + { + usedItemKeyword = true; + Advance(); + } + else if (itemKeywordRequired) + { + ParseJunction(); + if (_result.Error is not null) + _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a QuickSyntax expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + if (_currentToken.Type == TokenType.Identifier || _currentToken.TypeGroup == TokenTypeGroup.Qeyword || _currentToken.Type == TokenType.LeftParenthesis) + { + ParseJunction(); + if (_result.Error is not null) + return; + + Node variable = _result.Node; + if (_currentToken.TypeGroup == TokenTypeGroup.AssignmentSymbol) + { + TokenType assignmentOperator = _currentToken.Type; + Advance(); + + ParseExpression(); + if (_result.Error is not null) + return; + + Node value = _result.Node; + _result.Success(new VariableAssignmentNode(variable, assignmentOperator, value, accessibilityModifiers, startPosition, value.EndPosition)); + return; + } + else if (usedItemKeyword || ((accessibilityModifiers & AccessMod.PrivateConstant) != 0)) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + else + Reverse(_result.AdvanceCount - startingAdvanceCount); + } + else if (usedItemKeyword) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a variable name! The variable name is where the value will be assigned.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + else + Reverse(_result.AdvanceCount - startingAdvanceCount); + } + + ParseJunction(); + if (_result.Error is not null) + _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a QuickSyntax expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + /// + /// Tries parsing a 'junction' structure. + /// + private void ParseJunction() + { + BinaryOperation(ParseInversion, ParseInversion, [TokenType.KeywordAnd, TokenType.KeywordOr]); + } + + /// + /// Tries parsing an 'inversion' structure. + /// + private void ParseInversion() + { + Position startPosition = _currentToken.StartPosition; + int startingAdvanceCount = _result.AdvanceCount; + + if (_currentToken.Type is TokenType.KeywordInvert or TokenType.KeywordNot) + { + TokenType @operator = _currentToken.Type; + Advance(); + + ParseInversion(); + if (_result.Error is not null) + return; + + Node operand = _result.Node; + _result.Success(new UnaryOperationNode(operand, @operator, startPosition, operand.EndPosition)); + return; + } + else if (_currentToken.Type == TokenType.ExclamationMark) + { + Advance(); + + if (_currentToken.Type == TokenType.QeywordV) + { + TokenType @operator = _currentToken.Type; + Advance(); + + ParseInversion(); + if (_result.Error is not null) + return; + + Node operand = _result.Node; + _result.Success(new UnaryOperationNode(operand, @operator, startPosition, operand.EndPosition)); + return; + } + else + Reverse(_result.AdvanceCount - startingAdvanceCount); + } + + ParseContainsCheck(); + if (_result.Error is not null) + _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an inversion expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + } + + /// + /// Tries parsing a 'contains-check' structure. + /// + private void ParseContainsCheck() + { + BinaryOperation(ParseComparison, ParseComparison, + [ + TokenType.KeywordIn, + TokenType.KeywordNot, + ], + (TokenType.KeywordNot, () => + { + if (_currentToken.Type != TokenType.KeywordIn) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'in' keyword! The 'in' keyword is the second part of a check-not-in operation.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + } + )); + } + + /// + /// Tries parsing a 'comparison' structure. + /// + private void ParseComparison() + { + BinaryOperation(ParseBitwiseOr, ParseBitwiseOr, + [ + TokenType.EqualSign, + TokenType.ExclamationMark, + TokenType.LessThanSign, + TokenType.GreaterThanSign, + TokenType.LessThanOrEqual, + TokenType.GreaterThanOrEqual, + ]); + } + + /// + /// Tries parsing a 'bitwise-or' structure. + /// + private void ParseBitwiseOr() + { + BinaryOperation(ParseBitwiseXOr, ParseBitwiseXOr, [TokenType.VerticalBar]); + } + + /// + /// Tries parsing a 'bitwise-xor' structure. + /// + private void ParseBitwiseXOr() + { + BinaryOperation(ParseBitwiseAnd, ParseBitwiseAnd, [TokenType.Backslash]); + } + + /// + /// Tries parsing a 'bitwise-and' structure. + /// + private void ParseBitwiseAnd() + { + BinaryOperation(ParseBitwiseShift, ParseBitwiseShift, [TokenType.Ampersand]); + } + + /// + /// Tries creating a 'bitwise-shift' structure. + /// + private void ParseBitwiseShift() + { + BinaryOperation(ParseArithmeticExpression, ParseArithmeticExpression, [TokenType.BitwiseLeftShift, TokenType.BitwiseRightShift]); + } + + /// + /// Tries parsing an 'arithmetic-expression' structure. + /// + private void ParseArithmeticExpression() + { + BinaryOperation(ParseTerm, ParseTerm, [TokenType.Plus, TokenType.HyphenMinus]); + } + + /// + /// Tries parsing a 'term' structure. + /// + private void ParseTerm() + { + BinaryOperation(ParseFactor, ParseFactor, [TokenType.Asterisk, TokenType.Slash, TokenType.PercentSign]); + } + + /// + /// Tries parsing a 'factor' structure. + /// + private void ParseFactor() + { + Position startPosition = _currentToken.StartPosition; + + TokenType @operator = _currentToken.Type; + if (@operator is TokenType.Plus or TokenType.HyphenMinus or TokenType.Tilde) + { + Advance(); + + ParseFactor(); + if (_result.Error is not null) + return; + + Node operand = _result.Node; + _result.Success(new UnaryOperationNode(operand, @operator, startPosition, operand.EndPosition)); + return; + } + + ParsePower(); + } + + /// + /// Tries parsing a 'power' structure. + /// + private void ParsePower() + { + BinaryOperation(ParseObjectAttributeAccess, ParseObjectAttributeAccess, [TokenType.Caret]); + } + + /// + /// Tries parsing an 'object-attribute-access' structure. + /// + private void ParseObjectAttributeAccess() + { + BinaryOperation(ParseCall, ParseCall, [TokenType.Period]); + } + + /// + /// Tries parsing a 'call' structure. + /// + private void ParseCall() + { + Position startPosition = _currentToken.StartPosition; + + ParseAtom(); + if (_result.Error is not null) + return; + + if (_currentToken.Type != TokenType.LeftParenthesis) + return; + + Node node = _result.Node; + Advance(); + + Token possibleErrorToken = _currentToken; + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + Position endPosition; + List arguments = []; + if (_currentToken.Type == TokenType.RightParenthesis) + { + endPosition = _currentToken.EndPosition; + Advance(); + } + else + { + ParseExpression(); + if (_result.Error is not null) + { + _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + return; + } + + arguments.Add(_result.Node); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + while (_currentToken.Type == TokenType.Comma) + { + possibleErrorToken = _currentToken; + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + ParseExpression(); + if (_result.Error is not null) + { + _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + return; + } + arguments.Add(_result.Node); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + } + + if (_currentToken.Type != TokenType.RightParenthesis) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma or right-parenthesis symbol! Commas are used to seperate the arguments of the function/object call expression, and the right-parenthesis is used to end it.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + endPosition = _currentToken.EndPosition; + Advance(); + } + + _result.Success(new CallNode(node, arguments, startPosition, endPosition)); + } + + /// + /// Tries parsing a 'atom' structure. + /// + private void ParseAtom() + { + Token startToken = _currentToken; + switch (startToken.Type) + { + case TokenType.KeywordGlobal: + Token nextToken = PeekNext(); + int peek = 1; + + AccessMod accessibilityModifiers = AccessMod.Global; + bool readOnly = false; + + if (nextToken.Type == TokenType.KeywordStatic) + { + nextToken = PeekNext(++peek); + accessibilityModifiers |= AccessMod.Static; + } + + if (nextToken.Type == TokenType.Identifier || nextToken.TypeGroup == TokenTypeGroup.Qeyword) + { + Advance(accessibilityModifiers == AccessMod.GlobalStatic ? 2 : 1); + + Token variable = _currentToken; + Position endPosition = _currentToken.EndPosition; + Advance(); + + _result.Success(new VariableAccessNode(variable, accessibilityModifiers, startToken.StartPosition, endPosition)); + return; + } + + if (nextToken.Type == TokenType.KeywordConstant) + { + nextToken = PeekNext(++peek); + accessibilityModifiers |= AccessMod.Constant; + } + + if (nextToken.Type == TokenType.KeywordReadonly) + { + nextToken = PeekNext(++peek); + readOnly = true; + } + + if (!readOnly && nextToken.Type == TokenType.KeywordFunction) + { + ParseFunctionDefinitionExpression(); + return; + } + else if (nextToken.Type == TokenType.KeywordObject) + { + ParseClassDefinitionExpression(); + return; + } + + bool isConstant = (accessibilityModifiers & AccessMod.Constant) == AccessMod.Constant; + string onConstant = isConstant ? "constant " : string.Empty; + string onVariable = isConstant ? string.Empty : "variable "; + + string onStatic = (accessibilityModifiers & AccessMod.Static) == AccessMod.Static ? "static " : string.Empty; + + string errorMessage = (readOnly, isConstant) switch + { + (true, _) => $"Expected the 'object' keyword! In this case, the 'object' keyword is used to declare a global {onStatic}{onConstant}read-only class.", + (false, true) => $"Expected a variable assignment expression or the 'function' or 'object' keywords! In this case, a variable assignment expression will assign a global {onStatic}{onConstant}{onVariable}and the 'function' or 'object' keywords will declare a global {onStatic}{onConstant}function or class, respectively.", + (false, false) => $"Expected a variable assignment expression, variable access expression or the 'function' or 'object' keywords! In this case, a variable assignment expression will assign a global {onStatic}variable, a variable access expression references a global {onStatic}variable and the 'function' or 'object' keywords will declare a global {onStatic}function or class, respectively.", + }; + + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); + break; + case TokenType.KeywordPrivate: + nextToken = PeekNext(); + peek = 1; + + accessibilityModifiers = AccessMod.Private; + readOnly = false; + + if (nextToken.Type == TokenType.KeywordStatic) + { + nextToken = PeekNext(++peek); + accessibilityModifiers |= AccessMod.Static; + } + + if (nextToken.Type == TokenType.KeywordConstant) + { + nextToken = PeekNext(++peek); + accessibilityModifiers |= AccessMod.Constant; + } + + if (nextToken.Type == TokenType.KeywordReadonly) + { + nextToken = PeekNext(++peek); + readOnly = true; + } + + if (!readOnly && nextToken.Type == TokenType.KeywordFunction) + { + ParseFunctionDefinitionExpression(); + return; + } + else if (nextToken.Type == TokenType.KeywordObject) + { + ParseClassDefinitionExpression(); + return; + } + + isConstant = (accessibilityModifiers & AccessMod.Constant) == AccessMod.Constant; + onConstant = isConstant ? "constant " : string.Empty; + onVariable = isConstant ? string.Empty : "variable "; + + onStatic = (accessibilityModifiers & AccessMod.Static) == AccessMod.Static ? "static " : string.Empty; + + errorMessage = readOnly + ? $"Expected the 'object' keyword! In this case, the 'object' keyword is used to declare a private {onStatic}{onConstant}read-only class." + : $"Expected a variable assignment expression or the 'function' or 'object' keywords! In this case, a variable assignment expression will assign a private {onStatic}{onConstant}{onVariable}and the 'function' or 'object' keywords will declare a private {onStatic}{onConstant}function or class, respectively."; + + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); + break; + case TokenType.KeywordStatic: + nextToken = PeekNext(); + peek = 1; + + accessibilityModifiers = AccessMod.Static; + readOnly = false; + + if (nextToken.Type == TokenType.Identifier || nextToken.TypeGroup == TokenTypeGroup.Qeyword) + { + Advance(); + + Token variable = _currentToken; + Position endPosition = _currentToken.EndPosition; + Advance(); + + _result.Success(new VariableAccessNode(variable, accessibilityModifiers, startToken.StartPosition, endPosition)); + return; + } + + if (nextToken.Type == TokenType.KeywordConstant) + { + nextToken = PeekNext(++peek); + accessibilityModifiers |= AccessMod.Constant; + } + + if (nextToken.Type == TokenType.KeywordReadonly) + { + nextToken = PeekNext(++peek); + readOnly = true; + } + + if (!readOnly && nextToken.Type == TokenType.KeywordFunction) + { + ParseFunctionDefinitionExpression(); + return; + } + else if (nextToken.Type == TokenType.KeywordObject) + { + ParseClassDefinitionExpression(); + return; + } + + isConstant = (accessibilityModifiers & AccessMod.Constant) == AccessMod.Constant; + onConstant = isConstant ? "constant " : string.Empty; + onVariable = isConstant ? string.Empty : "variable "; + + errorMessage = (readOnly, isConstant) switch + { + (true, _) => $"Expected the 'object' keyword! In this case, the 'object' keyword is used to declare a static {onConstant}read-only class.", + (false, true) => $"Expected a variable assignment expression or the 'function' or 'object' keywords! In this case, a variable assignment expression will assign a static {onConstant}{onVariable}and the 'function' or 'object' keywords will declare a static {onConstant}function or class, respectively.", + (false, false) => $"Expected a variable assignment expression, variable access expression or the 'function' or 'object' keywords! In this case, a variable assignment expression will assign a static variable, a variable access expression references a static variable and the 'function' or 'object' keywords will declare a static function or class, respectively.", + }; + + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); + break; + case TokenType.KeywordConstant: + nextToken = PeekNext(); + + readOnly = false; + if (nextToken.Type == TokenType.KeywordReadonly) + { + nextToken = PeekNext(2); + readOnly = true; + } + + if (!readOnly && nextToken.Type == TokenType.KeywordFunction) + { + ParseFunctionDefinitionExpression(); + return; + } + else if (nextToken.Type == TokenType.KeywordObject) + { + ParseClassDefinitionExpression(); + return; + } + + errorMessage = readOnly + ? "Expected the 'object' keyword! In this case, the 'object' keyword is used to declare a constant read-only class." + : "Expected a variable assignment expression or the 'function' or 'object' keywords! In this case, a variable assignment expression will assign a constant, while the 'function' or 'object' keywords will declare a constant function or class, respectively."; + + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); + break; + case TokenType.KeywordReadonly: + nextToken = PeekNext(); + + if (nextToken.Type != TokenType.KeywordObject) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'object' keyword! In this case, the 'object' keyword is used to declare a read-only class.", nextToken.StartPosition, nextToken.EndPosition)); + return; + } + + ParseClassDefinitionExpression(); + break; + case TokenType.LeftParenthesis: + ParseArrayOrParentheticalExpression(); + break; + case TokenType.LeftSquareBracket: + ParseList(); + break; + case TokenType.LeftCurlyBracket: + ParseDictionary(); + break; + case TokenType.KeywordIf: + ParseIfExpression(); + break; + case TokenType.KeywordCount: + ParseCountExpression(); + break; + case TokenType.KeywordWhile: + ParseWhileExpression(); + break; + case TokenType.KeywordTry: + ParseTryExpression(); + break; + case TokenType.KeywordFunction: + ParseFunctionDefinitionExpression(); + break; + case TokenType.KeywordObject: + ParseClassDefinitionExpression(); + break; + case TokenType.KeywordInclude: + ParseIncludeExpression(); + break; + case TokenType.KeywordDefine: + ParseDefineBlockExpression(); + break; + +#pragma warning disable CS0618 + case TokenType.KeywordSpecial: + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "The \"special function\" structure has been removed from ezr². Please use normal functions with dedicated names for operator overloading. Check [DOCUMENTATION LINK HERE] for more info.", _currentToken.StartPosition, _currentToken.EndPosition)); + break; +#pragma warning restore CS0618 + + default: + if (startToken.TypeGroup == TokenTypeGroup.Value) + { + Advance(); + + _result.Success(new ValueNode(startToken, startToken.StartPosition, startToken.EndPosition)); + return; + } + else if (startToken.Type == TokenType.Identifier || startToken.TypeGroup == TokenTypeGroup.Qeyword) + { + Advance(); + + _result.Success(new VariableAccessNode(startToken, AccessMod.None, startToken.StartPosition, startToken.EndPosition)); + return; + } + + _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an integer, float, string, character, character list, identifier, 'if' expression, 'count' expression, 'while' expression...", _currentToken.StartPosition, _currentToken.EndPosition)); + break; + } + } + + /// + /// Tries parsing an array, an with set to OR a parenthetical expression. Starts from , which should be of . + /// + private void ParseArrayOrParentheticalExpression() + { + Position startPosition = _currentToken.StartPosition; + Advance(); + + Token possibleErrorToken = _currentToken; + List elements = []; + bool isArray = false; + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + Position endPosition; + if (_currentToken.Type == TokenType.RightParenthesis) + { + endPosition = _currentToken.EndPosition; + Advance(); + } + else + { + ParseExpression(); + if (_result.Error is not null) + { + _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! An array/parenthetical expression must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + return; + } + + elements.Add(_result.Node); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + while (_currentToken.Type == TokenType.Comma) + { + isArray = true; + possibleErrorToken = _currentToken; + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + if (_currentToken.Type == TokenType.RightParenthesis && elements.Count == 1) + break; + + ParseExpression(); + if (_result.Error is not null) + { + _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! An array must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + return; + } + + elements.Add(_result.Node); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + } + + if (_currentToken.Type != TokenType.RightParenthesis) + { + if (isArray) + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma or a right-parenthesis symbol! Commas seperate the elements of the array, while the right-parenthesis ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma or a right-parenthesis symbol! The comma is used to create an array and seperate its elements, while the right-parenthesis declares the end of a parenthetical expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + endPosition = _currentToken.EndPosition; + Advance(); + } + + if (!isArray && elements.Count > 0) + { + _result.Node.StartPosition = startPosition; + _result.Node.EndPosition = endPosition; + } + else + _result.Success(new ArrayLikeNode(elements, false, startPosition, endPosition)); + } + + /// + /// Tries parsing a list, an with set to . Starts from , which should be of . + /// + private void ParseList() + { + Position startPosition = _currentToken.StartPosition; + Advance(); + + Token possibleErrorToken = _currentToken; + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + Position endPosition; + List elements = []; + if (_currentToken.Type == TokenType.RightSquareBracket) + { + endPosition = _currentToken.EndPosition; + Advance(); + } + else + { + ParseExpression(); + if (_result.Error is not null) + { + _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + return; + } + elements.Add(_result.Node); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + while (_currentToken.Type == TokenType.Comma) + { + possibleErrorToken = _currentToken; + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + ParseExpression(); + if (_result.Error is not null) + { + _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + return; + } + elements.Add(_result.Node); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + } + + if (_currentToken.Type != TokenType.RightSquareBracket) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma or a right-square-bracket symbol! Commas are used to seperate elements in the list, while the right-square-bracket ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + endPosition = _currentToken.EndPosition; + Advance(); + } + + _result.Success(new ArrayLikeNode(elements, true, startPosition, endPosition)); + } + + /// + /// Tries parsing a dictionary. Starts from , which should be of . + /// + private void ParseDictionary() + { + Position startPosition = _currentToken.StartPosition; + Advance(); + + Token possibleErrorToken = _currentToken; + List<(Node Key, Node Value)> pairs = []; + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + Position endPosition; + if (_currentToken.Type == TokenType.RightCurlyBracket) + { + endPosition = _currentToken.EndPosition; + Advance(); + } + else + { + ParseExpression(true); + if (_result.Error is not null) + { + _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + return; + } + + Node left = _result.Node; + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + if (_currentToken.Type != TokenType.Colon) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + ParseExpression(); + if (_result.Error is not null) + return; + + Node right = _result.Node; + pairs.Add(new(left, right)); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + while (_currentToken.Type == TokenType.Comma) + { + possibleErrorToken = _currentToken; + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + ParseExpression(true); + if (_result.Error is not null) + { + _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + return; + } + + left = _result.Node; + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + if (_currentToken.Type != TokenType.Colon) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + ParseExpression(); + if (_result.Error is not null) + return; + + right = _result.Node; + pairs.Add(new(left, right)); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + } + + if (_currentToken.Type != TokenType.RightCurlyBracket) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma or right-curly-bracket symbol! Commas are used to seperate key-value pairs in the dictionary, and the right-curly-bracket declares its end.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + endPosition = _currentToken.EndPosition; + Advance(); + } + + _result.Success(new DictionaryNode(pairs, startPosition, endPosition)); + } + + /// + /// Tries parsing an if expression. Starts from , which should be of . + /// + private void ParseIfExpression() + { + Position startPosition = _currentToken.StartPosition; + Advance(); + + List<(Node Condition, Node Body)> cases = []; + Node? elseCase = null; + + ParseExpression(); + if (_result.Error is not null) + return; + + Node condition = _result.Node; + if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + Node body; + if (_currentToken.Type == TokenType.NewLine) + { + Advance(); + + ParseStatements(); + if (_result.Error is not null) + return; + + body = _result.Node; + Position endPosition; + + cases.Add(new(condition, body)); + if (_currentToken.Type == TokenType.KeywordEnd) + { + endPosition = _currentToken.EndPosition; + Advance(); + } + else if (_currentToken.Type == TokenType.KeywordElse) + { + while (_currentToken.Type == TokenType.KeywordElse) + { + Advance(); + + if (_currentToken.Type == TokenType.KeywordIf) + { + if (elseCase is not null) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + ParseExpression(); + if (_result.Error is not null) + return; + + condition = _result.Node; + if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + ParseStatements(); + if (_result.Error is not null) + return; + + body = _result.Node; + cases.Add(new(condition, body)); + } + else if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + else + { + if (elseCase is not null) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + ParseStatements(); + if (_result.Error is not null) + return; + + elseCase = _result.Node; + } + } + + if (_currentToken.Type != TokenType.KeywordEnd) + { + if (elseCase is null) + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + endPosition = _currentToken.EndPosition; + Advance(); + } + else + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + _result.Success(new IfNode(cases, elseCase, startPosition, endPosition)); + return; + } + + ParseStatement(); + if (_result.Error is not null) + return; + + body = _result.Node; + cases.Add(new(condition, body)); + + while (_currentToken.Type == TokenType.KeywordElse) + { + Advance(); + + if (_currentToken.Type == TokenType.KeywordIf) + { + if (elseCase is not null) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + ParseExpression(); + if (_result.Error is not null) + return; + + condition = _result.Node; + if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + ParseStatement(); + if (_result.Error is not null) + return; + + body = _result.Node; + cases.Add(new(condition, body)); + } + else if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + else + { + if (elseCase is not null) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + ParseStatement(); + if (_result.Error is not null) + return; + + elseCase = _result.Node; + } + } + + _result.Success(new IfNode(cases, elseCase, startPosition, PeekPrevious().EndPosition)); + } + + /// + /// Tries parsing a count expression. Starts from , which should be of . + /// + private void ParseCountExpression() + { + Position startPosition = _currentToken.StartPosition; + Advance(); + + Node to = InvalidNode.s_invalidNode; + Node? from = null; + Node? step = null; + Node? iterationVariable = null; + + if (_currentToken.Type == TokenType.KeywordFrom) + { + Advance(); + ParseExpression(); + if (_result.Error is not null) + return; + + from = _result.Node; + } + + if (_currentToken.Type != TokenType.KeywordTo) + { + if (from is null) + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'to' or 'from' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop, and the optional 'from' keyword and the following expression is the amount to count from.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'to' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + ParseExpression(); + if (_result.Error is not null) + return; + + to = _result.Node; + if (_currentToken.Type == TokenType.KeywordStep) + { + Advance(); + + ParseExpression(); + if (_result.Error is not null) + return; + + step = _result.Node; + } + + if (_currentToken.Type == TokenType.KeywordAs) + { + Advance(); + ParseExpression(); + if (_result.Error is not null) + return; + + iterationVariable = _result.Node; + } + + if (_currentToken.Type != TokenType.KeywordDo) + { + if (step is null && iterationVariable is null) + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do', 'step' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, the optional 'step' keyword and the following expression is the increment, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); + else if (iterationVariable is null) + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + Node body; + Position endPosition; + if (_currentToken.Type == TokenType.NewLine) + { + Advance(); + + ParseStatements(); + if (_result.Error is not null) + return; + + body = _result.Node; + if (_currentToken.Type != TokenType.KeywordEnd) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + endPosition = _currentToken.EndPosition; + Advance(); + } + else + { + ParseStatement(); + if (_result.Error is not null) + return; + + body = _result.Node; + endPosition = body.EndPosition; + } + + _result.Success(new CountNode(to, from, step, iterationVariable, body, startPosition, endPosition)); + } + + /// + /// Tries parsing a while expression. Starts from , which should be of . + /// + private void ParseWhileExpression() + { + Position startPosition = _currentToken.StartPosition; + Advance(); + + ParseExpression(); + if (_result.Error is not null) + return; + + Node condition = _result.Node; + if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + Node body; + Position endPosition; + if (_currentToken.Type == TokenType.NewLine) + { + Advance(); + + ParseStatements(); + if (_result.Error is not null) + return; + + body = _result.Node; + if (_currentToken.Type != TokenType.KeywordEnd) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + endPosition = _currentToken.EndPosition; + Advance(); + } + else + { + ParseStatement(); + if (_result.Error is not null) + return; + + body = _result.Node; + endPosition = body.EndPosition; + } + + _result.Success(new WhileNode(condition, body, startPosition, endPosition)); + } + + /// + /// Tries parsing a try expression. Starts from , which should be of . + /// + private void ParseTryExpression() + { + Position startPosition = _currentToken.StartPosition; + Advance(); + + Node block; + List<(Node ErrorType, Node? Variable, Node Body)> cases = []; + (Node? Variable, Node Body)? emptyCase = null; + + if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + Node body; + if (_currentToken.Type == TokenType.NewLine) + { + Advance(); + + ParseStatements(); + if (_result.Error is not null) + return; + + block = _result.Node; + Position endPosition; + if (_currentToken.Type == TokenType.KeywordEnd) + { + endPosition = _currentToken.EndPosition; + Advance(); + } + else if (_currentToken.Type == TokenType.KeywordCatch) + { + while (_currentToken.Type == TokenType.KeywordCatch) + { + Advance(); + + Node? error = null; + bool isErrorNull = true; + + ErrorExpressionEvaluation: + bool isAsKeyword = _currentToken.Type == TokenType.KeywordAs; + if (_currentToken.Type == TokenType.KeywordDo || isAsKeyword) + { + if (emptyCase is not null) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There should only be one empty \"catch\" expression! You cannot have multiple empty \"catch\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } + + Node? @as = null; + if (isAsKeyword) + { + Advance(); + ParseExpression(); + if (_result.Error is not null) + return; + + @as = _result.Node; + if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + } + + Advance(); + + ParseStatements(); + if (_result.Error is not null) + return; + + body = _result.Node; + if (error is not null) + cases.Add(new(error, @as, body)); + else + emptyCase = new(@as, body); + } + else if (isErrorNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) + { + if (emptyCase is not null) + { + Token previous = PeekPrevious(); + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There can't be any \"catch\" expressions after an empty \"catch\" expression!", previous.StartPosition, previous.EndPosition)); + return; + } + + ParseExpression(); + if (_result.Error is not null) + return; + + error = _result.Node; + isErrorNull = false; + goto ErrorExpressionEvaluation; + } + else if (isErrorNull) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an expression or the 'as' or 'do' keywords! An expression after the 'catch' keyword defines what error(s) will lead to the \"catch\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + else + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + } + + if (_currentToken.Type != TokenType.KeywordEnd) + { + if (emptyCase is null) + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'catch' or 'end' keywords! The 'catch' keyword defines the start of an \"catch\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + endPosition = _currentToken.EndPosition; + Advance(); + } + else + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'catch' or 'end' keywords! The 'catch' keyword defines the start of an \"catch\" expression, and the 'end' keyword declares the end of the whole \"try\" expression. Note: In newer versions of ezr², 'error' has been replaced by 'catch' and is now recognized as an identifier. Check [DOCUMENTATION LINK HERE] for more info.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + _result.Success(new TryNode(block, cases, emptyCase, startPosition, endPosition)); + return; + } + + ParseStatement(); + if (_result.Error is not null) + return; + + block = _result.Node; + while (_currentToken.Type == TokenType.KeywordCatch) + { + Advance(); + + Node? error = null; + bool isErrorNull = true; + + ErrorExpressionEvaluation: + bool isAsKeyword = _currentToken.Type == TokenType.KeywordAs; + if (_currentToken.Type == TokenType.KeywordDo || isAsKeyword) + { + if (emptyCase is not null) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There should only be one empty \"catch\" expression! You cannot have multiple empty \"catch\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + return; + } + + Node? @as = null; + if (isAsKeyword) + { + Advance(); + ParseExpression(); + if (_result.Error is not null) + return; + + @as = _result.Node; + if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + } + + Advance(); + + ParseStatement(); + if (_result.Error is not null) + return; + + body = _result.Node; + if (error is not null) + cases.Add(new(error, @as, body)); + else + emptyCase = new(@as, body); + } + else if (isErrorNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) + { + if (emptyCase is not null) + { + Token previous = PeekPrevious(); + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There can't be any \"catch\" expressions after an empty \"catch\" expression!", previous.StartPosition, previous.EndPosition)); + return; + } + + ParseExpression(); + if (_result.Error is not null) + return; + + error = _result.Node; + isErrorNull = false; + goto ErrorExpressionEvaluation; + } + else if (isErrorNull) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an expression or the 'as' or 'do' keywords! An expression after the 'catch' keyword defines what error(s) will lead to the \"catch\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + else + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + } + + _result.Success(new TryNode(block, cases, emptyCase, startPosition, PeekPrevious().EndPosition)); + } + + /// + /// Tries parsing a function definition expression. Starts from , which should be of . + /// + private void ParseFunctionDefinitionExpression() + { + Position startPosition = _currentToken.StartPosition; + AccessMod accessibilityModifiers = AccessMod.None; + bool returnLast = false; + + if (_currentToken.Type == TokenType.KeywordGlobal) + { + accessibilityModifiers |= AccessMod.Global; + Advance(); + } + else if (_currentToken.Type == TokenType.KeywordPrivate) + { + accessibilityModifiers |= AccessMod.Private; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordStatic) + { + accessibilityModifiers |= AccessMod.Static; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordConstant) + { + accessibilityModifiers |= AccessMod.Constant; + Advance(); + } + + Advance(); + Node? name = null; + List parameters = []; + Node? keywordArguments = null; + Node body; + + Position endPosition; + bool isNameNull = true; + + FunctionDefinitionEvaluation: + bool isWithKeyword = _currentToken.Type == TokenType.KeywordWith; + if (_currentToken.Type == TokenType.KeywordDo || isWithKeyword) + { + if (isWithKeyword) + { + do + { + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + if (_currentToken.Type == TokenType.KeywordMore) + { + Advance(); + if (_currentToken.Type != TokenType.KeywordAs) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'as' keyword! The 'as' keyword comes in-between the 'from' keyword and an expression when declaring extra parameters for an object.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + ParseExpression(true); + if (_result.Error is not null) + return; + + keywordArguments = _result.Node; + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + if (_currentToken.Type == TokenType.Comma) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Cannot have more parameters after declaring extra parameters! Declaring extra parameters must be done last, after declaring all mandatory parameters.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + break; + } + + ParseExpression(); + if (_result.Error is not null) + return; + parameters.Add(_result.Node); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + } while (_currentToken.Type == TokenType.Comma); + + if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parameter and the 'do' keyword declares the start of the body of the \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + } + + if (name is null && accessibilityModifiers != AccessMod.None) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "The accessibility of an anonymous function cannot be declared in the definition! Anonymous functions are meant to be stored in variables or constants, where the accessibility is determined.", startPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + { + Advance(); + + ParseStatements(); + if (_result.Error is not null) + return; + + body = _result.Node; + if (_currentToken.Type != TokenType.KeywordEnd) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + endPosition = _currentToken.EndPosition; + Advance(); + } + else + { + ParseStatement(); + if (_result.Error is not null) + return; + + body = _result.Node; + endPosition = body.EndPosition; + returnLast = true; + } + } + else if (isNameNull && _currentToken.Type != TokenType.EndOfFile && _currentToken.Type != TokenType.NewLine) + { + ParseExpression(); + if (_result.Error is not null) + return; + + name = _result.Node; + isNameNull = false; + goto FunctionDefinitionEvaluation; + } + else if (isNameNull) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an expression or the 'with' or 'do' keywords! An expression after the 'function' keyword defines the name, the 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + else + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'with' or 'do' keywords! The 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + _result.Success(new FunctionDefinitionNode(name, accessibilityModifiers, returnLast, parameters, keywordArguments, body, startPosition, endPosition)); + } + + /// + /// Tries parsing an class definition expression. Starts from , which should be of . + /// + private void ParseClassDefinitionExpression() + { + Position startPosition = _currentToken.StartPosition; + AccessMod accessibilityModifiers = AccessMod.None; + bool readOnly = false; + + if (_currentToken.Type == TokenType.KeywordGlobal) + { + accessibilityModifiers |= AccessMod.Global; + Advance(); + } + else if (_currentToken.Type == TokenType.KeywordPrivate) + { + accessibilityModifiers |= AccessMod.Private; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordStatic) + { + accessibilityModifiers |= AccessMod.Static; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordConstant) + { + accessibilityModifiers |= AccessMod.Constant; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordReadonly) + { + readOnly = true; + Advance(); + } + + Advance(); + Node? name = null; + List parents = []; + Node body; + + Position endPosition; + + if (_currentToken.Type is not TokenType.KeywordFrom and not TokenType.KeywordDo and not TokenType.EndOfFile and not TokenType.NewLine) + { + ParseExpression(); + name = _result.Node; + if (_result.Error is not null) + return; + } + else if (accessibilityModifiers != AccessMod.None) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "The accessibility of an anonymous class cannot be declared in the definition! Anonymous classes are meant to be stored in variables or constants, where the accessibility is determined.", startPosition, _currentToken.EndPosition)); + return; + } + + if (_currentToken.Type == TokenType.KeywordFrom) + { + do + { + Advance(); + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + ParseExpression(); + if (_result.Error is not null) + return; + parents.Add(_result.Node); + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + } + while (_currentToken.Type == TokenType.Comma); + + if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parent and the 'do' keyword declares the start of the body of the class definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + } + + if (_currentToken.Type == TokenType.KeywordDo) + { + Advance(); + + if (_currentToken.Type == TokenType.NewLine) + { + Advance(); + + ParseStatements(); + body = _result.Node; + if (_result.Error is not null) + return; + + if (_currentToken.Type != TokenType.KeywordEnd) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole class definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + endPosition = _currentToken.EndPosition; + Advance(); + } + else + { + ParseStatement(); + if (_result.Error is not null) + return; + + body = _result.Node; + endPosition = body.EndPosition; + } + + _result.Success(new ClassDefinitionNode(name, accessibilityModifiers, readOnly, parents, body, startPosition, endPosition)); + return; + } + + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, + (name is null && parents.Count == 0) + ? "Expected an expression or the 'from' or 'do' keywords! An expression after the 'object' keyword defines the name, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents and the 'do' keyword declares the start of the body of the class." + : (parents.Count == 0) + ? "Expected the 'from' or 'do' keywords! The 'from' keyword and the following expression(s, seperated by commas) define(s) the parents and the 'do' keyword declares the start of the body of the class." + : "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the class.", + _currentToken.StartPosition, _currentToken.EndPosition)); + } + + /// + /// Tries parsing an include expression. Starts from , which should be of . + /// + private void ParseIncludeExpression() + { + Position startPosition = _currentToken.StartPosition; + Advance(); + + Node? subStructure = null; + Node? nickname = null; + bool isDumped = false; + Node script; + + if (_currentToken.Type is not TokenType.KeywordAll and not TokenType.Comma) + { + ParseExpression(); + subStructure = _result.Node; + if (_result.Error is not null) + return; + } + else + { + isDumped = true; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordFrom) + { + Advance(); + + ParseExpression(); + script = _result.Node; + if (_result.Error is not null) + return; + } + else if (subStructure is not null) + { + script = subStructure; + subStructure = null; + } + else + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'from' keyword! If a specific object being included from a script (when the object's name is provided after the 'include' keyword) or if the whole script is added to the script (using the 'all' keyword or a comma symbol after the 'include' keyword), the 'from' keyword followed by an expression declaring the script's name or path must be provided.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + if (_currentToken.Type == TokenType.KeywordAs) + { + Advance(); + + ParseExpression(); + nickname = _result.Node; + if (_result.Error is not null) + return; + } + + _result.Success(new IncludeNode(script, subStructure, isDumped, nickname, startPosition, PeekPrevious().EndPosition)); + } + + /// + /// Tries parsing a define block expression. Starts from , which should be of . + /// + private void ParseDefineBlockExpression() + { + Position startPosition = _currentToken.StartPosition; + AccessMod accessibilityModifiers = AccessMod.None; + + Advance(); + if (_currentToken.Type == TokenType.KeywordGlobal) + { + accessibilityModifiers |= AccessMod.Global; + Advance(); + } + else if (_currentToken.Type == TokenType.KeywordPrivate) + { + accessibilityModifiers |= AccessMod.Private; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordStatic) + { + accessibilityModifiers |= AccessMod.Static; + Advance(); + } + + if (_currentToken.Type == TokenType.KeywordConstant) + { + accessibilityModifiers |= AccessMod.Constant; + Advance(); + } + + if (accessibilityModifiers == AccessMod.None) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'private', 'global', 'static' or 'constant' keywords! The \"define block\" needs at least one accessibility modifier. The 'private' or 'global' keywords declare all variables, constants, functions and classes defined in the block as private or global - not both, the 'static' or 'constant' keywords declare them as statically bound or constants - can be both.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + ParseStatements(); + if (_result.Error is not null) + return; + + Node body = _result.Node; + if (_currentToken.Type != TokenType.KeywordEnd) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"define block\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Position endPosition = _currentToken.EndPosition; + Advance(); + + _result.Success(new DefineBlockNode(body, accessibilityModifiers, startPosition, endPosition)); + } +} diff --git a/src/Token.cs b/src/Token.cs new file mode 100644 index 0000000..8c4f3c8 --- /dev/null +++ b/src/Token.cs @@ -0,0 +1,70 @@ +namespace EzrSquared; + +/// +/// The smallest component in the script identified by the , grouped together into objects to from source code constructs. +/// +public class Token +{ + /// + /// The identifying of the . + /// + public readonly TokenType Type; + + /// + /// The of the . + /// + public readonly TokenTypeGroup TypeGroup; + + /// + /// The value of the ; may be empty. + /// + public readonly string Value; + + /// + /// The starting of the in the script. + /// + public readonly Position StartPosition; + + /// + /// The ending of the in the script. + /// + public readonly Position EndPosition; + + /// + /// An empty token value. + /// + public static readonly Token Empty = new(TokenType.Invalid, TokenTypeGroup.Special, string.Empty, Position.None); + + /// + /// Creates a new object. + /// + /// The identifying of the . + /// The of the . + /// The value of the ; may be empty. + /// The starting of the in the script. + /// The ending of the in the script. If not given, copies and advances it. + public Token(TokenType type, TokenTypeGroup typeGroup, string value, Position startPosition, Position? endPosition = null) + { + Type = type; + TypeGroup = typeGroup; + Value = value; + + StartPosition = startPosition; + if (endPosition is not null) + EndPosition = endPosition; + else + { + EndPosition = startPosition.Copy(); + EndPosition.Advance(); + } + } + + /// + /// Converts the into a , for debugging purposes. + /// + /// The representation of the . + public override string ToString() + { + return $"{nameof(Token)}({Type}, {TypeGroup}, \"{Value}\")"; + } +} \ No newline at end of file diff --git a/src/TokenType.cs b/src/TokenType.cs new file mode 100644 index 0000000..c630ee5 --- /dev/null +++ b/src/TokenType.cs @@ -0,0 +1,516 @@ +using System; + +namespace EzrSquared; + +/// +/// The identifying type of a . +/// +public enum TokenType : ushort +{ + /// + /// An integer, part of the type-group. + /// + Integer, + + /// + /// A floating-point number, part of the type-group. + /// + FloatingPoint, + + /// + /// A text-string, string, or a sequence of characters, part of the type-group. + /// + String, + + /// + /// A character, part of the type-group. + /// + Character, + + /// + /// A character list, which is a mutable string, part of the type-group. + /// + CharacterList, + + /// + /// The keyword "and", case-insensitive, part of the type-group. + /// + KeywordAnd, + + /// + /// The keyword "or", case-insensitive, part of the type-group. + /// + KeywordOr, + + /// + /// The keyword "invert", case-insensitive, part of the type-group. + /// + KeywordInvert, + + /// + /// The keyword "not", case-insensitive, part of the type-group. + /// + KeywordNot, + + /// + /// The keyword "in", case-insensitive, part of the type-group. + /// + KeywordIn, + + /// + /// The keyword "global", case-insensitive, part of the type-group. + /// + KeywordGlobal, + + /// + /// The keyword "private", case-insensitive, part of the type-group. + /// + KeywordPrivate, + + /// + /// The keyword "constant", case-insensitive, part of the type-group. + /// + KeywordConstant, + + /// + /// The keyword "readonly", case-insensitive, part of the type-group. + /// + KeywordReadonly, + + /// + /// The keyword "item", case-insensitive, part of the type-group. + /// + KeywordItem, + + /// + /// The keyword "if", case-insensitive, part of the type-group. + /// + KeywordIf, + + /// + /// The keyword "else", case-insensitive, part of the type-group. + /// + KeywordElse, + + /// + /// The keyword "count", case-insensitive, part of the type-group. + /// + KeywordCount, + + /// + /// The keyword "from", case-insensitive, part of the type-group. + /// + KeywordFrom, + + /// + /// The keyword "to", case-insensitive, part of the type-group. + /// + KeywordTo, + + /// + /// The keyword "step", case-insensitive, part of the type-group. + /// + KeywordStep, + + /// + /// The keyword "as", case-insensitive, part of the type-group. + /// + KeywordAs, + + /// + /// The keyword "while", case-insensitive, part of the type-group. + /// + KeywordWhile, + + /// + /// The keyword "skip", case-insensitive, part of the type-group. + /// + KeywordSkip, + + /// + /// The keyword "stop", case-insensitive, part of the type-group. + /// + KeywordStop, + + /// + /// The keyword "more", case-insensitive, part of the type-group. + /// + KeywordMore, + + /// + /// The keyword "function", case-insensitive, part of the type-group. + /// + KeywordFunction, + + /// + /// The keyword "special", case-insensitive, part of the type-group. + /// + /// + /// This keyword was previously used in the "special functions" structure,
+ /// which were like magic functions in Python, i.e. operator overloading functions.
+ ///
+ /// Since the structure has now been replaced with normal functions with dedicated names,
+ /// this keyword is no longer in use and will be removed in later versions of ezr² if no
+ /// new uses are found. + ///
+ [Obsolete("The \"special\" keyword, used in the \"special functions\" structure which was used for operator overloading, has become obsolete. It will likely be removed in future versions of ezr² due to the structure being replaced with named functions.")] + KeywordSpecial, + + /// + /// The keyword "object", case-insensitive, part of the type-group. + /// + KeywordObject, + + /// + /// The keyword "with", case-insensitive, part of the type-group. + /// + KeywordWith, + + /// + /// The keyword "return", case-insensitive, part of the type-group. + /// + KeywordReturn, + + /// + /// The keyword "last", case-insensitive, part of the type-group. + /// + KeywordLast, + + /// + /// The keyword "try", case-insensitive, part of the type-group. + /// + KeywordTry, + + /// + /// The keyword "catch", case-insensitive, part of the type-group. + /// + KeywordCatch, + + /// + /// The keyword "define", case-insensitive, part of the type-group. + /// + KeywordDefine, + + /// + /// The keyword "static", case-insensitive, part of the type-group. + /// + KeywordStatic, + + /// + /// The keyword "do", case-insensitive, part of the type-group. + /// + KeywordDo, + + /// + /// The keyword "end", case-insensitive, part of the type-group. + /// + KeywordEnd, + + /// + /// The keyword "include", case-insensitive, part of the type-group. + /// + KeywordInclude, + + /// + /// The keyword "all", case-insensitive, part of the type-group. + /// + KeywordAll, + + /// + /// The QuickSyntax keyword "f", case-insensitive, part of the type-group. + /// + QeywordF, + + /// + /// The QuickSyntax keyword "l", case-insensitive, part of the type-group. + /// + QeywordL, + + /// + /// The QuickSyntax keyword "e", case-insensitive, part of the type-group. + /// + QeywordE, + + /// + /// The QuickSyntax keyword "c", case-insensitive, part of the type-group. + /// + QeywordC, + + /// + /// The QuickSyntax keyword "t", case-insensitive, part of the type-group. + /// + QeywordT, + + /// + /// The QuickSyntax keyword "n", case-insensitive, part of the type-group. + /// + QeywordN, + + /// + /// The QuickSyntax keyword "w", case-insensitive, part of the type-group. + /// + QeywordW, + + /// + /// The QuickSyntax keyword "fd", case-insensitive, part of the type-group. + /// + QeywordFd, + + /// + /// The QuickSyntax keyword "sd", case-insensitive, part of the type-group. + /// + QeywordSd, + + /// + /// The QuickSyntax keyword "sb", case-insensitive, part of the type-group. + /// + QeywordSb, + + /// + /// The QuickSyntax keyword "od", case-insensitive, part of the type-group. + /// + QeywordOd, + + /// + /// The QuickSyntax keyword "i", case-insensitive, part of the type-group. + /// + QeywordI, + + /// + /// The QuickSyntax keyword "s", case-insensitive, part of the type-group. + /// + QeywordS, + + /// + /// The QuickSyntax keyword "d", case-insensitive, part of the type-group. + /// + QeywordD, + + /// + /// The QuickSyntax keyword "g", case-insensitive, part of the type-group. + /// + QeywordG, + + /// + /// The QuickSyntax keyword "p", case-insensitive, part of the type-group. + /// + QeywordP, + + /// + /// The QuickSyntax keyword "v", case-insensitive, part of the type-group. + /// + QeywordV, + + /// + /// The '+' symbol, part of the type-group. + /// + Plus, + + /// + /// The '-' symbol, part of the type-group. + /// + HyphenMinus, + + /// + /// The '*' symbol, part of the type-group. + /// + Asterisk, + + /// + /// The '/' symbol, part of the type-group. + /// + Slash, + + /// + /// The '%' symbol, part of the type-group. + /// + PercentSign, + + /// + /// The '^' symbol, part of the type-group. + /// + Caret, + + /// + /// The '&' symbol, part of the type-group. + /// + Ampersand, + + /// + /// The '|' symbol, part of the type-group. + /// + VerticalBar, + + /// + /// The '\' symbol, part of the type-group. + /// + Backslash, + + /// + /// The '~' symbol, part of the type-group. + /// + Tilde, + + /// + /// The '(' symbol, part of the type-group. + /// + LeftParenthesis, + + /// + /// The ')' symbol, part of the type-group. + /// + RightParenthesis, + + /// + /// The '[' symbol, part of the type-group. + /// + LeftSquareBracket, + + /// + /// The ']' symbol, part of the type-group. + /// + RightSquareBracket, + + /// + /// The '{' symbol, part of the type-group. + /// + LeftCurlyBracket, + + /// + /// The '}' symbol, part of the type-group. + /// + RightCurlyBracket, + + /// + /// The '=' symbol, part of the type-group. + /// + EqualSign, + + /// + /// The '!' symbol, part of the type-group. + /// + ExclamationMark, + + /// + /// The '<' symbol, part of the type-group. + /// + LessThanSign, + + /// + /// The '>' symbol, part of the type-group. + /// + GreaterThanSign, + + /// + /// The ',' symbol, part of the type-group. + /// + Comma, + + /// + /// The '.' symbol, part of the type-group. + /// + Period, + + /// + /// The '<<' symbols, used in the bitwise-left-shift operation, part of the type-group. + /// + BitwiseLeftShift, + + /// + /// The '>>' symbols, used in the bitwise-right-shift operation, part of the type-group. + /// + BitwiseRightShift, + + /// + /// The '<=' symbols, used in comparison operations, part of the type-group. + /// + LessThanOrEqual, + + /// + /// The '>=' symbols, used in comparison operations, part of the type-group. + /// + GreaterThanOrEqual, + + /// + /// The ':' symbol, used in assignment operations, part of the type-group. + /// + Colon, + + /// + /// The ':+' symbols, used in assignment operations, part of the type-group. + /// + AssignmentAddition, + + /// + /// The ':-' symbols, used in assignment operations, part of the type-group. + /// + AssignmentSubtraction, + + /// + /// The ':*' symbols, used in assignment operations, part of the type-group. + /// + AssignmentMultiplication, + + /// + /// The ':/' symbols, used in assignment operations, part of the type-group. + /// + AssignmentDivision, + + /// + /// The ':%' symbols, used in assignment operations, part of the type-group. + /// + AssignmentModulo, + + /// + /// The ':^' symbols, used in assignment operations, part of the type-group. + /// + AssignmentPower, + + /// + /// The ':&' symbols, used in assignment operations, part of the type-group. + /// + AssignmentBitwiseAnd, + + /// + /// The ':|' symbols, used in assignment operations, part of the type-group. + /// + AssignmentBitwiseOr, + + /// + /// The ':\' symbols, used in assignment operations, part of the type-group. + /// + AssignmentBitwiseXOr, + + /// + /// The ':<<' symbols, used in assignment operations, part of the type-group. + /// + AssignmentBitwiseLeftShift, + + /// + /// The ':>>' symbols, used in assignment operations, part of the type-group. + /// + AssignmentBitwiseRightShift, + + /// + /// Represents an identifier, a name that is assigned by the programmer for an element such as variable, class, function, etc.
Part of the type-group. + ///
+ Identifier, + + /// + /// Represents a new line, part of the type-group. + /// + NewLine, + + /// + /// Represents the end of a script, part of the type-group. + /// + EndOfFile, + + /// + /// Represents an invalid token, part of the type-group. + /// + /// + /// If this is passed onto any stage after the Parser, something has gone real wrong. + /// + Invalid +} diff --git a/src/TokenTypeGroup.cs b/src/TokenTypeGroup.cs new file mode 100644 index 0000000..804a503 --- /dev/null +++ b/src/TokenTypeGroup.cs @@ -0,0 +1,40 @@ +namespace EzrSquared; + +/// +/// The type group of a . +/// +/// +/// If you want to see which group a token type is in, check the documentation for that type. +/// +public enum TokenTypeGroup : ushort +{ + /// + /// Groups primitive-type tokens, like integers or strings. + /// + Value, + + /// + /// Groups keyword tokens. + /// + Keyword, + + /// + /// Groups QuickSyntax keyword tokens. + /// + Qeyword, + + /// + /// Groups variable assignment symbol tokens. + /// + AssignmentSymbol, + + /// + /// Groups general symbol tokens. + /// + Symbol, + + /// + /// Groups special tokens. + /// + Special +} diff --git a/src/Util/BigIntegerExtensions.cs b/src/Util/BigIntegerExtensions.cs new file mode 100644 index 0000000..572a770 --- /dev/null +++ b/src/Util/BigIntegerExtensions.cs @@ -0,0 +1,43 @@ +using System.Numerics; + +namespace EzrSquared.Util.Extensions; + +/// +/// Static class extending the type. +/// +public static class BigIntegerExtensions +{ + /// + /// Extension for the power operation between two values. + /// + /// The current . + /// The other which acts as the exponent. + /// The resulting . + public static BigInteger Power(this BigInteger thiz, BigInteger other) + { + BigInteger newValue = thiz; + other--; + + for (BigInteger i = 0; i < other; i++) + newValue *= thiz; + + return newValue; + } + + /// + /// Extension for the power operation between a and a value. + /// + /// The current . + /// The other which acts as the exponent. + /// The resulting . + public static BigInteger Power(this char thiz, BigInteger other) + { + BigInteger newValue = thiz; + other--; + + for (BigInteger i = 0; i < other; i++) + newValue *= thiz; + + return newValue; + } +} diff --git a/src/Util/Utils.cs b/src/Util/Utils.cs new file mode 100644 index 0000000..42e8b33 --- /dev/null +++ b/src/Util/Utils.cs @@ -0,0 +1,121 @@ +using System; +using System.Text; + +namespace EzrSquared.Util; + +/// +/// Utilities functions used in ezrSquared. +/// +public static class Utils +{ + /// + /// value for the last generated unique identifier. + /// + private static long s_currentId = 0; + + /// + /// Generates an incremental unique identifier. + /// + /// A new unique identifier. + public static long GetNextUniqueId() + { + return System.Threading.Interlocked.Increment(ref s_currentId); + } + + /// + /// Converts an index to a power of two, so that the index can be used like an enum flag. + /// + /// + /// This function is used to check if all arguments have been provided to and types.
+ /// The indices of the given arguments are converted to powers of two and bitwise-ored together, then bitwise-anded with the index of a defined parameter which is also converted to a power of two.
+ /// Finally, if the result is the same as the power of two of the parameter's index, this tells the interpreter that the particular required parameter has been provided. + ///
+ /// The index to be converted. + /// The power of two. + public static int IndexToFlag(int index) + { + return (index++ < 3) ? index : (4 * index) - 8; + } + + /// + /// Creates formatted text which contains the text between and , underlined with tilde (~) symbols. + /// + /// The formatted text. + public static (int AdjustedLineNumber, string SourceWithUnderline) SourceWithUnderline(Position startPosition, Position endPosition) + { + string text = startPosition.Script; + int textLength = text.Length; + + int startIndex = startPosition.Index; + int line = startPosition.Line; + + // Adjust the start index if it points to a newline character and the range is empty + if (startIndex < textLength && text[startIndex] == '\n' && endPosition.Index - startIndex == 1) + { + char currentChar = text[startIndex]; + while (startIndex > 0 && char.IsWhiteSpace(currentChar)) + { + if (currentChar == '\n') + line--; + + startIndex--; + currentChar = text[startIndex]; + } + } + + // Find the start of the line containing the start position + // I always forget that LastIndexOf counts backwards from startIndex. + int lineStart = text.LastIndexOf('\n', Math.Min(startIndex, textLength - 1)) + 1; + + // Find the end of the line containing the end position + int lineEnd = endPosition.Index < textLength ? text.IndexOf('\n', endPosition.Index) : -1; + if (lineEnd == -1) + lineEnd = textLength - (startPosition.Index - startIndex); + + // Move start to the first non-whitespace character on the line + while (lineStart < textLength && char.IsWhiteSpace(text[lineStart])) + lineStart++; + + // Determine if the error spans multiple lines + int firstNewLineAfterStart = text.IndexOf('\n', lineStart); + bool isMultiline = firstNewLineAfterStart >= 0 && firstNewLineAfterStart < lineEnd; + + // Build the result string + StringBuilder result = new(" "); + result.Append(text, lineStart, lineEnd - lineStart); + + if (isMultiline) + result.Replace("\n", "\n "); + else + { + result.Append('\n'); + result.Append(' ', Math.Max(0, Math.Min(startIndex + 1, startPosition.Index) - lineStart) + 2); + + result.Append('~', Math.Max(1, endPosition.Index - startPosition.Index)); + } + + return (line, result.ToString()); + } + + /// + /// Converts a string from PascalCase to snake_case. + /// + /// The text to convert in PascalCase. + /// The converted text in snake_case. + public static string PascalToSnakeCase(string text) + { + StringBuilder result = new(); + result.Append(char.ToLowerInvariant(text[0])); + + for (int i = 1; i < text.Length; ++i) + { + char c = text[i]; + if (char.IsUpper(c)) + result.Append('_').Append(char.ToLowerInvariant(c)); + else + result.Append(c); + } + + return result.ToString(); + } +} diff --git a/tests/calculator++.ezr2 b/tests/calculator++.ezr2 new file mode 100644 index 0000000..ecc1cf5 --- /dev/null +++ b/tests/calculator++.ezr2 @@ -0,0 +1,609 @@ +\editor + +define static + object utils do + function char_is_valid_letter with char do (char >= 97 and char <= 122) or (char >= 65 and char <= 90) or char = `_` + + function string_index_of with string, char, start_index do + string_length: string_length(string) + + if start_index < 0 or start_index >= string_length do return -1 + count from start_index to string_length - start_index as i do + if string < i = char do return i + end + + return -1 + end + + function string_last_index_of with string, char, start_index do + string_length: string_length(string) + + if start_index < 0 or start_index >= string_length do return -1 + + last_index: -1 + count from start_index to string_length - start_index as i do + if string < i = char do last_index: i + end + + return last_index + end + + function string_length with string do + length: 0 + + while true do + try do + string < length + catch value_out_of_range_error do + stop + end + + length:+ 1 + end + + return length + end + + function string_with_underline with start_position, end_position do + text: start_position.script + text_length: string_length(text) + + start_index: start_position.index + if start_index < text_length and text < start_index = `\n` and end_position.index - start_index = 1 do + start_index: if start_index - 2 < 0 do 0 else do start_index - 2 + end + + start: string_last_index_of(text, `\n`, if start_index < text_length - 1 do start_index else do text_length - 1) + 1 + + while start < text_length and text < start in (` `, `\t`, `\n`) do + start:+ 1 + end + + end_: string_index_of(text, `\n`, start) + if end_ = -1 do end_: text_length - 1 + + result: ' ' + result + (text < (start, end_)) + result + `\n` + + loop_iterations: (if start_position.index - start < 0 do 0 else do start_position.index - start) + 2 + + count to loop_iterations do + result + ` ` + end + + loop_iterations: if end_position.index - start_position.index < 1 do 1 else do end_position.index - start_position.index + count to loop_iterations do + result + `~` + end + + result + `\n` + return result + end + end +end + +object position do + define static + private _none: nothing + + constant function none do + if _none = nothing do + _none: position(-1, -1, "", "") + end + + return _none + end + end + + constant function initialize with index, line, file, script do + this.index: index + this.line: line + this.file: file + this.script: script + end + + function advance with current_char: `\0` do + this.index:+ 1 + + if current_char = `\n` do + this.line :+ 1 + end + end + + function to_string do type_name_of(this) + `(` + this.index + ", " + this.line + `)` +end + +object token do + constant function initialize with type, value, start_position, end_position: nothing do + this.type: type + this.value: value + this.start_position: start_position + + if end_position = nothing do + this.end_position: copy(this.start_position) + this.end_position.advance() + else do + this.end_position: end_position + end + end + + constant function to_string do + return type_name_of(this) + `(` + this.type + ", " + this.value + `)` + end +end + +object exception do + define static constant + invalid_grammar: "Invalid grammar" + unexpected_character: "Unexpected character" + undefined_variable: "Undefined variable" + end + + constant function initialize with title, details, start_position, end_position: nothing do + this.title: title + this.details: details + this.start_position: start_position + + if end_position ! nothing do + this.end_position: end_position + else do + this.end_position: copy(start_position) + this.end_position.advance() + end + end + + function to_string do this.title + + " in " + this.start_position.file + + ", line " + this.start_position.line + + ": " + this.details + `\n` + + utils.string_with_underline(this.start_position, this.end_position) +end + +object lexer do + constant function initialize with file, script do + define private + this.file: file + this.script: script + + this.position: position(-1, 1, this.file, this.script) + this.current_char: `\0` + this.reached_end: false + end + + advance() + end + + private function advance do + this.position.advance(this.current_char) + + try do + this.current_char: this.script < this.position.index + catch value_out_of_range_error do + this.reached_end: true + end + end + + function tokenize do + error: nothing + tokens: [] + + while not this.reached_end do + if this.current_char = `\r` + or this.current_char = `\t` + or this.current_char = ` ` do + advance() + else if this.current_char in (`\n`, `;`) do + tokens + compile_new_lines() + else if this.current_char in (`+`, `-`, `*`, `/`, `%`, `^`, `(`, `)`) do + tokens + token(this.current_char, "", copy(this.position)) + advance() + else if this.current_char >= 48 and this.current_char <= 57 do + tokens + compile_number() + else if utils.char_is_valid_letter(this.current_char) do + tokens + compile_identifier() + else do + error: exception(exception.unexpected_character, "Unexpected character '" + this.current_char + `'`, copy(this.position)) + stop + end + end + + tokens + token("endoffile", "", copy(this.position)) + return (tokens, error) + end + + private function compile_new_lines do + while not this.reached_end and this.current_char in (`\n`, `;`) do + advance() + end + + return token("newline", "", copy(this.position)) + end + + private function compile_identifier do + identifier: '' + start_position: copy(this.position) + + while not this.reached_end and utils.char_is_valid_letter(this.current_char) do + identifier + this.current_char + advance() + end + + if identifier = "def" do + return token(identifier, "", start_position, copy(this.position)) + else do + return token("identifier", identifier, start_position, copy(this.position)) + end + end + + private function compile_number do + start_position: copy(this.position) + number: 0 + + while not this.reached_end and this.current_char >= 48 and this.current_char <= 57 do + number: (number * 10) + (this.current_char - 48) + advance() + end + + return token("integer", number, start_position, copy(this.position)) + end +end + +object node do + constant function initialize with type, data, start_position, end_position do + this.type: type + this.data: data + this.start_position: start_position + this.end_position: end_position + end + + constant function to_string do + return type_name_of(this) + `(` + this.type + ", " + this.data + `)` + end +end + +object result do + constant function initialize do + reset() + end + + function success with value do + this.value: value + end + + function failure with priority, error do + if this.error = nothing or this.error_priority <= priority do + this.error_priority: priority + this.error: error + end + end + + function reset do + this.error: nothing + this.value: nothing + this.advance_count: 0 + this.error_priority: 0 + end +end + +object parser do + constant function initialize with tokens do + define private + this.tokens: tokens + this.current_token: nothing + this.result: result() + + this.index: -1 + this.reached_end: false + end + + advance() + end + + private function advance with advance_count: 1 do + this.index:+ advance_count + this.result.advance_count:+ advance_count + + try do + this.current_token: this.tokens < this.index + catch value_out_of_range_error do + this.reached_end: true + end + end + + private function reverse with reverse_count: 1 do + advance(-reverse_count) + end + + function parse do + parse_statements() + if this.result.error = nothing and this.current_token.type ! "endoffile" do + this.result.failure(10, exception(exception.invalid_grammar, "Did not expect this!", this.current_token.start_position, this.current_token.end_position)) + end + + return this.result + end + + private function binary_operation with left, right, operators do + start_position: this.current_token.start_position + + left() + if this.result.error ! nothing do return + + left_node: this.result.value + reverse_to: this.result.advance_count + + if this.current_token.type = "newline" do advance() + + while not this.reached_end and this.current_token.type in operators do + operator: this.current_token.type + advance() + + if this.current_token.type = "newline" do advance() + + right() + if this.result.error ! nothing do return + + right_node: this.result.value + + left_node: node("binary_operation", (left_node, right_node, operator), start_position, this.current_token.end_position) + reverse_to: this.result.advance_count + + if this.current_token.type = "newline" do advance() + end + + reverse(this.result.advance_count - reverse_to) + this.result.success(left_node) + end + + private function parse_statements do + statements: [] + start_position: this.current_token.start_position + + if this.current_token.type = "newline" do advance() + + parse_expression() + if this.result.error ! nothing do return + + statements + this.result.value + while true do + if this.current_token.type = "newline" do + advance() + else do + stop + end + + if this.current_token.type = "endoffile" do stop + + parse_expression() + if this.result.error ! nothing do return + + statements + this.result.value + end + + this.result.success(node("array", statements, start_position, this.current_token.end_position)) + end + + private function parse_expression do + start_position: this.current_token.start_position + + if this.current_token.type = "def" do + advance() + + if this.current_token.type ! "identifier" do + this.result.failure(10, exception(exception.invalid_grammar, "Expected an identifier as the 'def' keyword was used!", this.current_token.start_position, this.current_token.end_position)) + return + end + + identifier: this.current_token.value + advance() + + parse_expression() + if this.result.error ! nothing do return + + this.result.success(node("assignment", (identifier, this.result.value), start_position, this.current_token.end_position)) + return + end + + parse_arithmetic_expression() + if this.result.error ! nothing do + this.result.failure(4, exception(exception.invalid_grammar, "Expected an expression!", this.current_token.start_position, this.current_token.end_position)) + end + end + + private function parse_arithmetic_expression do + binary_operation(parse_term, parse_term, (`+`,`-`)) + end + + private function parse_term do + binary_operation(parse_factor, parse_factor, (`*`,`/`, `%`)) + end + + private function parse_factor do + start_position: this.current_token.start_position + + operator: this.current_token.type + if operator in (`+`, `-`) do + advance() + + parse_factor() + if this.result.error ! nothing do return + + this.result.success(node("factor", (operator, this.result.value), start_position, this.current_token.end_position)) + return + end + + parse_power() + end + + private function parse_power do + binary_operation(parse_atom, parse_atom, (`^`,)) + end + + private function parse_atom do + token: this.current_token + + if token.type = "identifier" do + this.result.success(node("access", token.value, token.start_position, token.end_position)) + else if token.type = "integer" do + this.result.success(node("integer", token.value, token.start_position, token.end_position)) + else if token.type = `(` do + advance() + + parse_expression() + if this.result.error ! nothing do return + + if this.current_token.type ! `)` do + this.result.failure(10, exception(exception.invalid_grammar, "Expected ')' as you started a parenthetical expression!", this.current_token.start_position, this.current_token.end_position)) + return + end + else do + this.result.failure(4, exception(exception.invalid_grammar, "Expected an integer, identifier, 'def' expression, and so on.", this.current_token.start_position, this.current_token.end_position)) + return + end + + advance() + end +end + +object interpreter do + constant function initialize do + this.context: {} + this.result: result() + end + + function execute with node do + this.result.reset() + visit_node(node) + + return this.result + end + + private function visit_node with node do + if node.type = "integer" do + this.result.success(node.data) + else if node.type = "factor" do + operator: node.data < 0 + + visit_node(node.data < 1) + if this.result.error ! nothing do return + + if operator = `+` do + this.result.success(+this.result.value) + else do + this.result.success(-this.result.value) + end + else if node.type = "binary_operation" do + visit_binary_operation(node) + else if node.type = "array" do + visit_array(node) + else if node.type = "access" do + visit_access(node) + else if node.type = "assignment" do + visit_assignment(node) + else do + throw_error(unexpected_type_error("Unexpected node type: " + node.type)) + end + end + + private function visit_array with node do + index: 0 + results: [] + + while true do + try do + statement: node.data < index + catch value_out_of_range_error do + stop + end + + visit_node(statement) + if this.result.error ! nothing do return + + results + this.result.value + index:+ 1 + end + + this.result.success(results) + end + + private function visit_access with node do + try do + value: this.context < node.data + catch key_not_found_error do + this.result.failure(10, exception(exception.undefined_variable, "Undefined variable \"" + node.data + "\"!", node.start_position, node.end_position)) + return + end + + this.result.success(value) + end + + private function visit_assignment with node do + visit_node(node.data < 1) + if this.result.error ! nothing do return + + value: this.result.value + this.context + (node.data < 0, value) + + this.result.success(value) + end + + private function visit_binary_operation with node do + visit_node(node.data < 0) + if this.result.error ! nothing do return + + left: this.result.value + + visit_node(node.data < 1) + if this.result.error ! nothing do return + + (right, operator): (this.result.value, node.data < 2) + if operator = `+` do + this.result.success(left + right) + else if operator = `-` do + this.result.success(left - right) + else if operator = `*` do + this.result.success(left * right) + else if operator = `/` do + this.result.success(left / right) + else if operator = `%` do + this.result.success(left % right) + else if operator = `^` do + this.result.success(left ^ right) + else do + throw_error(unexpected_type_error("Unexpected binary operator \"" + operator + "\"!")) + end + end +end + +function main do + interpreter: interpreter() + + while true do + input: get(">> ") + if input = `q` do stop + + (tokens, error): lexer("shell", input).tokenize() + if error ! nothing do + show("LEXER ERROR! " + error + "\nTokens: " + tokens) + else do + show(tokens) + end + + parse_result: parser(tokens).parse() + if parse_result.error ! nothing do + show("PARSER ERROR! " + parse_result.error + "\nNode: " + parse_result.value) + else do + show(parse_result.value) + end + + runtime_result: interpreter.execute(parse_result.value) + if runtime_result.error ! nothing do + show("RUNTIME ERROR! " + runtime_result.error + "\nValue: " + runtime_result.value) + else do + show(runtime_result.value) + end + end +end + +\run diff --git a/tests/calculator.ezr2 b/tests/calculator.ezr2 new file mode 100644 index 0000000..14b582b --- /dev/null +++ b/tests/calculator.ezr2 @@ -0,0 +1,95 @@ +\editor + +function get_input with message: "", skip_spaces: true do + raw_input: get(message) + + input_components: [] + + index: 0 + + number: 0 + was_previous_number: false + + while true do + try do + char: raw_input < index + catch value_out_of_range_error do + if was_previous_number do input_components + number + + stop + catch as other_error do + throw_error(other_error) + end + + if char >= 48 and char <= 57 do + if not was_previous_number do number: 0 + + number: (number * 10) + (char - 48) + was_previous_number: true + else do + if was_previous_number do input_components + number + + was_previous_number: false + + if char ! ` ` or not skip_spaces do input_components + char + end + + index :+ 1 + end + + return input_components +end + +function calculate with input_components do + result: nothing + + index: 0 + + number: 0 + operator: nothing + + while true do + try do + component: input_components < index + catch value_out_of_range_error do + stop + catch as other_error do + throw_error(other_error) + end + + if type_name_of(component) = "integer" do + if result = nothing do result: component else do number: component + + if operator ! nothing do + if operator = `+` do + result :+ number + else if operator = `-` do + result :- number + else if operator = `x` do + result :* number + else if operator = `/` do + result :/ number + end + + operator = nothing + end + else do + operator: component + end + + index:+ 1 + end + + return result +end + +while true do + input: get_input("Enter calculation: ") + try do + if input < 0 = `q` do stop + end + + show(calculate(input)) +end + +\run diff --git a/tests/full_test.ezr2 b/tests/full_test.ezr2 index 63f2c7c..87fc51f 100644 --- a/tests/full_test.ezr2 +++ b/tests/full_test.ezr2 @@ -1,81 +1,119 @@ -@ This is still todo. -show("----item test----") - item a: 2 - show(a) - item a: 3 - show(a) - a: 4 - show(a) - a: 2 - show(a) +\editor -show("----and/or test----") - show(a and 6) - show(a and 0) - show(a or 6) - show(a or 0) - -show("----invert test----") - show(invert a) - show(invert true) - show(invert 0) - show(invert 65) - -show("----if test----") - if a do - show("sds") - else do - show("sd") - end - - if invert a do - show("sds") - else do - show("sd") - end - - if invert a do - show("sds") - else if invert 1 do - show("sd") - else do - show("dssdf") - end +@ Example Test Script for ezrSquared -show("----count test----") - count from 0 to 10 as i do - show("sd") - end +@ Variable Assignments +item a : 10 +item b : 20 +item c : a + b +item d : a * b - count from 0 to 10 step 2 as i do - show("sd_") - end +@ Assert variable assignments +assert(a = 10) +assert(b = 20) +assert(c = 30) +assert(d = 200) - count from 0 to 10 as i do - if i = 5 do - skip - end - - show("sd" + i.as_string()) - end +@ Condition Checking +item isEqual : (a = b) +item isGreater : (a > b) +item isLess : (a < b) - count from 0 to 10 as i do - if i = 5 do - stop - end - - show("sd2" + i.as_string()) - end +@ Assert condition checking +assert(isEqual = false) @ a is not equal to b +assert(isGreater = false) @ a is not greater than b +assert(isLess = true) @ a is less than b + +@ Logical Operators +item andCondition : (a < b) and (b > 15) +item orCondition : (a < b) or (b < 10) + +@ Assert logical operations +assert(andCondition = true) @ a < b is true, and b > 15 is true +assert(orCondition = true) @ a < b is true, but b < 10 is false + +@ Negations +item notCondition : not (a = b) + +@ Assert negation +assert(notCondition = true) @ a is not equal to b + +@ Complex Expressions +item complexExpression : (a + b > 25) and (d / a = b) + +@ Assert complex expressions +assert(complexExpression = true) @ (a + b > 25) is true and (d / a = b) is true + +@ Nested Assertions +item x : 5 +item y : 10 +item z : x + y + +assert(x = 5 and y = 10 and z = 15) @ All conditions must be true + +@ If-Else Logic Simulation +item result : "" + +if (a < b) do + result : "a is less than b" +else if (a = b) do + result : "a is equal to b" +else do + result : "a is not less than b and not equal to b" +end + +@ Assert if-else logic +assert(result = "a is less than b") + +@ Loops +@ Shortest version +item sum : 0 +count to 5 do + sum : sum + 1 +end + +@ Assert shortest loop result +assert(sum = 5) @ Loop counts from 1 to 5, summing up to 5 + +@ Full version +item total : 0 +count from 1 to 5 step 1 as i do + total : total + i +end + +@ Assert full loop result +assert(total = 10) @ Sum of numbers from 1 to 4 is 10 + +@ Functions +@ Function without parameters +function add do + return 5 + 7 +end + +item functionResult : add() + +@ Assert function result +assert(functionResult = 12) @ Function add returns 12 + +@ Function with parameters +function addNumbers with a, b do + return a + b +end + +item sumResult : addNumbers(5, 7) + +@ Assert function with parameters +assert(sumResult = 12) @ 5 + 7 should be 12 show("----while test----") while a do show(a) - item a: a - 1 + a:- 1 end item a: 30 while a do - item a: a - 1 + a:- 1 if a = 20 do skip end @@ -85,7 +123,7 @@ show("----while test----") item a: 30 while a do - item a: a - 1 + item a:- 1 if a = 20 do stop end @@ -93,23 +131,6 @@ show("----while test----") show(a) end -show("----function test----") - function name with args do - show(args) - end - - function nameno do - show("noargs") - end - - function retu do - return 2 - end - - show(name("fdgffdf")) - show(nameno()) - show(retu()) - show("----try test----") try do 1/0 @@ -117,47 +138,47 @@ show("----try test----") try do 1/0 - error do + catch do show("errrrr") end try do 1/0 - error "math-error" do + catch math_error do show("errrrr") - error do + catch do show("sdfsdf") end try do 1/0 - error "MAH" do + catch illegal_operation_error do show("errrrr") - error do + catch do show("sdfsdf") end -show("----include test----") - include "time.py" - show(time.time()) - show(time.localTime(time.time())) - show(time.localTime(time.time()).readableTime()) - include "time.py" as t - show(t.time()) - show(t.localTime(t.time())) - show(t.localTime(t.time()).readableTime()) +@ show("----include test----") +@ include "time.py" +@ show(time.time()) +@ show(time.localTime(time.time())) +@ show(time.localTime(time.time()).readableTime()) +@ include "time.py" as t +@ show(t.time()) +@ show(t.localTime(t.time())) +@ show(t.localTime(t.time()).readableTime()) show("----global test----") function ChangeA with NewA do - show("a: " + a.as_string()) + show("a: " + a) function localChangeA with localNewA do function local2ChangeA with local2NewA do - global item a: local2NewA + global a: local2NewA end local2ChangeA(localNewA) - show("a: " + a.as_string()) + show("a: " + a) end localChangeA(NewA) @@ -180,7 +201,7 @@ show("----array test----") show((1)) show((1,)) show((1,2,3)) - show((1,2,3)<=1) + show((1,2,3)<1) show((1,2,3)*6) show(((1,2,3)*6)/2) @@ -194,7 +215,7 @@ show("----list test----") show(a) a + [3,[3,4],4] show(a) - show(a<=5<=1) + show(a<=5<1) a - 5 show(a) show(a*2) @@ -227,19 +248,26 @@ show("----dict test----") show("----object test----") object obj do - item a: 4 - + + constant function initialize do + this.a: 4 + end + function name with args do show("obj") show(args) end end - object objtoo with args do - item a: args + object objtoo do + + constant function initialize with args do + this.a: args + end + function name do show("obj") - show(args) + show(this.a) end end @@ -250,4 +278,7 @@ show("----object test----") show(objtoo("dsfsfdfdsfsd").a) show(objtoo("dsfsfdfdsfsd").name()) -show("----test complete----") \ No newline at end of file +show("----test complete----") + +\run + From 10a3e81187f91f8f896015deb253df4184c0e73f Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sun, 4 Aug 2024 23:37:05 +0530 Subject: [PATCH 018/113] Fixed README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0438f96..2ee354c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ More information and documentation about ezr² is available at ***https://uralstech.github.io/ezrSquared***! ## What's the 'ezrSquared-re' branch? -ezr² is being rewritten from the ground up! Expect more features, better performance and better code documentation! +ezr² is being rewritten from the ground up! Expect more features, better performance and better code documentation! ## Update! The development status of ezr² is now available on [***the ezr² project***](https://github.com/users/Uralstech/projects/3) and [***my blog***](https://uralstech.github.io/). From 4bf3de285673cd102e9631a32a65fead8649270c Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sun, 4 Aug 2024 23:59:47 +0530 Subject: [PATCH 019/113] Updated LICENSE and README. --- LICENSE.txt | 2 +- README.md | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 5211d18..9061c69 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2022 - 2023 URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED + Copyright 2022 - 2024 URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 2ee354c..6afe8a1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ # The `ezr²` Programming Language **ezr², or ezrSquared when you can't use the `²` symbol (or it's too inconvenient) - is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#!** -More information and documentation about ezr² is available at ***https://uralstech.github.io/ezrSquared***! +More information and documentation about ezr² is available at ******! + +For reference documentation on ezr²'s code, check out ******. +The offline reference documentation is available in the releases section of this repository. ## What's the 'ezrSquared-re' branch? ezr² is being rewritten from the ground up! Expect more features, better performance and better code documentation! From 0f0139e693f07e2bf4df39a458b5c88743b403e3 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Mon, 5 Aug 2024 19:57:34 +0530 Subject: [PATCH 020/113] =?UTF-8?q?Added=20ezr=C2=B2=20RE=20graphics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- graphics/{ => Icon PNGs}/Icon (14x14).png | Bin graphics/{ => Icon PNGs}/Icon (16x16).png | Bin graphics/{ => Icon PNGs}/Icon (24x24).png | Bin graphics/{ => Icon PNGs}/Icon (256x256).png | Bin graphics/{ => Icon PNGs}/Icon (32x32).png | Bin graphics/{ => Icon PNGs}/Icon (48x48).png | Bin graphics/{ => Icon PNGs}/Icon (64x64).png | Bin graphics/RE Graphics/ezrSquared RE Final.piskel | 1 + .../RE Graphics/ezrSquared RE Variants.piskel | 1 + graphics/RE Graphics/ezrSquared RE template.png | Bin 0 -> 5134 bytes graphics/RE Graphics/ezrSquared RE.png | Bin 0 -> 9099 bytes 11 files changed, 2 insertions(+) rename graphics/{ => Icon PNGs}/Icon (14x14).png (100%) rename graphics/{ => Icon PNGs}/Icon (16x16).png (100%) rename graphics/{ => Icon PNGs}/Icon (24x24).png (100%) rename graphics/{ => Icon PNGs}/Icon (256x256).png (100%) rename graphics/{ => Icon PNGs}/Icon (32x32).png (100%) rename graphics/{ => Icon PNGs}/Icon (48x48).png (100%) rename graphics/{ => Icon PNGs}/Icon (64x64).png (100%) create mode 100644 graphics/RE Graphics/ezrSquared RE Final.piskel create mode 100644 graphics/RE Graphics/ezrSquared RE Variants.piskel create mode 100644 graphics/RE Graphics/ezrSquared RE template.png create mode 100644 graphics/RE Graphics/ezrSquared RE.png diff --git a/graphics/Icon (14x14).png b/graphics/Icon PNGs/Icon (14x14).png similarity index 100% rename from graphics/Icon (14x14).png rename to graphics/Icon PNGs/Icon (14x14).png diff --git a/graphics/Icon (16x16).png b/graphics/Icon PNGs/Icon (16x16).png similarity index 100% rename from graphics/Icon (16x16).png rename to graphics/Icon PNGs/Icon (16x16).png diff --git a/graphics/Icon (24x24).png b/graphics/Icon PNGs/Icon (24x24).png similarity index 100% rename from graphics/Icon (24x24).png rename to graphics/Icon PNGs/Icon (24x24).png diff --git a/graphics/Icon (256x256).png b/graphics/Icon PNGs/Icon (256x256).png similarity index 100% rename from graphics/Icon (256x256).png rename to graphics/Icon PNGs/Icon (256x256).png diff --git a/graphics/Icon (32x32).png b/graphics/Icon PNGs/Icon (32x32).png similarity index 100% rename from graphics/Icon (32x32).png rename to graphics/Icon PNGs/Icon (32x32).png diff --git a/graphics/Icon (48x48).png b/graphics/Icon PNGs/Icon (48x48).png similarity index 100% rename from graphics/Icon (48x48).png rename to graphics/Icon PNGs/Icon (48x48).png diff --git a/graphics/Icon (64x64).png b/graphics/Icon PNGs/Icon (64x64).png similarity index 100% rename from graphics/Icon (64x64).png rename to graphics/Icon PNGs/Icon (64x64).png diff --git a/graphics/RE Graphics/ezrSquared RE Final.piskel b/graphics/RE Graphics/ezrSquared RE Final.piskel new file mode 100644 index 0000000..ded664d --- /dev/null +++ b/graphics/RE Graphics/ezrSquared RE Final.piskel @@ -0,0 +1 @@ +{"modelVersion":2,"piskel":{"name":"Icon (256x256)","description":"","fps":0,"height":256,"width":512,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":1,\"chunks\":[{\"layout\":[[0]],\"base64PNG\":\"data:image/png;base64,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\"}]}"]}} \ No newline at end of file diff --git a/graphics/RE Graphics/ezrSquared RE Variants.piskel b/graphics/RE Graphics/ezrSquared RE Variants.piskel new file mode 100644 index 0000000..992173d --- /dev/null +++ b/graphics/RE Graphics/ezrSquared RE Variants.piskel @@ -0,0 +1 @@ +{"modelVersion":2,"piskel":{"name":"Icon (256x256)","description":"","fps":0,"height":256,"width":512,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":8,\"chunks\":[{\"layout\":[[0],[1],[2],[3],[4],[5],[6],[7]],\"base64PNG\":\"data:image/png;base64,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\"}]}"]}} \ No newline at end of file diff --git a/graphics/RE Graphics/ezrSquared RE template.png b/graphics/RE Graphics/ezrSquared RE template.png new file mode 100644 index 0000000000000000000000000000000000000000..f9363fbf28bd3a946f5b10cb43572d5ab95bd9fd GIT binary patch literal 5134 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 Date: Mon, 5 Aug 2024 20:56:25 +0530 Subject: [PATCH 021/113] =?UTF-8?q?ezr=C2=B2=20v0.1.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 10 +++++++- docs/_config.yml | 18 ++++++++++++-- docs/index.markdown | 25 ++++++++++++-------- src/EzrSquared.csproj | 3 +-- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 14 +++++------ src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 14 +++++------ src/Shell/Shell.csproj | 2 +- 8 files changed, 57 insertions(+), 31 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index c5b0c41..3fca10d 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,13 @@ CHANGELOG - What's new? - + +* ezr² RE - v0.1.1 [05-08-24] + * Updated documentation and some graphics. + +* ezr² RE - Part 3 [04-08-24] + * Almost completed rewriting the Interpreter and its supporting components. + * Fixed a ton of bugs in the Lexer, Parser and their supporting components. + * Added an improved Shell as a separate project from the main ezr² stuff. + * ezr² Rewrite - Part 2 [13-09-23] * Completed rewriting the Parser (without QuickSyntax support) and its supporting components. diff --git a/docs/_config.yml b/docs/_config.yml index a39d559..ee9d505 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -7,7 +7,7 @@ author: Uralstech exclude: ["offline/"] -remote_theme: just-the-docs/just-the-docs@v0.4.1 +remote_theme: just-the-docs/just-the-docs@v0.8.2 plugins: - jekyll-feed - jekyll-remote-theme @@ -34,7 +34,21 @@ callouts: title: Warning color: yellow +nav_external_links: + - title: ezr² RE Reference Documentation + url: https://uralstech.github.io/ezrSquaredRefDocs + opens_in_new_tab: true + footer_content: "ezrSquared is licensed under the Apache License, Version 2.0." +enable_copy_code_button: true + last_edit_timestamp: true -last_edit_time_format: "%b %e %Y at %I:%M %p" \ No newline at end of file +last_edit_time_format: "%b %e %Y at %I:%M %p" + +gh_edit_link: true +gh_edit_link_text: "Edit this page on GitHub." +gh_edit_repository: "https://github.com/Uralstech/ezrSquared" +gh_edit_branch: "ezrSquared-re" +gh_edit_source: docs +gh_edit_view_mode: "tree" \ No newline at end of file diff --git a/docs/index.markdown b/docs/index.markdown index 3c1f5bc..d2d50f0 100644 --- a/docs/index.markdown +++ b/docs/index.markdown @@ -7,7 +7,7 @@ nav_order: 2 # The `ezr²` Programming Language {: .no_toc } -**ezr², or ezrSquared when you can't use the `²` symbol - is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#! +**ezr² is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#! For more information check out the [*Learn ezr²*](https://uralstech.github.io/ezrSquared/Learn-ezrSquared) page.**
@@ -31,23 +31,23 @@ To install ezr² on your PC, follow these steps: #### Windows (x86 and x64) -* Download the appropriate installer from the [***GitHub Releases page***](https://github.com/uralstech/ezrSquared/releases), or, click on any of the download links. +* Download the appropriate installer from down below. * Run the installer and go through the installation.

-[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20(Windows%20x64)-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Installer.Windows.64-bit.exe) -[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20(Windows%20x86)-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Installer.Windows.32-bit.exe) +[ezr² Pre-release v1.5.1.3.0 for 32-bit Windows](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Installer.Windows.64-bit.exe){: .btn }
+[ezr² Pre-release v1.5.1.3.0 for 64-bit Windows](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Installer.Windows.32-bit.exe){: .btn } #### Linux (x64, ARM64 and ARM) -* Download the appropriate `tar.xz` archive from the [***GitHub Releases page***](https://github.com/uralstech/ezrSquared/releases), or, click on any of the download links. +* Download the appropriate build from down below. * Extract the `tar.xz` file to a folder of your choice. * Optionally, add the folder to your PATH environment variable.

-[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20(Linux%20x64)-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-x64.tar.gz) -[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20(Linux%20ARM64)-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-arm64.tar.gz) -[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20(Linux%20ARM)-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-arm.tar.gz) +[ezr² Pre-release v1.5.1.3.0 for Linux x64](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-x64.tar.gz){: .btn }
+[ezr² Pre-release v1.5.1.3.0 for Linux ARM64](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-arm64.tar.gz){: .btn }
+[ezr² Pre-release v1.5.1.3.0 for Linux ARM](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-arm.tar.gz){: .btn } ### Check the installation @@ -79,12 +79,17 @@ The official documentation for ezr² is available in the [***Learn ezr² page*** Meanwhile, check out some example programs in [***GitHub***](https://github.com/Uralstech/ezrSquared/tree/master/Tests). The offline version of the ezrSquared website was made possible with [***Jekyll Offline***](https://github.com/dohliam/jekyll-offline). -The documentation is packaged with the Windows installer. For other OSes, download and extract the `zip` archive from [***GitHub Releases page***](https://github.com/uralstech/ezrSquared/releases), or, click on the link below: +The documentation is packaged with the Windows installer. For other OSes, download and extract the `zip` archive from here: -[![Badge](https://img.shields.io/badge/pr--1.5.1.3.0%20Documentation-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Offline.Documentation.zip) +[ezr² Offline Documentation](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Offline.Documentation.zip){: .btn } ## Latest Updates +The latest version of ezr² ***RE*** has been released! ezr² ***RE***, or ***REwrite***, is the project's initiative to rewrite ezr². The latest working version of ezr² ***RE*** +has many more features than the latest version of ezr²! But, it is still in development, has some essential features missing. Like the `include` expression, or any built-in object +methods like `"a string".length` or `["a", "list"].insert`. If you want to help in testing it out and fixing bugs, feel free to download the latest version of ezr² ***RE*** from +the ezr² GitHub releases page and compiling it using the .NET SDK and/or Visual Studio. + ezr² now uses [***Semantic Versioning 2.0.0***](https://semver.org/) for new releases. ezr² development updates will be posted on [***my blog***](https://uralstech.github.io/). ## Contributing diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index fd644d0..f993751 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.1.0 + 0.1.1 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED @@ -59,7 +59,6 @@ - diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 26136c1..7b7ee2c 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.1.0"; + private const string Version = "0.1.1"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 5eaaad6..e0860d7 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -3,8 +3,8 @@ #include "environment.iss" -#define MyAppName "ezr²" -#define MyAppVersion "0.1.0" +#define MyAppName "ezr²" +#define MyAppVersion "0.1.1" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" @@ -35,7 +35,7 @@ InfoAfterFile=D:\Code\csharp\ezrSquared\Changelog.txt PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog OutputDir=D:\Code\csharp\ezrSquared\Binaries\Installer\ -OutputBaseFilename=ezr² Installer (Windows 32-bit) +OutputBaseFilename=ezr² Installer (Windows 32-bit) SetupIconFile=D:\Code\csharp\ezrSquared\src\Icon.ico Compression=lzma SolidCompression=yes @@ -58,12 +58,12 @@ Name: "bareMinimum"; Description: "The bare minimum - Excludes the standard libr Name: "custom"; Description: "Custom installation"; Flags: iscustom [Components] -Name: "main"; Description: "ezr² Code Executor"; Types: full compact bareMinimum custom; Flags: fixed -Name: "libs"; Description: "ezr² Standard Libraries"; Types: full compact -Name: "docs"; Description: "ezr² Documentation"; Types: full +Name: "main"; Description: "ezr² Code Executor"; Types: full compact bareMinimum custom; Flags: fixed +Name: "libs"; Description: "ezr² Standard Libraries"; Types: full compact +Name: "docs"; Description: "ezr² Documentation"; Types: full [Tasks] -Name: "addtopath"; Description: "Add ezr² to PATH environment variable"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce +Name: "addtopath"; Description: "Add ezr² to PATH environment variable"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce [Dirs] diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 44af479..df78c5e 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -3,8 +3,8 @@ #include "environment.iss" -#define MyAppName "ezr²" -#define MyAppVersion "0.1.0" +#define MyAppName "ezr²" +#define MyAppVersion "0.1.1" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" @@ -36,7 +36,7 @@ InfoAfterFile=D:\Code\csharp\ezrSquared\Changelog.txt PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog OutputDir=D:\Code\csharp\ezrSquared\Binaries\Installer\ -OutputBaseFilename=ezr² Installer (Windows 64-bit) +OutputBaseFilename=ezr² Installer (Windows 64-bit) SetupIconFile=D:\Code\csharp\ezrSquared\src\Icon.ico Compression=lzma SolidCompression=yes @@ -59,12 +59,12 @@ Name: "bareMinimum"; Description: "The bare minimum - Excludes the standard libr Name: "custom"; Description: "Custom installation"; Flags: iscustom [Components] -Name: "main"; Description: "ezr² Code Executor"; Types: full compact bareMinimum custom; Flags: fixed -Name: "libs"; Description: "ezr² Standard Libraries"; Types: full compact -Name: "docs"; Description: "ezr² Documentation"; Types: full +Name: "main"; Description: "ezr² Code Executor"; Types: full compact bareMinimum custom; Flags: fixed +Name: "libs"; Description: "ezr² Standard Libraries"; Types: full compact +Name: "docs"; Description: "ezr² Documentation"; Types: full [Tasks] -Name: "addtopath"; Description: "Add ezr² to PATH environment variable"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce +Name: "addtopath"; Description: "Add ezr² to PATH environment variable"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce [Dirs] diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index b8282a0..3d193f2 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.1.0 + 0.1.1 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From 69e12e91126ad363b2ec93a06beac31efbc2c6a4 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 6 Aug 2024 18:08:00 +0530 Subject: [PATCH 022/113] =?UTF-8?q?ezr=C2=B2=20v0.1.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pages-upload-action.yml | 43 +++ Changelog.txt | 4 + docs/.gitignore | 7 +- docs/404.html | 33 --- docs/Embedding-ezrSquared.markdown | 7 - docs/Gemfile | 18 -- docs/Gemfile.lock | 276 ------------------ docs/Get-started-with-CSAELs.markdown | 7 - docs/_config.yml | 54 ---- docs/docfx.json | 66 +++++ .../CSharp-and-ezrSquared.md} | 10 +- docs/docsrc/Embedding-ezrSquared.md | 1 + docs/docsrc/Get-started-with-CSAELs.md | 1 + .../Learn-ezrSquared.md} | 21 +- .../Multilingual-ezrSquared.md} | 6 - docs/docsrc/toc.yml | 15 + docs/{assets => }/images/favicon.ico | Bin docs/index.markdown | 101 ------- docs/index.md | 89 ++++++ docs/offline/config.yml | 3 - docs/offline/jekyll_offline.rb | 72 ----- docs/offline/lib_rellinks.rb | 75 ----- docs/offline/template.rhtml | 57 ---- docs/toc.yml | 6 + src/EzrSquared.csproj | 2 +- .../Collections/RuntimeEzrObjectDictionary.cs | 5 +- src/Runtime/Types/BaseTypes.cs | 12 +- src/Runtime/Types/Executables/EzrClass.cs | 11 +- .../Types/Executables/EzrClassInstance.cs | 48 +-- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- src/Syntax/Parser/Parser.cs | 2 +- 34 files changed, 280 insertions(+), 780 deletions(-) create mode 100644 .github/workflows/pages-upload-action.yml delete mode 100644 docs/404.html delete mode 100644 docs/Embedding-ezrSquared.markdown delete mode 100644 docs/Gemfile delete mode 100644 docs/Gemfile.lock delete mode 100644 docs/Get-started-with-CSAELs.markdown delete mode 100644 docs/_config.yml create mode 100644 docs/docfx.json rename docs/{CSharp-and-ezrSquared.markdown => docsrc/CSharp-and-ezrSquared.md} (77%) create mode 100644 docs/docsrc/Embedding-ezrSquared.md create mode 100644 docs/docsrc/Get-started-with-CSAELs.md rename docs/{Learn-ezrSquared.markdown => docsrc/Learn-ezrSquared.md} (97%) rename docs/{Multilingual-ezrSquared.markdown => docsrc/Multilingual-ezrSquared.md} (97%) create mode 100644 docs/docsrc/toc.yml rename docs/{assets => }/images/favicon.ico (100%) delete mode 100644 docs/index.markdown create mode 100644 docs/index.md delete mode 100644 docs/offline/config.yml delete mode 100644 docs/offline/jekyll_offline.rb delete mode 100644 docs/offline/lib_rellinks.rb delete mode 100644 docs/offline/template.rhtml create mode 100644 docs/toc.yml diff --git a/.github/workflows/pages-upload-action.yml b/.github/workflows/pages-upload-action.yml new file mode 100644 index 0000000..b8a0ea5 --- /dev/null +++ b/.github/workflows/pages-upload-action.yml @@ -0,0 +1,43 @@ +# Trigger the action on push to ezrSquared-re +on: + push: + branches: + - ezrSquared-re + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + actions: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + publish-docs: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Dotnet Setup + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 8.x + + - run: dotnet tool update -g docfx + - run: docfx docs/docfx.json + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload entire repository + path: 'docs/_site' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/Changelog.txt b/Changelog.txt index 3fca10d..53ef574 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,9 @@ CHANGELOG - What's new? +* ezr² RE - v0.1.2 [06-08-24] + * Updated documentation. + * Added new documentation website. + * ezr² RE - v0.1.1 [05-08-24] * Updated documentation and some graphics. diff --git a/docs/.gitignore b/docs/.gitignore index f40fbd8..fdabc9f 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,5 +1,2 @@ -_site -.sass-cache -.jekyll-cache -.jekyll-metadata -vendor +/api +/_site \ No newline at end of file diff --git a/docs/404.html b/docs/404.html deleted file mode 100644 index f1ecde9..0000000 --- a/docs/404.html +++ /dev/null @@ -1,33 +0,0 @@ ---- -permalink: /404.html -layout: default ---- - - - -
-

404

- -

Page not found :(

-

The requested page could not be found.

-
diff --git a/docs/Embedding-ezrSquared.markdown b/docs/Embedding-ezrSquared.markdown deleted file mode 100644 index 55fdcfe..0000000 --- a/docs/Embedding-ezrSquared.markdown +++ /dev/null @@ -1,7 +0,0 @@ ---- -layout: default -title: Embedding How-To -nav_order: 5 ---- - -# TODO \ No newline at end of file diff --git a/docs/Gemfile b/docs/Gemfile deleted file mode 100644 index f5b42d1..0000000 --- a/docs/Gemfile +++ /dev/null @@ -1,18 +0,0 @@ -source "https://rubygems.org" -gem "github-pages", "~> 228", group: :jekyll_plugins -gem "jekyll-theme-hacker", group: :jekyll_plugins -gem "just-the-docs" -gem "minima" - -group :jekyll_plugins do - gem "jekyll-feed", "~> 0.12" -end - -platforms :mingw, :x64_mingw, :mswin, :jruby do - gem "tzinfo", ">= 1", "< 3" - gem "tzinfo-data" -end - -gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] -gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] -gem "webrick", "~> 1.8" diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock deleted file mode 100644 index ea63b6a..0000000 --- a/docs/Gemfile.lock +++ /dev/null @@ -1,276 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - activesupport (7.0.4.3) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - addressable (2.8.1) - public_suffix (>= 2.0.2, < 6.0) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.11.1) - colorator (1.1.0) - commonmarker (0.23.8) - concurrent-ruby (1.2.2) - dnsruby (1.61.9) - simpleidn (~> 0.1) - em-websocket (0.5.3) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0) - ethon (0.16.0) - ffi (>= 1.15.0) - eventmachine (1.2.7) - execjs (2.8.1) - faraday (2.7.4) - faraday-net_http (>= 2.0, < 3.1) - ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.2) - ffi (1.15.5) - forwardable-extended (2.6.0) - gemoji (3.0.1) - github-pages (228) - github-pages-health-check (= 1.17.9) - jekyll (= 3.9.3) - jekyll-avatar (= 0.7.0) - jekyll-coffeescript (= 1.1.1) - jekyll-commonmark-ghpages (= 0.4.0) - jekyll-default-layout (= 0.1.4) - jekyll-feed (= 0.15.1) - jekyll-gist (= 1.5.0) - jekyll-github-metadata (= 2.13.0) - jekyll-include-cache (= 0.2.1) - jekyll-mentions (= 1.6.0) - jekyll-optional-front-matter (= 0.3.2) - jekyll-paginate (= 1.1.0) - jekyll-readme-index (= 0.3.0) - jekyll-redirect-from (= 0.16.0) - jekyll-relative-links (= 0.6.1) - jekyll-remote-theme (= 0.4.3) - jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.8.0) - jekyll-sitemap (= 1.4.0) - jekyll-swiss (= 1.0.0) - jekyll-theme-architect (= 0.2.0) - jekyll-theme-cayman (= 0.2.0) - jekyll-theme-dinky (= 0.2.0) - jekyll-theme-hacker (= 0.2.0) - jekyll-theme-leap-day (= 0.2.0) - jekyll-theme-merlot (= 0.2.0) - jekyll-theme-midnight (= 0.2.0) - jekyll-theme-minimal (= 0.2.0) - jekyll-theme-modernist (= 0.2.0) - jekyll-theme-primer (= 0.6.0) - jekyll-theme-slate (= 0.2.0) - jekyll-theme-tactile (= 0.2.0) - jekyll-theme-time-machine (= 0.2.0) - jekyll-titles-from-headings (= 0.5.3) - jemoji (= 0.12.0) - kramdown (= 2.3.2) - kramdown-parser-gfm (= 1.1.0) - liquid (= 4.0.4) - mercenary (~> 0.3) - minima (= 2.5.1) - nokogiri (>= 1.13.6, < 2.0) - rouge (= 3.26.0) - terminal-table (~> 1.4) - github-pages-health-check (1.17.9) - addressable (~> 2.3) - dnsruby (~> 1.60) - octokit (~> 4.0) - public_suffix (>= 3.0, < 5.0) - typhoeus (~> 1.3) - html-pipeline (2.14.3) - activesupport (>= 2) - nokogiri (>= 1.4) - http_parser.rb (0.8.0) - i18n (1.12.0) - concurrent-ruby (~> 1.0) - jekyll (3.9.3) - addressable (~> 2.4) - colorator (~> 1.0) - em-websocket (~> 0.5) - i18n (>= 0.7, < 2) - jekyll-sass-converter (~> 1.0) - jekyll-watch (~> 2.0) - kramdown (>= 1.17, < 3) - liquid (~> 4.0) - mercenary (~> 0.3.3) - pathutil (~> 0.9) - rouge (>= 1.7, < 4) - safe_yaml (~> 1.0) - jekyll-avatar (0.7.0) - jekyll (>= 3.0, < 5.0) - jekyll-coffeescript (1.1.1) - coffee-script (~> 2.2) - coffee-script-source (~> 1.11.1) - jekyll-commonmark (1.4.0) - commonmarker (~> 0.22) - jekyll-commonmark-ghpages (0.4.0) - commonmarker (~> 0.23.7) - jekyll (~> 3.9.0) - jekyll-commonmark (~> 1.4.0) - rouge (>= 2.0, < 5.0) - jekyll-default-layout (0.1.4) - jekyll (~> 3.0) - jekyll-feed (0.15.1) - jekyll (>= 3.7, < 5.0) - jekyll-gist (1.5.0) - octokit (~> 4.2) - jekyll-github-metadata (2.13.0) - jekyll (>= 3.4, < 5.0) - octokit (~> 4.0, != 4.4.0) - jekyll-include-cache (0.2.1) - jekyll (>= 3.7, < 5.0) - jekyll-mentions (1.6.0) - html-pipeline (~> 2.3) - jekyll (>= 3.7, < 5.0) - jekyll-optional-front-matter (0.3.2) - jekyll (>= 3.0, < 5.0) - jekyll-paginate (1.1.0) - jekyll-readme-index (0.3.0) - jekyll (>= 3.0, < 5.0) - jekyll-redirect-from (0.16.0) - jekyll (>= 3.3, < 5.0) - jekyll-relative-links (0.6.1) - jekyll (>= 3.3, < 5.0) - jekyll-remote-theme (0.4.3) - addressable (~> 2.0) - jekyll (>= 3.5, < 5.0) - jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) - rubyzip (>= 1.3.0, < 3.0) - jekyll-sass-converter (1.5.2) - sass (~> 3.4) - jekyll-seo-tag (2.8.0) - jekyll (>= 3.8, < 5.0) - jekyll-sitemap (1.4.0) - jekyll (>= 3.7, < 5.0) - jekyll-swiss (1.0.0) - jekyll-theme-architect (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-cayman (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-dinky (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-hacker (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-leap-day (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-merlot (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-midnight (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-minimal (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-modernist (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.6.0) - jekyll (> 3.5, < 5.0) - jekyll-github-metadata (~> 2.9) - jekyll-seo-tag (~> 2.0) - jekyll-theme-slate (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-tactile (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-time-machine (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-titles-from-headings (0.5.3) - jekyll (>= 3.3, < 5.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - jemoji (0.12.0) - gemoji (~> 3.0) - html-pipeline (~> 2.2) - jekyll (>= 3.0, < 5.0) - just-the-docs (0.4.2) - jekyll (>= 3.8.5) - jekyll-seo-tag (>= 2.0) - rake (>= 12.3.1) - kramdown (2.3.2) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.4) - listen (3.8.0) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - mercenary (0.3.6) - minima (2.5.1) - jekyll (>= 3.5, < 5.0) - jekyll-feed (~> 0.9) - jekyll-seo-tag (~> 2.1) - minitest (5.18.0) - nokogiri (1.14.2-x64-mingw-ucrt) - racc (~> 1.4) - octokit (4.25.1) - faraday (>= 1, < 3) - sawyer (~> 0.9) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (4.0.7) - racc (1.6.2) - rake (13.0.6) - rb-fsevent (0.11.2) - rb-inotify (0.10.1) - ffi (~> 1.0) - rexml (3.2.5) - rouge (3.26.0) - ruby2_keywords (0.0.5) - rubyzip (2.3.2) - safe_yaml (1.0.5) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sawyer (0.9.2) - addressable (>= 2.3.5) - faraday (>= 0.17.3, < 3) - simpleidn (0.2.1) - unf (~> 0.1.4) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - typhoeus (1.4.0) - ethon (>= 0.9.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - tzinfo-data (1.2023.2) - tzinfo (>= 1.0.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) - unicode-display_width (1.8.0) - wdm (0.1.1) - webrick (1.8.1) - -PLATFORMS - x64-mingw-ucrt - -DEPENDENCIES - github-pages (~> 228) - http_parser.rb (~> 0.6.0) - jekyll-feed (~> 0.12) - jekyll-theme-hacker - just-the-docs - minima - tzinfo (>= 1, < 3) - tzinfo-data - wdm (~> 0.1.1) - webrick (~> 1.8) - -BUNDLED WITH - 2.4.8 diff --git a/docs/Get-started-with-CSAELs.markdown b/docs/Get-started-with-CSAELs.markdown deleted file mode 100644 index 305239d..0000000 --- a/docs/Get-started-with-CSAELs.markdown +++ /dev/null @@ -1,7 +0,0 @@ ---- -layout: default -title: CSAELs How-To -nav_order: 6 ---- - -# TODO \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index ee9d505..0000000 --- a/docs/_config.yml +++ /dev/null @@ -1,54 +0,0 @@ -title: "ezrSquared" -email: info@uralstech.in -description: An easy to learn and practical programming language for beginners and experts alike! -markdown: kramdown -encoding: UTF-8 -author: Uralstech - -exclude: ["offline/"] - -remote_theme: just-the-docs/just-the-docs@v0.8.2 -plugins: - - jekyll-feed - - jekyll-remote-theme - -favicon_ico: "/assets/images/favicon.ico" -color_scheme: dark - -aux_links: - "ezrSquared on GitHub": - - "//github.com/Uralstech/ezrSquared" -aux_links_new_tab: true - -search: - heading_level: 3 - previews: 3 - preview_words_before: 5 - preview_words_after: 10 - tokenizer_separator: /[\s/]+/ - rel_url: true - button: true - -callouts: - warning: - title: Warning - color: yellow - -nav_external_links: - - title: ezr² RE Reference Documentation - url: https://uralstech.github.io/ezrSquaredRefDocs - opens_in_new_tab: true - -footer_content: "ezrSquared is licensed under the Apache License, Version 2.0." - -enable_copy_code_button: true - -last_edit_timestamp: true -last_edit_time_format: "%b %e %Y at %I:%M %p" - -gh_edit_link: true -gh_edit_link_text: "Edit this page on GitHub." -gh_edit_repository: "https://github.com/Uralstech/ezrSquared" -gh_edit_branch: "ezrSquared-re" -gh_edit_source: docs -gh_edit_view_mode: "tree" \ No newline at end of file diff --git a/docs/docfx.json b/docs/docfx.json new file mode 100644 index 0000000..6081ec7 --- /dev/null +++ b/docs/docfx.json @@ -0,0 +1,66 @@ +{ + "metadata": [ + { + "src": [ + { + "src": "../src", + "files": [ + "**/*.csproj" + ] + } + ], + "dest": "api", + "includePrivateMembers": true + } + ], + "build": { + "content": [ + { + "files": [ + "**/*.{md,yml}" + ], + "exclude": [ + "_site/**" + ] + } + ], + "resource": [ + { + "files": [ + "images/**" + ] + } + ], + "output": "_site", + "template": [ + "default", + "modern" + ], + "globalMetadata": { + "_appName": "ezr\u00B2 Documentation", + "_appTitle": "ezr\u00B2 Documentation", + "_appFaviconPath": "/images/favicon.ico", + "_appFooter": "(C) 2022 - 2024 URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED, licensed under the Apache License, Version 2.0.", + "_enableSearch": true + }, + "fileMetadata": { + "pdf": { + "api/toc.yml": true + }, + "pdfPrintBackground": { + "api/toc.yml": true + }, + "pdfTocPage": { + "api/toc.yml": true + }, + "pdfFileName": { + "api/toc.yml": "APIReferenceManual.pdf" + } + }, + "sitemap": { + "baseUrl": "https://uralstech.github.io/ezrSquared", + "priority": 1.0, + "changefreq": "monthly" + } + } +} \ No newline at end of file diff --git a/docs/CSharp-and-ezrSquared.markdown b/docs/docsrc/CSharp-and-ezrSquared.md similarity index 77% rename from docs/CSharp-and-ezrSquared.markdown rename to docs/docsrc/CSharp-and-ezrSquared.md index 7f2980a..d470868 100644 --- a/docs/CSharp-and-ezrSquared.markdown +++ b/docs/docsrc/CSharp-and-ezrSquared.md @@ -1,9 +1,3 @@ ---- -layout: default -title: C# and ezr² -nav_order: 4 ---- - # C# and ezr² ## Embedding ezr² to your application! @@ -11,7 +5,7 @@ nav_order: 4 ezr² can be embedded into other programs. This allows your users to write scripts in ezr² which can control various systems in your app. ezr² code is much simple and easier to learn and understand than, for example, C# code. -To learn more about embedding ezr² into your application, check the documentation [***here***](https://uralstech.github.io/ezrSquared/CSharp-and-ezrSquared/Embedding-ezrSquared) +To learn more about embedding ezr² into your application, check the documentation [***here***](Embedding-ezrSquared.md) ## ezr² doesn't have \[feature\] built-in! @@ -20,4 +14,4 @@ Now, this is where **CSAELs** step in. CSAELs, or, **CSharp Assisted ezr² Libra With CSAELs, anyone who knows C# can add any feature they want to ezr². These features can also be built-in to ezr² - it's a win-win situation! All you have to do is wrap C# variables, functions and whatnot with attributes the ezr² interpreter can identify. All these "wrapper" attributes are part of the ezr² API. -To learn more about CSAELs, check the documentation [***here***](https://uralstech.github.io/ezrSquared/CSharp-and-ezrSquared/Get-started-with-CSAELs) +To learn more about CSAELs, check the documentation [***here***](Get-started-with-CSAELs.md) diff --git a/docs/docsrc/Embedding-ezrSquared.md b/docs/docsrc/Embedding-ezrSquared.md new file mode 100644 index 0000000..f87f5c1 --- /dev/null +++ b/docs/docsrc/Embedding-ezrSquared.md @@ -0,0 +1 @@ +# TODO \ No newline at end of file diff --git a/docs/docsrc/Get-started-with-CSAELs.md b/docs/docsrc/Get-started-with-CSAELs.md new file mode 100644 index 0000000..f87f5c1 --- /dev/null +++ b/docs/docsrc/Get-started-with-CSAELs.md @@ -0,0 +1 @@ +# TODO \ No newline at end of file diff --git a/docs/Learn-ezrSquared.markdown b/docs/docsrc/Learn-ezrSquared.md similarity index 97% rename from docs/Learn-ezrSquared.markdown rename to docs/docsrc/Learn-ezrSquared.md index 824077a..2518812 100644 --- a/docs/Learn-ezrSquared.markdown +++ b/docs/docsrc/Learn-ezrSquared.md @@ -1,20 +1,4 @@ ---- -layout: default -title: "Learn ezr²" -nav_order: 2 ---- - # Learn ezr² -{: .no_toc } - -
- - Table of contents - - {: .text-delta } -- TOC -{:toc} -
## Why Learn ezr²? @@ -332,5 +316,6 @@ Here are all the list operators: You can **access the length of the list with the built-in `length` variable in the list**, just like with arrays. -### TODO: Dictionaries, Globalization of Variables, Functions, Objects and Classes, Special Functions, Built-ins, Modules, IO and STD Libraries, QuickSyntax -{: .no_toc } \ No newline at end of file +--- + +TODO: Dictionaries, Globalization of Variables, Functions, Objects and Classes, Special Functions, Built-ins, Modules, IO and STD Libraries, QuickSyntax diff --git a/docs/Multilingual-ezrSquared.markdown b/docs/docsrc/Multilingual-ezrSquared.md similarity index 97% rename from docs/Multilingual-ezrSquared.markdown rename to docs/docsrc/Multilingual-ezrSquared.md index f0bbea2..2b7e042 100644 --- a/docs/Multilingual-ezrSquared.markdown +++ b/docs/docsrc/Multilingual-ezrSquared.md @@ -1,9 +1,3 @@ ---- -layout: default -title: "Multilingual ezr²" -nav_order: 3 ---- - # Multilingual ezr² ## Why? diff --git a/docs/docsrc/toc.yml b/docs/docsrc/toc.yml new file mode 100644 index 0000000..e6e32ba --- /dev/null +++ b/docs/docsrc/toc.yml @@ -0,0 +1,15 @@ +pdfFileName: QuickStartDocumentation.pdf +pdfTocPage: true +pdf: true +pdfPrintBackground: true +items: +- name: Learn ezr² + href: Learn-ezrSquared.md +- name: C# and ezr² + href: CSharp-and-ezrSquared.md +- name: Embedding ezr² + href: Embedding-ezrSquared.md +- name: Get started with CSAELs + href: Get-started-with-CSAELs.md +- name: Multilingual ezr² + href: Multilingual-ezrSquared.md \ No newline at end of file diff --git a/docs/assets/images/favicon.ico b/docs/images/favicon.ico similarity index 100% rename from docs/assets/images/favicon.ico rename to docs/images/favicon.ico diff --git a/docs/index.markdown b/docs/index.markdown deleted file mode 100644 index d2d50f0..0000000 --- a/docs/index.markdown +++ /dev/null @@ -1,101 +0,0 @@ ---- -layout: default -title: The ezr² Programming Language -nav_order: 2 ---- - -# The `ezr²` Programming Language -{: .no_toc } - -**ezr² is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#! -For more information check out the [*Learn ezr²*](https://uralstech.github.io/ezrSquared/Learn-ezrSquared) page.** - -
- - Table of contents - - {: .text-delta } -- TOC -{:toc} -
- -## Advantages - -- As close to natural language as possible while being practical, with [***planned multilingual features***](https://uralstech.github.io/ezrSquared/Multilingual-ezrSquared) -- Easily extendible through C# Assisted ezr² Libraries -- Easily embeddable - -## PC Installation - -To install ezr² on your PC, follow these steps: - -#### Windows (x86 and x64) - -* Download the appropriate installer from down below. -* Run the installer and go through the installation. -

- -[ezr² Pre-release v1.5.1.3.0 for 32-bit Windows](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Installer.Windows.64-bit.exe){: .btn }
-[ezr² Pre-release v1.5.1.3.0 for 64-bit Windows](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Installer.Windows.32-bit.exe){: .btn } - -#### Linux (x64, ARM64 and ARM) - -* Download the appropriate build from down below. -* Extract the `tar.xz` file to a folder of your choice. -* Optionally, add the folder to your PATH environment variable. -

- -[ezr² Pre-release v1.5.1.3.0 for Linux x64](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-x64.tar.gz){: .btn }
-[ezr² Pre-release v1.5.1.3.0 for Linux ARM64](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-arm64.tar.gz){: .btn }
-[ezr² Pre-release v1.5.1.3.0 for Linux ARM](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-arm.tar.gz){: .btn } - -### Check the installation - ---- -* Run the `ezrSquared` command in a terminal (PowerShell, CMD, Bash, etc.) and the ezr² Shell should open. You can press Ctrl+C to exit. -* Start coding! - -## Android Installation - -Download [***ezr² Portable Interpreter on Google Play***](https://play.google.com/store/apps/details?id=com.Uralstech.ezrSquaredPortableInterpreter). - -If you are interested in how ezr² was embedded to the portable interpreter (a Unity app), check out the [***C# and ezr² page***](https://uralstech.github.io/ezrSquared/CSharp-and-ezrSquared). - -## Other Operating Systems - -For other OSes you can clone the [***repository***](https://github.com/Uralstech/ezrSquared/), and compile your own build. If you're a contributor, feel free to add the build to the latest release. - -## Usage - -An ezr² script has the extension `.ezr2`. To run an ezr² script, use the `ezrSquared` command followed by the path to the script file: - -```cmd -> ezrSquared hello.ezr2 -``` - -## Documentation - -The official documentation for ezr² is available in the [***Learn ezr² page***](https://uralstech.github.io/ezrSquared/Learn-ezrSquared), but is still **work in progress**. -Meanwhile, check out some example programs in [***GitHub***](https://github.com/Uralstech/ezrSquared/tree/master/Tests). - -The offline version of the ezrSquared website was made possible with [***Jekyll Offline***](https://github.com/dohliam/jekyll-offline). -The documentation is packaged with the Windows installer. For other OSes, download and extract the `zip` archive from here: - -[ezr² Offline Documentation](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Offline.Documentation.zip){: .btn } - -## Latest Updates - -The latest version of ezr² ***RE*** has been released! ezr² ***RE***, or ***REwrite***, is the project's initiative to rewrite ezr². The latest working version of ezr² ***RE*** -has many more features than the latest version of ezr²! But, it is still in development, has some essential features missing. Like the `include` expression, or any built-in object -methods like `"a string".length` or `["a", "list"].insert`. If you want to help in testing it out and fixing bugs, feel free to download the latest version of ezr² ***RE*** from -the ezr² GitHub releases page and compiling it using the .NET SDK and/or Visual Studio. - -ezr² now uses [***Semantic Versioning 2.0.0***](https://semver.org/) for new releases. ezr² development updates will be posted on [***my blog***](https://uralstech.github.io/). - -## Contributing - -ezr² is an open source project and welcomes contributions from anyone who wants to improve it. - -If you want to contribute to ezr², please contact Uralstech at `info@uralstech.in`. - -The contribution requirements will be revamped for the full release. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..e170ac3 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,89 @@ +--- +layout: landing +--- + +# The `ezr²` Programming Language + +**ezr² is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#! +For more information check out the [*Learn ezr²*](docsrc/Learn-ezrSquared.md) page.** + +## Advantages + +- As close to natural language as possible while being practical, with [***planned multilingual features***](docsrc/Multilingual-ezrSquared.md) +- Easily extendible through C# Assisted ezr² Libraries +- Easily embeddable + +## Installation + +> [!WARNING] +> ezr² is still in development, and with [ezr² ***REwrite***](https://github.com/Uralstech/ezrSquared/tree/ezrSquared-re) on the horizon, +> there will be some breaking changes in syntax in upcoming versions. + +To install ezr² on your PC, follow the steps for your Operating System: + +# [Windows](#tab/windows) + +* Download the appropriate installer. +* Run the installer and go through the installation. +
+ +[![ezr² Pre-release v1.5.1.3.0 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_Pre--release_v1.5.1.3.0_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Installer.Windows.64-bit.exe) +[![ezr² Pre-release v1.5.1.3.0 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_Pre--release_v1.5.1.3.0_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Installer.Windows.32-bit.exe) + +# [Linux](#tab/linux) + +* Download the appropriate build. +* Extract the `tar.xz` file to a folder of your choice. +* Optionally, add the folder to your PATH environment variable. +
+ +[![ezr² Pre-release v1.5.1.3.0 for Linux x64](https://img.shields.io/badge/ezr%C2%B2_Pre--release_v1.5.1.3.0_%28Linux_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-x64.tar.gz) +[![ezr² Pre-release v1.5.1.3.0 for Linux ARM64](https://img.shields.io/badge/ezr%C2%B2_Pre--release_v1.5.1.3.0_%28Linux_ARM64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-arm64.tar.gz) +[![ezr² Pre-release v1.5.1.3.0 for Linux ARM](https://img.shields.io/badge/ezr%C2%B2_Pre--release_v1.5.1.3.0_%28Linux_ARM%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared-linux-arm.tar.gz) + +# [Android](#tab/android) + +Download [***ezr² Portable Interpreter on Google Play***](https://play.google.com/store/apps/details?id=com.Uralstech.ezrSquaredPortableInterpreter). + +If you are interested in how ezr² was embedded to the portable interpreter (a Unity app), check out the [***C# and ezr² page***](docsrc/CSharp-and-ezrSquared.md). + +# [Other](#tab/other) + +For other OSes you can clone the [***repository***](https://github.com/Uralstech/ezrSquared/), and compile your own build. If you're a contributor, feel free to add the build to the latest release. + +--- + +## Usage + +An ezr² script has the extension `.ezr2`. To run an ezr² script, use the `ezrSquared` command followed by the path to the script file: + +```cmd +> ezrSquared hello.ezr2 +``` + +## Documentation + +The official documentation for ezr² is available in the [***Learn ezr² page***](docsrc/Learn-ezrSquared.md), but is still **work in progress**. +Meanwhile, check out some example programs in [***GitHub***](https://github.com/Uralstech/ezrSquared/tree/master/Tests). + +The offline version of the (old) ezrSquared website was made possible with [***Jekyll Offline***](https://github.com/dohliam/jekyll-offline). +The documentation is packaged with the Windows installer. For other OSes, download and extract the `zip` archive from here: + +[![ezr² Pre-release v1.5.1.3.0 Offline Documentation](https://img.shields.io/badge/ezr%C2%B2_Pre--release_v1.5.1.3.0_Offline_Documentation-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Offline.Documentation.zip) + +## Latest Updates + +The latest version of ezr² ***RE*** has been released! ezr² ***RE***, or ***REwrite***, is the project's initiative to rewrite ezr². The latest working version of ezr² ***RE*** +has many more features than the latest version of ezr²! But, it is still in development, has some essential features missing. Like the `include` expression, or any built-in object +methods like `"a string".length` or `["a", "list"].insert`. If you want to help in testing it out and fixing bugs, feel free to download the latest version of ezr² ***RE*** from +the ezr² GitHub releases page and compiling it using the .NET SDK and/or Visual Studio. + +ezr² now uses [***Semantic Versioning 2.0.0***](https://semver.org/) for new releases. ezr² development updates will be posted on [***my blog***](https://uralstech.github.io/). + +## Contributing + +ezr² is an open source project and welcomes contributions from anyone who wants to improve it. + +If you want to contribute to ezr², please contact Uralstech at `info@uralstech.in`. + +The contribution requirements will be revamped for the full release. diff --git a/docs/offline/config.yml b/docs/offline/config.yml deleted file mode 100644 index a15dfdf..0000000 --- a/docs/offline/config.yml +++ /dev/null @@ -1,3 +0,0 @@ -absolute_base: https://uralstech.github.io/ezrSquared/ -source_dir: D:/Code/csharp/ezrSquared/docs/_site/ -out_dir: D:/Code/csharp/ezrSquared/docs/offline/_site/ \ No newline at end of file diff --git a/docs/offline/jekyll_offline.rb b/docs/offline/jekyll_offline.rb deleted file mode 100644 index bcbfb2a..0000000 --- a/docs/offline/jekyll_offline.rb +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env ruby -require 'erb' -require 'fileutils' -require 'uri' -require 'yaml' - -require_relative 'lib_rellinks.rb' - -def copy_src_dir(src, trg) - dir_contents = Dir.glob(src + "*") - dir_contents.each do |d| - basename = File.basename(d) - if basename == ".git" - next - end - FileUtils.cp_r(d, trg) - end -end - -def preprocess_html(html) - html = prune_base(html) -end - -def postprocess_html(html) - html.gsub(/https:\/\/@/, "https://") -end - -def boilerplate(out_dir) - content = ERB.new(File.read("template.rhtml")).result - File.open(out_dir + "START_HERE.html", "w") {|f| f << content } -end - -def prune_base(html) - if @config[:relative_base] - html.gsub(/(href|src|data|value)(=["'])#{@config[:relative_base]}/, "\\1\\2") - else - html - end -end - -def clone_local_site(absolute_base, source_dir, out_dir) - FileUtils.rm_rf(out_dir) - FileUtils.mkdir_p(out_dir) - boilerplate(out_dir) - out_dir = out_dir + "site/" - FileUtils.mkdir_p(out_dir) - copy_src_dir(source_dir, out_dir) - - pages = Dir.glob(out_dir + "**/*.html") - - pages.each do |p| - page_content = File.read(p) - basename = File.basename(p) - html = preprocess_html(page_content) - page_output = convert_html(html, p, out_dir, absolute_base) - page_output = postprocess_html(page_output) - File.open(p, "w") {|f| f << page_output } - end -end - -@config = YAML.load_file('config.yml') - -custom_config = ARGV[0] -if custom_config - @config = YAML.load_file(custom_config) -end - -absolute_base = @config["absolute_base"] -source_dir = @config["source_dir"] -out_dir = @config["out_dir"] - -clone_local_site(absolute_base, source_dir, out_dir) diff --git a/docs/offline/lib_rellinks.rb b/docs/offline/lib_rellinks.rb deleted file mode 100644 index 959e20c..0000000 --- a/docs/offline/lib_rellinks.rb +++ /dev/null @@ -1,75 +0,0 @@ -# Takes an HTML file or folder of HTML files as input -# and adjusts all absolute links so that they are relative -# e.g., "/images" becomes "../images". -# Requires a (local) base directory to be specified as an -# argument: all links will then be rewritten relative to -# this base directory -module URI - def URI.decode(url) - url - end - - def URI.escape(url) - url - end -end - -def relativize(href, path, absolute_base, root_dir) - # href = actual href string on page - # path = actual current location / file path of current page - # absolute_base = the base url for the site - - href_url = URI.join(URI.escape(absolute_base), URI.escape(href)) - path_url = URI.join(absolute_base, URI.escape(path)) - relative_url = path_url.route_to(href_url).to_s - url_out = test_index(relative_url, href_url, absolute_base, root_dir) - if href.match(/^#/) - url_out = href - end - url_out -end - -def path_is_dir(href_url, absolute_base, root_dir) - decode_href = URI.decode(href_url.to_s.gsub(/%25/, "%")) - local_target = decode_href.gsub(absolute_base, root_dir + "/") - File.directory?(local_target) -end - -def test_index(relative_url, href_url, absolute_base, root_dir) - if path_is_dir(href_url, absolute_base, root_dir) - relative_url = rewrite_index(relative_url) - else - fixed_url = relative_url.to_s.gsub(/^\//,"") - test_url = URI.join(URI.escape(absolute_base), URI.escape(fixed_url)) - if path_is_dir(test_url, absolute_base, root_dir) - relative_url = rewrite_index(relative_url) - end - end - relative_url -end - -def rewrite_index(relative_url) - relative_url = relative_url.to_s.gsub(/\/+$/, "") + "/index.html" -end - -def convert_html(html, source_file, root_dir, absolute_base) - root_path = File.absolute_path(root_dir) - source_file_path = File.absolute_path(source_file) - path = source_file_path.gsub(/^#{root_path}/, "") - - out_html = html.gsub(/(href|src)=["'](.*?)["']/) do |h| - pre = $1 - href = $2 - if @config[:custom_filter] && href.match(/#{@config[:custom_filter]}/) - h - elsif h.match(absolute_base) || !h.match(/https*:\/\//) - href = href.gsub(/^\/\//, "/") - raw_out = pre + '="' + relativize(href, path, absolute_base, root_path) + '"' - URI.decode(raw_out) - else - h - end - end - - out_html -end diff --git a/docs/offline/template.rhtml b/docs/offline/template.rhtml deleted file mode 100644 index 733a2de..0000000 --- a/docs/offline/template.rhtml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - ezr² Offline - - - - - -
- - - -

Welcome to the ezr² Offline site!
This is an offline version of the ezr² website, which can be downloaded and used on a desktop or mobile device without an Internet connection. As of right now, not all features of the online website work here - if you would like to help fix these issues, contact Uralstech at info@uralstech.in! To enter the site, click on the button below.

- -
-
- Enter site -
- -
-
- -

License

-

The content and code of the website is the copyright of URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED, licensed under the Apache License, Version 2.0. For more specific licensing details, please check the LICENSE.txt file in the directory where ezr² is installed, in the source code or on the ezr² GitHub page. The code for generating this offline version of the site is part of the jekyll-offline project, and is released under an MIT license.

- - - diff --git a/docs/toc.yml b/docs/toc.yml new file mode 100644 index 0000000..2582993 --- /dev/null +++ b/docs/toc.yml @@ -0,0 +1,6 @@ +pdf: false +items: +- name: QuickStart and Documentation + href: docsrc/ +- name: API Reference + href: api/ \ No newline at end of file diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index f993751..3e67eaa 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.1.1 + 0.1.2 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index ee47e7f..a9d9358 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -6,7 +6,10 @@ namespace EzrSquared.Runtime.Collections; /// /// A Dictionary for s. /// -/// \bug If the keys can be access and are mutable objects, they can still be changed. +/// +/// > [!IMPORTANT] +/// > BUG: If the keys can be access and are mutable objects, they can still be changed. +/// public class RuntimeEzrObjectDictionary : IMutable { /// diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs index 53f6518..2dc4720 100644 --- a/src/Runtime/Types/BaseTypes.cs +++ b/src/Runtime/Types/BaseTypes.cs @@ -79,15 +79,15 @@ public int HashTag /// /// Creates a new object with the specified parent context and position. /// - /// The parent context. + /// The context in which this object was created in. /// The starting position of the object. /// The ending position of the object. - public EzrObject(Context parentContext, Position startPosition, Position endPosition) + public EzrObject(Context creationContext, Position startPosition, Position endPosition) { StartPosition = startPosition; EndPosition = endPosition; - _executionContext = _creationContext = parentContext; + _executionContext = _creationContext = creationContext; Context = new Context(TypeName, false, startPosition, _creationContext, _creationContext.StaticContext); } @@ -95,15 +95,15 @@ public EzrObject(Context parentContext, Position startPosition, Position endPosi /// Creates a new object with the specified internal context, parent context and position. /// /// The internal context, if , creates a new one. - /// The parent context. + /// The context in which this object was created in. /// The starting position of the object. /// The ending position of the object. - public EzrObject(Context? context, Context parentContext, Position startPosition, Position endPosition) + public EzrObject(Context? context, Context creationContext, Position startPosition, Position endPosition) { StartPosition = startPosition; EndPosition = endPosition; - _executionContext = _creationContext = parentContext; + _executionContext = _creationContext = creationContext; Context = context ?? new Context(TypeName, false, startPosition, _creationContext, _creationContext.StaticContext); } diff --git a/src/Runtime/Types/Executables/EzrClass.cs b/src/Runtime/Types/Executables/EzrClass.cs index ce7a914..57ba483 100644 --- a/src/Runtime/Types/Executables/EzrClass.cs +++ b/src/Runtime/Types/Executables/EzrClass.cs @@ -113,8 +113,6 @@ public class EzrClass : EzrRuntimeExecutable, IEzrMutableObject /// The parent context. /// The starting position of the object. /// The ending position of the object. - /// - /// \bug The name given to the parents is problematic, as two parents could have the same executable name. public EzrClass(string? name, Node body, (string Name, Node Node)[] parameters, (Position StartPosition, Position EndPosition, string Name)? keywordArguments, EzrClass[] parents, Reference[] staticParentReferences, bool isReadOnly, bool isStatic, Context staticContext, Context parentContext, Position startPosition, Position endPosition) : base(name, body, parameters, keywordArguments, parentContext, startPosition, endPosition, staticContext) { Parents = parents; @@ -123,6 +121,10 @@ public EzrClass(string? name, Node body, (string Name, Node Node)[] parameters, StaticParentReferences = staticParentReferences; } + /// + /// > [!IMPORTANT] + /// > BUG: The name given to the parents is problematic, as two parents could have the same executable name. + /// private void AddStaticParents(RuntimeResult result) { Context.SetNewLinkedContexts(Parents.Length); @@ -163,7 +165,10 @@ private void AddStaticParents(RuntimeResult result) } } - /// \bug The name given to the parents is problematic, as two parents could have the same executable name. + /// + /// > [!IMPORTANT] + /// > BUG: The name given to the parents is problematic, as two parents could have the same executable name. + /// private Reference[] AddParents(Reference[] arguments, Context context, Interpreter interpreter, RuntimeResult result) { List parentReferences = []; diff --git a/src/Runtime/Types/Executables/EzrClassInstance.cs b/src/Runtime/Types/Executables/EzrClassInstance.cs index bd2912d..89f7995 100644 --- a/src/Runtime/Types/Executables/EzrClassInstance.cs +++ b/src/Runtime/Types/Executables/EzrClassInstance.cs @@ -15,79 +15,79 @@ public class EzrClassInstance : EzrObject, IEzrMutableObject /// Special function name for initializer (constructor). public const string InitializationFunction = "initialize"; - /// Special function name for 'this = other' operator. + /// Special function name for 'this = other' operation. public const string IsEqualFunction = "is_equal"; - /// Special function name for 'this ! other' operator. + /// Special function name for 'this ! other' operation. public const string IsNotEqualFunction = "is_inequal"; - /// Special function name for 'this < other' operator. + /// Special function name for 'this < other' operation. public const string IsLessThanFunction = "is_less_than"; - /// Special function name for 'this > other' operator. + /// Special function name for 'this > other' operation. public const string IsGreaterThanFunction = "is_greater_than"; - /// Special function name for 'this <= other' operator. + /// Special function name for 'this <= other' operation. public const string IsLessThanOrEqualFunction = "is_less_than_or_equal"; - /// Special function name for 'this >= other' operator. + /// Special function name for 'this >= other' operation. public const string IsGreaterThanOrEqualFunction = "is_greater_than_or_equal"; - /// Special function name for 'this + other' operator. + /// Special function name for 'this + other' operation. public const string AdditionFunction = "addition"; - /// Special function name for 'this - other' operator. + /// Special function name for 'this - other' operation. public const string SubtractionFunction = "subtraction"; - /// Special function name for 'this * other' operator. + /// Special function name for 'this * other' operation. public const string MultiplicationFunction = "multiplication"; - /// Special function name for 'this / other' operator. + /// Special function name for 'this / other' operation. public const string DivisionFunction = "division"; - /// Special function name for 'this % other' operator. + /// Special function name for 'this % other' operation. public const string ModuloFunction = "modulo"; - /// Special function name for 'this ^ other' operator. + /// Special function name for 'this ^ other' operation. public const string PowerFunction = "power"; - /// Special function name for '-this' operator. + /// Special function name for '-this' operation. public const string NegationFunction = "negation"; - /// Special function name for '+this' operator. + /// Special function name for '+this' operation. public const string AffirmationFunction = "affirmation"; - /// Special function name for 'this | other' operator. + /// Special function name for 'this | other' operation. public const string BitwiseOrFunction = "bitwise_or"; - /// Special function name for 'this \ other' operator. + /// Special function name for 'this \ other' operation. public const string BitwiseXOrFunction = "bitwise_xor"; - /// Special function name for 'this & other' operator. + /// Special function name for 'this & other' operation. public const string BitwiseAndFunction = "bitwise_and"; - /// Special function name for 'this << other' operator. + /// Special function name for 'this << other' operation. public const string BitwiseLeftShiftunction = "bitwise_left_shift"; - /// Special function name for 'this >> other' operator. + /// Special function name for 'this >> other' operation. public const string BitwiseRightShiftFunction = "bitwise_right_shift"; - /// Special function name for '~this' operator. + /// Special function name for '~this' operation. public const string BitwiseNegationFunction = "bitwise_negation"; - /// Special function name for 'other in this' operator. + /// Special function name for 'other in this' operation. public const string ContainsFunction = "contains"; - /// Special function name for 'other not in this' operator. + /// Special function name for 'other not in this' operation. public const string DoesNotContainFunction = "does_not_contain"; - /// Special function name for 'invert this' operator. + /// Special function name for 'invert this' operation. public const string InversionFunction = "inversion"; /// Special function name for evaluation of the 'this' into a boolean. public const string EvaluateBooleanFunction = "evaluate_boolean"; - /// Special function name for 'this(arguments)' operator. + /// Special function name for 'this(arguments)' operation. public const string CalledFunction = "call_received"; /// Special function name for strict equality checking of 'this' and 'other'. diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 7b7ee2c..670d416 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.1.1"; + private const string Version = "0.1.2"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index e0860d7..fb11a5e 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "0.1.1" +#define MyAppVersion "0.1.2" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index df78c5e..8473c09 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "0.1.1" +#define MyAppVersion "0.1.2" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 3d193f2..3b9102f 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.1.1 + 0.1.2 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Syntax/Parser/Parser.cs b/src/Syntax/Parser/Parser.cs index 7c53dd4..37160bf 100644 --- a/src/Syntax/Parser/Parser.cs +++ b/src/Syntax/Parser/Parser.cs @@ -6,7 +6,7 @@ namespace EzrSquared.Syntax; /// -/// The ezr² Parser. The job of the Parser is to convert the input objects from the into objects to be given as the input to the . +/// The ezr² Parser. The job of the Parser is to convert the input objects from the into objects to be given as the input to the . /// public class Parser { From c81176624acc78342598032cd3ab154b6147433b Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 6 Aug 2024 18:40:57 +0530 Subject: [PATCH 023/113] Fixed GitHub pages action and updated dependencies. --- .github/workflows/pages-upload-action.yml | 2 ++ ezrSquared.sln | 5 ++++- src/EzrSquared.csproj | 1 + src/Shell/Shell.csproj | 4 ++-- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pages-upload-action.yml b/.github/workflows/pages-upload-action.yml index b8a0ea5..418f221 100644 --- a/.github/workflows/pages-upload-action.yml +++ b/.github/workflows/pages-upload-action.yml @@ -30,6 +30,8 @@ jobs: with: dotnet-version: 8.x + - run: dotnet build ezrSquared.sln -c Release + - run: dotnet tool update -g docfx - run: docfx docs/docfx.json diff --git a/ezrSquared.sln b/ezrSquared.sln index 21f5bb8..a3e7e1f 100644 --- a/ezrSquared.sln +++ b/ezrSquared.sln @@ -5,7 +5,10 @@ VisualStudioVersion = 17.4.33122.133 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EzrSquared", "src\EzrSquared.csproj", "{C2192D60-CF75-4781-B016-116E6709A76C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shell", "src\Shell\Shell.csproj", "{6F16EE16-DA61-47F9-9CAC-6E127A02DA2A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shell", "src\Shell\Shell.csproj", "{6F16EE16-DA61-47F9-9CAC-6E127A02DA2A}" + ProjectSection(ProjectDependencies) = postProject + {C2192D60-CF75-4781-B016-116E6709A76C} = {C2192D60-CF75-4781-B016-116E6709A76C} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 3e67eaa..136d64d 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -57,6 +57,7 @@ + diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 3b9102f..1f506eb 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -32,7 +32,7 @@ en - ..\..\Graphics\Icon.ico + ..\..\graphics\Icon.ico https://github.com/uralstech/ezrSquared @@ -40,7 +40,7 @@ True - + ..\..\Binaries\ezrSquared\Release\net8.0\ezrSquared-lib.dll From e676eae1e80003895b8ee4f44fa65f8662c2ef5c Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 6 Aug 2024 22:31:57 +0530 Subject: [PATCH 024/113] Updated website. --- Changelog.txt | 4 ++-- README.md | 5 +---- docs/.gitignore | 4 ++-- docs/index.md | 20 +++++++++++++++----- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 53ef574..e5a8926 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,8 +1,8 @@ CHANGELOG - What's new? * ezr² RE - v0.1.2 [06-08-24] - * Updated documentation. - * Added new documentation website. + * Updated build dependencies. + * Updated documentation and website. * ezr² RE - v0.1.1 [05-08-24] * Updated documentation and some graphics. diff --git a/README.md b/README.md index 6afe8a1..37310ec 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,7 @@ # The `ezr²` Programming Language **ezr², or ezrSquared when you can't use the `²` symbol (or it's too inconvenient) - is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#!** -More information and documentation about ezr² is available at ******! - -For reference documentation on ezr²'s code, check out ******. -The offline reference documentation is available in the releases section of this repository. +More information, documentation and the reference manual for ezr² is available at ******! ## What's the 'ezrSquared-re' branch? ezr² is being rewritten from the ground up! Expect more features, better performance and better code documentation! diff --git a/docs/.gitignore b/docs/.gitignore index fdabc9f..750cbf1 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,2 +1,2 @@ -/api -/_site \ No newline at end of file +api/ +_site/ \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index e170ac3..462190f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,7 +5,7 @@ layout: landing # The `ezr²` Programming Language **ezr² is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#! -For more information check out the [*Learn ezr²*](docsrc/Learn-ezrSquared.md) page.** +For more information, check out the [*learn ezr² page*](docsrc/Learn-ezrSquared.md).** ## Advantages @@ -73,17 +73,27 @@ The documentation is packaged with the Windows installer. For other OSes, downlo ## Latest Updates +More frequent development updates will be posted on [***my blog***](https://uralstech.github.io/). + +### New website + +The website has been updated! Now, this website also contains the reference documentation! Please note that the reference documentation is only for ezr² ***RE***, not for older versions. + +### ezr² ***RE*** Release + The latest version of ezr² ***RE*** has been released! ezr² ***RE***, or ***REwrite***, is the project's initiative to rewrite ezr². The latest working version of ezr² ***RE*** has many more features than the latest version of ezr²! But, it is still in development, has some essential features missing. Like the `include` expression, or any built-in object methods like `"a string".length` or `["a", "list"].insert`. If you want to help in testing it out and fixing bugs, feel free to download the latest version of ezr² ***RE*** from the ezr² GitHub releases page and compiling it using the .NET SDK and/or Visual Studio. -ezr² now uses [***Semantic Versioning 2.0.0***](https://semver.org/) for new releases. ezr² development updates will be posted on [***my blog***](https://uralstech.github.io/). +### New Versioning Format + +ezr² now uses [***Semantic Versioning 2.0.0***](https://semver.org/) for new releases. ## Contributing -ezr² is an open source project and welcomes contributions from anyone who wants to improve it. +> [!NOTE] +> The contribution requirements will be revamped for the full ezr² ***RE*** release. +ezr² is an open source project and welcomes contributions from anyone who wants to improve it. If you want to contribute to ezr², please contact Uralstech at `info@uralstech.in`. - -The contribution requirements will be revamped for the full release. From dc43304b8b8577f4adf65a6b74ffc9b12d9d7ea2 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 7 Aug 2024 10:25:45 +0530 Subject: [PATCH 025/113] Fixed formatting, removed unused imports. --- src/Runtime/Interpreter.cs | 34 +++++++++---------- src/Runtime/Reference.cs | 4 +-- src/Runtime/Types/BaseTypes.cs | 4 +-- .../Core/RuntimeErrors/EzrAssertionError.cs | 1 - .../RuntimeErrors/EzrIllegalOperationError.cs | 1 - .../Core/RuntimeErrors/EzrKeyNotFoundError.cs | 1 - .../Types/Core/RuntimeErrors/EzrMathError.cs | 1 - .../EzrMissingRequiredArgumentError.cs | 1 - .../EzrPrivateMemberOperationError.cs | 1 - .../Core/RuntimeErrors/EzrRuntimeError.cs | 1 - .../RuntimeErrors/EzrUndefinedValueError.cs | 1 - .../EzrUnexpectedArgumentError.cs | 1 - .../RuntimeErrors/EzrUnexpectedTypeError.cs | 1 - .../EzrUnsupportedWrappingError.cs | 1 - .../RuntimeErrors/EzrValueOutOfRangeError.cs | 1 - .../RuntimeErrors/EzrWrapperExecutionError.cs | 1 - src/Runtime/Types/Executables/EzrClass.cs | 6 ++-- .../Types/Executables/EzrClassInstance.cs | 4 +-- .../Types/Executables/EzrRuntimeExecutable.cs | 10 +++--- src/Shell/EzrShellEditor.cs | 4 +-- src/Syntax/Lexer.cs | 16 ++++----- src/Syntax/Parser/Parser.cs | 10 +++--- 22 files changed, 46 insertions(+), 59 deletions(-) diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index e3576a4..f85806d 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -573,7 +573,7 @@ private void VisitBinaryOperationNode(BinaryOperationNode node, Context executio { case TokenType.Period: ExecuteObjectAttributeAccess(node, executionContext, callingContext, accessibilityModifiers, ignoreUndefinedVariable); break; - + case TokenType.KeywordOr: case TokenType.KeywordAnd: ExecuteConjunctiveOperators(node, executionContext, callingContext, accessibilityModifiers); break; @@ -607,7 +607,7 @@ private void ExecuteObjectAttributeAccess(BinaryOperationNode node, Context exec ? accessibilityModifiers & ~AccessMod.LocalScope : accessibilityModifiers; - VisitNode(node.Left, executionContext, callingContext, accessibilityModifiers & ~AccessMod.LocalScope); + VisitNode(node.Left, executionContext, callingContext, accessibilityModifiers & ~AccessMod.LocalScope); if (RuntimeResult.ShouldReturn) return; @@ -678,12 +678,12 @@ private void ExecuteBinaryOperation(IEzrObject first, IEzrObject second, Node no case TokenType.AssignmentAddition: first.Addition(second, RuntimeResult); break; - + case TokenType.HyphenMinus: case TokenType.AssignmentSubtraction: first.Subtraction(second, RuntimeResult); break; - + case TokenType.Asterisk: case TokenType.AssignmentMultiplication: first.Multiplication(second, RuntimeResult); @@ -693,12 +693,12 @@ private void ExecuteBinaryOperation(IEzrObject first, IEzrObject second, Node no case TokenType.AssignmentDivision: first.Division(second, RuntimeResult); break; - + case TokenType.Caret: case TokenType.AssignmentPower: first.Power(second, RuntimeResult); break; - + case TokenType.PercentSign: case TokenType.AssignmentModulo: first.Modulo(second, RuntimeResult); @@ -708,22 +708,22 @@ private void ExecuteBinaryOperation(IEzrObject first, IEzrObject second, Node no case TokenType.AssignmentBitwiseAnd: first.BitwiseAnd(second, RuntimeResult); break; - + case TokenType.VerticalBar: case TokenType.AssignmentBitwiseOr: first.BitwiseOr(second, RuntimeResult); break; - + case TokenType.Backslash: case TokenType.AssignmentBitwiseXOr: first.BitwiseXOr(second, RuntimeResult); break; - + case TokenType.BitwiseLeftShift: case TokenType.AssignmentBitwiseLeftShift: first.BitwiseLeftShift(second, RuntimeResult); break; - + case TokenType.BitwiseRightShift: case TokenType.AssignmentBitwiseRightShift: first.BitwiseRightShift(second, RuntimeResult); @@ -732,23 +732,23 @@ private void ExecuteBinaryOperation(IEzrObject first, IEzrObject second, Node no case TokenType.EqualSign: first.ComparisonEqual(second, RuntimeResult); break; - + case TokenType.ExclamationMark: first.ComparisonNotEqual(second, RuntimeResult); break; - + case TokenType.LessThanSign: first.ComparisonLessThan(second, RuntimeResult); break; - + case TokenType.GreaterThanSign: first.ComparisonGreaterThan(second, RuntimeResult); break; - + case TokenType.LessThanOrEqual: first.ComparisonLessThanOrEqual(second, RuntimeResult); break; - + case TokenType.GreaterThanOrEqual: first.ComparisonGreaterThanOrEqual(second, RuntimeResult); break; @@ -756,7 +756,7 @@ private void ExecuteBinaryOperation(IEzrObject first, IEzrObject second, Node no case TokenType.KeywordIn: second.HasValueContained(first, RuntimeResult); break; - + case TokenType.KeywordNot: second.NotHasValueContained(first, RuntimeResult); break; @@ -1327,7 +1327,7 @@ private void VisitCallNode(CallNode node, Context executionContext, Context call { Context argumentsContext = new($"<{receiver.TypeName} arguments>", false, receiver.StartPosition, callingContext, callingContext.StaticContext); arguments = new Reference[node.Arguments.Count]; - + for (int i = 0; i < node.Arguments.Count; i++) { Node argument = node.Arguments[i]; diff --git a/src/Runtime/Reference.cs b/src/Runtime/Reference.cs index 16c7c81..d1c17a3 100644 --- a/src/Runtime/Reference.cs +++ b/src/Runtime/Reference.cs @@ -73,10 +73,10 @@ public Reference Reset(IEzrObject? @object, AccessMod accessibilityModifiers, st { Object = @object ?? EzrRuntimeInvalidObject.s_instance; AccessibilityModifiers = accessibilityModifiers; - + Name = name; IsEmpty = @object is null; - + RegisteredContext = null; RegisteredIn = 0; diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs index 2dc4720..f446ca9 100644 --- a/src/Runtime/Types/BaseTypes.cs +++ b/src/Runtime/Types/BaseTypes.cs @@ -284,7 +284,7 @@ public virtual void Interpret(Node code, Context callingContext, Interpreter int result.Failure(new EzrUndefinedValueError($"You cannot create nor change members of a read-only object!", Context, StartPosition, EndPosition)); return; } - + if (IsReadOnly) result.Success( ReferencePool.Get( @@ -449,7 +449,7 @@ protected internal EzrIllegalOperationError IllegalOperation() /// The error. protected internal EzrIllegalOperationError IllegalOperation(IEzrObject other, bool isRightHandSide = true) { - return + return isRightHandSide ? new EzrIllegalOperationError($"Illegal operation for types \"{TypeName}\" and \"{other.TypeName}\"!", _executionContext, StartPosition, other.EndPosition) : new EzrIllegalOperationError($"Illegal operation for types \"{other.TypeName}\" and \"{TypeName}\"!", _executionContext, other.StartPosition, EndPosition); diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs index 88bd11e..a0f3d20 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs index de047ff..6a09753 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs index f3d41bc..2ccc1f6 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs index 658a761..a634ff5 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs index ddc21e8..118813b 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs index 4f4c32a..1ceefa6 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs index cc96122..a17795d 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs @@ -2,7 +2,6 @@ using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; -using System.Collections.Generic; using System.Text; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs index 30e681a..6f15529 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs index 799b01b..6d6a465 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs index f26ecce..76b2d84 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs index 4934f74..15a3555 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs index d89408d..b68b3f6 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs index 2944e33..ba07d52 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.WrapperAttributes; -using System.Collections.Generic; namespace EzrSquared.Runtime.Types.Core.Errors; diff --git a/src/Runtime/Types/Executables/EzrClass.cs b/src/Runtime/Types/Executables/EzrClass.cs index 57ba483..bba6ec0 100644 --- a/src/Runtime/Types/Executables/EzrClass.cs +++ b/src/Runtime/Types/Executables/EzrClass.cs @@ -1,7 +1,7 @@ -using System; -using System.Collections.Generic; -using EzrSquared.Runtime.Nodes; +using EzrSquared.Runtime.Nodes; using EzrSquared.Runtime.Types.Core.Errors; +using System; +using System.Collections.Generic; namespace EzrSquared.Runtime.Types; diff --git a/src/Runtime/Types/Executables/EzrClassInstance.cs b/src/Runtime/Types/Executables/EzrClassInstance.cs index 89f7995..dbe44d5 100644 --- a/src/Runtime/Types/Executables/EzrClassInstance.cs +++ b/src/Runtime/Types/Executables/EzrClassInstance.cs @@ -1,9 +1,9 @@ -using System; -using EzrSquared.Runtime.Nodes; +using EzrSquared.Runtime.Nodes; using EzrSquared.Runtime.Types.Core; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; +using System; namespace EzrSquared.Runtime.Types; diff --git a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs index d9720e3..d87d162 100644 --- a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs +++ b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs @@ -1,8 +1,8 @@ -using EzrSquared.Runtime.Types.Collections; +using EzrSquared.Runtime.Collections; +using EzrSquared.Runtime.Nodes; +using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Text; -using EzrSquared.Runtime.Collections; -using EzrSquared.Runtime.Nodes; using EzrSquared.Util; using System; @@ -125,7 +125,7 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context // Is the key already exist? bool hasKey = isValidIndex && context.IsDefined(key); - + // If parameterIndex is out of bounds, or the key is already defined and the argument is a keyword argument, or if all the arguments have already been set: if (!isValidIndex || (hasKey && (isKeywordArgument || parameterIndex + 1 >= Parameters.Length))) { @@ -234,7 +234,7 @@ public override string ToString(RuntimeResult result) string[] paramterNames = Array.ConvertAll(Parameters, parameter => parameter.Name); return (Parameters.Length > 0, IsAnonymous) switch { - (true, true) => $"<{TypeName} {ExecutableName}, with \"{string.Join("\", \"", paramterNames)}\">", + (true, true) => $"<{TypeName} {ExecutableName}, with \"{string.Join("\", \"", paramterNames)}\">", (true, false) => $"<{TypeName} \"{ExecutableName}\", with \"{string.Join("\", \"", paramterNames)}\">", (false, true) => $"<{TypeName} {ExecutableName}>", diff --git a/src/Shell/EzrShellEditor.cs b/src/Shell/EzrShellEditor.cs index df5dd8a..5217dad 100644 --- a/src/Shell/EzrShellEditor.cs +++ b/src/Shell/EzrShellEditor.cs @@ -1,6 +1,6 @@ -using System.IO; +using System; +using System.IO; using System.Text; -using System; namespace EzrSquaredCli; diff --git a/src/Syntax/Lexer.cs b/src/Syntax/Lexer.cs index 1e7fe36..c42110f 100644 --- a/src/Syntax/Lexer.cs +++ b/src/Syntax/Lexer.cs @@ -67,7 +67,7 @@ private void Advance() _currentChar = '\0'; } } - + /// /// Reverses to the given index. /// @@ -81,12 +81,12 @@ private void ReverseTo(int index) _currentChar = _script[_position.Index]; } -/// -/// Creates a of objects from the given script. -/// -/// The created of objects. -/// Any that occurred in the lexing; if none occurred. -public SyntaxError? Tokenize(out List tokens) + /// + /// Creates a of objects from the given script. + /// + /// The created of objects. + /// Any that occurred in the lexing; if none occurred. + public SyntaxError? Tokenize(out List tokens) { SyntaxError? error; tokens = []; @@ -379,7 +379,7 @@ private Token CompileStringLike(out SyntaxError? error) tooLong ? "Value too long to be a character!" : "A character cannot be empty!", startPosition, _position); - + return Token.Empty; } diff --git a/src/Syntax/Parser/Parser.cs b/src/Syntax/Parser/Parser.cs index 37160bf..f09191f 100644 --- a/src/Syntax/Parser/Parser.cs +++ b/src/Syntax/Parser/Parser.cs @@ -246,10 +246,10 @@ or TokenType.EndOfFile or TokenType.KeywordEnd or TokenType.KeywordElse or TokenType.KeywordCatch) - // || (_usingQuickSyntax - // && (_currentToken.Type == TokenType.QeywordL - // || _currentToken.Type == TokenType.QeywordE - // || _currentToken.Type == TokenType.QeywordS))) + // || (_usingQuickSyntax + // && (_currentToken.Type == TokenType.QeywordL + // || _currentToken.Type == TokenType.QeywordE + // || _currentToken.Type == TokenType.QeywordS))) { _result.Success(new ReturnNode(null, false, startPosition, possibleEndPosition)); return; @@ -2109,7 +2109,7 @@ private void ParseClassDefinitionExpression() return; } - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, (name is null && parents.Count == 0) ? "Expected an expression or the 'from' or 'do' keywords! An expression after the 'object' keyword defines the name, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents and the 'do' keyword declares the start of the body of the class." : (parents.Count == 0) From 64d5ede43c976c6bb6c67af49da16f967bf656df Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 7 Aug 2024 19:50:53 +0530 Subject: [PATCH 026/113] =?UTF-8?q?ezr=C2=B2=20v0.2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 14 ++++ src/EzrSquared.csproj | 2 +- .../Builtins/EzrBuiltinsUtility.cs | 25 +++--- .../EzrSharpCompatibilityObjectInstance.cs | 2 +- .../EzrSharpCompatibilityType.cs | 20 ++++- .../EzrSharpCompatibilityConstructor.cs | 4 +- .../EzrSharpSourceExecutableWrapper.cs | 29 ++++++- .../EzrSharpSourceTypeWrapper.cs | 83 +++++++++++-------- .../Core/RuntimeErrors/EzrAssertionError.cs | 12 +-- .../RuntimeErrors/EzrIllegalOperationError.cs | 19 ++--- .../Core/RuntimeErrors/EzrKeyNotFoundError.cs | 19 ++--- .../Types/Core/RuntimeErrors/EzrMathError.cs | 25 ++---- .../EzrMissingRequiredArgumentError.cs | 19 ++--- .../EzrPrivateMemberOperationError.cs | 21 ++--- .../Core/RuntimeErrors/EzrRuntimeError.cs | 45 +++++----- .../RuntimeErrors/EzrUndefinedValueError.cs | 19 ++--- .../EzrUnexpectedArgumentError.cs | 19 ++--- .../RuntimeErrors/EzrUnexpectedTypeError.cs | 19 ++--- .../EzrUnsupportedWrappingError.cs | 19 ++--- .../RuntimeErrors/EzrValueOutOfRangeError.cs | 19 ++--- .../RuntimeErrors/EzrWrapperExecutionError.cs | 19 ++--- .../SharpFieldWrapperAttribute.cs | 4 +- .../SharpMethodWrapperAttribute.cs | 14 ++-- .../SharpTypeWrapperAttribute.cs | 52 ++++++++---- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 28 files changed, 277 insertions(+), 254 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index e5a8926..f52e1ff 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,19 @@ CHANGELOG - What's new? +See the GitHub releases for more detailed info: +https://github.com/Uralstech/ezrSquared/releases + +* ezr² RE - v0.2.0 [07-08-24] + * [BREAKING CHANGE] SharpTypeWrapperAttribute will now require the type to have one SharpMethodWrapper wrapped constructor to create objects. + * [BREAKING CHANGE] EzrSharpSourceExecutableWrapper now inherits directly from EzrObject and implements some overrides. + * Static wrapped methods in SharpTypeWrapper wrapped types should work now. + * SharpMethodWrapperAttribute now also supports constructors. + * Updated error messages returned by SharpFieldWrapperAttribute's validation methods. + * Updated all declarations of DynamicallyAccessedMembers attributes to be more specific. + * Added some missing built-ins in EzrBuiltinsUtility. + * Fixed formatting, removed unused imports. + * Updated documentation. + * ezr² RE - v0.1.2 [06-08-24] * Updated build dependencies. * Updated documentation and website. diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 136d64d..6836dc6 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.1.2 + 0.2.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs index 1a4a58f..c97591c 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs @@ -45,29 +45,32 @@ public static void AddBuiltinFunctions(Context context) public static void AddBuiltinTypes(Context context) { EzrSharpSourceTypeWrapper runtimeError = new(typeof(EzrRuntimeError), context, Position.None, Position.None); + context.Set(null, runtimeError.SharpTypeName, ReferencePool.Get(runtimeError, AccessMod.Constant)); + + EzrSharpSourceTypeWrapper assertionError = new(typeof(EzrAssertionError), context, Position.None, Position.None); EzrSharpSourceTypeWrapper illegalOperationError = new(typeof(EzrIllegalOperationError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper undefinedValueError = new(typeof(EzrUndefinedValueError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper privateValueAccessError = new(typeof(EzrPrivateMemberOperationError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper mathError = new(typeof(EzrMathError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper valueOutOfRangeError = new(typeof(EzrValueOutOfRangeError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper unexpectedTypeError = new(typeof(EzrUnexpectedTypeError), context, Position.None, Position.None); EzrSharpSourceTypeWrapper keyNotFoundError = new(typeof(EzrKeyNotFoundError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper mathError = new(typeof(EzrMathError), context, Position.None, Position.None); EzrSharpSourceTypeWrapper missingRequiredArgumentError = new(typeof(EzrMissingRequiredArgumentError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper privateMemberOperationError = new(typeof(EzrPrivateMemberOperationError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper undefinedValueError = new(typeof(EzrUndefinedValueError), context, Position.None, Position.None); EzrSharpSourceTypeWrapper unexpectedArgumentError = new(typeof(EzrUnexpectedArgumentError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper unexpectedTypeError = new(typeof(EzrUnexpectedTypeError), context, Position.None, Position.None); EzrSharpSourceTypeWrapper unsupportedWrappingError = new(typeof(EzrUnsupportedWrappingError), context, Position.None, Position.None); + EzrSharpSourceTypeWrapper valueOutOfRangeError = new(typeof(EzrValueOutOfRangeError), context, Position.None, Position.None); EzrSharpSourceTypeWrapper wrapperExecutionError = new(typeof(EzrWrapperExecutionError), context, Position.None, Position.None); - context.Set(null, runtimeError.SharpTypeName, ReferencePool.Get(runtimeError, AccessMod.Constant)); + context.Set(null, assertionError.SharpTypeName, ReferencePool.Get(assertionError, AccessMod.Constant)); context.Set(null, illegalOperationError.SharpTypeName, ReferencePool.Get(illegalOperationError, AccessMod.Constant)); - context.Set(null, undefinedValueError.SharpTypeName, ReferencePool.Get(undefinedValueError, AccessMod.Constant)); - context.Set(null, privateValueAccessError.SharpTypeName, ReferencePool.Get(privateValueAccessError, AccessMod.Constant)); - context.Set(null, mathError.SharpTypeName, ReferencePool.Get(mathError, AccessMod.Constant)); - context.Set(null, valueOutOfRangeError.SharpTypeName, ReferencePool.Get(valueOutOfRangeError, AccessMod.Constant)); - context.Set(null, unexpectedTypeError.SharpTypeName, ReferencePool.Get(unexpectedTypeError, AccessMod.Constant)); context.Set(null, keyNotFoundError.SharpTypeName, ReferencePool.Get(keyNotFoundError, AccessMod.Constant)); + context.Set(null, mathError.SharpTypeName, ReferencePool.Get(mathError, AccessMod.Constant)); context.Set(null, missingRequiredArgumentError.SharpTypeName, ReferencePool.Get(missingRequiredArgumentError, AccessMod.Constant)); + context.Set(null, privateMemberOperationError.SharpTypeName, ReferencePool.Get(privateMemberOperationError, AccessMod.Constant)); + context.Set(null, undefinedValueError.SharpTypeName, ReferencePool.Get(undefinedValueError, AccessMod.Constant)); context.Set(null, unexpectedArgumentError.SharpTypeName, ReferencePool.Get(unexpectedArgumentError, AccessMod.Constant)); + context.Set(null, unexpectedTypeError.SharpTypeName, ReferencePool.Get(unexpectedTypeError, AccessMod.Constant)); context.Set(null, unsupportedWrappingError.SharpTypeName, ReferencePool.Get(unsupportedWrappingError, AccessMod.Constant)); + context.Set(null, valueOutOfRangeError.SharpTypeName, ReferencePool.Get(valueOutOfRangeError, AccessMod.Constant)); context.Set(null, wrapperExecutionError.SharpTypeName, ReferencePool.Get(wrapperExecutionError, AccessMod.Constant)); } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index 1249e7b..61abd9c 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -22,7 +22,7 @@ public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper public EzrSharpCompatibilityObjectInstance(object instance, - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] Type instanceType, RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index f74c106..7cfdab9 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -17,13 +17,25 @@ public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpType"; - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] - public readonly Type SharpType; + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.PublicConstructors + | DynamicallyAccessedMemberTypes.NonPublicConstructors + )] public readonly Type SharpType; + public readonly string SharpTypeName; public EzrSharpCompatibilityType( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] - Type type, + + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.PublicConstructors + | DynamicallyAccessedMemberTypes.NonPublicConstructors + )]Type type, RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index e15f8c2..2de59d3 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -9,14 +9,14 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.E public class EzrSharpCompatibilityConstructor : EzrSharpCompatibilityExecutable { - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] public readonly Type ConstructingType; public readonly string ConstructingTypeName; public readonly ConstructorInfo SharpConstructor; public EzrSharpCompatibilityConstructor(ConstructorInfo sharpConstructor, - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] Type constructType, Context context, Position startPosition, Position endPosition) : base(sharpConstructor, null, context, startPosition, endPosition) diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs index 015287e..b8075b1 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs @@ -1,12 +1,11 @@ using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; using EzrSquared.Util; using System; using System.Collections.Generic; namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; -public abstract class EzrSharpSourceExecutableWrapper : EzrSharpCompatibilityWrapper +public abstract class EzrSharpSourceExecutableWrapper : EzrObject { /// public override string TypeName { get; protected internal set; } = "csharp source executable wrapper"; @@ -115,4 +114,30 @@ protected internal Dictionary CheckAndPopulateArguments(Refer return argumentReferences; } + + /// + public override void ComparisonEqual(IEzrObject other, RuntimeResult result) + { + bool equal = StrictEquals(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(equal)); + } + + /// + public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) + { + bool equal = StrictEquals(other, result); + if (result.ShouldReturn) + return; + + result.Success(NewBooleanConstant(!equal)); + } + + /// + public override bool EvaluateBoolean(RuntimeResult result) + { + return true; + } } diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index 0be83e7..49bbbda 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -16,17 +16,27 @@ public class EzrSharpSourceTypeWrapper : EzrSharpSourceExecutableWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceTypeWrapper"; - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] - public readonly Type SharpType; + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.PublicConstructors + | DynamicallyAccessedMemberTypes.NonPublicConstructors + )] public readonly Type SharpType; public readonly string SharpTypeName; - public readonly EzrSharpSourceWrappableMethod Constructor; + public readonly ConstructorInfo Constructor; public EzrSharpSourceTypeWrapper( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] - Type type, + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.PublicConstructors + | DynamicallyAccessedMemberTypes.NonPublicConstructors + )] Type type, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { @@ -44,46 +54,44 @@ public EzrSharpSourceTypeWrapper( SharpTypeName = typeAttribute.Name; Tag = $"{Tag}.{SharpTypeName}.{Utils.GetNextUniqueId()}"; - // Get constructor info. - MethodInfo constructor = SharpType.GetMethod(typeAttribute.Constructor, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreReturn) - ?? throw new NullReferenceException($"Could not find constructor method \"{typeAttribute.Constructor}\" in type \"{type.Name}\"!"); + Exception? typeAttributeException = SharpTypeWrapperAttribute.ValidateMethodParameters(SharpType, + out (ConstructorInfo Info, SharpMethodWrapperAttribute Attribute)? constructor); - // Get constructor attribute. - SharpMethodWrapperAttribute constructorAttribute = constructor.GetCustomAttribute(true) - ?? throw new ArgumentException($"No \"{nameof(SharpMethodWrapperAttribute)}\" attribute found in constructor method \"{constructor.Name}\"!", nameof(type)); + if (typeAttributeException is not null) + throw typeAttributeException; - Exception? parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(constructor); + Exception? parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(constructor!.Value.Info); if (parameterException is not null) throw parameterException; // Get constructor parameters. - int requiredParameters = constructorAttribute.RequiredParameters.Length; - Parameters = new (string Name, bool IsRequired)[constructorAttribute.RequiredParameters.Length + constructorAttribute.OptionalParameters.Length]; + int requiredParameters = constructor.Value.Attribute.RequiredParameters.Length; + Parameters = new (string Name, bool IsRequired)[constructor.Value.Attribute.RequiredParameters.Length + constructor.Value.Attribute.OptionalParameters.Length]; // Required parameters. for (int j = 0; j < requiredParameters; j++) - Parameters[j] = new(constructorAttribute.RequiredParameters[j], true); + Parameters[j] = new(constructor.Value.Attribute.RequiredParameters[j], true); // Optional parameters. - for (int j = 0; j < constructorAttribute.OptionalParameters.Length; j++) - Parameters[j + requiredParameters] = new(constructorAttribute.OptionalParameters[j], false); + for (int j = 0; j < constructor.Value.Attribute.OptionalParameters.Length; j++) + Parameters[j + requiredParameters] = new(constructor.Value.Attribute.OptionalParameters[j], false); // Set variables. - HasKeywordArguments = constructorAttribute.HasKeywordArguments; - Constructor = (EzrSharpSourceWrappableMethod)constructor.CreateDelegate(typeof(EzrSharpSourceWrappableMethod)); + HasKeywordArguments = constructor.Value.Attribute.HasKeywordArguments; + Constructor = constructor.Value.Info; // Get static methods to wrap. - MethodInfo[] staticMethods = SharpType.GetMethods(BindingFlags.Static); + MethodInfo[] staticMethods = SharpType.GetMethods(BindingFlags.Public | BindingFlags.Static); for (int i = 0; i < staticMethods.Length; i++) { MethodInfo method = staticMethods[i]; - // Check if abstract or same as constructor. - if (method.IsAbstract || method.Name == constructor.Name) + // Check if abstract. + if (method.IsAbstract) continue; // Check if method can be wrapped. - SharpMethodWrapperAttribute? methodAttribute = constructor.GetCustomAttribute(true); + SharpMethodWrapperAttribute? methodAttribute = method.GetCustomAttribute(false); if (methodAttribute is null) continue; @@ -125,17 +133,24 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run if (result.ShouldReturn) return; - Constructor.Invoke(new SharpMethodParameters - ( - argumentReferences, - _executionContext, - _creationContext, - Context, - StartPosition, - EndPosition, - interpreter, - result - )); + IEzrObject newObject = (IEzrObject)Constructor.Invoke( + [ + new SharpMethodParameters + ( + argumentReferences, + _executionContext, + _creationContext, + Context, + StartPosition, + EndPosition, + interpreter, + result + ) + ] + ); + + if (!result.ShouldReturn) + result.Success(ReferencePool.Get(newObject, AccessMod.PrivateConstant)); } /// diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs index a0f3d20..464a5a7 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs @@ -8,7 +8,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("assertion_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("assertion_error")] public class EzrAssertionError(Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Assertion failed", "The assertion conditions were not met!", context, startPosition, endPosition) { /// @@ -22,13 +22,5 @@ public class EzrAssertionError(Context context, Position startPosition, Position /// /// The constructor arguments. [SharpMethodWrapper()] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - arguments.Result.Success(ReferencePool.Get( - new EzrAssertionError( - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition), - AccessMod.PrivateConstant)); - } + public EzrAssertionError(SharpMethodParameters arguments) : this(arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs index 6a09753..809a9cb 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("illegal_operation_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("illegal_operation_error")] public class EzrIllegalOperationError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Illegal operation", details, context, startPosition, endPosition) { /// @@ -23,15 +23,10 @@ public class EzrIllegalOperationError(string details, Context context, Position /// /// The constructor arguments. [SharpMethodWrapper(RequiredParameters = ["details"])] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrIllegalOperationError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } + public EzrIllegalOperationError(SharpMethodParameters arguments) : this( + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs index 2ccc1f6..f6c9452 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("key_not_found_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("key_not_found_error")] public class EzrKeyNotFoundError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Key not found", details, context, startPosition, endPosition) { /// @@ -23,15 +23,10 @@ public class EzrKeyNotFoundError(string details, Context context, Position start /// /// The constructor arguments. [SharpMethodWrapper(RequiredParameters = ["details"])] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrKeyNotFoundError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } + public EzrKeyNotFoundError(SharpMethodParameters arguments) : this( + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs index a634ff5..f3696aa 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs @@ -10,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("math_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("math_error")] public class EzrMathError(string title, string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError(title, details, context, startPosition, endPosition) { /// @@ -24,20 +24,11 @@ public class EzrMathError(string title, string details, Context context, Positio /// /// The constructor arguments. [SharpMethodWrapper(RequiredParameters = ["title", "details"])] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference titleReference = arguments.ArgumentReferences["title"]; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string title = GetStringArgument("title", titleReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrMathError(title, details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } + public EzrMathError(SharpMethodParameters arguments) : this( + GetStringArgument("title", arguments.ArgumentReferences["title"].Object, arguments.ExecutionContext, arguments.Result), + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs index 118813b..b825b77 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("missing_required_argument_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("missing_required_argument_error")] public class EzrMissingRequiredArgumentError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Missing required argument", details, context, startPosition, endPosition) { /// @@ -23,15 +23,10 @@ public class EzrMissingRequiredArgumentError(string details, Context context, Po /// /// The constructor arguments. [SharpMethodWrapper(RequiredParameters = ["details"])] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrMissingRequiredArgumentError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } + public EzrMissingRequiredArgumentError(SharpMethodParameters arguments) : this( + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs index 1ceefa6..a832e27 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs @@ -9,11 +9,11 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("private_member_operation_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("private_member_operation_error")] public class EzrPrivateMemberOperationError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Private member operation", details, context, startPosition, endPosition) { /// - public override string TypeName { get; protected internal set; } = "Private member operation error"; + public override string TypeName { get; protected internal set; } = "private member operation error"; /// public override string Tag { get; protected internal set; } = "ezrSquared.PrivateMemberOperationError"; @@ -23,15 +23,10 @@ public class EzrPrivateMemberOperationError(string details, Context context, Pos /// /// The constructor arguments. [SharpMethodWrapper(RequiredParameters = ["details"])] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrPrivateMemberOperationError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } + public EzrPrivateMemberOperationError(SharpMethodParameters arguments) : this( + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs index a17795d..11868a8 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// /// Base of all error type objects. /// -[SharpTypeWrapper("runtime_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("runtime_error")] public class EzrRuntimeError : EzrObject { /// @@ -63,6 +63,20 @@ public EzrRuntimeError(string title, string details, Context context, Position s Context.Set(null, "details", ReferencePool.Get(new EzrString(Details, Context, StartPosition, EndPosition), AccessMod.Constant)); } + + /// + /// Wrapper constructor for creating the error object. + /// + /// The constructor arguments. + [SharpMethodWrapper(RequiredParameters = ["title", "details"])] + public EzrRuntimeError(SharpMethodParameters arguments) : this( + GetStringArgument("title", arguments.ArgumentReferences["title"].Object, arguments.ExecutionContext, arguments.Result), + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } + /// /// Converts the given argument to a string. /// @@ -73,6 +87,11 @@ public EzrRuntimeError(string title, string details, Context context, Position s /// The string, or if failed. protected internal static string GetStringArgument(string argumentName, IEzrObject ezrObject, Context context, RuntimeResult result) { + // Added so that if this is being called after a faulty GetStringArgument call, the error can be passed on to the interpreter + // without being overridden by another error. + if (result.ShouldReturn) + return string.Empty; + switch (ezrObject) { case EzrString ezrString: @@ -90,28 +109,6 @@ protected internal static string GetStringArgument(string argumentName, IEzrObje } } - /// - /// Wrapper constructor for creating the error object. - /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["title", "details"])] - public static void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference titleReference = arguments.ArgumentReferences["title"]; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string title = GetStringArgument("title", titleReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrRuntimeError(title, details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } - /// /// Generates the trace back to the error. /// @@ -165,7 +162,7 @@ public override bool StrictEquals(IEzrObject other, RuntimeResult result) /// public override string ToString(RuntimeResult result) { - return $"<{TypeName} \"{Title}\">"; + return $"<{TypeName}>"; } /// diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs index 6f15529..a45c301 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("undefined_value_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("undefined_value_error")] public class EzrUndefinedValueError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Undefined value", details, context, startPosition, endPosition) { /// @@ -23,15 +23,10 @@ public class EzrUndefinedValueError(string details, Context context, Position st /// /// The constructor arguments. [SharpMethodWrapper(RequiredParameters = ["details"])] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrUndefinedValueError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } + public EzrUndefinedValueError(SharpMethodParameters arguments) : this( + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs index 6d6a465..ff39a8a 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("unexpected_argument_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("unexpected_argument_error")] public class EzrUnexpectedArgumentError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unexpected argument(s)", details, context, startPosition, endPosition) { /// @@ -23,15 +23,10 @@ public class EzrUnexpectedArgumentError(string details, Context context, Positio /// /// The constructor arguments. [SharpMethodWrapper(RequiredParameters = ["details"])] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrUnexpectedArgumentError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } + public EzrUnexpectedArgumentError(SharpMethodParameters arguments) : this( + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs index 76b2d84..b850961 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("unexpected_type_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("unexpected_type_error")] public class EzrUnexpectedTypeError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unexpected type", details, context, startPosition, endPosition) { /// @@ -23,15 +23,10 @@ public class EzrUnexpectedTypeError(string details, Context context, Position st /// /// The constructor arguments. [SharpMethodWrapper(RequiredParameters = ["details"])] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrUnexpectedTypeError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } + public EzrUnexpectedTypeError(SharpMethodParameters arguments) : this( + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs index 15a3555..8654d43 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("unsupported_wrapping_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("unsupported_wrapping_error")] public class EzrUnsupportedWrappingError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unsupported wrapping", details, context, startPosition, endPosition) { /// @@ -23,15 +23,10 @@ public class EzrUnsupportedWrappingError(string details, Context context, Positi /// /// The constructor arguments. [SharpMethodWrapper(RequiredParameters = ["details"])] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrUnsupportedWrappingError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } + public EzrUnsupportedWrappingError(SharpMethodParameters arguments) : this( + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs index b68b3f6..b048698 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("value_out_of_range_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("value_out_of_range_error")] public class EzrValueOutOfRangeError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Value out of range", details, context, startPosition, endPosition) { /// @@ -23,15 +23,10 @@ public class EzrValueOutOfRangeError(string details, Context context, Position s /// /// The constructor arguments. [SharpMethodWrapper(RequiredParameters = ["details"])] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrValueOutOfRangeError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } + public EzrValueOutOfRangeError(SharpMethodParameters arguments) : this( + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs index ba07d52..6782d40 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("wrapper_execution_error", nameof(WrapperConstructor))] +[SharpTypeWrapper("wrapper_execution_error")] public class EzrWrapperExecutionError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Wrapper execution error", details, context, startPosition, endPosition) { /// @@ -23,15 +23,10 @@ public class EzrWrapperExecutionError(string details, Context context, Position /// /// The constructor arguments. [SharpMethodWrapper(RequiredParameters = ["details"])] - public static new void WrapperConstructor(SharpMethodParameters arguments) - { - RuntimeResult result = arguments.Result; - Reference detailsReference = arguments.ArgumentReferences["details"]; - - string details = GetStringArgument("details", detailsReference.Object, arguments.ExecutionContext, result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrWrapperExecutionError(details, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); - } + public EzrWrapperExecutionError(SharpMethodParameters arguments) : this( + GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), + arguments.ExecutionContext, + arguments.StartPosition, + arguments.EndPosition + ) { } } diff --git a/src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs index 0fd1c89..298e509 100644 --- a/src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs @@ -29,7 +29,7 @@ public class SharpFieldWrapperAttribute(string name) : Attribute public static ArgumentException? ValidateField(FieldInfo fieldInfo) { return !typeof(IEzrObject).IsAssignableFrom(fieldInfo.FieldType) - ? new($"Expected field \"{fieldInfo.Name}\" to be of type {nameof(IEzrObject)}, as it uses the attribute \"{nameof(SharpFieldWrapperAttribute)}\"", fieldInfo.Name) + ? new($"Expected field \"{fieldInfo.Name}\" to be of type {nameof(IEzrObject)}, as it uses the attribute \"{nameof(SharpFieldWrapperAttribute)}\"", nameof(fieldInfo)) : null; } @@ -41,7 +41,7 @@ public class SharpFieldWrapperAttribute(string name) : Attribute public static ArgumentException? ValidateProperty(PropertyInfo propertyInfo) { return !typeof(IEzrObject).IsAssignableFrom(propertyInfo.PropertyType) - ? new($"Expected property \"{propertyInfo.Name}\" to be of type {nameof(IEzrObject)}, as it uses the attribute \"{nameof(SharpFieldWrapperAttribute)}\"", propertyInfo.Name) + ? new($"Expected property \"{propertyInfo.Name}\" to be of type {nameof(IEzrObject)}, as it uses the attribute \"{nameof(SharpFieldWrapperAttribute)}\"", nameof(propertyInfo)) : null; } } diff --git a/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs index fc06c43..0d33e1a 100644 --- a/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs @@ -6,13 +6,13 @@ namespace EzrSquared.Runtime.WrapperAttributes; /// -/// Attribute for C# methods which will be wrapped into ezr². +/// Attribute for C# methods and constructors which will be wrapped into ezr². /// -[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, AllowMultiple = false, Inherited = true)] public class SharpMethodWrapperAttribute : Attribute { /// - /// The ezr² name for the method. + /// The ezr² name for the method, optional. /// public readonly string Name = string.Empty; @@ -46,18 +46,18 @@ public SharpMethodWrapperAttribute(string name) public SharpMethodWrapperAttribute() { } /// - /// Checks if the given method has all the required parameter. + /// Checks if the given method or constructor has the required parameters. /// - /// The method. + /// The method or constructor to check. /// if the check was successful, an otherwise. - public static Exception? ValidateMethodParameters(MethodInfo methodInfo) + public static Exception? ValidateMethodParameters(MethodBase methodInfo) { // Get the parameter types of the method Type[] parameterTypes = Array.ConvertAll(methodInfo.GetParameters(), p => p.ParameterType); // Check if the number of parameters matches if (parameterTypes.Length != 1) - return new TargetParameterCountException($"\"{methodInfo.Name}\": Method must have exactly one parameter, as it uses the {nameof(SharpMethodWrapperAttribute)} attribute."); + return new TargetParameterCountException($"\"{methodInfo.Name}\": Method or constructor must have exactly one parameter, as it uses the {nameof(SharpMethodWrapperAttribute)} attribute."); // Check if the required parameter types match return parameterTypes[0] != typeof(SharpMethodParameters) diff --git a/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs index 6c134d7..ff42e2e 100644 --- a/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs @@ -1,4 +1,7 @@ -using System; +using EzrSquared.Runtime.Types; +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; namespace EzrSquared.Runtime.WrapperAttributes; @@ -6,9 +9,8 @@ namespace EzrSquared.Runtime.WrapperAttributes; /// Attribute for C# classes which will be wrapped into ezr². /// /// The ezr² name for the type. -/// The name of the static constructor method. See for more details. [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] -public class SharpTypeWrapperAttribute(string name, string constructor) : Attribute +public class SharpTypeWrapperAttribute(string name) : Attribute { /// /// The ezr² name for the type. @@ -16,16 +18,38 @@ public class SharpTypeWrapperAttribute(string name, string constructor) : Attrib public readonly string Name = name; /// - /// The name of the static constructor method. + /// Checks if the given type has a constructor with the attribute. /// - /// - /// The static constructor method should have the following arguments: - ///
Context context, - ///
Position startPosition, - ///
Position endPosition, - ///
Dictionary<, EzrObjectReference> arguments, - ///
interpreter, - ///
result - ///
- public readonly string Constructor = constructor; + /// The type to check. + /// The constructor and its attribute. + /// if the check was successful, an otherwise. + public static Exception? ValidateMethodParameters( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type typeInfo, + + out (ConstructorInfo Info, SharpMethodWrapperAttribute Attribute)? constructor) + { + constructor = null; + if (!typeof(IEzrObject).IsAssignableFrom(typeInfo)) + return new ArgumentException($"Expected type \"{typeInfo.Name}\" to inherit from {nameof(IEzrObject)}, as it uses the attribute \"{nameof(SharpTypeWrapperAttribute)}\"", nameof(typeInfo)); + + ConstructorInfo[] constructors = typeInfo.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance); + + foreach (ConstructorInfo constructorInfo in constructors) + { + SharpMethodWrapperAttribute? attribute = constructorInfo.GetCustomAttribute(false); + if (constructor is not null && attribute is not null) + return new AmbiguousMatchException($"Found multiple constructors for type \"{typeInfo.Name}\" with attribute {nameof(SharpMethodWrapperAttribute)}"); + else if (attribute is not null) + { + constructor = (constructorInfo, attribute); + if (SharpMethodWrapperAttribute.ValidateMethodParameters(constructorInfo) is Exception exception) + return exception; + } + } + + return constructor is null + ? new ArgumentException($"No constructor with attribute {nameof(SharpMethodWrapperAttribute)} found for type \"{typeInfo.Name}\"!", nameof(typeInfo)) + : null; + } } \ No newline at end of file diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 670d416..9b10e7b 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; ///
internal class Shell { - private const string Version = "0.1.2"; + private const string Version = "0.2.0"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index fb11a5e..4040631 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "0.1.2" +#define MyAppVersion "0.2.0" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 8473c09..2b426a4 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "0.1.2" +#define MyAppVersion "0.2.0" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 1f506eb..bf0cdab 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.1.2 + 0.2.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From db98d08ef93bac6f5677c9955b1dde9111b1aeb2 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 7 Aug 2024 20:04:25 +0530 Subject: [PATCH 027/113] Updated changelog. --- Changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.txt b/Changelog.txt index f52e1ff..3e7a0a6 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -5,6 +5,7 @@ https://github.com/Uralstech/ezrSquared/releases * ezr² RE - v0.2.0 [07-08-24] * [BREAKING CHANGE] SharpTypeWrapperAttribute will now require the type to have one SharpMethodWrapper wrapped constructor to create objects. + * [BREAKING CHANGE] All static `WrapperConstructor` methods in runtime error classes have been removed and converted to regular constructors. * [BREAKING CHANGE] EzrSharpSourceExecutableWrapper now inherits directly from EzrObject and implements some overrides. * Static wrapped methods in SharpTypeWrapper wrapped types should work now. * SharpMethodWrapperAttribute now also supports constructors. From 652b0737bdc77f3df44fdd92754a120151a04a3f Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 8 Aug 2024 16:13:20 +0530 Subject: [PATCH 028/113] Revamped executables. --- src/Runtime/Interpreter.cs | 1 + src/Runtime/Types/BaseTypes.cs | 6 +- .../EzrSharpCompatibilityType.cs | 36 ++-- .../EzrSharpCompatibilityWrapper.cs | 44 ++++- .../EzrSharpCompatibilityConstructor.cs | 16 +- .../EzrSharpCompatibilityExecutable.cs | 28 ++- .../EzrSharpCompatibilityFunction.cs | 26 +-- .../EzrSharpCompatibilityField.cs | 7 +- .../EzrSharpCompatibilityProperty.cs | 7 +- .../EzrSharpSourceExecutableWrapper.cs | 45 ++++- .../EzrSharpSourceFieldWrapper.cs | 53 +++--- .../EzrSharpSourceFunctionWrapper.cs | 72 +++++++- .../EzrSharpSourcePropertyWrapper.cs | 47 +++++ .../EzrSharpSourceTypeWrapper.cs | 160 ++++++++++++++---- src/Runtime/Types/Executables/EzrClass.cs | 2 +- .../Types/Executables/EzrClassInstance.cs | 2 +- src/Runtime/Types/Executables/EzrFunction.cs | 2 +- .../Types/Executables/EzrRuntimeExecutable.cs | 4 +- .../SharpAutoCompatibilityWrapperAttribute.cs | 68 ++++++++ src/Util/Utils.cs | 2 +- 20 files changed, 490 insertions(+), 138 deletions(-) create mode 100644 src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index f85806d..d2be250 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -7,6 +7,7 @@ using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; using EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; +using EzrSquared.Runtime.Types.Executables; using System; using System.Collections.Generic; using System.Numerics; diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs index f446ca9..fcdc8bc 100644 --- a/src/Runtime/Types/BaseTypes.cs +++ b/src/Runtime/Types/BaseTypes.cs @@ -79,15 +79,15 @@ public int HashTag /// /// Creates a new object with the specified parent context and position. /// - /// The context in which this object was created in. + /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrObject(Context creationContext, Position startPosition, Position endPosition) + public EzrObject(Context parentContext, Position startPosition, Position endPosition) { StartPosition = startPosition; EndPosition = endPosition; - _executionContext = _creationContext = creationContext; + _executionContext = _creationContext = parentContext; Context = new Context(TypeName, false, startPosition, _creationContext, _creationContext.StaticContext); } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index 7cfdab9..576ff41 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -17,17 +17,12 @@ public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpType"; - [DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields - | DynamicallyAccessedMemberTypes.PublicMethods - | DynamicallyAccessedMemberTypes.PublicProperties - | DynamicallyAccessedMemberTypes.PublicConstructors - | DynamicallyAccessedMemberTypes.NonPublicConstructors - )] public readonly Type SharpType; + public readonly Type SharpType; public readonly string SharpTypeName; public EzrSharpCompatibilityType( + string name, [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields @@ -35,12 +30,12 @@ public EzrSharpCompatibilityType( | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors - )]Type type, + )] Type type, RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpType = type; - SharpTypeName = Utils.PascalToSnakeCase(SharpType.Name); + SharpTypeName = name; Tag = $"{Tag}.{SharpTypeName}.{Utils.GetNextUniqueId()}"; if (SharpType.IsGenericType) @@ -49,7 +44,7 @@ public EzrSharpCompatibilityType( return; } - MethodInfo[] publicStaticMethods = SharpType.GetMethods(BindingFlags.Static | BindingFlags.Public); + MethodInfo[] publicStaticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public); Dictionary duplicateNames = new(publicStaticMethods.Length); for (int i = 0; i < publicStaticMethods.Length; i++) { @@ -76,32 +71,45 @@ public EzrSharpCompatibilityType( Context.Set(null, methodObjectName, ReferencePool.Get(methodObject, AccessMod.Constant)); } - PropertyInfo[] publicStaticProperties = SharpType.GetProperties(BindingFlags.Static | BindingFlags.Public); + PropertyInfo[] publicStaticProperties = type.GetProperties(BindingFlags.Static | BindingFlags.Public); for (int i = 0; i < publicStaticProperties.Length; i++) { EzrSharpCompatibilityProperty property = new(publicStaticProperties[i], null, Context, StartPosition, EndPosition); Context.Set(null, property.SharpPropertyName, ReferencePool.Get(property, AccessMod.Constant)); } - FieldInfo[] publicStaticFields = SharpType.GetFields(BindingFlags.Static | BindingFlags.Public); + FieldInfo[] publicStaticFields = type.GetFields(BindingFlags.Static | BindingFlags.Public); for (int i = 0; i < publicStaticFields.Length; i++) { EzrSharpCompatibilityField field = new(publicStaticFields[i], null, Context, StartPosition, EndPosition); Context.Set(null, field.SharpFieldName, ReferencePool.Get(field, AccessMod.Constant)); } - ConstructorInfo[] publicConstructors = SharpType.GetConstructors(); + ConstructorInfo[] publicConstructors = type.GetConstructors(); for (int i = 0; i < publicConstructors.Length; i++) { ConstructorInfo constructor = publicConstructors[i]; if (!constructor.IsPublic) continue; - IEzrObject constructorObject = new EzrSharpCompatibilityConstructor(constructor, SharpType, Context, StartPosition, EndPosition); + IEzrObject constructorObject = new EzrSharpCompatibilityConstructor(constructor, type, Context, StartPosition, EndPosition); Context.Set(null, $"make_{i}", ReferencePool.Get(constructorObject, AccessMod.Constant)); } } + public EzrSharpCompatibilityType( + + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.PublicConstructors + | DynamicallyAccessedMemberTypes.NonPublicConstructors + )] Type type, + + RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) + : this(Utils.PascalToSnakeCase(type.Name), type, result, parentContext, startPosition, endPosition) { } + /// public override int ComputeHashCode(RuntimeResult result) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index d004c42..bdeb467 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -16,6 +16,31 @@ public abstract class EzrSharpCompatibilityWrapper : EzrObject public EzrSharpCompatibilityWrapper(Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { } + /// + /// Checks if the given type is supported by the primitive compatibility wrappers. + /// + /// The type to check. + /// if yes, otherwise. + public static bool IsSupportedPrimitiveType(Type type) + { + TypeCode typeCode = Type.GetTypeCode(type); + return typeCode is TypeCode.Empty + or TypeCode.Int16 + or TypeCode.Int32 + or TypeCode.Int64 + or TypeCode.UInt16 + or TypeCode.UInt32 + or TypeCode.UInt64 + or TypeCode.Byte + or TypeCode.SByte + or TypeCode.Single + or TypeCode.Double + or TypeCode.Decimal + or TypeCode.Boolean + or TypeCode.Char + or TypeCode.String; + } + protected internal object? EzrObjectToPrimitive(IEzrObject value, TypeCode typeCode, RuntimeResult result) { switch (typeCode) @@ -130,6 +155,12 @@ public EzrSharpCompatibilityWrapper(Context parentContext, Position startPositio if (value is EzrFloat doubleValue) return doubleValue.Value; + result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.Decimal: + if (value is EzrFloat decimalValue) + return (decimal)decimalValue.Value; + result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; case TypeCode.Boolean: @@ -149,8 +180,10 @@ public EzrSharpCompatibilityWrapper(Context parentContext, Position startPositio return stringValue.Value; else if (value is EzrCharacterList characterListValue) return characterListValue.StringValue; + else if (value is EzrCharacter stringCharacterValue) + return stringCharacterValue.Value.ToString(); - result.Failure(new EzrUnexpectedTypeError($"Expected string or character list, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + result.Failure(new EzrUnexpectedTypeError($"Expected string, character or character list, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; case TypeCode.Empty: if (value is EzrNothing) @@ -159,7 +192,7 @@ public EzrSharpCompatibilityWrapper(Context parentContext, Position startPositio result.Failure(new EzrUnexpectedTypeError($"Expected type nothing, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; default: - result.Failure(new EzrUnsupportedWrappingError($"Object of type \"{value.TypeName}\" cannot be converted from to CSharp type!", Context, value.StartPosition, value.EndPosition)); + result.Failure(new EzrUnsupportedWrappingError($"Object of type \"{value.TypeName}\" cannot be converted to CSharp type \"{typeCode}\"!", Context, value.StartPosition, value.EndPosition)); break; } @@ -200,10 +233,7 @@ protected internal void PrimitiveToEzrObject(object? value, TypeCode typeCode, R case TypeCode.SByte: result.Success(NewIntegerConstant((sbyte)value)); break; - case TypeCode.Single: - result.Success(NewFloatConstant((float)value)); - break; - case TypeCode.Double: + case TypeCode.Single or TypeCode.Double or TypeCode.Decimal: result.Success(NewFloatConstant((double)value)); break; case TypeCode.Boolean: @@ -216,7 +246,7 @@ protected internal void PrimitiveToEzrObject(object? value, TypeCode typeCode, R result.Success(NewStringConstant((string)value)); break; default: - result.Failure(new EzrUnsupportedWrappingError($"CSharp type \"{value.GetType().Name}\" cannot be converted to EzrSquared type!", Context, StartPosition, EndPosition)); + result.Failure(new EzrUnsupportedWrappingError($"CSharp type \"{value.GetType().Name}\" cannot be converted to an ezr² type!", Context, StartPosition, EndPosition)); break; } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index 2de59d3..dffe9b3 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -12,7 +12,6 @@ public class EzrSharpCompatibilityConstructor : EzrSharpCompatibilityExecutable [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] public readonly Type ConstructingType; public readonly string ConstructingTypeName; - public readonly ConstructorInfo SharpConstructor; public EzrSharpCompatibilityConstructor(ConstructorInfo sharpConstructor, @@ -21,7 +20,6 @@ public EzrSharpCompatibilityConstructor(ConstructorInfo sharpConstructor, Context context, Position startPosition, Position endPosition) : base(sharpConstructor, null, context, startPosition, endPosition) { - SharpConstructor = sharpConstructor; ConstructingType = constructType; ConstructingTypeName = Utils.PascalToSnakeCase(ConstructingType.Name); } @@ -38,7 +36,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run try { - object? output = SharpConstructor.Invoke(mappedArguments); + object? output = ((ConstructorInfo)Executable).Invoke(mappedArguments); if (output is null) result.Success(NewNothingConstant()); @@ -58,18 +56,6 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run } } - /// - public override bool StrictEquals(IEzrObject other, RuntimeResult result) - { - return (other as EzrSharpCompatibilityConstructor)?.SharpConstructor == SharpConstructor && other.HashTag == HashTag; - } - - /// - public override int ComputeHashCode(RuntimeResult result) - { - return HashCode.Combine(HashTag, SharpConstructor); - } - /// public override string ToString(RuntimeResult result) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index b82f4e1..2a6898a 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -16,19 +16,24 @@ public abstract class EzrSharpCompatibilityExecutable : EzrSharpCompatibilityWra public readonly ParameterInfo[] Parameters; public readonly string[] ParameterNames; + public readonly MethodBase Executable; public readonly object? Instance; public readonly string SharpRuntimeExecutableName; - public EzrSharpCompatibilityExecutable(MethodBase sharpMember, object? instance, Context context, Position startPosition, Position endPosition) : base(context, startPosition, endPosition) + public EzrSharpCompatibilityExecutable(string name, MethodBase sharpMember, object? instance, Context context, Position startPosition, Position endPosition) : base(context, startPosition, endPosition) { - SharpRuntimeExecutableName = Utils.PascalToSnakeCase(sharpMember.Name); + SharpRuntimeExecutableName = name; Tag = $"{Tag}.{SharpRuntimeExecutableName}.{Utils.GetNextUniqueId()}"; - - Parameters = sharpMember.GetParameters(); + + Executable = sharpMember; + Parameters = Executable.GetParameters(); ParameterNames = Array.ConvertAll(Parameters, p => Utils.PascalToSnakeCase(p.Name ?? string.Empty)); Instance = instance; } + public EzrSharpCompatibilityExecutable(MethodBase sharpMember, object? instance, Context context, Position startPosition, Position endPosition) + : this(Utils.PascalToSnakeCase(sharpMember.Name), sharpMember, instance, context, startPosition, endPosition) { } + protected internal Dictionary ArgumentsArrayToDictionary(Reference[] arguments, RuntimeResult result) { Dictionary formattedArguments = new(arguments.Length); @@ -123,4 +128,19 @@ protected internal Dictionary ArgumentsArrayToDictionary(Ref return formattedArguments; } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return HashCode.Combine(HashTag, Executable); + } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return other is EzrSharpCompatibilityExecutable executable + && executable.Executable == Executable + && executable.Instance?.GetHashCode() == Instance?.GetHashCode() + && other.HashTag == HashTag; + } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs index 4e2d2b1..f899713 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs @@ -13,12 +13,11 @@ public class EzrSharpCompatibilityFunction : EzrSharpCompatibilityExecutable /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpFunction"; - public readonly MethodInfo SharpFunction; + public EzrSharpCompatibilityFunction(string name, MethodInfo sharpFunction, object? instance, Context context, Position startPosition, Position endPosition) + : base(name, sharpFunction, instance, context, startPosition, endPosition) { } - public EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context context, Position startPosition, Position endPosition) : base(sharpFunction, instance, context, startPosition, endPosition) - { - SharpFunction = sharpFunction; - } + public EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context context, Position startPosition, Position endPosition) + : base(sharpFunction, instance, context, startPosition, endPosition) { } public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { @@ -32,7 +31,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run try { - object? output = SharpFunction.Invoke(Instance, mappedArguments); + object? output = Executable.Invoke(Instance, mappedArguments); if (output is null) result.Success(NewNothingConstant()); @@ -46,21 +45,6 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run } } - /// - public override int ComputeHashCode(RuntimeResult result) - { - return HashCode.Combine(HashTag, SharpFunction); - } - - /// - public override bool StrictEquals(IEzrObject other, RuntimeResult result) - { - return other is EzrSharpCompatibilityFunction function - && function.SharpFunction == SharpFunction - && function.Instance?.GetHashCode() == Instance?.GetHashCode() - && other.HashTag == HashTag; - } - /// public override string ToString(RuntimeResult result) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index 19fe27f..09d1025 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -17,14 +17,17 @@ public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper public readonly object? Instance; public readonly string SharpFieldName; - public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + public EzrSharpCompatibilityField(string name, FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpField = sharpField; Instance = instance; - SharpFieldName = Utils.PascalToSnakeCase(SharpField.Name); + SharpFieldName = name; Tag = $"{Tag}.{SharpFieldName}.{Utils.GetNextUniqueId()}"; } + public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition) + : this(Utils.PascalToSnakeCase(sharpField.Name), sharpField, instance, parentContext, startPosition, endPosition) { } + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { if (arguments.Length > 1) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs index cc900ff..fb3822f 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -17,14 +17,17 @@ public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper public readonly object? Instance; public readonly string SharpPropertyName; - public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + public EzrSharpCompatibilityProperty(string name, PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpProperty = sharpProperty; Instance = instance; - SharpPropertyName = Utils.PascalToSnakeCase(SharpProperty.Name); + SharpPropertyName = name; Tag = $"{Tag}.{SharpPropertyName}.{Utils.GetNextUniqueId()}"; } + public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition) + : this(Utils.PascalToSnakeCase(sharpProperty.Name), sharpProperty, instance, parentContext, startPosition, endPosition) { } + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { if (arguments.Length > 1) diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs index b8075b1..88358e3 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs @@ -2,10 +2,17 @@ using EzrSquared.Util; using System; using System.Collections.Generic; +using System.Text; namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; -public abstract class EzrSharpSourceExecutableWrapper : EzrObject +/// +/// Parent of all wrapper classes which wrap executable members written in C# so that they can be used in ezr². +/// +/// The context in which this object was created. +/// The starting position of the object. +/// The ending position of the object. +public abstract class EzrSharpSourceExecutableWrapper(Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) { /// public override string TypeName { get; protected internal set; } = "csharp source executable wrapper"; @@ -13,14 +20,44 @@ public abstract class EzrSharpSourceExecutableWrapper : EzrObject /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceExecutableWrapper"; - public (string Name, bool IsRequired)[] Parameters; + /// + /// The name of the executable's parameters and if they are required. + /// + public (string Name, bool IsRequired)[] Parameters = []; + + /// + /// Does the executable accept extra keyword arguments? + /// public bool HasKeywordArguments; - public EzrSharpSourceExecutableWrapper(Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + /// + /// Converts a string from PascalCase to lowecase plain text, seperated by spaces. + /// + /// The text to convert in PascalCase. + /// The converted text in lowecase plain text. + internal protected static string PascalCaseToLowerCasePlainText(string text) { - Parameters = []; + StringBuilder result = new(); + result.Append(char.ToLowerInvariant(text[0])); + + for (int i = 1; i < text.Length; ++i) + { + char c = text[i]; + if (char.IsUpper(c)) + result.Append(' ').Append(char.ToLowerInvariant(c)); + else + result.Append(c); + } + + return result.ToString(); } + /// + /// Checks and populates the arguments given by the user's ezr² code into a dictionary. + /// + /// The array of arguments. + /// Runtime result for carrying the result and any errors. + /// The dictionary of all the arguments. protected internal Dictionary CheckAndPopulateArguments(Reference[] arguments, RuntimeResult result) { int calculatedParameterIndex = 0; diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs index 4aa481d..efd4488 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs @@ -4,10 +4,12 @@ using System; using System.Collections.Generic; using System.Reflection; -using System.Text; namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; +/// +/// A class to wrap fields written in C# so that they can be used in ezr². +/// public class EzrSharpSourceFieldWrapper : EzrSharpSourceExecutableWrapper { /// @@ -16,12 +18,39 @@ public class EzrSharpSourceFieldWrapper : EzrSharpSourceExecutableWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceFieldWrapper"; + /// + /// The object which the field is a part of, if static. + /// public readonly object? SharpInstance; + + /// + /// Reflection information about the field. + /// public readonly FieldInfo SharpField; + + /// + /// The type of the field's value. + /// public readonly Type SharpFieldType; + + /// + /// The name of the field, in snake_case. + /// public readonly string SharpFieldName; + /// + /// Is the field read-only? + /// public readonly bool IsReadOnlyField; + /// + /// Creates a new . + /// + /// The field to wrap. + /// The object which the field is a part of, if static. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. + /// Thrown if is not found in the field. public EzrSharpSourceFieldWrapper(FieldInfo fieldInfo, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpInstance = instance; @@ -44,27 +73,9 @@ public EzrSharpSourceFieldWrapper(FieldInfo fieldInfo, object? instance, Context } /// - /// Converts a string from PascalCase to lowecase plain text, seperated by spaces. + /// If there are no arguments, accesses the field's value. If the field is not read-only and there is an arguments, sets the field's value. /// - /// The text to convert in PascalCase. - /// The converted text in lowecase plain text. - private static string PascalCaseToLowerCasePlainText(string text) - { - StringBuilder result = new(); - result.Append(char.ToLowerInvariant(text[0])); - - for (int i = 1; i < text.Length; ++i) - { - char c = text[i]; - if (char.IsUpper(c)) - result.Append(' ').Append(char.ToLowerInvariant(c)); - else - result.Append(c); - } - - return result.ToString(); - } - + /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs index 7d8e359..e0849ca 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs @@ -6,6 +6,9 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; +/// +/// A class to wrap methods written in C# so that they can be used in ezr². +/// public partial class EzrSharpSourceFunctionWrapper : EzrSharpSourceExecutableWrapper { /// @@ -14,21 +17,77 @@ public partial class EzrSharpSourceFunctionWrapper : EzrSharpSourceExecutableWra /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceFunctionWrapper"; + /// + /// The wrapped function. + /// public readonly EzrSharpSourceWrappableMethod SharpFunction; + + /// + /// The name of the function, in snake_case. + /// public readonly string SharpFunctionName; + /// + /// Creates a new from a function's . + /// + /// The method to wrap. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. + public EzrSharpSourceFunctionWrapper(MethodInfo function, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + Exception? parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(function); + if (parameterException is not null) + throw parameterException; + + SharpFunction = (EzrSharpSourceWrappableMethod)function.CreateDelegate(typeof(EzrSharpSourceWrappableMethod)); + (SharpFunctionName, SharpMethodWrapperAttribute attribute) = GetFunctionInfo(function); + + AddParameters(attribute); + } + + /// + /// Creates a new from a function. + /// + /// The method to wrap. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. public EzrSharpSourceFunctionWrapper(EzrSharpSourceWrappableMethod function, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpFunction = function; - SharpMethodWrapperAttribute attribute = SharpFunction.Method.GetCustomAttribute(true) ?? throw new ArgumentException($"No \"{nameof(SharpMethodWrapperAttribute)}\" attribute found!", nameof(function)); + (SharpFunctionName, SharpMethodWrapperAttribute attribute) = GetFunctionInfo(function.Method); - Exception? parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(SharpFunction.Method); - if (parameterException is not null) - throw parameterException; + AddParameters(attribute); + } + /// + /// Gets the function's ezr² (snake_case) name and wrapper attribute. + /// + /// The function's . + /// The function's ezr² name and wrapper attribute + /// + /// Thrown if the attribute was not found in the function + /// or if the name given in the function's is empty. + /// + private (string, SharpMethodWrapperAttribute) GetFunctionInfo(MethodInfo function) + { + SharpMethodWrapperAttribute attribute = function.GetCustomAttribute(true) + ?? throw new ArgumentException($"No \"{nameof(SharpMethodWrapperAttribute)}\" attribute found in function \"{function.Name}\"!", nameof(function)); + if (string.IsNullOrEmpty(attribute.Name)) - throw new ArgumentException($"ezrSquared compliant name not provided in {nameof(SharpMethodWrapperAttribute)} of function!", nameof(function)); + throw new ArgumentException($"Name not provided in {nameof(SharpMethodWrapperAttribute)} of function \"{function.Name}\"!", nameof(function)); + + Tag = $"{Tag}.{attribute.Name}.{Utils.GetNextUniqueId()}"; + return (attribute.Name, attribute); + } + /// + /// Adds the parameters of the function to be wrapped to the object. + /// + /// The attribute of the function containing the details for optional, required and extra keyword parameters. + private void AddParameters(SharpMethodWrapperAttribute attribute) + { int requiredParameters = attribute.RequiredParameters.Length; Parameters = new (string Name, bool IsRequired)[attribute.RequiredParameters.Length + attribute.OptionalParameters.Length]; @@ -39,10 +98,9 @@ public EzrSharpSourceFunctionWrapper(EzrSharpSourceWrappableMethod function, Con Parameters[j + requiredParameters] = new(attribute.OptionalParameters[j], false); HasKeywordArguments = attribute.HasKeywordArguments; - SharpFunctionName = attribute.Name; - Tag = $"{Tag}.{SharpFunctionName}.{Utils.GetNextUniqueId()}"; } + /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs index 7b14f5d..837429a 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs @@ -1,4 +1,5 @@ using EzrSquared.Runtime.Types.Core; +using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; @@ -6,6 +7,10 @@ using System.Reflection; namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; + +/// +/// A class to wrap properties written in C# so that they can be used in ezr². +/// public class EzrSharpSourcePropertyWrapper : EzrSharpSourceExecutableWrapper { /// @@ -14,10 +19,35 @@ public class EzrSharpSourcePropertyWrapper : EzrSharpSourceExecutableWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceFieldWrapper"; + /// + /// The object which the property is a part of, if static. + /// public readonly object? SharpInstance; + + /// + /// Reflection information about the property. + /// public readonly PropertyInfo SharpProperty; + + /// + /// The type of the property's value. + /// + public readonly Type SharpPropertyType; + + /// + /// The name of the property, in snake_case. + /// public readonly string SharpPropertyName; + /// + /// Creates a new . + /// + /// The property to wrap. + /// The object which the property is a part of, if static. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. + /// Thrown if is not found in the property. public EzrSharpSourcePropertyWrapper(PropertyInfo propertyInfo, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpInstance = instance; @@ -30,6 +60,7 @@ public EzrSharpSourcePropertyWrapper(PropertyInfo propertyInfo, object? instance throw propertyTypeException; SharpPropertyName = attribute.Name; + SharpPropertyType = propertyInfo.PropertyType; if (SharpProperty.CanWrite && !attribute.IsReadOnly) Parameters = [("value", false)]; @@ -37,6 +68,10 @@ public EzrSharpSourcePropertyWrapper(PropertyInfo propertyInfo, object? instance Tag = $"{Tag}.{SharpPropertyName}.{Utils.GetNextUniqueId()}"; } + /// + /// If there are no arguments, accesses the property's value. If the property is not read-only and there is an arguments, sets the property's value. + /// + /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); @@ -44,7 +79,19 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run return; if (argumentReferences.TryGetValue("value", out Reference? newValue)) + { + if (!SharpPropertyType.IsAssignableFrom(newValue.Object.GetType())) + { + string sharpFieldType = SharpPropertyType.Name; + if (sharpFieldType.StartsWith("Ezr")) + sharpFieldType = sharpFieldType[3..]; + + result.Failure(new EzrUnexpectedTypeError($"Expected object of type \"{PascalCaseToLowerCasePlainText(sharpFieldType)}\", but got object of type \"{newValue.Object.TypeName}\"!", _executionContext, StartPosition, EndPosition)); + return; + } + SharpProperty.SetValue(SharpInstance, newValue.Object); + } IEzrObject value = (IEzrObject?)SharpProperty.GetValue(SharpInstance) ?? EzrConstants.Nothing; result.Success(ReferencePool.Get(value, AccessMod.PrivateConstant)); diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index 49bbbda..df6b7ab 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -1,4 +1,5 @@ using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; @@ -8,6 +9,9 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; +/// +/// A class to wrap types written in C# so that they can be used in ezr². +/// public class EzrSharpSourceTypeWrapper : EzrSharpSourceExecutableWrapper { /// @@ -16,24 +20,43 @@ public class EzrSharpSourceTypeWrapper : EzrSharpSourceExecutableWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceTypeWrapper"; - [DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicMethods - | DynamicallyAccessedMemberTypes.PublicFields - | DynamicallyAccessedMemberTypes.PublicProperties - | DynamicallyAccessedMemberTypes.PublicConstructors - | DynamicallyAccessedMemberTypes.NonPublicConstructors - )] public readonly Type SharpType; + /// + /// The wrapped type. + /// + public readonly Type SharpType; + /// + /// The name of the type, in snake_case. + /// public readonly string SharpTypeName; + /// + /// Reflection information about the type's constructor. + /// public readonly ConstructorInfo Constructor; + /// + /// Creates a new . + /// + /// The type to wrap. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. + /// + /// Thrown if the type to be wrapped is generic or if the was not found in the type. + /// + /// + /// Thrown if there are multiple methods/properties/fields with the same name. + /// public EzrSharpSourceTypeWrapper( [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.NonPublicFields | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.NonPublicProperties | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors )] Type type, @@ -43,18 +66,18 @@ public EzrSharpSourceTypeWrapper( SharpType = type; // Check generics. - if (SharpType.IsGenericType) - throw new ArgumentException($"Cannot wrap generic CSharp type {SharpType.Name}!", nameof(type)); + if (type.IsGenericType) + throw new ArgumentException($"Cannot wrap generic CSharp type {type.Name}!", nameof(type)); // Check for type attribute. - SharpTypeWrapperAttribute typeAttribute = SharpType.GetCustomAttribute(true) + SharpTypeWrapperAttribute typeAttribute = type.GetCustomAttribute(true) ?? throw new ArgumentException($"No \"{nameof(SharpTypeWrapperAttribute)}\" attribute found for type \"{type.Name}\"!", nameof(type)); // Set name and tag. SharpTypeName = typeAttribute.Name; Tag = $"{Tag}.{SharpTypeName}.{Utils.GetNextUniqueId()}"; - Exception? typeAttributeException = SharpTypeWrapperAttribute.ValidateMethodParameters(SharpType, + Exception? typeAttributeException = SharpTypeWrapperAttribute.ValidateMethodParameters(type, out (ConstructorInfo Info, SharpMethodWrapperAttribute Attribute)? constructor); if (typeAttributeException is not null) @@ -81,7 +104,7 @@ public EzrSharpSourceTypeWrapper( Constructor = constructor.Value.Info; // Get static methods to wrap. - MethodInfo[] staticMethods = SharpType.GetMethods(BindingFlags.Public | BindingFlags.Static); + MethodInfo[] staticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < staticMethods.Length; i++) { MethodInfo method = staticMethods[i]; @@ -90,43 +113,118 @@ public EzrSharpSourceTypeWrapper( if (method.IsAbstract) continue; + IEzrObject wrappedMethod; + string methodName; + // Check if method can be wrapped. - SharpMethodWrapperAttribute? methodAttribute = method.GetCustomAttribute(false); - if (methodAttribute is null) + if (method.GetCustomAttribute(false) is SharpMethodWrapperAttribute methodAttribute) + (wrappedMethod, methodName) = GetWrappedMethod(method); + else if (method.GetCustomAttribute(false) is SharpAutoCompatibilityWrapperAttribute autoWrapAttribute) + (wrappedMethod, methodName) = GetAutoWrappedMethod(method, autoWrapAttribute); + else continue; - // Check if parameters of the method are valid. - parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(method); - if (parameterException is not null) - throw parameterException; - - // Set in context. - EzrSharpSourceFunctionWrapper methodObject = new((EzrSharpSourceWrappableMethod)method.CreateDelegate(typeof(EzrSharpSourceWrappableMethod)), Context, startPosition, endPosition); - // Check if name already defined. - if (Context.IsDefined(methodObject.SharpFunctionName)) - throw new ArgumentException($"Cannot wrap CSharp static method \"{methodObject.SharpFunctionName}\" of type {SharpType.Name} as another method with the same name already exists!", nameof(type)); + if (Context.IsDefined(methodName)) + throw new AmbiguousMatchException($"Cannot wrap CSharp static method \"{methodName}\" of type {type.Name} as another member with the same name already exists!"); - Context.Set(null, methodObject.SharpFunctionName, ReferencePool.Get(methodObject, AccessMod.Constant)); + // Set in context. + Context.Set(null, methodName, ReferencePool.Get(wrappedMethod, AccessMod.Constant)); } // Get public static properties. - PropertyInfo[] publicStaticProperties = SharpType.GetProperties(BindingFlags.Static | BindingFlags.Public); + PropertyInfo[] publicStaticProperties = type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < publicStaticProperties.Length; i++) { - EzrSharpCompatibilityProperty property = new(publicStaticProperties[i], null, Context, StartPosition, EndPosition); - Context.Set(null, property.SharpPropertyName, ReferencePool.Get(property, AccessMod.Constant)); + PropertyInfo property = publicStaticProperties[i]; + IEzrObject wrappedProperty; + string propertyName; + + // Check if property can be wrapped. + if (property.GetCustomAttribute(false) is SharpFieldWrapperAttribute propertyAttribute) + { + EzrSharpSourcePropertyWrapper sourceWrapper = new(property, null, Context, StartPosition, EndPosition); + (wrappedProperty, propertyName) = (sourceWrapper, sourceWrapper.SharpPropertyName); + } + else if (property.GetCustomAttribute(false) is SharpAutoCompatibilityWrapperAttribute autoWrapAttribute) + { + EzrSharpCompatibilityProperty compatWrapper = !string.IsNullOrEmpty(autoWrapAttribute.Name) + ? new(autoWrapAttribute.Name, property, null, Context, StartPosition, EndPosition) + : new(property, null, Context, StartPosition, EndPosition); + + (wrappedProperty, propertyName) = (compatWrapper, compatWrapper.SharpPropertyName); + } + else + continue; + + // Check if name already defined. + if (Context.IsDefined(propertyName)) + throw new AmbiguousMatchException($"Cannot wrap CSharp static property \"{propertyName}\" of type {type.Name} as another member with the same name already exists!"); + + Context.Set(null, propertyName, ReferencePool.Get(wrappedProperty, AccessMod.Constant)); } // Get public static fields. - FieldInfo[] publicStaticFields = SharpType.GetFields(BindingFlags.Static | BindingFlags.Public); + FieldInfo[] publicStaticFields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < publicStaticFields.Length; i++) { - EzrSharpCompatibilityField field = new(publicStaticFields[i], null, Context, StartPosition, EndPosition); - Context.Set(null, field.SharpFieldName, ReferencePool.Get(field, AccessMod.Constant)); + FieldInfo field = publicStaticFields[i]; + IEzrObject wrappedField; + string fieldName; + + // Check if property can be wrapped. + if (field.GetCustomAttribute(false) is SharpFieldWrapperAttribute fieldAttribute) + { + EzrSharpSourceFieldWrapper sourceWrapper = new(field, null, Context, StartPosition, EndPosition); + (wrappedField, fieldName) = (sourceWrapper, sourceWrapper.SharpFieldName); + } + else if (field.GetCustomAttribute(false) is SharpAutoCompatibilityWrapperAttribute autoWrapAttribute) + { + EzrSharpCompatibilityField compatWrapper = !string.IsNullOrEmpty(autoWrapAttribute.Name) + ? new(autoWrapAttribute.Name, field, null, Context, StartPosition, EndPosition) + : new(field, null, Context, StartPosition, EndPosition); + + (wrappedField, fieldName) = (compatWrapper, compatWrapper.SharpFieldName); + } + else + continue; + + // Check if name already defined. + if (Context.IsDefined(fieldName)) + throw new AmbiguousMatchException($"Cannot wrap CSharp static fieldName \"{fieldName}\" of type {type.Name} as another member with the same name already exists!"); + + Context.Set(null, fieldName, ReferencePool.Get(wrappedField, AccessMod.Constant)); } } + private (IEzrObject, string) GetWrappedMethod(MethodInfo method) + { + // Check if parameters of the method are valid. + Exception? parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(method); + if (parameterException is not null) + throw parameterException; + + // Create the wrapper object. + EzrSharpSourceFunctionWrapper wrapper = new(method, Context, StartPosition, EndPosition); + return (wrapper, wrapper.SharpFunctionName); + } + + private (IEzrObject, string) GetAutoWrappedMethod(MethodInfo method, SharpAutoCompatibilityWrapperAttribute attribute) + { + // Check if the method is eligible for automatic wrapping. + ArgumentException? formatException = SharpAutoCompatibilityWrapperAttribute.ValidateMethod(method); + if (formatException is not null) + throw formatException; + + // Create the wrapper object. + EzrSharpCompatibilityFunction wrapper = !string.IsNullOrEmpty(attribute.Name) + ? new(attribute.Name, method, null, Context, StartPosition, EndPosition) + : new(method, null, Context, StartPosition, EndPosition); + + return (wrapper, wrapper.SharpRuntimeExecutableName); + } + + /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); diff --git a/src/Runtime/Types/Executables/EzrClass.cs b/src/Runtime/Types/Executables/EzrClass.cs index bba6ec0..60d3bc5 100644 --- a/src/Runtime/Types/Executables/EzrClass.cs +++ b/src/Runtime/Types/Executables/EzrClass.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -namespace EzrSquared.Runtime.Types; +namespace EzrSquared.Runtime.Types.Executables; /// /// The "type" type object? You know. diff --git a/src/Runtime/Types/Executables/EzrClassInstance.cs b/src/Runtime/Types/Executables/EzrClassInstance.cs index dbe44d5..ad81f63 100644 --- a/src/Runtime/Types/Executables/EzrClassInstance.cs +++ b/src/Runtime/Types/Executables/EzrClassInstance.cs @@ -5,7 +5,7 @@ using EzrSquared.Runtime.Types.Core.Text; using System; -namespace EzrSquared.Runtime.Types; +namespace EzrSquared.Runtime.Types.Executables; /// /// The "instance of a class" type object? diff --git a/src/Runtime/Types/Executables/EzrFunction.cs b/src/Runtime/Types/Executables/EzrFunction.cs index 61079c2..f7164f9 100644 --- a/src/Runtime/Types/Executables/EzrFunction.cs +++ b/src/Runtime/Types/Executables/EzrFunction.cs @@ -1,6 +1,6 @@ using EzrSquared.Runtime.Nodes; -namespace EzrSquared.Runtime.Types; +namespace EzrSquared.Runtime.Types.Executables; /// /// The function type object. diff --git a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs index d87d162..d18768e 100644 --- a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs +++ b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs @@ -6,7 +6,7 @@ using EzrSquared.Util; using System; -namespace EzrSquared.Runtime.Types; +namespace EzrSquared.Runtime.Types.Executables; /// /// The base root class of all runtime executables. @@ -98,7 +98,6 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context string key = isValidIndex ? Parameters[parameterIndex].Name : string.Empty; if (isKeywordArgument) - { // If it is a keyword argument, and it exists in Parameters: if (Array.FindIndex(Parameters, paramter => paramter.Name == argument.Name) != -1) key = argument.Name; // Choose that as the key. @@ -121,7 +120,6 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context argumentIndex++; continue; } - } // Is the key already exist? bool hasKey = isValidIndex && context.IsDefined(key); diff --git a/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs new file mode 100644 index 0000000..7373e72 --- /dev/null +++ b/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs @@ -0,0 +1,68 @@ +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; +using System; +using System.Reflection; + +namespace EzrSquared.Runtime.WrapperAttributes; + +/// +/// Attribute for C# type members which to be automatically wrapped from primitive C# types into ezr² types. +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] +public class SharpAutoCompatibilityWrapperAttribute : Attribute +{ + /// + /// The ezr² name for the member. + /// + public string Name = string.Empty; + + /// + /// Is the member read-only? Only for properties and fields. + /// + public bool IsReadOnly; + + /// + /// Checks if the given field is a supported primitive type. + /// + /// The field. + /// if the check was successful, an otherwise. + public static ArgumentException? ValidateField(FieldInfo fieldInfo) + { + return !EzrSharpCompatibilityWrapper.IsSupportedPrimitiveType(fieldInfo.FieldType) + ? new($"Expected field \"{fieldInfo.Name}\" to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\"", nameof(fieldInfo)) + : null; + } + + /// + /// Checks if the given property is a supported primitive type. + /// + /// The property. + /// if the check was successful, an otherwise. + public static ArgumentException? ValidateProperty(PropertyInfo propertyInfo) + { + return !EzrSharpCompatibilityWrapper.IsSupportedPrimitiveType(propertyInfo.PropertyType) + ? new($"Expected property \"{propertyInfo.Name}\" to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\"", nameof(propertyInfo)) + : null; + } + + /// + /// Checks if the given method has the supported signature. + /// + /// The method. + /// if the check was successful, an otherwise. + public static ArgumentException? ValidateMethod(MethodInfo methodInfo) + { + if (methodInfo.IsGenericMethod) + return new($"The \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\" attribute does not support generic method \"{methodInfo.Name}\".", nameof(methodInfo)); + + if (methodInfo.ReturnType != typeof(void) && !EzrSharpCompatibilityWrapper.IsSupportedPrimitiveType(methodInfo.ReturnType)) + return new($"Expected method \"{methodInfo.Name}\"'s return type to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\"", nameof(methodInfo)); + + foreach (ParameterInfo parameterInfo in methodInfo.GetParameters()) + { + if (!EzrSharpCompatibilityWrapper.IsSupportedPrimitiveType(parameterInfo.ParameterType)) + return new($"Expected all of method \"{methodInfo.Name}\"'s parameters to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\", but found parameter \"{parameterInfo.Name}\" of type \"{parameterInfo.ParameterType.Name}\"", nameof(methodInfo)); + } + + return null; + } +} diff --git a/src/Util/Utils.cs b/src/Util/Utils.cs index 42e8b33..5dc6e69 100644 --- a/src/Util/Utils.cs +++ b/src/Util/Utils.cs @@ -26,7 +26,7 @@ public static long GetNextUniqueId() /// Converts an index to a power of two, so that the index can be used like an enum flag. /// /// - /// This function is used to check if all arguments have been provided to and types.
+ /// This function is used to check if all arguments have been provided to and types.
/// The indices of the given arguments are converted to powers of two and bitwise-ored together, then bitwise-anded with the index of a defined parameter which is also converted to a power of two.
/// Finally, if the result is the same as the power of two of the parameter's index, this tells the interpreter that the particular required parameter has been provided. ///
From fb53fc04ee9ad4f91093aa213c4a83691cc7a942 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 8 Aug 2024 20:16:06 +0530 Subject: [PATCH 029/113] Fixed EzrSharpCompatibilityWrapper. --- .../EzrSharpCompatibilityWrapper.cs | 72 ++++++++++++++++--- 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index bdeb467..2cec7e5 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -6,7 +6,13 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; -public abstract class EzrSharpCompatibilityWrapper : EzrObject +/// +/// Parent class for all automatic wrappers which wrap existing C# objects and members so that they can be used in ezr². +/// +/// The context in which this object was created. +/// The starting position of the object. +/// The ending position of the object. +public abstract class EzrSharpCompatibilityWrapper(Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) { /// public override string TypeName { get; protected internal set; } = "csharp wrapper"; @@ -14,8 +20,6 @@ public abstract class EzrSharpCompatibilityWrapper : EzrObject /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpWrapper"; - public EzrSharpCompatibilityWrapper(Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { } - /// /// Checks if the given type is supported by the primitive compatibility wrappers. /// @@ -41,6 +45,13 @@ or TypeCode.Char or TypeCode.String; } + /// + /// Converts an ezr² type to a C# primitive type. + /// + /// The to convert. + /// The primitive type to convert it to. + /// Runtime result for carrying the result and any errors. + /// The converted object. protected internal object? EzrObjectToPrimitive(IEzrObject value, TypeCode typeCode, RuntimeResult result) { switch (typeCode) @@ -148,20 +159,50 @@ or TypeCode.Char else return (float)output; } + else if (value is EzrInteger integerValue) + { + double output = integerValue.GetDoubleRepresentation(); + if (output is < float.MinValue or > float.MaxValue) + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + return (float)output; + } else result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; case TypeCode.Double: if (value is EzrFloat doubleValue) return doubleValue.Value; - - result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + else if (value is EzrInteger integerValue) + { + double output = integerValue.GetDoubleRepresentation(); + if (output is < double.MinValue or > double.MaxValue) + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + return output; + } + else + result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; case TypeCode.Decimal: if (value is EzrFloat decimalValue) - return (decimal)decimalValue.Value; - - result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + { + double output = decimalValue.Value; + if (output is < (double)decimal.MinValue or > (double)decimal.MaxValue) + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + return (decimal)output; + } + else if (value is EzrInteger integerValue) + { + double output = integerValue.GetDoubleRepresentation(); + if (output is < (double)decimal.MinValue or > (double)decimal.MaxValue) + result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); + else + return (decimal)output; + } + else + result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; case TypeCode.Boolean: if (value is EzrBoolean booleanValue) @@ -199,6 +240,13 @@ or TypeCode.Char return 0; } + /// + /// Converts a C# primitive type to an ezr² type. + /// + /// The C# object to convert. + /// The primitive type to convert from. + /// Runtime result for carrying the result and any errors. + /// The converted . protected internal void PrimitiveToEzrObject(object? value, TypeCode typeCode, RuntimeResult result) { if (value is null) @@ -233,9 +281,15 @@ protected internal void PrimitiveToEzrObject(object? value, TypeCode typeCode, R case TypeCode.SByte: result.Success(NewIntegerConstant((sbyte)value)); break; - case TypeCode.Single or TypeCode.Double or TypeCode.Decimal: + case TypeCode.Single: + result.Success(NewFloatConstant((float)value)); + break; + case TypeCode.Double: result.Success(NewFloatConstant((double)value)); break; + case TypeCode.Decimal: + result.Success(NewFloatConstant((double)(decimal)value)); + break; case TypeCode.Boolean: result.Success(NewBooleanConstant((bool)value)); break; From e7ccfae6624f3bca88c1f7345ccba418100ed90b Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 8 Aug 2024 22:44:43 +0530 Subject: [PATCH 030/113] Fixes related to contexts. --- src/Runtime/Reference.cs | 3 ++ src/Runtime/Types/BaseTypes.cs | 29 ++++++++++--------- .../EzrSharpSourceFunctionWrapper.cs | 2 +- .../EzrSharpSourceTypeWrapper.cs | 2 +- src/Runtime/Types/Executables/EzrClass.cs | 4 +-- .../Types/Executables/EzrClassInstance.cs | 2 +- src/Runtime/Types/Executables/EzrFunction.cs | 4 +-- src/Runtime/Types/IEzrObject.cs | 11 +++++++ 8 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/Runtime/Reference.cs b/src/Runtime/Reference.cs index d1c17a3..454c4fe 100644 --- a/src/Runtime/Reference.cs +++ b/src/Runtime/Reference.cs @@ -105,6 +105,9 @@ public void UpdateObject(IEzrObject @object, AccessMod accessibilityModifiers = public void UpdateRegisteredContext(Context? context) { RegisteredContext = context; + + if (context is not null && ReferenceEquals(Object.CreationContext, Context.Empty)) + Object.UpdateCreationContext(context); } /// diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs index fcdc8bc..42f8dff 100644 --- a/src/Runtime/Types/BaseTypes.cs +++ b/src/Runtime/Types/BaseTypes.cs @@ -61,6 +61,9 @@ public int HashTag /// public Context Context { get; private set; } + /// + public Context CreationContext { get; private set; } + /// /// Is the current object read-only? /// @@ -71,11 +74,6 @@ public int HashTag /// protected internal Context _executionContext; - /// - /// The context under which the object was created. - /// - protected internal Context _creationContext; - /// /// Creates a new object with the specified parent context and position. /// @@ -87,8 +85,8 @@ public EzrObject(Context parentContext, Position startPosition, Position endPosi StartPosition = startPosition; EndPosition = endPosition; - _executionContext = _creationContext = parentContext; - Context = new Context(TypeName, false, startPosition, _creationContext, _creationContext.StaticContext); + _executionContext = CreationContext = parentContext; + Context = new Context(TypeName, false, startPosition, CreationContext, CreationContext.StaticContext); } /// @@ -103,17 +101,20 @@ public EzrObject(Context? context, Context creationContext, Position startPositi StartPosition = startPosition; EndPosition = endPosition; - _executionContext = _creationContext = creationContext; - Context = context ?? new Context(TypeName, false, startPosition, _creationContext, _creationContext.StaticContext); + _executionContext = CreationContext = creationContext; + Context = context ?? new Context(TypeName, false, startPosition, CreationContext, CreationContext.StaticContext); } - /// - /// Changes and the parent of . Be careful when you use this function. - /// - /// The new creation context. + /// public void UpdateCreationContext(Context newCreationContext) { - _creationContext = newCreationContext; + CreationContext = newCreationContext; + + if (ReferenceEquals(Context.Parent, Context.Empty)) + { + Context.UpdateParent(CreationContext); + Context.UpdateStaticContext(CreationContext.StaticContext); + } } /// diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs index e0849ca..01a7548 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs @@ -111,7 +111,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run ( argumentReferences, _executionContext, - _creationContext, + CreationContext, Context, StartPosition, EndPosition, diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index df6b7ab..6da6ff6 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -237,7 +237,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run ( argumentReferences, _executionContext, - _creationContext, + CreationContext, Context, StartPosition, EndPosition, diff --git a/src/Runtime/Types/Executables/EzrClass.cs b/src/Runtime/Types/Executables/EzrClass.cs index 60d3bc5..be16461 100644 --- a/src/Runtime/Types/Executables/EzrClass.cs +++ b/src/Runtime/Types/Executables/EzrClass.cs @@ -227,7 +227,7 @@ private void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResu return; } - Context newContext = new($"<{TypeName} \"{ExecutableName}\" instance>", false, StartPosition, Context, Context, Parents.Length); + Context newContext = new($"<{TypeName} \"{ExecutableName}\" instance>", false, StartPosition, _executionContext, Context, Parents.Length); Reference[] instanceParentReferences = AddParents(arguments, newContext, interpreter, result); if (result.ShouldReturn) return; @@ -271,6 +271,6 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run copy.LinkedContexts[i] = reference.Object.Context; } - return new EzrClass(IsAnonymous ? null : ExecutableName, Body, Parameters, KeywordArguments, Parents, staticParentReferences, IsReadOnly, IsStatic, copy!, _creationContext, StartPosition, EndPosition); + return new EzrClass(IsAnonymous ? null : ExecutableName, Body, Parameters, KeywordArguments, Parents, staticParentReferences, IsReadOnly, IsStatic, copy!, CreationContext, StartPosition, EndPosition); } } diff --git a/src/Runtime/Types/Executables/EzrClassInstance.cs b/src/Runtime/Types/Executables/EzrClassInstance.cs index ad81f63..85f1203 100644 --- a/src/Runtime/Types/Executables/EzrClassInstance.cs +++ b/src/Runtime/Types/Executables/EzrClassInstance.cs @@ -572,6 +572,6 @@ public override string ToPureString(RuntimeResult result) copy.LinkedContexts[i] = reference.Object.Context; } - return new EzrClassInstance(Class, parentReferences, IsReadOnly, Interpreter, copy!, _creationContext, StartPosition, EndPosition); + return new EzrClassInstance(Class, parentReferences, IsReadOnly, Interpreter, copy!, CreationContext, StartPosition, EndPosition); } } diff --git a/src/Runtime/Types/Executables/EzrFunction.cs b/src/Runtime/Types/Executables/EzrFunction.cs index f7164f9..c6bbf6d 100644 --- a/src/Runtime/Types/Executables/EzrFunction.cs +++ b/src/Runtime/Types/Executables/EzrFunction.cs @@ -35,7 +35,7 @@ public class EzrFunction(string? name, Node body, (string Name, Node Node)[] par /// Should the function ignore extra arguments? public void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result, bool ignoreExtraArguments) { - Context newContext = new($"<{TypeName} \"{ExecutableName}\">", false, StartPosition, _creationContext, _creationContext.StaticContext); + Context newContext = new($"<{TypeName} \"{ExecutableName}\">", false, StartPosition, CreationContext, CreationContext.StaticContext); CheckAndPopulateArguments(arguments, newContext, interpreter, result, ignoreExtraArguments); if (result.ShouldReturn) return; @@ -66,6 +66,6 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run /// public IMutable? DeepCopy(RuntimeResult result) { - return new EzrFunction(IsAnonymous ? null : ExecutableName, Body, Parameters, KeywordArguments, ReturnLast, _creationContext, StartPosition, EndPosition); + return new EzrFunction(IsAnonymous ? null : ExecutableName, Body, Parameters, KeywordArguments, ReturnLast, CreationContext, StartPosition, EndPosition); } } diff --git a/src/Runtime/Types/IEzrObject.cs b/src/Runtime/Types/IEzrObject.cs index c5dbfd3..e0306f0 100644 --- a/src/Runtime/Types/IEzrObject.cs +++ b/src/Runtime/Types/IEzrObject.cs @@ -38,6 +38,17 @@ public interface IEzrObject /// public Context Context { get; } + /// + /// The context under which the object was created. + /// + public Context CreationContext { get; } + + /// + /// Changes and the parent of . Be careful when you use this function. + /// + /// The new creation context. + public void UpdateCreationContext(Context newCreationContext); + /// /// Updates the context and position of the object. /// From 26816c919f22c15a07437af724a513be5ba252c9 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 9 Aug 2024 00:56:25 +0530 Subject: [PATCH 031/113] Updated documentation. --- .../EzrSharpCompatibilityObjectInstance.cs | 19 ++++++ .../EzrSharpCompatibilityType.cs | 26 ++++++++ .../EzrSharpCompatibilityWrapper.cs | 2 +- .../EzrSharpCompatibilityConstructor.cs | 21 ++++++- .../EzrSharpCompatibilityExecutable.cs | 59 +++++++++++++++++-- .../EzrSharpCompatibilityFunction.cs | 29 +++++++-- .../EzrSharpCompatibilityField.cs | 35 +++++++++++ .../EzrSharpCompatibilityProperty.cs | 35 +++++++++++ .../EzrSharpSourceExecutableWrapper.cs | 2 +- .../EzrSharpSourceFieldWrapper.cs | 1 + .../Core/RuntimeErrors/EzrRuntimeError.cs | 2 +- src/Runtime/Types/Executables/EzrClass.cs | 2 +- .../Types/Executables/EzrClassInstance.cs | 2 +- src/Runtime/Types/Executables/EzrFunction.cs | 2 +- .../Types/Executables/EzrRuntimeExecutable.cs | 2 +- src/Runtime/Types/IEzrObject.cs | 6 +- 16 files changed, 226 insertions(+), 19 deletions(-) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index 61abd9c..cda6c76 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -9,6 +9,9 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; +/// +/// Class to automatically wrap instances of already-wrapped C# types so that they can be used in ezr². +/// public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper { /// @@ -17,9 +20,25 @@ public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpObjectInstance"; + /// + /// The object to wrap. + /// public readonly object Instance; + + /// + /// The name of the type of the wrapped instance, in ezr² (snake_case) format. + /// public readonly string InstanceTypeName; + /// + /// Creates a new . + /// + /// The object to wrap. + /// The type of the wrapped instance + /// Runtime result for carrying any errors. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. public EzrSharpCompatibilityObjectInstance(object instance, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index 576ff41..35bfd50 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -9,6 +9,9 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; +/// +/// Class to automatically wrap C# types so that they can be used in ezr². +/// public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper { /// @@ -17,10 +20,25 @@ public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpType"; + /// + /// The type to wrap. + /// public readonly Type SharpType; + /// + /// The name of the type to wrap, in ezr² format (snake_case). + /// public readonly string SharpTypeName; + /// + /// Creates a new . + /// + /// The name of the type to wrap, in ezr² format (snake_case). + /// The type to wrap. + /// Runtime result for carrying any errors. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. public EzrSharpCompatibilityType( string name, @@ -97,6 +115,14 @@ public EzrSharpCompatibilityType( } } + /// + /// Creates a new . Infers the name by converting the member's name to snake_case. + /// + /// The type to wrap. + /// Runtime result for carrying any errors. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. public EzrSharpCompatibilityType( [DynamicallyAccessedMembers( diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 2cec7e5..251a9b1 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -50,7 +50,7 @@ or TypeCode.Char ///
/// The to convert. /// The primitive type to convert it to. - /// Runtime result for carrying the result and any errors. + /// Runtime result for carrying any errors. /// The converted object. protected internal object? EzrObjectToPrimitive(IEzrObject value, TypeCode typeCode, RuntimeResult result) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index dffe9b3..e2023c1 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -7,23 +7,42 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +/// +/// Class to automatically wrap C# constructors so that they can be used in ezr². +/// public class EzrSharpCompatibilityConstructor : EzrSharpCompatibilityExecutable { + /// + /// Reflection information about the type which is constructed by the wrapped constructor. + /// [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] public readonly Type ConstructingType; + + /// + /// The name of the constructor's constructing type, in ezr² format (snake_case). + /// public readonly string ConstructingTypeName; + /// + /// Creates a new . + /// + /// The constructor to wrap. + /// The type which is constructed by the constructor. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. public EzrSharpCompatibilityConstructor(ConstructorInfo sharpConstructor, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] Type constructType, - Context context, Position startPosition, Position endPosition) : base(sharpConstructor, null, context, startPosition, endPosition) + Context parentContext, Position startPosition, Position endPosition) : base(sharpConstructor, null, parentContext, startPosition, endPosition) { ConstructingType = constructType; ConstructingTypeName = Utils.PascalToSnakeCase(ConstructingType.Name); } + /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { Dictionary formattedArguments = ArgumentsArrayToDictionary(arguments, result); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index 2a6898a..c1a91cd 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -6,6 +6,9 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +/// +/// Base class for all automatic wrappers which wrap C# executables so that they can be used in ezr². +/// public abstract class EzrSharpCompatibilityExecutable : EzrSharpCompatibilityWrapper { /// @@ -14,13 +17,41 @@ public abstract class EzrSharpCompatibilityExecutable : EzrSharpCompatibilityWra /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpRuntimeExecutable"; + /// + /// Reflection information about the parameters of the executable to wrap. + /// public readonly ParameterInfo[] Parameters; + + /// + /// The names of the parameters of the executable to wrap, in ezr² (snake_case) format. + /// public readonly string[] ParameterNames; + + /// + /// The executable to wrap. + /// public readonly MethodBase Executable; + + /// + /// The object which contains the executable, if static. + /// public readonly object? Instance; + + /// + /// The name of the executable to wrap, in ezr² (snake_case) format. + /// public readonly string SharpRuntimeExecutableName; - public EzrSharpCompatibilityExecutable(string name, MethodBase sharpMember, object? instance, Context context, Position startPosition, Position endPosition) : base(context, startPosition, endPosition) + /// + /// Creates a new . + /// + /// The name of the executable to wrap, in ezr² format (snake_case). + /// The executable to wrap. + /// The object which contains the executable, if static. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrSharpCompatibilityExecutable(string name, MethodBase sharpMember, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpRuntimeExecutableName = name; Tag = $"{Tag}.{SharpRuntimeExecutableName}.{Utils.GetNextUniqueId()}"; @@ -31,9 +62,23 @@ public EzrSharpCompatibilityExecutable(string name, MethodBase sharpMember, obje Instance = instance; } - public EzrSharpCompatibilityExecutable(MethodBase sharpMember, object? instance, Context context, Position startPosition, Position endPosition) - : this(Utils.PascalToSnakeCase(sharpMember.Name), sharpMember, instance, context, startPosition, endPosition) { } - + /// + /// Creates a new . Infers the name by converting the member's name to snake_case. + /// + /// The executable to wrap. + /// The object which contains the executable, if static. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrSharpCompatibilityExecutable(MethodBase sharpMember, object? instance, Context parentContext, Position startPosition, Position endPosition) + : this(Utils.PascalToSnakeCase(sharpMember.Name), sharpMember, instance, parentContext, startPosition, endPosition) { } + + /// + /// Converts an array of arguments from ezr² code to an ordered dictionary. + /// + /// The arguments. + /// Runtime result for carrying errors. + /// The dictionary. protected internal Dictionary ArgumentsArrayToDictionary(Reference[] arguments, RuntimeResult result) { Dictionary formattedArguments = new(arguments.Length); @@ -85,6 +130,12 @@ protected internal Dictionary ArgumentsArrayToDictionary(Ref return formattedArguments; } + /// + /// Converts an ordered dictionary of named arguments into an array of primitive C# objects in the order the executable expects them in. + /// + /// The arguments. + /// Runtime result for carrying errors. + /// The array of objects. protected internal object?[] CheckAndPopulateArguments(Dictionary arguments, RuntimeResult result) { object?[] formattedArguments = new object?[Parameters.Length]; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs index f899713..3986218 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs @@ -5,6 +5,9 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +/// +/// Class to automatically wrap C# methods so that they can be used in ezr². +/// public class EzrSharpCompatibilityFunction : EzrSharpCompatibilityExecutable { /// @@ -13,12 +16,30 @@ public class EzrSharpCompatibilityFunction : EzrSharpCompatibilityExecutable /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpFunction"; - public EzrSharpCompatibilityFunction(string name, MethodInfo sharpFunction, object? instance, Context context, Position startPosition, Position endPosition) - : base(name, sharpFunction, instance, context, startPosition, endPosition) { } + /// + /// Creates a new . Infers the name by converting the member's name to snake_case. + /// + /// The name of the method to wrap, in ezr² format (snake_case). + /// The method to wrap. + /// The object which contains the method, if static. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. + public EzrSharpCompatibilityFunction(string name, MethodInfo sharpFunction, object? instance, Context parentContext, Position startPosition, Position endPosition) + : base(name, sharpFunction, instance, parentContext, startPosition, endPosition) { } - public EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context context, Position startPosition, Position endPosition) - : base(sharpFunction, instance, context, startPosition, endPosition) { } + /// + /// Creates a new . + /// + /// The method to wrap. + /// The object which contains the method, if static. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. + public EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context parentContext, Position startPosition, Position endPosition) + : base(sharpFunction, instance, parentContext, startPosition, endPosition) { } + /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { Dictionary formattedArguments = ArgumentsArrayToDictionary(arguments, result); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index 09d1025..054654c 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -5,6 +5,9 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +/// +/// Class to automatically wrap C# fields so that they can be used in ezr². +/// public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper { /// @@ -13,10 +16,30 @@ public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpField"; + /// + /// Reflection information about the wrapped field. + /// public readonly FieldInfo SharpField; + + /// + /// The object which contains the field, if static. + /// public readonly object? Instance; + + /// + /// The name of the field to wrap, in ezr² format (snake_case). + /// public readonly string SharpFieldName; + /// + /// Creates a new . + /// + /// The name of the field to wrap, in ezr² format (snake_case). + /// The field to wrap. + /// The object which contains the field, if static. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. public EzrSharpCompatibilityField(string name, FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpField = sharpField; @@ -25,9 +48,21 @@ public EzrSharpCompatibilityField(string name, FieldInfo sharpField, object? ins Tag = $"{Tag}.{SharpFieldName}.{Utils.GetNextUniqueId()}"; } + /// + /// Creates a new . Infers the name by converting the member's name to snake_case. + /// + /// The field to wrap. + /// The object which contains the field, if static. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition) : this(Utils.PascalToSnakeCase(sharpField.Name), sharpField, instance, parentContext, startPosition, endPosition) { } + /// + /// If there are no arguments, accesses the field's value. If the field is not read-only and there is an arguments, sets the field's value. + /// + /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { if (arguments.Length > 1) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs index fb3822f..66b0c18 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -5,6 +5,9 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +/// +/// Class to automatically wrap C# properties so that they can be used in ezr². +/// public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper { /// @@ -13,10 +16,30 @@ public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpProperty"; + /// + /// Reflection information about the wrapped property. + /// public readonly PropertyInfo SharpProperty; + + /// + /// The object which contains the property, if static. + /// public readonly object? Instance; + + /// + /// The name of the property to wrap, in ezr² format (snake_case). + /// public readonly string SharpPropertyName; + /// + /// Creates a new . + /// + /// The name of the property to wrap, in ezr² format (snake_case). + /// The property to wrap. + /// The object which contains the property, if static. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. public EzrSharpCompatibilityProperty(string name, PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpProperty = sharpProperty; @@ -25,9 +48,21 @@ public EzrSharpCompatibilityProperty(string name, PropertyInfo sharpProperty, ob Tag = $"{Tag}.{SharpPropertyName}.{Utils.GetNextUniqueId()}"; } + /// + /// Creates a new . Infers the name by converting the member's name to snake_case. + /// + /// The property to wrap. + /// The object which contains the property, if static. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition) : this(Utils.PascalToSnakeCase(sharpProperty.Name), sharpProperty, instance, parentContext, startPosition, endPosition) { } + /// + /// If there are no arguments, accesses the property's value. If the property is not read-only and there is an arguments, sets the property's value. + /// + /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { if (arguments.Length > 1) diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs index 88358e3..d38d43d 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs @@ -56,7 +56,7 @@ internal protected static string PascalCaseToLowerCasePlainText(string text) /// Checks and populates the arguments given by the user's ezr² code into a dictionary. ///
/// The array of arguments. - /// Runtime result for carrying the result and any errors. + /// Runtime result for carrying any errors. /// The dictionary of all the arguments. protected internal Dictionary CheckAndPopulateArguments(Reference[] arguments, RuntimeResult result) { diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs index efd4488..6cf23f2 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs @@ -37,6 +37,7 @@ public class EzrSharpSourceFieldWrapper : EzrSharpSourceExecutableWrapper /// The name of the field, in snake_case. ///
public readonly string SharpFieldName; + /// /// Is the field read-only? /// diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs index 11868a8..7d07311 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs @@ -83,7 +83,7 @@ public EzrRuntimeError(SharpMethodParameters arguments) : this( /// The name of the argument. /// The argument object. /// The context of the argument. - /// Runtime result for carrying errors. + /// Runtime result for carrying any errors. /// The string, or if failed. protected internal static string GetStringArgument(string argumentName, IEzrObject ezrObject, Context context, RuntimeResult result) { diff --git a/src/Runtime/Types/Executables/EzrClass.cs b/src/Runtime/Types/Executables/EzrClass.cs index be16461..087fff6 100644 --- a/src/Runtime/Types/Executables/EzrClass.cs +++ b/src/Runtime/Types/Executables/EzrClass.cs @@ -217,7 +217,7 @@ private Reference[] AddParents(Reference[] arguments, Context context, Interpret /// /// The arguments of the execution. /// The interpreter to be used in execution. - /// Runtime result for carrying any errors. + /// Runtime result for carrying the result and any errors. /// Should the arguments checker ignore extra parameters? private void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result, bool ignoreExtraArguments) { diff --git a/src/Runtime/Types/Executables/EzrClassInstance.cs b/src/Runtime/Types/Executables/EzrClassInstance.cs index 85f1203..a445a58 100644 --- a/src/Runtime/Types/Executables/EzrClassInstance.cs +++ b/src/Runtime/Types/Executables/EzrClassInstance.cs @@ -128,7 +128,7 @@ public class EzrClassInstance : EzrObject, IEzrMutableObject /// The source code body of the object. /// Is the object read-only? /// The interpreter for executing parts of the object. - /// Runtime result for carrying errors. + /// Runtime result for carrying any errors. /// The parent context. /// The starting position of the object. /// The ending position of the object. diff --git a/src/Runtime/Types/Executables/EzrFunction.cs b/src/Runtime/Types/Executables/EzrFunction.cs index c6bbf6d..e886eb8 100644 --- a/src/Runtime/Types/Executables/EzrFunction.cs +++ b/src/Runtime/Types/Executables/EzrFunction.cs @@ -31,7 +31,7 @@ public class EzrFunction(string? name, Node body, (string Name, Node Node)[] par /// /// The arguments of the execution. /// The interpreter to be used in execution. - /// Runtime result for carrying any errors. + /// Runtime result for carrying the result and any errors. /// Should the function ignore extra arguments? public void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result, bool ignoreExtraArguments) { diff --git a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs index d18768e..b21cbc5 100644 --- a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs +++ b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs @@ -69,7 +69,7 @@ public EzrRuntimeExecutable(string? name, Node body, (string Name, Node Node)[] /// The arguments to check. /// The context to populate /// The interpreter for executing parameter default values. - /// Runtime result for carrying errors. + /// Runtime result for carrying any errors. /// Should the checker ignore extra arguments? protected internal void CheckAndPopulateArguments(Reference[] arguments, Context context, Interpreter interpreter, RuntimeResult result, bool ignoreExtraArguments) { diff --git a/src/Runtime/Types/IEzrObject.cs b/src/Runtime/Types/IEzrObject.cs index e0306f0..0cc5785 100644 --- a/src/Runtime/Types/IEzrObject.cs +++ b/src/Runtime/Types/IEzrObject.cs @@ -227,7 +227,7 @@ public interface IEzrObject /// The node to interpret. /// The context calling on this action. /// The interpreter to use. - /// Runtime result for carrying any errors. + /// Runtime result for carrying the result and any errors. /// Should the interpretation ignore undefined variables? Useful in getting empty variable references. public void Interpret(Node code, Context callingContext, Interpreter interpreter, RuntimeResult result, bool ignoreUndefinedVariable = false); @@ -236,14 +236,14 @@ public interface IEzrObject /// /// The arguments of the execution. /// The interpreter to be used in execution. - /// Runtime result for carrying any errors. + /// Runtime result for carrying the result and any errors. public void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result); /// /// Strictly compares the current object to another, taking into account inheritance. /// /// The other object in the operation. - /// Runtime result for carrying the result and any errors. + /// Runtime result for carrying any errors. public bool StrictEquals(IEzrObject other, RuntimeResult result); /// From 64f695ece5425d6a81ea6b70202f59374a8b0a52 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 9 Aug 2024 01:07:55 +0530 Subject: [PATCH 032/113] Fixed inconsistencies regarding EzrSharpCompatibilityObjectInstance and EzrSharpCompatibilityConstructor. --- .../EzrSharpCompatibilityObjectInstance.cs | 24 +++++++++++++++-- .../EzrSharpCompatibilityType.cs | 2 +- .../EzrSharpCompatibilityConstructor.cs | 26 ++++++++++++++++--- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index cda6c76..1fa0bbe 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -33,13 +33,16 @@ public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper /// /// Creates a new . /// + /// The name of the type of the wrapped instance, in ezr² (snake_case) format. /// The object to wrap. /// The type of the wrapped instance /// Runtime result for carrying any errors. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrSharpCompatibilityObjectInstance(object instance, + public EzrSharpCompatibilityObjectInstance( + string typeName, + object instance, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] Type instanceType, @@ -47,7 +50,7 @@ public EzrSharpCompatibilityObjectInstance(object instance, RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { Instance = instance; - InstanceTypeName = Utils.PascalToSnakeCase(instanceType.Name); + InstanceTypeName = typeName; Tag = $"{Tag}.{InstanceTypeName}.{Utils.GetNextUniqueId()}"; MethodInfo[] publicMethods = instanceType.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); @@ -92,6 +95,23 @@ public EzrSharpCompatibilityObjectInstance(object instance, } } + /// + /// Creates a new . Infers the type's name by converting it to snake_case. + /// + /// The object to wrap. + /// The type of the wrapped instance + /// Runtime result for carrying any errors. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. + public EzrSharpCompatibilityObjectInstance(object instance, + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] + Type instanceType, + + RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) + : this(Utils.PascalToSnakeCase(instanceType.Name), instance, instanceType, result, parentContext, startPosition, endPosition) { } + /// public override int ComputeHashCode(RuntimeResult result) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index 35bfd50..f279e4d 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -110,7 +110,7 @@ public EzrSharpCompatibilityType( if (!constructor.IsPublic) continue; - IEzrObject constructorObject = new EzrSharpCompatibilityConstructor(constructor, type, Context, StartPosition, EndPosition); + IEzrObject constructorObject = new EzrSharpCompatibilityConstructor(SharpTypeName, constructor, type, Context, StartPosition, EndPosition); Context.Set(null, $"make_{i}", ReferencePool.Get(constructorObject, AccessMod.Constant)); } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index e2023c1..16896ca 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -26,12 +26,15 @@ public class EzrSharpCompatibilityConstructor : EzrSharpCompatibilityExecutable /// /// Creates a new . /// + /// The name of the constructor's constructing type, in ezr² format (snake_case). /// The constructor to wrap. /// The type which is constructed by the constructor. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrSharpCompatibilityConstructor(ConstructorInfo sharpConstructor, + public EzrSharpCompatibilityConstructor( + string constructTypeName, + ConstructorInfo sharpConstructor, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] Type constructType, @@ -39,9 +42,26 @@ public EzrSharpCompatibilityConstructor(ConstructorInfo sharpConstructor, Context parentContext, Position startPosition, Position endPosition) : base(sharpConstructor, null, parentContext, startPosition, endPosition) { ConstructingType = constructType; - ConstructingTypeName = Utils.PascalToSnakeCase(ConstructingType.Name); + ConstructingTypeName = constructTypeName; } + /// + /// Creates a new . Infers the constructing type's name by converting it to snake_case. + /// + /// The constructor to wrap. + /// The type which is constructed by the constructor. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. + public EzrSharpCompatibilityConstructor( + ConstructorInfo sharpConstructor, + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] + Type constructType, + + Context parentContext, Position startPosition, Position endPosition) + : this(Utils.PascalToSnakeCase(constructType.Name), sharpConstructor, constructType, parentContext, startPosition, endPosition) { } + /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { @@ -61,7 +81,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run result.Success(NewNothingConstant()); else { - IEzrObject wrapper = new EzrSharpCompatibilityObjectInstance(output, ConstructingType, result, _executionContext, StartPosition, EndPosition); + IEzrObject wrapper = new EzrSharpCompatibilityObjectInstance(ConstructingTypeName, output, ConstructingType, result, _executionContext, StartPosition, EndPosition); if (result.ShouldReturn) return; From 8926c3391267a104fbb9b5efb7eed4c20ddfd573 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 9 Aug 2024 01:33:12 +0530 Subject: [PATCH 033/113] Updated even more documentation. --- src/Runtime/Context.cs | 2 +- src/Syntax/Lexer.cs | 3 +++ src/Syntax/Parser/ParseResult.cs | 2 -- src/Util/Utils.cs | 4 +++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Runtime/Context.cs b/src/Runtime/Context.cs index 90d82d1..17177cb 100644 --- a/src/Runtime/Context.cs +++ b/src/Runtime/Context.cs @@ -307,7 +307,7 @@ public GetStatus Get(Context? callingContext, string symbol, out Reference objec /// The new to be assigned and the name of the symbol, in the format ( Object, Name). /// The old reference to assign to. /// Accessibility modifiers of the operation, by default. - /// The , representing the result of the operation. + /// The , representing the result of the operation, and the reference to the set symbol. public (SetStatus, Reference) Set(Context? callingContext, (IEzrObject Object, string Name) newObject, Reference oldReference, AccessMod accessibilityModifiers = AccessMod.None) { if (oldReference.IsEmpty) diff --git a/src/Syntax/Lexer.cs b/src/Syntax/Lexer.cs index c42110f..42b6078 100644 --- a/src/Syntax/Lexer.cs +++ b/src/Syntax/Lexer.cs @@ -259,6 +259,9 @@ private void ReverseTo(int index) return null; } + /// + /// Skips a comment in the ezr² code. + /// private void SkipComment() { do diff --git a/src/Syntax/Parser/ParseResult.cs b/src/Syntax/Parser/ParseResult.cs index ff74adb..0e18761 100644 --- a/src/Syntax/Parser/ParseResult.cs +++ b/src/Syntax/Parser/ParseResult.cs @@ -32,7 +32,6 @@ public class ParseResult /// Sets as the result of successful parsing. /// /// The result of the parsing. - /// The same object. public void Success(Node node) { Node = node; @@ -47,7 +46,6 @@ public void Success(Node node) /// /// The priority/fatality of the failure. /// The that occurred in parsing. - /// The same object. public void Failure(int priority, SyntaxError error) { if (Error is null || _errorPriority < priority) diff --git a/src/Util/Utils.cs b/src/Util/Utils.cs index 5dc6e69..e070d2d 100644 --- a/src/Util/Utils.cs +++ b/src/Util/Utils.cs @@ -40,7 +40,9 @@ public static int IndexToFlag(int index) /// /// Creates formatted text which contains the text between and , underlined with tilde (~) symbols. /// - /// The formatted text. + /// The starting position of the underlining. + /// The ending position of the underlining. + /// The formatted text and the actual starting line number of the error. public static (int AdjustedLineNumber, string SourceWithUnderline) SourceWithUnderline(Position startPosition, Position endPosition) { string text = startPosition.Script; From e0b9fc4212bb02081150ca486bfe32118643a009 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 9 Aug 2024 01:47:13 +0530 Subject: [PATCH 034/113] Updated documentation. --- .../SourceWrappers/EzrSharpSourceTypeWrapper.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index 6da6ff6..1f0fd7d 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -197,6 +197,11 @@ public EzrSharpSourceTypeWrapper( } } + /// + /// Creates a from a -decorated method. + /// + /// The method to wrap. + /// The method wrapper and its ezr² (snake_case) formatted name. private (IEzrObject, string) GetWrappedMethod(MethodInfo method) { // Check if parameters of the method are valid. @@ -209,6 +214,12 @@ public EzrSharpSourceTypeWrapper( return (wrapper, wrapper.SharpFunctionName); } + /// + /// Creates a from a -decorated method. + /// + /// The method to wrap. + /// The wrapper attribute. + /// The method wrapper and its ezr² (snake_case) formatted name. private (IEzrObject, string) GetAutoWrappedMethod(MethodInfo method, SharpAutoCompatibilityWrapperAttribute attribute) { // Check if the method is eligible for automatic wrapping. From 01c3e3922c1515ca803aed76bed83e1aeb7a8c78 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 9 Aug 2024 18:11:49 +0530 Subject: [PATCH 035/113] Improved wrappers. * Improved compatibility for async tasks. * Improved error messages from wrapper executions. * Fixed inconsistency of wrapped method's names in EzrSharpCompatibilityObjectInstance. --- .../EzrSharpCompatibilityObjectInstance.cs | 2 +- .../EzrSharpCompatibilityWrapper.cs | 57 +++++++++++++++++-- .../EzrSharpCompatibilityConstructor.cs | 3 +- .../EzrSharpCompatibilityFunction.cs | 5 +- .../EzrSharpCompatibilityField.cs | 2 +- .../EzrSharpCompatibilityProperty.cs | 2 +- 6 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index 1fa0bbe..4e25a46 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -67,7 +67,7 @@ public EzrSharpCompatibilityObjectInstance( if (method.IsAbstract) continue; - string methodObjectName = method.Name; + string methodObjectName = Utils.PascalToSnakeCase(method.Name); if (duplicateNames.TryGetValue(method.Name, out int duplicates)) { methodObjectName += $"_{duplicates}"; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 251a9b1..2e0ab7c 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -241,21 +241,27 @@ or TypeCode.Char } /// - /// Converts a C# primitive type to an ezr² type. + /// Converts a C# primitive type object or a task which returns a C# primitive type object to an ezr² object. /// /// The C# object to convert. - /// The primitive type to convert from. + /// The type to convert from. /// Runtime result for carrying the result and any errors. /// The converted . - protected internal void PrimitiveToEzrObject(object? value, TypeCode typeCode, RuntimeResult result) + protected internal void PrimitiveToEzrObject( + object? value, + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] + Type? valueType, + + RuntimeResult result) { - if (value is null) + if (value is null || valueType is null) { result.Success(NewNothingConstant()); return; } - switch (typeCode) + switch (Type.GetTypeCode(valueType)) { case TypeCode.Int16: result.Success(NewIntegerConstant((short)value)); @@ -299,12 +305,53 @@ protected internal void PrimitiveToEzrObject(object? value, TypeCode typeCode, R case TypeCode.String: result.Success(NewStringConstant((string)value)); break; + case TypeCode.Object when typeof(Task).IsAssignableFrom(valueType): + HandleAsynchronousObject(value, valueType, result); + break; default: result.Failure(new EzrUnsupportedWrappingError($"CSharp type \"{value.GetType().Name}\" cannot be converted to an ezr² type!", Context, StartPosition, EndPosition)); break; } } + /// + /// Waits for a task to complete and returns the result as an ezr² object. + /// + /// The task to await. + /// The type of the task. + /// Runtime result for carrying the result and any errors. + protected internal void HandleAsynchronousObject( + object value, + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] + Type type, + + RuntimeResult result) + { + try + { + ((Task)value).Wait(); + + // Get the Result property of the Task + PropertyInfo? resultProperty = type.GetProperty("Result"); + + // Check if it's a Task + if (resultProperty is not null) + { + // Get the value of the Result property + object taskResult = resultProperty.GetValue(value)!; + + PrimitiveToEzrObject(taskResult, taskResult.GetType(), result); + } + else + result.Success(NewNothingConstant()); + } + catch (Exception error) + { + result.Failure(new EzrWrapperExecutionError(error.InnerException?.Message ?? error.Message, Context, StartPosition, EndPosition)); + } + } + /// public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index 16896ca..04d39c5 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -90,8 +90,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run } catch (Exception error) { - result.Failure(new EzrWrapperExecutionError(error.Message, Context, StartPosition, EndPosition)); - return; + result.Failure(new EzrWrapperExecutionError(error.InnerException?.Message ?? error.Message, Context, StartPosition, EndPosition)); } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs index 3986218..3e4fafe 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs @@ -57,12 +57,11 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run if (output is null) result.Success(NewNothingConstant()); else - PrimitiveToEzrObject(output, Type.GetTypeCode(output.GetType()), result); + PrimitiveToEzrObject(output, output.GetType(), result); } catch (Exception error) { - result.Failure(new EzrWrapperExecutionError(error.Message, Context, StartPosition, EndPosition)); - return; + result.Failure(new EzrWrapperExecutionError(error.InnerException?.Message ?? error.Message, Context, StartPosition, EndPosition)); } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index 054654c..5c8dc8f 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -74,7 +74,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run if (arguments.Length == 0) { object? value = SharpField.GetValue(Instance); - PrimitiveToEzrObject(value, Type.GetTypeCode(value?.GetType()), result); + PrimitiveToEzrObject(value, value?.GetType(), result); } else { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs index 66b0c18..f9ef16d 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -74,7 +74,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run if (arguments.Length == 0) { object? value = SharpProperty.GetValue(Instance); - PrimitiveToEzrObject(value, Type.GetTypeCode(value?.GetType()), result); + PrimitiveToEzrObject(value, value?.GetType(), result); } else { From acea738fe532b6e5af2a643dd3d35468ff44e6fa Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 9 Aug 2024 18:12:10 +0530 Subject: [PATCH 036/113] Added missing imports. --- .../CompatWrappers/EzrSharpCompatibilityWrapper.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 2e0ab7c..d305f38 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -3,6 +3,9 @@ using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Threading.Tasks; namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; From 044e3e98358682acce71b4762f0dda848c3c4d00 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Mon, 12 Aug 2024 02:15:06 +0530 Subject: [PATCH 037/113] Updated EzrObject constructor. --- src/Runtime/Types/BaseTypes.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs index 42f8dff..1a012c1 100644 --- a/src/Runtime/Types/BaseTypes.cs +++ b/src/Runtime/Types/BaseTypes.cs @@ -93,15 +93,15 @@ public EzrObject(Context parentContext, Position startPosition, Position endPosi /// Creates a new object with the specified internal context, parent context and position. /// /// The internal context, if , creates a new one. - /// The context in which this object was created in. + /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrObject(Context? context, Context creationContext, Position startPosition, Position endPosition) + public EzrObject(Context? context, Context parentContext, Position startPosition, Position endPosition) { StartPosition = startPosition; EndPosition = endPosition; - _executionContext = CreationContext = creationContext; + _executionContext = CreationContext = parentContext; Context = context ?? new Context(TypeName, false, startPosition, CreationContext, CreationContext.StaticContext); } From c523a3fe0eeacf40c26ffc2cf976c97a2623f68c Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Mon, 12 Aug 2024 03:28:26 +0530 Subject: [PATCH 038/113] Fixed Task return type for SharpAutoCompatibilityWrapper wrapped methods. --- .../EzrSharpCompatibilityWrapper.cs | 15 +++++++++++++++ .../SharpAutoCompatibilityWrapperAttribute.cs | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index d305f38..64a54d6 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -31,6 +31,7 @@ public abstract class EzrSharpCompatibilityWrapper(Context parentContext, Positi public static bool IsSupportedPrimitiveType(Type type) { TypeCode typeCode = Type.GetTypeCode(type); + return typeCode is TypeCode.Empty or TypeCode.Int16 or TypeCode.Int32 @@ -48,6 +49,20 @@ or TypeCode.Char or TypeCode.String; } + /// + /// Checks if the given type is supported by the primitive compatibility wrappers, including generic objects. + /// + /// The type to check. + /// if yes, otherwise. + public static bool IsSupportedReturnType(Type type) + { + return Type.GetTypeCode(type) switch + { + TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArguments.Length == 0 || IsSupportedPrimitiveType(type.GenericTypeArguments[0]), + _ => IsSupportedPrimitiveType(type), + }; + } + /// /// Converts an ezr² type to a C# primitive type. /// diff --git a/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs index 7373e72..06fafdd 100644 --- a/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs @@ -54,7 +54,7 @@ public class SharpAutoCompatibilityWrapperAttribute : Attribute if (methodInfo.IsGenericMethod) return new($"The \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\" attribute does not support generic method \"{methodInfo.Name}\".", nameof(methodInfo)); - if (methodInfo.ReturnType != typeof(void) && !EzrSharpCompatibilityWrapper.IsSupportedPrimitiveType(methodInfo.ReturnType)) + if (methodInfo.ReturnType != typeof(void) && !EzrSharpCompatibilityWrapper.IsSupportedReturnType(methodInfo.ReturnType)) return new($"Expected method \"{methodInfo.Name}\"'s return type to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\"", nameof(methodInfo)); foreach (ParameterInfo parameterInfo in methodInfo.GetParameters()) From 4cd8147fbef043c1646125fbca3802c144e5dcfa Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 14 Aug 2024 00:05:55 +0530 Subject: [PATCH 039/113] =?UTF-8?q?ezr=C2=B2=20v0.3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 18 ++++++++++++++++++ src/EzrSquared.csproj | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 3e7a0a6..0b590a6 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,24 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.3.0 [14-08-24] + * [BREAKING CHANGE] All core executable types have been moved to `EzrSquared.Runtime.Types.Executables`. + * [BREAKING CHANGE] Auto wrapped methods in `EzrSharpCompatibilityObjectInstance` will now have their names in snake_case. + * [BREAKING CHANGE] `UpdateCreationContext` in `EzrObject` is now part of `IEzrObject`. + * [BREAKING CHANGE] `_creationContext` in `EzrObject` is now public as `CreationContext` and is part of `IEzrObject`. + * [BREAKING CHANGE] `PascalCaseToLowerCasePlainText` has been moved from `EzrSharpSourceFieldWrapper` to `EzrSharpSourceExecutableWrapper` as an internal protected static method. + * [BREAKING CHANGE] The `DynamicallyAccessedMembers` attribute has been removed for `EzrSharpCompatibilityType.SharpType` and `EzrSharpSourceTypeWrapper.SharpType`. + * [BREAKING CHANGE] The constructors for `EzrSharpCompatibilityType` and `EzrSharpSourceTypeWrapper` now use the `type` parameter to access the members of the C# type. + * [BREAKING CHANGE] The `creationContext` parameter in the constructors for `EzrObject` has been renamed to `parentContext` to maintain consistency. + * Auto wrappers now support async `Task`s that return one of the supported primitive types. + * `EzrSharpSourceTypeWrapper` now supports auto-wrapping static members through the new `SharpAutoCompatibilityWrapperAttribute` attribute. + * Added utility methods in `EzrSharpCompatibilityWrapper` to check if a given type is supported by the C#-to-ezr² and ezr²-to-C# converters. + * Added support for `decimal` type in the C#-to-ezr² and ezr²-to-C# converters. + * All auto-wrapper types now support overriding the names for members which would be named using `Utils.PascalToSnakeCase` otherwise. + * Added type checking in `EzrSharpSourcePropertyWrapper`. + * Objects created with `Context.Empty` will have their creation context updated to be the first context they are assigned to. + * Improved error messages here and there. + * ezr² RE - v0.2.0 [07-08-24] * [BREAKING CHANGE] SharpTypeWrapperAttribute will now require the type to have one SharpMethodWrapper wrapped constructor to create objects. * [BREAKING CHANGE] All static `WrapperConstructor` methods in runtime error classes have been removed and converted to regular constructors. diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 6836dc6..aef1d05 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.2.0 + 0.3.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 4040631..bd396d1 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "0.2.0" +#define MyAppVersion "0.3.0" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 2b426a4..64fc848 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "0.2.0" +#define MyAppVersion "0.3.0" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index bf0cdab..4d503b0 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.2.0 + 0.3.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From 188c69f652ad7f9a74bb69b7ebf881286d745277 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 14 Aug 2024 00:26:25 +0530 Subject: [PATCH 040/113] =?UTF-8?q?ezr=C2=B2=20v0.3.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 3 +++ src/EzrSquared.csproj | 2 +- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 6 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 0b590a6..fc4f3f2 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,9 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.3.1 [14-08-24] + * Updated shell with new version. + * ezr² RE - v0.3.0 [14-08-24] * [BREAKING CHANGE] All core executable types have been moved to `EzrSquared.Runtime.Types.Executables`. * [BREAKING CHANGE] Auto wrapped methods in `EzrSharpCompatibilityObjectInstance` will now have their names in snake_case. diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index aef1d05..bb4220f 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.3.0 + 0.3.1 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 9b10e7b..8c623c5 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.2.0"; + private const string Version = "0.3.1"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index bd396d1..8ab836e 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "0.3.0" +#define MyAppVersion "0.3.1" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 64fc848..ff40a67 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "0.3.0" +#define MyAppVersion "0.3.1" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 4d503b0..80a62f8 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.3.0 + 0.3.1 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From 53e454f96f9986163415cb32a121e8411d622251 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 27 Sep 2024 18:42:09 +0530 Subject: [PATCH 041/113] =?UTF-8?q?ezr=C2=B2=20RE=20v0.4.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 4 + README.md | 3 - src/EzrSquared.csproj | 2 +- .../Collections/RuntimeEzrObjectDictionary.cs | 7 +- src/Runtime/Interpreter.cs | 4 +- src/Runtime/RuntimeResult.cs | 4 +- .../Builtins/EzrBuiltinFunctions.cs | 6 +- .../Core/RuntimeErrors/EzrRuntimeError.cs | 46 ++++-------- .../Core/RuntimeErrors/IEzrRuntimeError.cs | 32 ++++++++ src/Runtime/Types/Core/Text/EzrCharacter.cs | 41 ++++------- .../Types/Core/Text/EzrCharacterList.cs | 70 +++++------------- src/Runtime/Types/Core/Text/EzrString.cs | 73 ++++++------------- src/Runtime/Types/Core/Text/IEzrString.cs | 12 +++ src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 17 files changed, 135 insertions(+), 177 deletions(-) create mode 100644 src/Runtime/Types/Core/RuntimeErrors/IEzrRuntimeError.cs create mode 100644 src/Runtime/Types/Core/Text/IEzrString.cs diff --git a/Changelog.txt b/Changelog.txt index fc4f3f2..040512a 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,10 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.4.0 [27-09-24] + * Text objects (strings, characters, character lists), now implement a common interface `IEzrString`. + * Runtime errors now implement a common interface `IEzrRuntimeError`. + * ezr² RE - v0.3.1 [14-08-24] * Updated shell with new version. diff --git a/README.md b/README.md index 37310ec..70ecfe1 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,6 @@ More information, documentation and the reference manual for ezr² is available ## What's the 'ezrSquared-re' branch? ezr² is being rewritten from the ground up! Expect more features, better performance and better code documentation! -## Update! -The development status of ezr² is now available on [***the ezr² project***](https://github.com/users/Uralstech/projects/3) and [***my blog***](https://uralstech.github.io/). - ## Contributing ezr² is an open source project and welcomes contributions from anyone who wants to improve it. diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index bb4220f..66b3129 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.3.1 + 0.4.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index a9d9358..e9d0d2a 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -15,20 +15,20 @@ public class RuntimeEzrObjectDictionary : IMutable /// /// The collection of s stored in the , in the format Dictionary<hashOfKey, KeyValuePair<key, valueReference>>. /// - private readonly Dictionary> _items; + private readonly IDictionary> _items; /// /// Creates a new . /// public RuntimeEzrObjectDictionary() { - _items = []; + _items = new Dictionary>(); } /// /// Creates a new from an existing . /// - public RuntimeEzrObjectDictionary(Dictionary> items) + public RuntimeEzrObjectDictionary(IDictionary> items) { _items = items; } @@ -273,7 +273,6 @@ public void Release() } _items.Clear(); - _items.TrimExcess(); } /// Destructor. diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index d2be250..c59ed38 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -1069,7 +1069,7 @@ private void VisitTryNode(TryNode node, Context executionContext, Context callin if (RuntimeResult.ShouldReturnTryCatch || RuntimeResult.Error is null) return; - EzrRuntimeError error = RuntimeResult.Error!; + IEzrRuntimeError error = RuntimeResult.Error!; RuntimeResult.Reset(); for (int i = 0; i < node.Cases.Count; i++) @@ -1081,7 +1081,7 @@ private void VisitTryNode(TryNode node, Context executionContext, Context callin return; IEzrObject targetObject = RuntimeResult.Reference.Object; - if (targetObject is not EzrSharpSourceTypeWrapper target || !typeof(EzrRuntimeError).IsAssignableFrom(target.SharpType)) + if (targetObject is not EzrSharpSourceTypeWrapper target || !typeof(IEzrRuntimeError).IsAssignableFrom(target.SharpType)) { RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected error type, but got object of type \"{targetObject.TypeName}\"!", executionContext, errorType.StartPosition, errorType.EndPosition)); return; diff --git a/src/Runtime/RuntimeResult.cs b/src/Runtime/RuntimeResult.cs index 8f10396..6333be4 100644 --- a/src/Runtime/RuntimeResult.cs +++ b/src/Runtime/RuntimeResult.cs @@ -16,7 +16,7 @@ public class RuntimeResult /// /// The error that occured in interpretation, if none occured, this is . /// - public EzrRuntimeError? Error; + public IEzrRuntimeError? Error; /// /// Should the interpreter return from the current execution? @@ -164,7 +164,7 @@ public void Success(Reference reference) /// Sets a failed expression execution. /// /// The error that caused the failure. - public void Failure(EzrRuntimeError error) + public void Failure(IEzrRuntimeError error) { Reset(); Error = error; diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs index 720b807..8af0c6e 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs @@ -67,14 +67,14 @@ public static void Show(SharpMethodParameters arguments) } /// - /// Basic error throwing function. Implements . + /// Basic error throwing function. Implements . /// /// /// ezr² parameters: /// /// /// error - /// () The error to throw. + /// () The error to throw. /// /// /// @@ -97,7 +97,7 @@ public static void ThrowError(SharpMethodParameters arguments) Reference reference = arguments.ArgumentReferences["error"]; IEzrObject referenceObject = reference.Object; - if (referenceObject is not EzrRuntimeError error) + if (referenceObject is not IEzrRuntimeError error) arguments.Result.Failure(new EzrUnexpectedTypeError($"Expected runtime error, but got object of type \"{referenceObject.TypeName}\"!", arguments.ExecutionContext, referenceObject.StartPosition, referenceObject.EndPosition)); else arguments.Result.Failure(error); diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs index 7d07311..3267bb8 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs @@ -7,10 +7,10 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// -/// Base of all error type objects. +/// Implementation of with some utility methods. /// [SharpTypeWrapper("runtime_error")] -public class EzrRuntimeError : EzrObject +public class EzrRuntimeError : EzrObject, IEzrRuntimeError { /// public override string TypeName { get; protected internal set; } = "runtime error"; @@ -18,30 +18,20 @@ public class EzrRuntimeError : EzrObject /// public override string Tag { get; protected internal set; } = "ezrSquared.RuntimeError"; - /// - /// The name of the . - /// - public readonly string Title; + /// + public string Title { get; } - /// - /// The reason why the occurred. - /// - public readonly string Details; + /// + public string Details { get; } - /// - /// The context where the error occurred. - /// - public readonly Context ErrorContext; + /// + public Context ErrorContext { get; } - /// - /// The starting position of the error. - /// - public readonly Position ErrorStartPosition; + /// + public Position ErrorStartPosition { get; } - /// - /// The ending position of the error. - /// - public readonly Position ErrorEndPosition; + /// + public Position ErrorEndPosition { get; } /// /// Creates a new runtime error object. @@ -94,17 +84,11 @@ protected internal static string GetStringArgument(string argumentName, IEzrObje switch (ezrObject) { - case EzrString ezrString: - return ezrString.Value; - - case EzrCharacter ezrCharacter: - return ezrCharacter.Value.ToString(); - - case EzrCharacterList ezrCharacterList: - return ezrCharacterList.StringValue; + case IEzrString ezrString: + return ezrString.StringValue; default: - result.Failure(new EzrUnexpectedTypeError($"Expected {argumentName} of type string, character or character list, but got object of type \"{ezrObject.TypeName}\"!", context, ezrObject.StartPosition, ezrObject.EndPosition)); + result.Failure(new EzrUnexpectedTypeError($"Expected {argumentName} to be text, but got object of type \"{ezrObject.TypeName}\"!", context, ezrObject.StartPosition, ezrObject.EndPosition)); return string.Empty; } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/IEzrRuntimeError.cs b/src/Runtime/Types/Core/RuntimeErrors/IEzrRuntimeError.cs new file mode 100644 index 0000000..8e1cb18 --- /dev/null +++ b/src/Runtime/Types/Core/RuntimeErrors/IEzrRuntimeError.cs @@ -0,0 +1,32 @@ +namespace EzrSquared.Runtime.Types.Core.Errors; + +/// +/// Base of all error types. +/// +public interface IEzrRuntimeError : IEzrObject +{ + /// + /// The title of the error. + /// + public string Title { get; } + + /// + /// The reason why the error occurred. + /// + public string Details { get; } + + /// + /// The context where the error occurred. + /// + public Context ErrorContext { get; } + + /// + /// The starting position of the error. + /// + public Position ErrorStartPosition { get; } + + /// + /// The ending position of the error. + /// + public Position ErrorEndPosition { get; } +} diff --git a/src/Runtime/Types/Core/Text/EzrCharacter.cs b/src/Runtime/Types/Core/Text/EzrCharacter.cs index 2a040d0..d28a577 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacter.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacter.cs @@ -13,7 +13,7 @@ namespace EzrSquared.Runtime.Types.Core.Text; /// The parent context. /// The starting position of the object. /// The ending position of the object. -public class EzrCharacter(char value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) +public class EzrCharacter(char value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrString { /// public override string TypeName { get; protected internal set; } = "character"; @@ -26,6 +26,9 @@ public class EzrCharacter(char value, Context parentContext, Position startPosit /// public readonly char Value = value; + /// + public string StringValue => Value.ToString(); + /// public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { @@ -37,10 +40,8 @@ public override void ComparisonEqual(IEzrObject other, RuntimeResult result) result.Success(NewBooleanConstant(Value == otherInteger.Value)); break; case EzrFloat otherFloat: result.Success(NewBooleanConstant(Value == otherFloat.Value)); break; - case EzrString otherString: - result.Success(NewBooleanConstant(Value.ToString() == otherString.Value)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(Value.ToString() == otherCharacterList.StringValue)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(StringValue == otherString.StringValue)); break; default: result.Success(NewBooleanConstant(false)); break; } @@ -57,10 +58,8 @@ public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) result.Success(NewBooleanConstant(Value != otherInteger.Value)); break; case EzrFloat otherFloat: result.Success(NewBooleanConstant(Value != otherFloat.Value)); break; - case EzrString otherString: - result.Success(NewBooleanConstant(Value.ToString() != otherString.Value)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(Value.ToString() != otherCharacterList.StringValue)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(StringValue != otherString.StringValue)); break; default: result.Success(NewBooleanConstant(true)); break; } @@ -77,10 +76,8 @@ public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) result.Success(NewBooleanConstant(Value < otherInteger.Value)); break; case EzrFloat otherFloat: result.Success(NewBooleanConstant(Value < otherFloat.Value)); break; - case EzrString otherString: - result.Success(NewBooleanConstant(Value.CompareTo(otherString.Value) < 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(Value.CompareTo(otherCharacterList.StringValue) < 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(Value.CompareTo(otherString.StringValue) < 0)); break; default: result.Failure(IllegalOperation(other)); break; } @@ -97,10 +94,8 @@ public override void ComparisonGreaterThan(IEzrObject other, RuntimeResult resul result.Success(NewBooleanConstant(Value > otherInteger.Value)); break; case EzrFloat otherFloat: result.Success(NewBooleanConstant(Value > otherFloat.Value)); break; - case EzrString otherString: - result.Success(NewBooleanConstant(Value.CompareTo(otherString.Value) > 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(Value.CompareTo(otherCharacterList.StringValue) > 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(Value.CompareTo(otherString.StringValue) > 0)); break; default: result.Failure(IllegalOperation(other)); break; } @@ -117,10 +112,8 @@ public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult r result.Success(NewBooleanConstant(Value <= otherInteger.Value)); break; case EzrFloat otherFloat: result.Success(NewBooleanConstant(Value <= otherFloat.Value)); break; - case EzrString otherString: - result.Success(NewBooleanConstant(Value.CompareTo(otherString.Value) <= 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(Value.CompareTo(otherCharacterList.StringValue) <= 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(Value.CompareTo(otherString.StringValue) <= 0)); break; default: result.Failure(IllegalOperation(other)); break; } @@ -137,10 +130,8 @@ public override void ComparisonGreaterThanOrEqual(IEzrObject other, RuntimeResul result.Success(NewBooleanConstant(Value >= otherInteger.Value)); break; case EzrFloat otherFloat: result.Success(NewBooleanConstant(Value >= otherFloat.Value)); break; - case EzrString otherString: - result.Success(NewBooleanConstant(Value.CompareTo(otherString.Value) >= 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(Value.CompareTo(otherCharacterList.StringValue) >= 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(Value.CompareTo(otherString.StringValue) >= 0)); break; default: result.Failure(IllegalOperation(other)); break; } diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index 1c63ade..a92ca5c 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -14,7 +14,7 @@ namespace EzrSquared.Runtime.Types.Core.Text; /// The parent context. /// The starting position of the object. /// The ending position of the object. -public class EzrCharacterList(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrMutableObject +public class EzrCharacterList(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrMutableObject, IEzrString { /// public override string TypeName { get; protected internal set; } = "character list"; @@ -37,12 +37,8 @@ public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(StringValue == otherString.Value)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(StringValue == otherCharacterList.StringValue)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(StringValue == otherCharacter.Value.ToString())); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(StringValue == otherString.StringValue)); break; default: result.Success(NewBooleanConstant(false)); break; } @@ -53,12 +49,8 @@ public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(StringValue != otherString.Value)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(StringValue != otherCharacterList.StringValue)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(StringValue != otherCharacter.Value.ToString())); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(StringValue != otherString.StringValue)); break; default: result.Success(NewBooleanConstant(true)); break; } @@ -138,12 +130,8 @@ public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) result.Success(NewCharacterListConstant(StringValue[startIndexInt..(endIndexInt + 1)])); break; - case EzrString otherString: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.Value) < 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacterList.StringValue) < 0)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacter.Value.ToString()) < 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.StringValue) < 0)); break; default: result.Failure(IllegalOperation(other)); break; } @@ -154,12 +142,8 @@ public override void ComparisonGreaterThan(IEzrObject other, RuntimeResult resul { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.Value) > 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacterList.StringValue) > 0)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacter.Value.ToString()) > 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.StringValue) > 0)); break; default: result.Failure(IllegalOperation(other)); break; } @@ -178,12 +162,8 @@ public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult r ComparisonLessThan(other, result); break; - case EzrString otherString: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.Value) <= 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacterList.StringValue) <= 0)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacter.Value.ToString()) <= 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.StringValue) <= 0)); break; default: result.Failure(IllegalOperation(other)); break; } @@ -194,12 +174,8 @@ public override void ComparisonGreaterThanOrEqual(IEzrObject other, RuntimeResul { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.Value) >= 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacterList.StringValue) >= 0)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherCharacter.Value.ToString()) >= 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(StringValue, otherString.StringValue) >= 0)); break; default: result.Failure(IllegalOperation(other)); break; } @@ -213,12 +189,8 @@ public override void Addition(IEzrObject other, RuntimeResult result) { switch (other) { - case EzrCharacterList otherCharacterList: - Value.Append(otherCharacterList.Value); break; - case EzrString otherString: - Value.Append(otherString.Value); break; - case EzrCharacter otherCharacter: - Value.Append(otherCharacter.Value); break; + case IEzrString otherString: + Value.Append(otherString.StringValue); break; default: string otherStringValue = other.ToPureString(result); if (result.ShouldReturn) @@ -426,10 +398,8 @@ public override void HasValueContained(IEzrObject other, RuntimeResult result) { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(StringValue.Contains(otherString.Value))); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(StringValue.Contains(otherCharacterList.StringValue))); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(StringValue.Contains(otherString.StringValue))); break; default: result.Failure(IllegalOperation(other, false)); break; } @@ -440,10 +410,8 @@ public override void NotHasValueContained(IEzrObject other, RuntimeResult result { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(!StringValue.Contains(otherString.Value))); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(!StringValue.Contains(otherCharacterList.StringValue))); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(!StringValue.Contains(otherString.StringValue))); break; default: result.Failure(IllegalOperation(other, false)); break; } diff --git a/src/Runtime/Types/Core/Text/EzrString.cs b/src/Runtime/Types/Core/Text/EzrString.cs index 1e3c130..b878ad2 100644 --- a/src/Runtime/Types/Core/Text/EzrString.cs +++ b/src/Runtime/Types/Core/Text/EzrString.cs @@ -14,7 +14,7 @@ namespace EzrSquared.Runtime.Types.Core.Text; /// The parent context. /// The starting position of the object. /// The ending position of the object. -public class EzrString(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) +public class EzrString(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrString { /// public override string TypeName { get; protected internal set; } = "string"; @@ -27,17 +27,16 @@ public class EzrString(string value, Context parentContext, Position startPositi /// public readonly string Value = value; + /// + public string StringValue => Value; + /// public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(Value == otherString.Value)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(Value == otherCharacterList.StringValue)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(Value == otherCharacter.Value.ToString())); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(Value == otherString.StringValue)); break; default: result.Success(NewBooleanConstant(false)); break; } @@ -48,12 +47,8 @@ public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(Value != otherString.Value)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(Value != otherCharacterList.StringValue)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(Value != otherCharacter.Value.ToString())); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(Value != otherString.StringValue)); break; default: result.Success(NewBooleanConstant(true)); break; } @@ -133,12 +128,8 @@ public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) result.Success(NewStringConstant(Value[startIndexInt..(endIndexInt + 1)])); break; - case EzrString otherString: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.Value) < 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacterList.StringValue) < 0)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacter.Value.ToString()) < 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.StringValue) < 0)); break; default: result.Failure(IllegalOperation(other)); break; } @@ -149,12 +140,8 @@ public override void ComparisonGreaterThan(IEzrObject other, RuntimeResult resul { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.Value) > 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacterList.StringValue) > 0)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacter.Value.ToString()) > 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.StringValue) > 0)); break; default: result.Failure(IllegalOperation(other)); break; } @@ -173,12 +160,8 @@ public override void ComparisonLessThanOrEqual(IEzrObject other, RuntimeResult r ComparisonLessThan(other, result); break; - case EzrString otherString: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.Value) <= 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacterList.StringValue) <= 0)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacter.Value.ToString()) <= 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.StringValue) <= 0)); break; default: result.Failure(IllegalOperation(other)); break; } @@ -189,12 +172,8 @@ public override void ComparisonGreaterThanOrEqual(IEzrObject other, RuntimeResul { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.Value) >= 0)); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacterList.StringValue) >= 0)); break; - case EzrCharacter otherCharacter: - result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherCharacter.Value.ToString()) >= 0)); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(string.CompareOrdinal(Value, otherString.StringValue) >= 0)); break; default: result.Failure(IllegalOperation(other)); break; } @@ -209,12 +188,8 @@ public override void Addition(IEzrObject other, RuntimeResult result) string newValue = Value; switch (other) { - case EzrCharacterList otherCharacterList: - newValue += otherCharacterList.StringValue; break; - case EzrString otherString: - newValue += otherString.Value; break; - case EzrCharacter otherCharacter: - newValue += otherCharacter.Value; break; + case IEzrString otherString: + newValue += otherString.StringValue; break; default: newValue += other.ToPureString(result); if (result.ShouldReturn) @@ -416,10 +391,8 @@ public override void HasValueContained(IEzrObject other, RuntimeResult result) { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(Value.Contains(otherString.Value))); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(Value.Contains(otherCharacterList.StringValue))); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(Value.Contains(otherString.StringValue))); break; default: result.Failure(IllegalOperation(other, false)); break; } @@ -430,10 +403,8 @@ public override void NotHasValueContained(IEzrObject other, RuntimeResult result { switch (other) { - case EzrString otherString: - result.Success(NewBooleanConstant(!Value.Contains(otherString.Value))); break; - case EzrCharacterList otherCharacterList: - result.Success(NewBooleanConstant(!Value.Contains(otherCharacterList.StringValue))); break; + case IEzrString otherString: + result.Success(NewBooleanConstant(!Value.Contains(otherString.StringValue))); break; default: result.Failure(IllegalOperation(other, false)); break; } diff --git a/src/Runtime/Types/Core/Text/IEzrString.cs b/src/Runtime/Types/Core/Text/IEzrString.cs new file mode 100644 index 0000000..9e0602c --- /dev/null +++ b/src/Runtime/Types/Core/Text/IEzrString.cs @@ -0,0 +1,12 @@ +namespace EzrSquared.Runtime.Types.Core.Text; + +/// +/// Interface for getting the value of string-like ezr² objects as C# strings. +/// +public interface IEzrString : IEzrObject +{ + /// + /// The string value. + /// + public string StringValue { get; } +} diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 8c623c5..ce2ce3c 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.3.1"; + private const string Version = "0.4.0"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 8ab836e..4bbc145 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "0.3.1" +#define MyAppVersion "0.4.0" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index ff40a67..c45a3bd 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr²" -#define MyAppVersion "0.3.1" +#define MyAppVersion "0.4.0" #define MyAppPublisher "Uralstech" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 80a62f8..94c3b95 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.3.1 + 0.4.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From adb630abc1004f5f8cd7343fcd309ca323627cc6 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sun, 6 Oct 2024 14:42:42 +0530 Subject: [PATCH 042/113] Minor constructor changes. --- src/Runtime/Types/BaseTypes.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs index 1a012c1..7804d27 100644 --- a/src/Runtime/Types/BaseTypes.cs +++ b/src/Runtime/Types/BaseTypes.cs @@ -92,17 +92,17 @@ public EzrObject(Context parentContext, Position startPosition, Position endPosi /// /// Creates a new object with the specified internal context, parent context and position. /// - /// The internal context, if , creates a new one. + /// The internal context. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrObject(Context? context, Context parentContext, Position startPosition, Position endPosition) + public EzrObject(Context context, Context parentContext, Position startPosition, Position endPosition) { StartPosition = startPosition; EndPosition = endPosition; _executionContext = CreationContext = parentContext; - Context = context ?? new Context(TypeName, false, startPosition, CreationContext, CreationContext.StaticContext); + Context = context; } /// From 5999ddbf877f79a6dc64469717a2160958fc8328 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 30 Oct 2024 23:43:49 +0530 Subject: [PATCH 043/113] Moved IMutable to its own file, fixed cast in Context. --- src/Runtime/Context.cs | 2 +- src/Runtime/IMutable.cs | 18 ++++++++++++++++++ src/Runtime/Types/IEzrMutableObject.cs | 17 ----------------- 3 files changed, 19 insertions(+), 18 deletions(-) create mode 100644 src/Runtime/IMutable.cs diff --git a/src/Runtime/Context.cs b/src/Runtime/Context.cs index 17177cb..3b5c17b 100644 --- a/src/Runtime/Context.cs +++ b/src/Runtime/Context.cs @@ -445,7 +445,7 @@ public bool IsDefined(string name) if (copy.Object is IEzrMutableObject mutable) { mutable.Context.UpdateParent(newContext); - (mutable as EzrObject)?.UpdateCreationContext(newContext); + (mutable as IEzrObject)?.UpdateCreationContext(newContext); } newSymbols[keyValuePair.Key] = copy; diff --git a/src/Runtime/IMutable.cs b/src/Runtime/IMutable.cs new file mode 100644 index 0000000..a99cd87 --- /dev/null +++ b/src/Runtime/IMutable.cs @@ -0,0 +1,18 @@ +namespace EzrSquared.Runtime; + +/// +/// A mutable object. +/// +/// The type inheriting this interface. +public interface IMutable +{ + /// + /// Creates a deep copy of the . + /// + /// + /// The deep copy here means that all properties and fields in the object are also copied. + /// + /// Runtime result for raising errors./ + /// The copy, or, if failed. + public IMutable? DeepCopy(RuntimeResult result); +} diff --git a/src/Runtime/Types/IEzrMutableObject.cs b/src/Runtime/Types/IEzrMutableObject.cs index 1802ebc..74c8005 100644 --- a/src/Runtime/Types/IEzrMutableObject.cs +++ b/src/Runtime/Types/IEzrMutableObject.cs @@ -1,22 +1,5 @@ namespace EzrSquared.Runtime.Types; -/// -/// A mutable object. -/// -/// The type inheriting this interface. -public interface IMutable -{ - /// - /// Creates a deep copy of the . - /// - /// - /// The deep copy here means that all properties and fields in the object are also copied. - /// - /// Runtime result for raising errors./ - /// The copy, or, if failed. - public IMutable? DeepCopy(RuntimeResult result); -} - /// /// A mutable . /// From 4b912669c2daac6cdfaa2d5aaae8858c2a5cc3d6 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 31 Oct 2024 07:56:28 +0530 Subject: [PATCH 044/113] Added the for-each loop! --- src/EzrGrammar.txt | 7 ++ src/Runtime/Interpreter.cs | 82 ++++++++++++++++++- .../ControlFlowStructureNodes/CountNode.cs | 2 +- .../ControlFlowStructureNodes/ForEachNode.cs | 31 +++++++ src/Runtime/Types/Collections/EzrArray.cs | 14 ++++ src/Runtime/Types/Collections/EzrList.cs | 14 ++++ .../Collections/IEzrIndexedCollection.cs | 6 +- src/Syntax/Lexer.cs | 2 + src/Syntax/Parser/Parser.cs | 66 +++++++++++++++ src/TokenType.cs | 10 +++ 10 files changed, 228 insertions(+), 6 deletions(-) create mode 100644 src/Runtime/Nodes/ControlFlowStructureNodes/ForEachNode.cs diff --git a/src/EzrGrammar.txt b/src/EzrGrammar.txt index c3927af..95a13a2 100644 --- a/src/EzrGrammar.txt +++ b/src/EzrGrammar.txt @@ -127,6 +127,7 @@ atom: | '{' '\n'+? (expression '\n'+? ':' '\n'+? expression '\n'+? (',' '\n'+? expression '\n'+? ':' '\n'+? expression '\n'+?)+?)? '}' | if-expression | count-expression + | for-each-expression | while-expression | try-expression | function-definition-expression @@ -144,6 +145,12 @@ count-expression: "count" ("from" expression)? "to" expression ("step" expression)? ("as" expression)? "do" statements "end" | "count" ("from" expression)? "to" expression ("step" expression)? ("as" expression)? "do" statement +@ 'for-each-expression' structures contain declarations of for-each loops. +@ Here, the expression must be a 'contains-check'. +for-each-expression: + "for" "each" expression "do" statements "end" + | "for" "each" expression "do" statement + @ 'while-expression' structures contain declarations of while loops. while-expression: "while" expression "do" ((statements "end") | statement) diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index c59ed38..fe7de75 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -84,6 +84,9 @@ internal void VisitNode(Node astNode, Context executionContext, Context? calling case CountNode node: VisitCountNode(node, executionContext, callingContext, accessibilityModifiers); break; + case ForEachNode node: + VisitForEachNode(node, executionContext, callingContext, accessibilityModifiers); + break; case WhileNode node: VisitWhileNode(node, executionContext, callingContext, accessibilityModifiers); break; @@ -995,13 +998,12 @@ iBigInteger is not null VisitNode(node.Body, executionContext, callingContext, accessibilityModifiers); if (RuntimeResult.ShouldReturnLoop) return -1; - - if (RuntimeResult.SkipSet) + else if (RuntimeResult.SkipSet) { RuntimeResult.Reset(); return 1; } - if (RuntimeResult.StopSet) + else if (RuntimeResult.StopSet) { RuntimeResult.Reset(); return 2; @@ -1011,6 +1013,80 @@ iBigInteger is not null return 0; } + /// + /// Executes a and creates a for-each loop. + /// + /// The to execute. + /// The under which the loop will be executed. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + private void VisitForEachNode(ForEachNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + VisitNode(node.Expression.Left, executionContext, callingContext, accessibilityModifiers, true); + if (RuntimeResult.ShouldReturn) + return; + + Reference iterationVariableReference = RuntimeResult.Reference; + string iterationVariableName = iterationVariableReference.Name; + Context iterationVariableRegisteredContext = iterationVariableReference.RegisteredContext ?? executionContext; + + if (!iterationVariableReference.IsRegistered) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for iteration variable name, but got object of type \"{iterationVariableReference.Object.TypeName}\"!", executionContext, node.Expression.Left.StartPosition, node.Expression.Left.EndPosition)); + return; + } + + VisitNode(node.Expression.Right, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + + Reference iterableObjectReference = RuntimeResult.Reference; + if (iterableObjectReference.Object is not IEzrIndexedCollection iterableObject) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected an iterable object to iterate, but got object of type \"{iterableObjectReference.Object.TypeName}\"!", executionContext, node.Expression.Right.StartPosition, node.Expression.Right.EndPosition)); + return; + } + + AccessMod operationAccessibilityModifiers = accessibilityModifiers; + if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) + operationAccessibilityModifiers |= AccessMod.LocalScope; + + List returns = new(iterableObject.Length); + foreach (IEzrObject ezrObject in iterableObject) + { + ezrObject.Update(executionContext, node.Expression.StartPosition, node.Expression.EndPosition); + (IEzrObject Object, string Name) newIterationVariable = (ezrObject, iterationVariableName); + + HandleSetStatus( + iterationVariableRegisteredContext.Set(callingContext, newIterationVariable, iterationVariableReference, operationAccessibilityModifiers), + iterationVariableName, + node.Expression.Left, + iterationVariableRegisteredContext + ); + + if (RuntimeResult.ShouldReturn) + return; + + VisitNode(node.Body, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturnLoop) + return; + else if (RuntimeResult.SkipSet) + { + RuntimeResult.Reset(); + continue; + } + else if (RuntimeResult.StopSet) + { + RuntimeResult.Reset(); + break; + } + + returns.Add(RuntimeResult.Reference.Object); + } + + RuntimeResult.Success(ReferencePool.Get(new EzrArray([.. returns], executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); + } + /// /// Executes a and creates a while (condition = true) loop. /// diff --git a/src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs b/src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs index 5e2e1fe..d2bd754 100644 --- a/src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs +++ b/src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs @@ -6,7 +6,7 @@ /// The amount to count to. /// The amount to count from - optional. /// The increment of each iteration - optional. -/// TThe variable to store the iteration number in - optional. +/// The variable to store the iteration number in - optional. /// The body of the count loop. /// The starting of the . /// The ending of the . diff --git a/src/Runtime/Nodes/ControlFlowStructureNodes/ForEachNode.cs b/src/Runtime/Nodes/ControlFlowStructureNodes/ForEachNode.cs new file mode 100644 index 0000000..f4fe64e --- /dev/null +++ b/src/Runtime/Nodes/ControlFlowStructureNodes/ForEachNode.cs @@ -0,0 +1,31 @@ +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for a for-each expression. +/// +/// A check-in expression, where the LHS is the variable to store the iterated values and RHS is the collection to iterate. +/// The body of the loop. +/// The starting of the . +/// The ending of the . +public class ForEachNode(BinaryOperationNode expression, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// A check-in expression, where the LHS is the variable to store the iterated values and RHS is the collection to iterate. + /// + public BinaryOperationNode Expression = expression; + + /// + /// The body of the count loop. + /// + public Node Body = body; + + /// + /// Creates a representation of the .
+ /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". + ///
+ /// The representation. + public override string ToString() + { + return $"{nameof(ForEachNode)}({Expression}, {Body})"; + } +} diff --git a/src/Runtime/Types/Collections/EzrArray.cs b/src/Runtime/Types/Collections/EzrArray.cs index 3471fa8..011d6d5 100644 --- a/src/Runtime/Types/Collections/EzrArray.cs +++ b/src/Runtime/Types/Collections/EzrArray.cs @@ -1,6 +1,8 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using System; +using System.Collections; +using System.Collections.Generic; using System.Numerics; namespace EzrSquared.Runtime.Types.Collections; @@ -70,6 +72,18 @@ public IEzrObject At(int index) return Value[index]; } + /// + public IEnumerator GetEnumerator() + { + return ((IEnumerable)Value).GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return Value.GetEnumerator(); + } + /// public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index 30a4394..e7dd3a1 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -2,6 +2,8 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using System; +using System.Collections; +using System.Collections.Generic; using System.Numerics; namespace EzrSquared.Runtime.Types.Collections; @@ -71,6 +73,18 @@ public IEzrObject At(int index) return Value[index].Object; } + /// + public IEnumerator GetEnumerator() + { + return Value.ConvertAll(reference => reference.Object).GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + /// public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { diff --git a/src/Runtime/Types/Collections/IEzrIndexedCollection.cs b/src/Runtime/Types/Collections/IEzrIndexedCollection.cs index 6d6d823..62e0a11 100644 --- a/src/Runtime/Types/Collections/IEzrIndexedCollection.cs +++ b/src/Runtime/Types/Collections/IEzrIndexedCollection.cs @@ -1,9 +1,11 @@ -namespace EzrSquared.Runtime.Types.Collections; +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Collections; /// /// Interface for an indexed collection of ezr² objects. /// -internal interface IEzrIndexedCollection : IEzrObject +public interface IEzrIndexedCollection : IEzrObject, IEnumerable { /// /// The length of the collection. diff --git a/src/Syntax/Lexer.cs b/src/Syntax/Lexer.cs index 42b6078..d8d61eb 100644 --- a/src/Syntax/Lexer.cs +++ b/src/Syntax/Lexer.cs @@ -609,6 +609,8 @@ private Token CompileIdentifier() "else" => new Token(TokenType.KeywordElse, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), "do" => new Token(TokenType.KeywordDo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), "count" => new Token(TokenType.KeywordCount, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "for" => new Token(TokenType.KeywordFor, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "each" => new Token(TokenType.KeywordEach, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), "from" => new Token(TokenType.KeywordFrom, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), "as" => new Token(TokenType.KeywordAs, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), "to" => new Token(TokenType.KeywordTo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), diff --git a/src/Syntax/Parser/Parser.cs b/src/Syntax/Parser/Parser.cs index f09191f..f5953cd 100644 --- a/src/Syntax/Parser/Parser.cs +++ b/src/Syntax/Parser/Parser.cs @@ -968,6 +968,9 @@ private void ParseAtom() case TokenType.KeywordCount: ParseCountExpression(); break; + case TokenType.KeywordFor: + ParseForEachExpression(); + break; case TokenType.KeywordWhile: ParseWhileExpression(); break; @@ -1562,6 +1565,69 @@ private void ParseCountExpression() _result.Success(new CountNode(to, from, step, iterationVariable, body, startPosition, endPosition)); } + /// + /// Tries parsing a for-each expression. Starts from , which should be of . + /// + private void ParseForEachExpression() + { + Position startPosition = _currentToken.StartPosition; + Advance(); + + if (_currentToken.Type != TokenType.KeywordEach) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'each' keyword! The 'each' keyword is essential for forming a \"for each\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + ParseExpression(); + if (_result.Error is not null) + return; + + if (_result.Node is not BinaryOperationNode expression || expression.Operator != TokenType.KeywordIn) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a binary expression in the format \"[iteration variable] in [iterable collection]\".", _result.Node.StartPosition, _result.Node.EndPosition)); + return; + } + + if (_currentToken.Type != TokenType.KeywordDo) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"for each\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + Advance(); + + Node body; + Position endPosition; + if (_currentToken.Type == TokenType.NewLine) + { + ParseStatements(); + if (_result.Error is not null) + return; + else if (_currentToken.Type != TokenType.KeywordEnd) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"for each\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; + } + + body = _result.Node; + endPosition = _currentToken.EndPosition; + Advance(); + } + else + { + ParseStatement(); + if (_result.Error is not null) + return; + + body = _result.Node; + endPosition = PeekPrevious().EndPosition; + } + + _result.Success(new ForEachNode(expression, body, startPosition, endPosition)); + } + /// /// Tries parsing a while expression. Starts from , which should be of . /// diff --git a/src/TokenType.cs b/src/TokenType.cs index c630ee5..1e25527 100644 --- a/src/TokenType.cs +++ b/src/TokenType.cs @@ -97,6 +97,16 @@ public enum TokenType : ushort /// KeywordCount, + /// + /// The keyword "for", case-insensitive, part of the type-group. + /// + KeywordFor, + + /// + /// The keyword "each", case-insensitive, part of the type-group. + /// + KeywordEach, + /// /// The keyword "from", case-insensitive, part of the type-group. /// From 7121a6f777aa47e6db62047be246f97dac9397ab Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 31 Oct 2024 10:07:03 +0530 Subject: [PATCH 045/113] Added iteration support for strings and charlists. --- .../Types/Core/Text/EzrCharacterList.cs | 51 ++++++++++++++++++- src/Runtime/Types/Core/Text/EzrString.cs | 51 ++++++++++++++++++- 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index a92ca5c..9cc81a3 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -2,6 +2,8 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using System; +using System.Collections; +using System.Collections.Generic; using System.Numerics; using System.Text; @@ -14,7 +16,7 @@ namespace EzrSquared.Runtime.Types.Core.Text; /// The parent context. /// The starting position of the object. /// The ending position of the object. -public class EzrCharacterList(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrMutableObject, IEzrString +public class EzrCharacterList(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrMutableObject, IEzrString, IEzrIndexedCollection { /// public override string TypeName { get; protected internal set; } = "character list"; @@ -32,6 +34,49 @@ public class EzrCharacterList(string value, Context parentContext, Position star /// public string StringValue => Value.ToString(); + /// + public int Length => Value.Length; + + /// + /// Compares the current character list with another collection. + /// + /// The other collection. + /// The result of the comparison. + private bool Compare(IEzrIndexedCollection other) + { + if (Value.Length != other.Length) + return false; + + for (int i = 0; i < Value.Length; i++) + { + // This is not a strict equality check, unlike array/list comparisons. So, if the value in the other collection + // inherits from EzrCharacter, this should still return true if the values are the same. + if (other.At(i) is not EzrCharacter ezrCharacter || ezrCharacter.Value != Value[i]) + return false; + } + + return true; + } + + /// + public IEzrObject At(int index) + { + return new EzrCharacter(Value[index], _executionContext, StartPosition, EndPosition); + } + + /// + public IEnumerator GetEnumerator() + { + for (int i = 0; i < Value.Length; i++) + yield return new EzrCharacter(Value[i], _executionContext, StartPosition, EndPosition); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + /// public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { @@ -39,6 +84,8 @@ public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { case IEzrString otherString: result.Success(NewBooleanConstant(StringValue == otherString.StringValue)); break; + case IEzrIndexedCollection otherCollection: + result.Success(NewBooleanConstant(Compare(otherCollection))); break; default: result.Success(NewBooleanConstant(false)); break; } @@ -51,6 +98,8 @@ public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) { case IEzrString otherString: result.Success(NewBooleanConstant(StringValue != otherString.StringValue)); break; + case IEzrIndexedCollection otherCollection: + result.Success(NewBooleanConstant(!Compare(otherCollection))); break; default: result.Success(NewBooleanConstant(true)); break; } diff --git a/src/Runtime/Types/Core/Text/EzrString.cs b/src/Runtime/Types/Core/Text/EzrString.cs index b878ad2..81f7ecc 100644 --- a/src/Runtime/Types/Core/Text/EzrString.cs +++ b/src/Runtime/Types/Core/Text/EzrString.cs @@ -2,6 +2,8 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using System; +using System.Collections; +using System.Collections.Generic; using System.Numerics; using System.Text; @@ -14,7 +16,7 @@ namespace EzrSquared.Runtime.Types.Core.Text; /// The parent context. /// The starting position of the object. /// The ending position of the object. -public class EzrString(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrString +public class EzrString(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrString, IEzrIndexedCollection { /// public override string TypeName { get; protected internal set; } = "string"; @@ -30,6 +32,49 @@ public class EzrString(string value, Context parentContext, Position startPositi /// public string StringValue => Value; + /// + public int Length => Value.Length; + + /// + /// Compares the current string with another collection. + /// + /// The other collection. + /// The result of the comparison. + private bool Compare(IEzrIndexedCollection other) + { + if (Value.Length != other.Length) + return false; + + for (int i = 0; i < Value.Length; i++) + { + // This is not a strict equality check, unlike array/list comparisons. So, if the value in the other collection + // inherits from EzrCharacter, this should still return true if the values are the same. + if (other.At(i) is not EzrCharacter ezrCharacter || ezrCharacter.Value != Value[i]) + return false; + } + + return true; + } + + /// + public IEzrObject At(int index) + { + return new EzrCharacter(Value[index], _executionContext, StartPosition, EndPosition); + } + + /// + public IEnumerator GetEnumerator() + { + foreach (char @char in Value) + yield return new EzrCharacter(@char, _executionContext, StartPosition, EndPosition); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + /// public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { @@ -37,6 +82,8 @@ public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { case IEzrString otherString: result.Success(NewBooleanConstant(Value == otherString.StringValue)); break; + case IEzrIndexedCollection otherCollection: + result.Success(NewBooleanConstant(Compare(otherCollection))); break; default: result.Success(NewBooleanConstant(false)); break; } @@ -49,6 +96,8 @@ public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) { case IEzrString otherString: result.Success(NewBooleanConstant(Value != otherString.StringValue)); break; + case IEzrIndexedCollection otherCollection: + result.Success(NewBooleanConstant(!Compare(otherCollection))); break; default: result.Success(NewBooleanConstant(true)); break; } From 2f65b3a46ba2834622798fba114626583c56a423 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 31 Oct 2024 12:17:51 +0530 Subject: [PATCH 046/113] =?UTF-8?q?ezr=C2=B2=20v0.5.0=20-=20Improved=20ins?= =?UTF-8?q?tallers.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 7 ++++ src/EzrSquared.csproj | 6 +-- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 36 ++++++++-------- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 43 +++++++++++--------- src/Shell/Shell.csproj | 6 +-- 6 files changed, 53 insertions(+), 47 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 040512a..102fcd5 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,13 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.5.0 [31-10-24] + * [BREAKING CHANGE] `IMutable` has been moved to the `EzrSquared.Runtime` namespace. + * [BREAKING CHANGE] The `context` parameter in the constructor for `EzrObject` is no longer nullable. + * Added for-each loops! You can now iterate through collections (including strings and character lists) effortlessly. + * Strings and character lists are now `IEzrIndexedCollection`-s and can compare against other `IEzrIndexedCollection`-s. + * Fixed a cast to `EzrObject` in `Context`. + * ezr² RE - v0.4.0 [27-09-24] * Text objects (strings, characters, character lists), now implement a common interface `IEzrString`. * Runtime errors now implement a common interface `IEzrRuntimeError`. diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 66b3129..674c7f8 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -1,8 +1,8 @@  Library - win-x64;linux-x64;osx-x64 - AnyCPU;x64;arm64 + win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64 + AnyCPU net8.0;netstandard2.1 12 @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.4.0 + 0.5.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index ce2ce3c..6d3aafe 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.4.0"; + private const string Version = "0.5.0"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 4bbc145..3718caf 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -3,19 +3,19 @@ #include "environment.iss" -#define MyAppName "ezr²" -#define MyAppVersion "0.4.0" -#define MyAppPublisher "Uralstech" +#define MyAppName "ezr² Shell" +#define MyAppVersion "0.5.0" +#define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" -#define MyAppAssocName MyAppName + " Source Code" +#define MyAppAssocName "ezr² Script" #define MyAppAssocExt ".ezr2" #define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt [Setup] ; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) -AppId={{2A507B20-D8C0-4E66-891F-13CFC590FCFA} +AppId={{C6784FE6-35A9-409E-A438-45ECA651F10F} AppName={#MyAppName} AppVersion={#MyAppVersion} ;AppVerName={#MyAppName} {#MyAppVersion} @@ -25,8 +25,6 @@ AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} DefaultDirName={autopf}\{#MyAppName} ChangesAssociations=yes -ChangesEnvironment=yes -MinVersion=6.1.7600 DefaultGroupName={#MyAppName} AllowNoIcons=yes LicenseFile=D:\Code\csharp\ezrSquared\LICENSE.txt @@ -34,9 +32,9 @@ InfoAfterFile=D:\Code\csharp\ezrSquared\Changelog.txt ; Remove the following line to run in administrative install mode (install for all users.) PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog -OutputDir=D:\Code\csharp\ezrSquared\Binaries\Installer\ -OutputBaseFilename=ezr² Installer (Windows 32-bit) -SetupIconFile=D:\Code\csharp\ezrSquared\src\Icon.ico +OutputDir=D:\Code\csharp\ezrSquared\Binaries\Shell\Release\Installers +OutputBaseFilename=ezr² Shell Setup (Win32) +SetupIconFile=D:\Code\csharp\ezrSquared\graphics\Icon.ico Compression=lzma SolidCompression=yes WizardStyle=modern @@ -54,28 +52,27 @@ LocalDocumentation=%1 Offline Documentation [Types] Name: "full"; Description: "Full installation" Name: "compact"; Description: "Compact installation - Without documentation" -Name: "bareMinimum"; Description: "The bare minimum - Excludes the standard libraries" +Name: "bareMinimum"; Description: "The bare minimum - Just the shell and interpreter" Name: "custom"; Description: "Custom installation"; Flags: iscustom [Components] -Name: "main"; Description: "ezr² Code Executor"; Types: full compact bareMinimum custom; Flags: fixed -Name: "libs"; Description: "ezr² Standard Libraries"; Types: full compact +Name: "main"; Description: "ezr² Shell & Interpreter"; Types: full compact bareMinimum custom; Flags: fixed +; Name: "libs"; Description: "ezr² Standard Libraries"; Types: full compact Name: "docs"; Description: "ezr² Documentation"; Types: full [Tasks] -Name: "addtopath"; Description: "Add ezr² to PATH environment variable"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce +Name: "addtopath"; Description: "Add the ezr² Shell to the PATH environment variable"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce [Dirs] Name: "{app}\Libraries" [Files] -Source: "D:\Code\csharp\ezrSquared\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x86\publish\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion +Source: "D:\Code\csharp\ezrSquared\docs\_site\api\APIReferenceManual.pdf"; DestDir: "{app}\Documentation"; Flags: ignoreversion; Components: docs +Source: "D:\Code\csharp\ezrSquared\docs\_site\docsrc\QuickStartDocumentation.pdf"; DestDir: "{app}\Documentation"; Flags: ignoreversion; Components: docs Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x86\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs -Source: "D:\Code\csharp\ezrSquared\docs\offline\_site\*"; DestDir: "{app}\Documentation"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: docs -Source: "D:\Code\csharp\ezrSquared\bin\Libraries\IO\Release\net7.0-windows10.0.22621.0\win-x86\IO.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs -Source: "D:\Code\csharp\ezrSquared\bin\Libraries\STD\Release\net7.0-windows10.0.22621.0\win-x86\STD.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs +Source: "D:\Code\csharp\ezrSquared\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Registry] @@ -101,8 +98,7 @@ end; [Icons] Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" Name: "{group}\{cm:WebDocumentation,{#MyAppName}}"; Filename: "{#MyAppURL}" -Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" -Name: "{group}\{cm:LocalDocumentation,{#MyAppName}}"; Filename: "{app}\Documentation\START_HERE.html"; Components: docs +Name: "{group}\{cm:LocalDocumentation,{#MyAppName}}"; Filename: "{app}\Documentation\QuickStartDocumentation.pdf"; Components: docs Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon [Run] diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index c45a3bd..5b2225b 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -3,19 +3,19 @@ #include "environment.iss" -#define MyAppName "ezr²" -#define MyAppVersion "0.4.0" -#define MyAppPublisher "Uralstech" +#define MyAppName "ezr² Shell" +#define MyAppVersion "0.5.0" +#define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" -#define MyAppAssocName MyAppName + " Source Code" +#define MyAppAssocName "ezr² Script" #define MyAppAssocExt ".ezr2" #define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt [Setup] ; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) -AppId={{0F1DF58D-F539-4FEB-8174-04F973E54F03} +AppId={{B84F04C4-4945-4687-8455-7E179F3A05A0} AppName={#MyAppName} AppVersion={#MyAppVersion} ;AppVerName={#MyAppName} {#MyAppVersion} @@ -24,10 +24,15 @@ AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} DefaultDirName={autopf}\{#MyAppName} +; "ArchitecturesAllowed=x64compatible" specifies that Setup cannot run +; on anything but x64 and Windows 11 on Arm. +ArchitecturesAllowed=x64compatible +; "ArchitecturesInstallIn64BitMode=x64compatible" requests that the +; install be done in "64-bit mode" on x64 or Windows 11 on Arm, +; meaning it should use the native 64-bit Program Files directory and +; the 64-bit view of the registry. +ArchitecturesInstallIn64BitMode=x64compatible ChangesAssociations=yes -ChangesEnvironment=yes -MinVersion=6.1.7600 -ArchitecturesAllowed=x64 DefaultGroupName={#MyAppName} AllowNoIcons=yes LicenseFile=D:\Code\csharp\ezrSquared\LICENSE.txt @@ -35,9 +40,9 @@ InfoAfterFile=D:\Code\csharp\ezrSquared\Changelog.txt ; Remove the following line to run in administrative install mode (install for all users.) PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog -OutputDir=D:\Code\csharp\ezrSquared\Binaries\Installer\ -OutputBaseFilename=ezr² Installer (Windows 64-bit) -SetupIconFile=D:\Code\csharp\ezrSquared\src\Icon.ico +OutputDir=D:\Code\csharp\ezrSquared\Binaries\Shell\Release\Installers +OutputBaseFilename=ezr² Shell Setup (Win64) +SetupIconFile=D:\Code\csharp\ezrSquared\graphics\Icon.ico Compression=lzma SolidCompression=yes WizardStyle=modern @@ -55,16 +60,16 @@ LocalDocumentation=%1 Offline Documentation [Types] Name: "full"; Description: "Full installation" Name: "compact"; Description: "Compact installation - Without documentation" -Name: "bareMinimum"; Description: "The bare minimum - Excludes the standard libraries" +Name: "bareMinimum"; Description: "The bare minimum - Just the shell and interpreter" Name: "custom"; Description: "Custom installation"; Flags: iscustom [Components] -Name: "main"; Description: "ezr² Code Executor"; Types: full compact bareMinimum custom; Flags: fixed -Name: "libs"; Description: "ezr² Standard Libraries"; Types: full compact +Name: "main"; Description: "ezr² Shell & Interpreter"; Types: full compact bareMinimum custom; Flags: fixed +; Name: "libs"; Description: "ezr² Standard Libraries"; Types: full compact Name: "docs"; Description: "ezr² Documentation"; Types: full [Tasks] -Name: "addtopath"; Description: "Add ezr² to PATH environment variable"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce +Name: "addtopath"; Description: "Add the ezr² Shell to the PATH environment variable"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce [Dirs] @@ -74,9 +79,8 @@ Name: "{app}\Libraries" Source: "D:\Code\csharp\ezrSquared\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x64\publish\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x64\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs -Source: "D:\Code\csharp\ezrSquared\docs\offline\_site\*"; DestDir: "{app}\Documentation"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: docs -Source: "D:\Code\csharp\ezrSquared\bin\Libraries\IO\Release\net7.0-windows10.0.22621.0\win-x64\IO.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs -Source: "D:\Code\csharp\ezrSquared\bin\Libraries\STD\Release\net7.0-windows10.0.22621.0\win-x64\STD.dll"; DestDir: "{app}\Libraries"; Flags: ignoreversion; Components: libs +Source: "D:\Code\csharp\ezrSquared\docs\_site\docsrc\QuickStartDocumentation.pdf"; DestDir: "{app}\Documentation"; Flags: ignoreversion; Components: docs +Source: "D:\Code\csharp\ezrSquared\docs\_site\api\APIReferenceManual.pdf"; DestDir: "{app}\Documentation"; Flags: ignoreversion; Components: docs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Registry] @@ -102,8 +106,7 @@ end; [Icons] Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" Name: "{group}\{cm:WebDocumentation,{#MyAppName}}"; Filename: "{#MyAppURL}" -Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" -Name: "{group}\{cm:LocalDocumentation,{#MyAppName}}"; Filename: "{app}\Documentation\START_HERE.html"; Components: docs +Name: "{group}\{cm:LocalDocumentation,{#MyAppName}}"; Filename: "{app}\Documentation\QuickStartDocumentation.pdf"; Components: docs Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon [Run] diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 94c3b95..9b421be 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -1,8 +1,8 @@  Exe - win-x64;linux-x64;osx-x64 - AnyCPU;x64;arm64 + win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64 + AnyCPU net8.0 12 @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.4.0 + 0.5.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From e6b60d56dc0209acf4faeecdaaf2ed09a1e6c36e Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 31 Oct 2024 18:40:03 +0530 Subject: [PATCH 047/113] Implemented optional extra positional parameters for methods. - Extra positional parameters do not work yet. - Also fixed functions and improved installers. --- src/EzrGrammar.txt | 2 +- src/Runtime/Interpreter.cs | 134 ++++++++---------- .../ExecutableNodes/FunctionDefinitionNode.cs | 14 +- src/Runtime/Types/BaseTypes.cs | 6 +- src/Runtime/Types/Executables/EzrClass.cs | 12 +- src/Runtime/Types/Executables/EzrFunction.cs | 7 +- .../Types/Executables/EzrRuntimeExecutable.cs | 63 +++++--- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Syntax/Lexer.cs | 1 + src/Syntax/Parser/Parser.cs | 48 +++++-- src/TokenType.cs | 5 + 12 files changed, 170 insertions(+), 126 deletions(-) diff --git a/src/EzrGrammar.txt b/src/EzrGrammar.txt index 95a13a2..39c2b0d 100644 --- a/src/EzrGrammar.txt +++ b/src/EzrGrammar.txt @@ -162,7 +162,7 @@ try-expression: @ 'function-definition-expression' structures contain declarations of functions. function-definition-expression: - ("global" | "private")? "static"? "constant"? "function" expression? ("with" (expression (',' expression)+?)? ("more" "as" expression))? "do" ((statements "end") | statement) + ("global" | "private")? "static"? "constant"? "function" expression? ("with" (expression (',' expression)+?)? (','? "more" "named"? "as" expression)+?)? "do" ((statements "end") | statement) @ 'class-definition-expression' structures contain declarations of classes. class-definition-expression: diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index fe7de75..c5a43cb 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -390,18 +390,11 @@ private void VisitVariableAssignmentNode(VariableAssignmentNode node, Context ex if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) operationAccessibilityModifiers |= AccessMod.LocalScope; - VisitNode(elementNode, executionContext, callingContext, operationAccessibilityModifiers, true); + Reference? reference = GetRegisteredReference(elementNode, executionContext, callingContext, operationAccessibilityModifiers); if (RuntimeResult.ShouldReturn) return; - Reference reference = RuntimeResult.Reference; - if (!reference.IsRegistered) - { - RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for variable name, but got object of type \"{reference.Object.TypeName}\"!", executionContext, elementNode.StartPosition, elementNode.EndPosition)); - return; - } - - variables[i] = reference; + variables[i] = reference!; } VisitNode(node.Value, executionContext, callingContext, accessibilityModifiers); @@ -411,6 +404,30 @@ private void VisitVariableAssignmentNode(VariableAssignmentNode node, Context ex AssignValuesToVariables(node, variables, isSingleVariable, executionContext, callingContext, accessibilityModifiers); } + /// + /// Gets and checks if a node represents a variable reference. + /// + /// The node to check. + /// The in which the variable will be assigned. + /// The calling on the execution of the . + /// The accessibility modifiers for objects that will be assigned from the executing . + /// The variable reference. if any error occurs. + private Reference? GetRegisteredReference(Node node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + VisitNode(node, executionContext, callingContext, accessibilityModifiers, true); + if (RuntimeResult.ShouldReturn) + return null; + + Reference reference = RuntimeResult.Reference; + if (!reference.IsRegistered) + { + RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for variable name, but got object of type \"{reference.Object.TypeName}\"!", executionContext, node.StartPosition, node.EndPosition)); + return null; + } + + return reference; + } + /// /// Assigns the value(s) to the variable(s) defined in the . /// @@ -874,18 +891,11 @@ private void VisitCountNode(CountNode node, Context executionContext, Context ca if (node.IterationVariable is not null) { - VisitNode(node.IterationVariable, executionContext, callingContext, operationAccessibilityModifiers, true); + iterationVariableReference = GetRegisteredReference(node.IterationVariable, executionContext, callingContext, operationAccessibilityModifiers); if (RuntimeResult.ShouldReturn) return; - iterationVariableReference = RuntimeResult.Reference; - if (!iterationVariableReference.IsRegistered) - { - RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for iteration variable name, but got object of type \"{iterationVariableReference.Object.TypeName}\"!", executionContext, node.IterationVariable.StartPosition, node.IterationVariable.EndPosition)); - return; - } - - iterationVariableName = iterationVariableReference.Name; + iterationVariableName = iterationVariableReference!.Name; iterationVariableRegisteredContext = iterationVariableReference.RegisteredContext ?? executionContext; } @@ -1022,20 +1032,17 @@ iBigInteger is not null /// The accessibility modifiers for objects that will be assigned from the executing . private void VisitForEachNode(ForEachNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) { - VisitNode(node.Expression.Left, executionContext, callingContext, accessibilityModifiers, true); + AccessMod operationAccessibilityModifiers = accessibilityModifiers; + if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) + operationAccessibilityModifiers |= AccessMod.LocalScope; + + Reference? iterationVariableReference = GetRegisteredReference(node.Expression.Left, executionContext, callingContext, operationAccessibilityModifiers); if (RuntimeResult.ShouldReturn) return; - Reference iterationVariableReference = RuntimeResult.Reference; - string iterationVariableName = iterationVariableReference.Name; + string iterationVariableName = iterationVariableReference!.Name; Context iterationVariableRegisteredContext = iterationVariableReference.RegisteredContext ?? executionContext; - if (!iterationVariableReference.IsRegistered) - { - RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for iteration variable name, but got object of type \"{iterationVariableReference.Object.TypeName}\"!", executionContext, node.Expression.Left.StartPosition, node.Expression.Left.EndPosition)); - return; - } - VisitNode(node.Expression.Right, executionContext, callingContext, accessibilityModifiers); if (RuntimeResult.ShouldReturn) return; @@ -1047,10 +1054,6 @@ private void VisitForEachNode(ForEachNode node, Context executionContext, Contex return; } - AccessMod operationAccessibilityModifiers = accessibilityModifiers; - if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) - operationAccessibilityModifiers |= AccessMod.LocalScope; - List returns = new(iterableObject.Length); foreach (IEzrObject ezrObject in iterableObject) { @@ -1171,18 +1174,11 @@ private void VisitTryNode(TryNode node, Context executionContext, Context callin if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) operationAccessibilityModifiers |= AccessMod.LocalScope; - VisitNode(errorVariableNode, executionContext, callingContext, operationAccessibilityModifiers, true); + Reference? reference = GetRegisteredReference(errorVariableNode, executionContext, callingContext, operationAccessibilityModifiers); if (RuntimeResult.ShouldReturn) return; - Reference reference = RuntimeResult.Reference; - if (!reference.IsRegistered) - { - RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for error variable name, but got object of type \"{reference.Object.TypeName}\"!", executionContext, errorVariableNode.StartPosition, errorVariableNode.EndPosition)); - return; - } - - Context assignmentContext = reference.RegisteredContext ?? executionContext; + Context assignmentContext = reference!.RegisteredContext ?? executionContext; error.Update(assignmentContext, errorVariableNode.StartPosition, errorVariableNode.EndPosition); (IEzrObject Object, string Name) newErrorVariable = (error, reference.Name); @@ -1205,18 +1201,11 @@ private void VisitTryNode(TryNode node, Context executionContext, Context callin if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) operationAccessibilityModifiers |= AccessMod.LocalScope; - VisitNode(emptyCaseVariable, executionContext, callingContext, operationAccessibilityModifiers, true); + Reference? reference = GetRegisteredReference(emptyCaseVariable, executionContext, callingContext, operationAccessibilityModifiers); if (RuntimeResult.ShouldReturn) return; - Reference reference = RuntimeResult.Reference; - if (!reference.IsRegistered) - { - RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for error variable name, but got object of type \"{reference.Object.TypeName}\"!", executionContext, emptyCaseVariable.StartPosition, emptyCaseVariable.EndPosition)); - return; - } - - Context assignmentContext = reference.RegisteredContext ?? executionContext; + Context assignmentContext = reference!.RegisteredContext ?? executionContext; error.Update(assignmentContext, emptyCaseVariable.StartPosition, emptyCaseVariable.EndPosition); (IEzrObject Object, string Name) newErrorVariable = (error, reference.Name); @@ -1262,21 +1251,24 @@ private void VisitFunctionDefinitionNode(FunctionDefinitionNode node, Context ex parameters[i] = (reference.Name, node.Parameters[i]); } - (Position StartPosition, Position EndPosition, string Name)? keywordArguments = null; - if (node.KeywordArguments is not null) + OptionalExtraArguments keywordArguments = null; + if (node.ExtraKeywordArguments is not null) { - VisitNode(node.KeywordArguments, newContext, callingContext, AccessMod.None, true); + Reference? reference = GetRegisteredReference(node.ExtraKeywordArguments, newContext, callingContext, AccessMod.None); if (RuntimeResult.ShouldReturn) return; - Reference reference = RuntimeResult.Reference; - if (string.IsNullOrEmpty(reference.Name)) - { - RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected an identifier to store keyword arguments in, but received object of type \"{reference.Object.TypeName}\"!", executionContext, node.KeywordArguments.StartPosition, node.KeywordArguments.EndPosition)); + keywordArguments = (node.ExtraKeywordArguments.StartPosition, node.ExtraKeywordArguments.EndPosition, reference!.Name); + } + + OptionalExtraArguments positionalArguments = null; + if (node.ExtraPositionalArguments is not null) + { + Reference? reference = GetRegisteredReference(node.ExtraPositionalArguments, newContext, callingContext, AccessMod.None); + if (RuntimeResult.ShouldReturn) return; - } - keywordArguments = (node.KeywordArguments.StartPosition, node.KeywordArguments.EndPosition, reference.Name); + positionalArguments = (node.ExtraPositionalArguments.StartPosition, node.ExtraPositionalArguments.EndPosition, reference!.Name); } newContext.Release(); @@ -1288,19 +1280,12 @@ private void VisitFunctionDefinitionNode(FunctionDefinitionNode node, Context ex if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) operationAccessibilityModifiers |= AccessMod.LocalScope; - VisitNode(node.Name, executionContext, callingContext, operationAccessibilityModifiers, true); + Reference? reference = GetRegisteredReference(node.Name, executionContext, callingContext, operationAccessibilityModifiers); if (RuntimeResult.ShouldReturn) return; - Reference reference = RuntimeResult.Reference; - if (!reference.IsRegistered) - { - RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for function name, but got object of type \"{reference.Object.TypeName}\"!", executionContext, node.Name.StartPosition, node.Name.EndPosition)); - return; - } - - Context assignmentContext = reference.RegisteredContext ?? executionContext; - function = new EzrFunction(reference.Name, node.Body, parameters, keywordArguments, node.ReturnLast, assignmentContext, node.StartPosition, node.EndPosition); + Context assignmentContext = reference!.RegisteredContext ?? executionContext; + function = new EzrFunction(reference.Name, node.Body, parameters, keywordArguments, positionalArguments, node.ReturnLast, assignmentContext, node.StartPosition, node.EndPosition); (IEzrObject Object, string Name) newFunctionVariable = (function, reference.Name); HandleSetStatus(assignmentContext.Set(callingContext, newFunctionVariable, reference, operationAccessibilityModifiers), reference.Name, node.Name, assignmentContext); @@ -1308,7 +1293,7 @@ private void VisitFunctionDefinitionNode(FunctionDefinitionNode node, Context ex return; } else - function = new EzrFunction(null, node.Body, parameters, keywordArguments, node.ReturnLast, executionContext, node.StartPosition, node.EndPosition); + function = new EzrFunction(null, node.Body, parameters, keywordArguments, positionalArguments, node.ReturnLast, executionContext, node.StartPosition, node.EndPosition); RuntimeResult.Success(ReferencePool.Get(function, AccessMod.PrivateConstant)); } @@ -1347,18 +1332,11 @@ private void VisitClassDefinitionNode(ClassDefinitionNode node, Context executio if ((operationAccessibilityModifiers & AccessMod.Global) != AccessMod.Global) operationAccessibilityModifiers |= AccessMod.LocalScope; - VisitNode(node.Name, executionContext, callingContext, operationAccessibilityModifiers, true); + Reference? reference = GetRegisteredReference(node.Name, executionContext, callingContext, operationAccessibilityModifiers); if (RuntimeResult.ShouldReturn) return; - Reference reference = RuntimeResult.Reference; - if (!reference.IsRegistered) - { - RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected reference or identifier for class name, but got object of type \"{reference.Object.TypeName}\"!", executionContext, node.Name.StartPosition, node.Name.EndPosition)); - return; - } - - Context assignmentContext = reference.RegisteredContext ?? executionContext; + Context assignmentContext = reference!.RegisteredContext ?? executionContext; @class = new EzrClass(reference.Name, node.Body, parents, node.Readonly, ((node.AccessibilityModifiers | accessibilityModifiers) & AccessMod.Static) == AccessMod.Static, this, RuntimeResult, assignmentContext, node.StartPosition, node.EndPosition); diff --git a/src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs b/src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs index 01a1c50..a3fe011 100644 --- a/src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs +++ b/src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs @@ -8,11 +8,12 @@ namespace EzrSquared.Runtime.Nodes; /// The accessibility modifiers for the function definition. /// The check for if the last expression of the function should be returned as its result. Only used in oneliners. /// The parameters of the function. -/// The reference to store the extra keyword arguments in. +/// The reference to store the extra keyword arguments in. +/// The reference to store the extra positional arguments in. /// The body of the function. /// The starting of the . /// The ending of the . -public class FunctionDefinitionNode(Node? name, AccessMod accessibilityModifiers, bool returnLast, List parameters, Node? keywordArguments, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +public class FunctionDefinitionNode(Node? name, AccessMod accessibilityModifiers, bool returnLast, List parameters, Node? extraKeywordArguments, Node? extraPositionalArguments, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) { /// /// The (optional) name of the function. @@ -38,7 +39,12 @@ public class FunctionDefinitionNode(Node? name, AccessMod accessibilityModifiers /// /// The reference to store the extra keyword arguments in. /// - public Node? KeywordArguments = keywordArguments; + public Node? ExtraKeywordArguments = extraKeywordArguments; + + /// + /// The reference to store the extra positional arguments in. + /// + public Node? ExtraPositionalArguments = extraPositionalArguments; /// /// The body of the function. @@ -56,6 +62,6 @@ public override string ToString() for (int i = 0; i < Parameters.Count; i++) parameters[i] = Parameters[i].ToString(); - return $"{nameof(FunctionDefinitionNode)}({Name?.ToString() ?? "null"}, {AccessibilityModifiers}, {ReturnLast}, [{string.Join(", ", parameters)}], {KeywordArguments?.ToString() ?? "null"}, {Body})"; + return $"{nameof(FunctionDefinitionNode)}({Name?.ToString() ?? "null"}, {AccessibilityModifiers}, {ReturnLast}, [{string.Join(", ", parameters)}], {ExtraKeywordArguments?.ToString() ?? "null"}, {ExtraPositionalArguments?.ToString() ?? "null"}, {Body})"; } } diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs index 7804d27..1a012c1 100644 --- a/src/Runtime/Types/BaseTypes.cs +++ b/src/Runtime/Types/BaseTypes.cs @@ -92,17 +92,17 @@ public EzrObject(Context parentContext, Position startPosition, Position endPosi /// /// Creates a new object with the specified internal context, parent context and position. /// - /// The internal context. + /// The internal context, if , creates a new one. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrObject(Context context, Context parentContext, Position startPosition, Position endPosition) + public EzrObject(Context? context, Context parentContext, Position startPosition, Position endPosition) { StartPosition = startPosition; EndPosition = endPosition; _executionContext = CreationContext = parentContext; - Context = context; + Context = context ?? new Context(TypeName, false, startPosition, CreationContext, CreationContext.StaticContext); } /// diff --git a/src/Runtime/Types/Executables/EzrClass.cs b/src/Runtime/Types/Executables/EzrClass.cs index 087fff6..049bdfc 100644 --- a/src/Runtime/Types/Executables/EzrClass.cs +++ b/src/Runtime/Types/Executables/EzrClass.cs @@ -44,7 +44,7 @@ public class EzrClass : EzrRuntimeExecutable, IEzrMutableObject /// The parent context. /// The starting position of the object. /// The ending position of the object. - public EzrClass(string? name, Node body, EzrClass[] parents, bool isReadOnly, bool isStatic, Interpreter interpreter, RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(name, body, [], null, parentContext, startPosition, endPosition, new Context($"<{$"\"{name}\"" ?? ""} static context>", true, startPosition, parentContext)) + public EzrClass(string? name, Node body, EzrClass[] parents, bool isReadOnly, bool isStatic, Interpreter interpreter, RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(name, body, [], null, null, parentContext, startPosition, endPosition, new Context($"<{$"\"{name}\"" ?? ""} static context>", true, startPosition, parentContext)) { IsReadOnly = isReadOnly; IsStatic = isStatic; @@ -93,7 +93,8 @@ public class EzrClass : EzrRuntimeExecutable, IEzrMutableObject EzrFunction initializationFunction = (EzrFunction)functionReference.Object; Parameters = initializationFunction.Parameters; - KeywordArguments = initializationFunction.KeywordArguments; + ExtraKeywordArguments = initializationFunction.ExtraKeywordArguments; + ExtraPositionalArguments = initializationFunction.ExtraPositionalArguments; newContext.Release(); } @@ -104,7 +105,8 @@ public class EzrClass : EzrRuntimeExecutable, IEzrMutableObject /// The name of the executable. /// The source code body of the executable. /// The source code of the class's parameters and their default values. - /// The position in source code and name of the variable for the class's extra keyword arguments. + /// The position in source code and name of the variable for the class's extra keyword arguments. + /// The position in source code and name of the variable for the class's extra positional arguments. /// The parents of the class. /// The references to the class's static parents. /// Is this a read-only class? @@ -113,7 +115,7 @@ public class EzrClass : EzrRuntimeExecutable, IEzrMutableObject /// The parent context. /// The starting position of the object. /// The ending position of the object. - public EzrClass(string? name, Node body, (string Name, Node Node)[] parameters, (Position StartPosition, Position EndPosition, string Name)? keywordArguments, EzrClass[] parents, Reference[] staticParentReferences, bool isReadOnly, bool isStatic, Context staticContext, Context parentContext, Position startPosition, Position endPosition) : base(name, body, parameters, keywordArguments, parentContext, startPosition, endPosition, staticContext) + public EzrClass(string? name, Node body, (string Name, Node Node)[] parameters, OptionalExtraArguments extraKeywordArguments, OptionalExtraArguments extraPositionalArguments, EzrClass[] parents, Reference[] staticParentReferences, bool isReadOnly, bool isStatic, Context staticContext, Context parentContext, Position startPosition, Position endPosition) : base(name, body, parameters, extraKeywordArguments, extraPositionalArguments, parentContext, startPosition, endPosition, staticContext) { Parents = parents; IsReadOnly = isReadOnly; @@ -271,6 +273,6 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run copy.LinkedContexts[i] = reference.Object.Context; } - return new EzrClass(IsAnonymous ? null : ExecutableName, Body, Parameters, KeywordArguments, Parents, staticParentReferences, IsReadOnly, IsStatic, copy!, CreationContext, StartPosition, EndPosition); + return new EzrClass(IsAnonymous ? null : ExecutableName, Body, Parameters, ExtraKeywordArguments, ExtraPositionalArguments, Parents, staticParentReferences, IsReadOnly, IsStatic, copy!, CreationContext, StartPosition, EndPosition); } } diff --git a/src/Runtime/Types/Executables/EzrFunction.cs b/src/Runtime/Types/Executables/EzrFunction.cs index e886eb8..4fc9f88 100644 --- a/src/Runtime/Types/Executables/EzrFunction.cs +++ b/src/Runtime/Types/Executables/EzrFunction.cs @@ -8,12 +8,13 @@ namespace EzrSquared.Runtime.Types.Executables; /// The name of the executable. /// The source code body of the executable. /// The source code of the executable's parameters and their default values. -/// The position in source code and name of the variable for the executable's extra keyword arguments. +/// The position in source code and name of the variable for the executable's extra keyword arguments. +/// The position in source code and name of the variable for the executable's extra positional arguments. /// Should the function return its last expression as the result? /// The parent context. /// The starting position of the object. /// The ending position of the object. -public class EzrFunction(string? name, Node body, (string Name, Node Node)[] parameters, (Position StartPosition, Position EndPosition, string Name)? keywordArguments, bool returnLast, Context parentContext, Position startPosition, Position endPosition) : EzrRuntimeExecutable(name, body, parameters, keywordArguments, parentContext, startPosition, endPosition), IEzrMutableObject +public class EzrFunction(string? name, Node body, (string Name, Node Node)[] parameters, OptionalExtraArguments extraKeywordArguments, OptionalExtraArguments extraPositionalArguments, bool returnLast, Context parentContext, Position startPosition, Position endPosition) : EzrRuntimeExecutable(name, body, parameters, extraKeywordArguments, extraPositionalArguments, parentContext, startPosition, endPosition), IEzrMutableObject { /// public override string TypeName { get; protected internal set; } = "function"; @@ -66,6 +67,6 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run /// public IMutable? DeepCopy(RuntimeResult result) { - return new EzrFunction(IsAnonymous ? null : ExecutableName, Body, Parameters, KeywordArguments, ReturnLast, CreationContext, StartPosition, EndPosition); + return new EzrFunction(IsAnonymous ? null : ExecutableName, Body, Parameters, ExtraKeywordArguments, ExtraPositionalArguments, ReturnLast, CreationContext, StartPosition, EndPosition); } } diff --git a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs index b21cbc5..cdf3260 100644 --- a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs +++ b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs @@ -1,4 +1,6 @@ -using EzrSquared.Runtime.Collections; +global using OptionalExtraArguments = (EzrSquared.Position StartPosition, EzrSquared.Position EndPosition, string Name)?; + +using EzrSquared.Runtime.Collections; using EzrSquared.Runtime.Nodes; using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; @@ -36,7 +38,12 @@ public abstract class EzrRuntimeExecutable : EzrObject /// /// The position in source code and name of the variable for the executable's extra keyword arguments. /// - public (Position StartPosition, Position EndPosition, string Name)? KeywordArguments { get; internal protected set; } + public OptionalExtraArguments ExtraKeywordArguments { get; internal protected set; } + + /// + /// The position in source code and name of the variable for the executable's extra positional arguments. + /// + public OptionalExtraArguments ExtraPositionalArguments { get; internal protected set; } /// /// Creates a new executable object. @@ -44,12 +51,13 @@ public abstract class EzrRuntimeExecutable : EzrObject /// The name of the executable. /// The source code body of the executable. /// The source code of the executable's parameters and their default values. - /// The position in source code and name of the variable for the executable's extra keyword arguments. + /// The position in source code and name of the variable for the executable's extra keyword arguments. + /// The position in source code and name of the variable for the executable's extra positional arguments. /// The internal context, if , creates a new one. /// The parent context. /// The starting position of the object. /// The ending position of the object. - public EzrRuntimeExecutable(string? name, Node body, (string Name, Node Node)[] parameters, (Position StartPosition, Position EndPosition, string Name)? keywordArguments, Context parentContext, Position startPosition, Position endPosition, Context? initializationContext = null) : base(initializationContext, parentContext, startPosition, endPosition) + public EzrRuntimeExecutable(string? name, Node body, (string Name, Node Node)[] parameters, OptionalExtraArguments extraKeywordArguments, OptionalExtraArguments extraPositionalArguments, Context parentContext, Position startPosition, Position endPosition, Context? initializationContext = null) : base(initializationContext, parentContext, startPosition, endPosition) { Tag = name is not null ? $"{Tag}.{name}.{Utils.GetNextUniqueId()}" @@ -58,7 +66,8 @@ public EzrRuntimeExecutable(string? name, Node body, (string Name, Node Node)[] Body = body; Parameters = parameters; - KeywordArguments = keywordArguments; + ExtraKeywordArguments = extraKeywordArguments; + ExtraPositionalArguments = extraPositionalArguments; IsAnonymous = string.IsNullOrEmpty(name); } @@ -73,8 +82,9 @@ public EzrRuntimeExecutable(string? name, Node body, (string Name, Node Node)[] /// Should the checker ignore extra arguments? protected internal void CheckAndPopulateArguments(Reference[] arguments, Context context, Interpreter interpreter, RuntimeResult result, bool ignoreExtraArguments) { - // Create dictionary to store extra keyword arguments, if allowed. - RuntimeEzrObjectDictionary? keywordArguments = KeywordArguments.HasValue ? new() : null; + // Create dictionary or list to store extra arguments, if allowed. + RuntimeEzrObjectDictionary? extraKeywordArguments = ExtraKeywordArguments.HasValue ? new() : null; + RuntimeEzrObjectList? extraPositionalArguments = ExtraPositionalArguments.HasValue ? new() : null; // Index for iterating through the ParameterNames array. int parameterIndex = 0; @@ -88,6 +98,9 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context Reference argument = arguments[argumentIndex]; IEzrObject argumentObject = argument.Object; + // Update the object's context. + argumentObject.Update(context, argumentObject.StartPosition, argumentObject.EndPosition); + // Is the parameterIndex in the bounds of the dictionary? bool isValidIndex = parameterIndex < Parameters.Length; @@ -98,18 +111,19 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context string key = isValidIndex ? Parameters[parameterIndex].Name : string.Empty; if (isKeywordArgument) + { // If it is a keyword argument, and it exists in Parameters: if (Array.FindIndex(Parameters, paramter => paramter.Name == argument.Name) != -1) key = argument.Name; // Choose that as the key. - else if (keywordArguments is not null) // If it doesn't, and extra keyword arguments are allowed: + else if (extraKeywordArguments is not null) // If it doesn't, and extra keyword arguments are allowed: { // Add the argument to the dictionary, and continue onto the next argument. - keywordArguments.Update(new EzrString(argument.Name, context, argumentObject.StartPosition, argumentObject.EndPosition), argumentObject, result); + extraKeywordArguments.Update(new EzrString(argument.Name, context, argumentObject.StartPosition, argumentObject.EndPosition), argumentObject, result); argumentIndex++; continue; } - else if (!ignoreExtraArguments) // If extra arguments are not allowed, and ignoreExtraArguments is not set: + else if (!ignoreExtraArguments) // If extra keyword arguments are not allowed, and ignoreExtraArguments is not set: { // Return an error. result.Failure(new EzrUnexpectedArgumentError($"Did not expect argument \"{argument.Name}\"!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); @@ -120,8 +134,9 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context argumentIndex++; continue; } + } - // Is the key already exist? + // Does the key already exist? bool hasKey = isValidIndex && context.IsDefined(key); // If parameterIndex is out of bounds, or the key is already defined and the argument is a keyword argument, or if all the arguments have already been set: @@ -145,8 +160,7 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context if (hasKey) continue; - // After all that, update the argument, and set it to the context. - argumentObject.Update(context, argumentObject.StartPosition, argumentObject.EndPosition); + // After all that, set it to the context. context.Set(null, key, ReferencePool.Get(argumentObject, AccessMod.Private)); // Add to the argument index. @@ -184,8 +198,12 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context } // If the extra keyword arguments dictionary should be set: - if (KeywordArguments.HasValue) - context.Set(null, KeywordArguments.Value.Name, ReferencePool.Get(new EzrDictionary(keywordArguments!, context, KeywordArguments.Value.StartPosition, KeywordArguments.Value.EndPosition), AccessMod.Private)); // Set it. + if (ExtraKeywordArguments.HasValue) + context.Set(null, ExtraKeywordArguments.Value.Name, ReferencePool.Get(new EzrDictionary(extraKeywordArguments!, context, ExtraKeywordArguments.Value.StartPosition, ExtraKeywordArguments.Value.EndPosition), AccessMod.Private)); // Set it. + + // If the extra positional arguments list should be set: + if (ExtraPositionalArguments.HasValue) + context.Set(null, ExtraPositionalArguments.Value.Name, ReferencePool.Get(new EzrList(extraPositionalArguments!, context, ExtraPositionalArguments.Value.StartPosition, ExtraPositionalArguments.Value.EndPosition), AccessMod.Private)); // Set it. } /// @@ -229,14 +247,19 @@ public override int ComputeHashCode(RuntimeResult result) /// public override string ToString(RuntimeResult result) { - string[] paramterNames = Array.ConvertAll(Parameters, parameter => parameter.Name); + static string ToEnabledOrDisabled(bool enabled) + { + return enabled ? "enabled" : "disabled"; + } + + string[] parameterNames = Array.ConvertAll(Parameters, parameter => parameter.Name); return (Parameters.Length > 0, IsAnonymous) switch { - (true, true) => $"<{TypeName} {ExecutableName}, with \"{string.Join("\", \"", paramterNames)}\">", - (true, false) => $"<{TypeName} \"{ExecutableName}\", with \"{string.Join("\", \"", paramterNames)}\">", + (true, true) => $"<{TypeName} {ExecutableName}, with \"{string.Join("\", \"", parameterNames)}\", extra keyword arguments {ToEnabledOrDisabled(ExtraKeywordArguments.HasValue)} and extra positional arguments {ToEnabledOrDisabled(ExtraPositionalArguments.HasValue)}>", + (true, false) => $"<{TypeName} \"{ExecutableName}\", with \"{string.Join("\", \"", parameterNames)}\", extra keyword arguments {ToEnabledOrDisabled(ExtraKeywordArguments.HasValue)} and extra positional arguments {ToEnabledOrDisabled(ExtraPositionalArguments.HasValue)}>", - (false, true) => $"<{TypeName} {ExecutableName}>", - (false, false) => $"<{TypeName} \"{ExecutableName}\">", + (false, true) => $"<{TypeName} {ExecutableName} with extra keyword arguments {ToEnabledOrDisabled(ExtraKeywordArguments.HasValue)} and extra positional arguments {ToEnabledOrDisabled(ExtraPositionalArguments.HasValue)}>", + (false, false) => $"<{TypeName} \"{ExecutableName}\" with extra keyword arguments {ToEnabledOrDisabled(ExtraKeywordArguments.HasValue)} and extra positional arguments {ToEnabledOrDisabled(ExtraPositionalArguments.HasValue)}>", }; } } diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 3718caf..c26eac8 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -33,7 +33,7 @@ InfoAfterFile=D:\Code\csharp\ezrSquared\Changelog.txt PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog OutputDir=D:\Code\csharp\ezrSquared\Binaries\Shell\Release\Installers -OutputBaseFilename=ezr² Shell Setup (Win32) +OutputBaseFilename=ezrSquared Shell Setup (Win32) SetupIconFile=D:\Code\csharp\ezrSquared\graphics\Icon.ico Compression=lzma SolidCompression=yes diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 5b2225b..ad0c7b1 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -41,7 +41,7 @@ InfoAfterFile=D:\Code\csharp\ezrSquared\Changelog.txt PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog OutputDir=D:\Code\csharp\ezrSquared\Binaries\Shell\Release\Installers -OutputBaseFilename=ezr² Shell Setup (Win64) +OutputBaseFilename=ezrSquared Shell Setup (Win64) SetupIconFile=D:\Code\csharp\ezrSquared\graphics\Icon.ico Compression=lzma SolidCompression=yes diff --git a/src/Syntax/Lexer.cs b/src/Syntax/Lexer.cs index d8d61eb..9199b0a 100644 --- a/src/Syntax/Lexer.cs +++ b/src/Syntax/Lexer.cs @@ -624,6 +624,7 @@ private Token CompileIdentifier() "with" => new Token(TokenType.KeywordWith, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), "more" => new Token(TokenType.KeywordMore, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "named" => new Token(TokenType.KeywordNamed, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), "end" => new Token(TokenType.KeywordEnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), "return" => new Token(TokenType.KeywordReturn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), "last" => new Token(TokenType.KeywordLast, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), diff --git a/src/Syntax/Parser/Parser.cs b/src/Syntax/Parser/Parser.cs index f5953cd..9b4b568 100644 --- a/src/Syntax/Parser/Parser.cs +++ b/src/Syntax/Parser/Parser.cs @@ -1933,7 +1933,8 @@ private void ParseFunctionDefinitionExpression() Advance(); Node? name = null; List parameters = []; - Node? keywordArguments = null; + Node? extraKeywordArguments = null; + Node? extraPositionalArguments = null; Node body; Position endPosition; @@ -1947,6 +1948,7 @@ private void ParseFunctionDefinitionExpression() { do { + Position paramStartPosition = _currentToken.StartPosition; Advance(); if (_currentToken.Type == TokenType.NewLine) @@ -1955,9 +1957,21 @@ private void ParseFunctionDefinitionExpression() if (_currentToken.Type == TokenType.KeywordMore) { Advance(); + + bool isNamedExtraParamters = false; + if (_currentToken.Type == TokenType.KeywordNamed) + { + isNamedExtraParamters = true; + Advance(); + } + if (_currentToken.Type != TokenType.KeywordAs) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'as' keyword! The 'as' keyword comes in-between the 'from' keyword and an expression when declaring extra parameters for an object.", _currentToken.StartPosition, _currentToken.EndPosition)); + if (isNamedExtraParamters) + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'as' keyword! The 'as' keyword comes in-between the 'named' keyword and an expression when declaring extra keyword parameters for an object.", _currentToken.StartPosition, _currentToken.EndPosition)); + else + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'as' or 'named' keywords! The 'named' keyword starts the definition of extra keyword parameters and the 'as' keyword comes in-between the 'from' or 'named' keyword and an expression when declaring extra positional or keyword parameters for an object.", _currentToken.StartPosition, _currentToken.EndPosition)); + return; } @@ -1966,17 +1980,31 @@ private void ParseFunctionDefinitionExpression() if (_result.Error is not null) return; - keywordArguments = _result.Node; - if (_currentToken.Type == TokenType.NewLine) - Advance(); - - if (_currentToken.Type == TokenType.Comma) + if (isNamedExtraParamters && extraKeywordArguments is not null) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Only one extra keyword parameter dictionary can be defined per function!", paramStartPosition, _currentToken.EndPosition)); + return; + } + else if (!isNamedExtraParamters && extraPositionalArguments is not null) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Cannot have more parameters after declaring extra parameters! Declaring extra parameters must be done last, after declaring all mandatory parameters.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Only one extra positional parameter list can be defined per function!", paramStartPosition, _currentToken.EndPosition)); return; } - break; + if (isNamedExtraParamters) + extraKeywordArguments = _result.Node; + else + extraPositionalArguments = _result.Node; + + if (_currentToken.Type == TokenType.NewLine) + Advance(); + + continue; + } + else if (extraKeywordArguments is not null || extraPositionalArguments is not null) + { + _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Normal mixed parameters must come before extra positional/keyword parameter list/dictionary definitions.", paramStartPosition, _currentToken.EndPosition)); + return; } ParseExpression(); @@ -2053,7 +2081,7 @@ private void ParseFunctionDefinitionExpression() return; } - _result.Success(new FunctionDefinitionNode(name, accessibilityModifiers, returnLast, parameters, keywordArguments, body, startPosition, endPosition)); + _result.Success(new FunctionDefinitionNode(name, accessibilityModifiers, returnLast, parameters, extraKeywordArguments, extraPositionalArguments, body, startPosition, endPosition)); } /// diff --git a/src/TokenType.cs b/src/TokenType.cs index 1e25527..5cdb481 100644 --- a/src/TokenType.cs +++ b/src/TokenType.cs @@ -147,6 +147,11 @@ public enum TokenType : ushort /// KeywordMore, + /// + /// The keyword "named", case-insensitive, part of the type-group. + /// + KeywordNamed, + /// /// The keyword "function", case-insensitive, part of the type-group. /// From 5d9b9fab173a0653883a451d8336dcf6f657d3c3 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 31 Oct 2024 23:15:04 +0530 Subject: [PATCH 048/113] =?UTF-8?q?ezr=C2=B2=20v0.6.0=20-=20Implemented=20?= =?UTF-8?q?EPAs=20(Extra=20Positional=20Arguments)!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 6 + src/EzrSquared.csproj | 2 +- src/Runtime/Interpreter.cs | 27 ++-- .../Types/Executables/EzrRuntimeExecutable.cs | 128 ++++++++++-------- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 8 files changed, 87 insertions(+), 84 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 102fcd5..d87d0a8 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,12 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.6.0 [31-10-24] + * [BREAKING CHANGE] EKAs (Extra Keyword Arguments) now use the following syntax: "function abc with more named as keyword_args do ..." + * Added EPA (Extra Positional Arguments) support! Define them like so: "function abc with more as epas do ...". Here, "epas" will be a `EzrList` of the extra arguments. + * Improved string representations of `EzrRuntimeExecutable`-s. + * Fixed scope handling in for-each loop assignments. + * ezr² RE - v0.5.0 [31-10-24] * [BREAKING CHANGE] `IMutable` has been moved to the `EzrSquared.Runtime` namespace. * [BREAKING CHANGE] The `context` parameter in the constructor for `EzrObject` is no longer nullable. diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 674c7f8..7f289cd 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.5.0 + 0.6.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index c5a43cb..4a7ef2c 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -57,8 +57,11 @@ internal void VisitNode(Node astNode, Context executionContext, Context? calling case ValueNode node: VisitValueNode(node, executionContext); break; + case ArrayLikeNode node when node.CreateList: + VisitArrayLikeNodeList(node, executionContext, callingContext, accessibilityModifiers); + break; case ArrayLikeNode node: - VisitArrayLikeNode(node, executionContext, callingContext, accessibilityModifiers); + VisitArrayLikeNodeArray(node, executionContext, callingContext, accessibilityModifiers); break; case DictionaryNode node: VisitDictionaryNode(node, executionContext, callingContext, accessibilityModifiers); @@ -199,21 +202,7 @@ private void VisitValueNode(ValueNode node, Context executionContext) } } - /// - /// Creates an array-like object, see , and for more information. - /// - /// The to execute. - /// The under which the array-like object will be created. - /// The calling on the execution of the . - /// The accessibility modifiers for objects that will be assigned from the executing . - #region private void VisitArrayLikeNode(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) - private void VisitArrayLikeNode(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) - { - if (node.CreateList) - CreateList(node, executionContext, callingContext, accessibilityModifiers); - else - CreateArray(node, executionContext, callingContext, accessibilityModifiers); - } + #region VisitArrayLikeNode /// /// Creates a list of references to its elements. @@ -222,7 +211,7 @@ private void VisitArrayLikeNode(ArrayLikeNode node, Context executionContext, Co /// The under which the list will be created. /// The calling on the execution of the . /// The accessibility modifiers for objects that will be assigned from the executing . - private void CreateList(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + private void VisitArrayLikeNodeList(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) { RuntimeEzrObjectList elementsReferences = new(node.Elements.Count); for (int i = 0; i < node.Elements.Count; i++) @@ -232,7 +221,7 @@ private void CreateList(ArrayLikeNode node, Context executionContext, Context ca if (RuntimeResult.ShouldReturn) return; - Reference reference = ReferencePool.Get(RuntimeResult.Reference.Object, AccessMod.None, string.Empty); + Reference reference = ReferencePool.Get(RuntimeResult.Reference.Object); reference.UpdateRegister(true); elementsReferences.Add(reference); @@ -248,7 +237,7 @@ private void CreateList(ArrayLikeNode node, Context executionContext, Context ca /// The under which the array will be created. /// The calling on the execution of the . /// The accessibility modifiers for objects that will be assigned from the executing . - private void CreateArray(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + private void VisitArrayLikeNodeArray(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) { IEzrObject[] elements = new IEzrObject[node.Elements.Count]; for (int i = 0; i < node.Elements.Count; i++) diff --git a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs index cdf3260..c97fbab 100644 --- a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs +++ b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs @@ -86,115 +86,123 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context RuntimeEzrObjectDictionary? extraKeywordArguments = ExtraKeywordArguments.HasValue ? new() : null; RuntimeEzrObjectList? extraPositionalArguments = ExtraPositionalArguments.HasValue ? new() : null; - // Index for iterating through the ParameterNames array. - int parameterIndex = 0; - - // Index for iterating through the arguments. - int argumentIndex = 0; - - while (argumentIndex < arguments.Length) + int currentIndexThroughParameters = 0; + for (int i = 0; i < arguments.Length; i++) { // Get the argument. Reference and object. - Reference argument = arguments[argumentIndex]; + Reference argument = arguments[i]; IEzrObject argumentObject = argument.Object; - // Update the object's context. + // Update the argument's context. argumentObject.Update(context, argumentObject.StartPosition, argumentObject.EndPosition); - // Is the parameterIndex in the bounds of the dictionary? - bool isValidIndex = parameterIndex < Parameters.Length; - - // Is this a keyword argument? As in, provided like name: value. + // Is the argument a keyword argument? As in, defined as name: value. bool isKeywordArgument = !string.IsNullOrEmpty(argument.Name) && !argument.IsRegistered; // The name of the argument as in Parameters or the given name. - string key = isValidIndex ? Parameters[parameterIndex].Name : string.Empty; + string parameterName = currentIndexThroughParameters < Parameters.Length ? Parameters[currentIndexThroughParameters].Name : string.Empty; + // Handle keyword arguments. if (isKeywordArgument) { - // If it is a keyword argument, and it exists in Parameters: - if (Array.FindIndex(Parameters, paramter => paramter.Name == argument.Name) != -1) - key = argument.Name; // Choose that as the key. - else if (extraKeywordArguments is not null) // If it doesn't, and extra keyword arguments are allowed: + string keywordArgumentName = argument.Name; + + // Check if there is a parameter with the same name as the keyword argument: + if (keywordArgumentName == parameterName || Array.Exists(Parameters, param => keywordArgumentName == param.Name)) + parameterName = keywordArgumentName; // If so, fine. + else if (extraKeywordArguments is not null) // Otherwise, if extra keyword arguments (EKAs) are allowed: { - // Add the argument to the dictionary, and continue onto the next argument. - extraKeywordArguments.Update(new EzrString(argument.Name, context, argumentObject.StartPosition, argumentObject.EndPosition), argumentObject, result); + // Add it to the EKA dictionary. + extraKeywordArguments.Update(new EzrString(keywordArgumentName, context, argumentObject.StartPosition, argumentObject.EndPosition), argumentObject, result); - argumentIndex++; + // Continue onto the next argument. + ReferencePool.TryRelease(argument); continue; } - else if (!ignoreExtraArguments) // If extra keyword arguments are not allowed, and ignoreExtraArguments is not set: + else if (!ignoreExtraArguments) // Otherwise still, if extra arguments should not be ignored: { - // Return an error. + // Throw an error. result.Failure(new EzrUnexpectedArgumentError($"Did not expect argument \"{argument.Name}\"!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); return; } - else // Otherwise, if ignoreExtraArguments is set, continue onto the next argument. + else // Otherwise, skip this argument. { - argumentIndex++; + ReferencePool.TryRelease(argument); continue; } } - // Does the key already exist? - bool hasKey = isValidIndex && context.IsDefined(key); + // Has the current parameter been defined? + bool parameterAlreadyDefined = context.IsDefined(parameterName); - // If parameterIndex is out of bounds, or the key is already defined and the argument is a keyword argument, or if all the arguments have already been set: - if (!isValidIndex || (hasKey && (isKeywordArgument || parameterIndex + 1 >= Parameters.Length))) + // If the argument is not a kwarg and there are no more parameters to define and EPAs are allowed: + if (!isKeywordArgument && currentIndexThroughParameters >= Parameters.Length && extraPositionalArguments is not null) + { + // Create a new reference. + Reference newReference = ReferencePool.Get(argumentObject); + newReference.UpdateRegister(true); + + // And add it to the EPA list. + extraPositionalArguments.Add(newReference); + ReferencePool.TryRelease(argument); + + continue; + } + else if ((parameterAlreadyDefined && isKeywordArgument) || currentIndexThroughParameters >= Parameters.Length) { // Return an error. result.Failure(new EzrUnexpectedArgumentError( isKeywordArgument - ? $"Did not expect argument \"{key}\", as it is already specified!" - : "Did not expect any more arguments!", + ? $"Did not expect argument \"{parameterName}\", as it is already specified!" + : "Did not expect any more positional arguments!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); + return; } - // Otherwise, if it is not a keyword argument: - if (!isKeywordArgument) - parameterIndex++; // Add to parameterIndex. + // Otherwise, if this is / corresponds to a positional argument previously undefined: + if (!isKeywordArgument || (Parameters[currentIndexThroughParameters].Name == parameterName)) + currentIndexThroughParameters++; // Add to currentIndexThroughParameters! - // If the argument is already defined, and it's not a keyword argument, then go to the next iteration while staying on the same argument. - // The parameterIndex will be added to again, and get onto the next required parameter. - if (hasKey) - continue; - - // After all that, set it to the context. - context.Set(null, key, ReferencePool.Get(argumentObject, AccessMod.Private)); - - // Add to the argument index. - argumentIndex++; + // After all that, set the argument to the context. + context.Set(null, parameterName, ReferencePool.Get(argumentObject, AccessMod.Private)); + ReferencePool.TryRelease(argument); } - // Go through all the parameters. - for (int i = parameterIndex; i < Parameters.Length; i++) + // Go through all the leftover parameters. + for (int i = currentIndexThroughParameters; i < Parameters.Length; i++) { - (string parameter, Node parameterNode) = Parameters[i]; - - // Check if it is defined: - if (context.IsDefined(parameter)) + (string parameterName, Node parameterCode) = Parameters[i]; + + // Check if it is defined as a kwarg: + if (context.IsDefined(parameterName)) continue; // If so, continue to the next. + + // The accessibility modifiers for the execution. + AccessMod operationAccessibilityModifiers = AccessMod.None; + if (parameterCode is VariableAccessNode vaNode) + { + operationAccessibilityModifiers = (vaNode.AccessibilityModifiers & AccessMod.Global) != AccessMod.Global + ? vaNode.AccessibilityModifiers |= AccessMod.LocalScope + : vaNode.AccessibilityModifiers; + } - // The accessibility modifiers for the execution; if it is a simple access node, the modifiers should be local-only. - AccessMod operationAccessibilityModifiers = parameterNode is VariableAccessNode ? AccessMod.LocalScope : AccessMod.None; - - // Otherwise, execute the parameter source code. - interpreter.VisitNode(parameterNode, context, null, operationAccessibilityModifiers, true); + // Execute the parameter source code! + interpreter.VisitNode(parameterCode, context, null, operationAccessibilityModifiers, true); if (result.ShouldReturn) // Check for errors and return if necessary. return; - + // If the result is empty, i.e. there is no default value: if (result.Reference.IsEmpty) { // Return an error. - result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{parameter}\"!", _executionContext, StartPosition, EndPosition)); + result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{parameterName}\"!", _executionContext, StartPosition, EndPosition)); return; } - + // Otherwise, if it is still not defined due to strange assignment practises by the programmer: - if (!context.IsDefined(parameter)) - context.Set(null, parameter, ReferencePool.Get(result.Reference.Object, AccessMod.Private)); // Set it. + if (!context.IsDefined(parameterName)) + context.Set(null, parameterName, ReferencePool.Get(result.Reference.Object, AccessMod.Private)); // Set it. } // If the extra keyword arguments dictionary should be set: diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 6d3aafe..9727361 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.5.0"; + private const string Version = "0.6.0"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index c26eac8..7825328 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.5.0" +#define MyAppVersion "0.6.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index ad0c7b1..79e9eb7 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.5.0" +#define MyAppVersion "0.6.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 9b421be..21ff33c 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.5.0 + 0.6.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From c4243a4e02152218448378db0977dac661f6bdd7 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 31 Oct 2024 23:21:28 +0530 Subject: [PATCH 049/113] Grammar.. --- Changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index d87d0a8..c52558d 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -5,7 +5,7 @@ https://github.com/Uralstech/ezrSquared/releases * ezr² RE - v0.6.0 [31-10-24] * [BREAKING CHANGE] EKAs (Extra Keyword Arguments) now use the following syntax: "function abc with more named as keyword_args do ..." - * Added EPA (Extra Positional Arguments) support! Define them like so: "function abc with more as epas do ...". Here, "epas" will be a `EzrList` of the extra arguments. + * Added EPA (Extra Positional Arguments) support! You can define them like so: "function abc with more as epas do ...". Here, "epas" will be an `EzrList` of the extra arguments. * Improved string representations of `EzrRuntimeExecutable`-s. * Fixed scope handling in for-each loop assignments. From dca483a5a509e243afea5604df897bcfdf0f425c Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 1 Nov 2024 00:55:01 +0530 Subject: [PATCH 050/113] Added slightly jank implementation of EPAs for source wrappers. --- .../Builtins/EzrBuiltinFunctions.cs | 63 ++++++++++++++----- .../EzrSharpSourceExecutableWrapper.cs | 47 +++++++++----- .../EzrSharpSourceFieldWrapper.cs | 2 +- .../EzrSharpSourceFunctionWrapper.cs | 8 ++- .../EzrSharpSourcePropertyWrapper.cs | 2 +- .../EzrSharpSourceTypeWrapper.cs | 8 ++- .../SharpMethodParameters.cs | 7 +++ .../SharpMethodWrapperAttribute.cs | 7 ++- 8 files changed, 104 insertions(+), 40 deletions(-) diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs index 8af0c6e..a7bef0a 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs @@ -4,6 +4,8 @@ using EzrSquared.Runtime.Types.Core.Text; using EzrSquared.Runtime.WrapperAttributes; using System; +using System.Collections.Generic; +using System.Text; namespace EzrSquared.Runtime.Types.CSharpWrappers.Builtins; @@ -19,12 +21,16 @@ public static class EzrBuiltinFunctions /// ezr² parameters: /// /// - /// message - /// () The message to display on the console. + /// Extra Positional Arguments + /// ( of s) The message(s) to display on the console. /// /// /// line_end - /// (Optional, , , ) Line end character(s) to use instead of \n. + /// (Optional, ) Line end character(s) to use instead of \n. + /// + /// + /// separator + /// (Optional, ) separator to separate each message to be printed. /// /// /// @@ -32,29 +38,56 @@ public static class EzrBuiltinFunctions /// ///
/// ezr² errors: - /// if "line_end" is not one of the specified types. + /// if no messages provided.
+ /// if "line_end" is not one of the specified types.
+ /// if "separator" is not one of the specified types. /// /// The constructor arguments. - [SharpMethodWrapper("show", RequiredParameters = ["message"], OptionalParameters = ["line_end"])] + [SharpMethodWrapper("show", HasExtraPositionalArguments = true, OptionalParameters = ["line_end", "separator"])] public static void Show(SharpMethodParameters arguments) { RuntimeResult result = arguments.Result; - Reference messageReference = arguments.ArgumentReferences["message"]; + List messageReferences = arguments.ExtraPositionalArgumentReferences!; - string message = messageReference.Object.ToPureString(result); - if (result.ShouldReturn) + if (messageReferences.Count == 0) + { + result.Failure(new EzrMissingRequiredArgumentError("At least one message must be provided!", arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition)); return; + } + + string separator = string.Empty; + if (arguments.ArgumentReferences.TryGetValue("separator", out Reference? separatorReference)) + { + IEzrObject separatorObject = separatorReference.Object; + if (separatorObject is IEzrString separatorString) + separator = separatorString.StringValue; + else + { + result.Failure(new EzrUnexpectedTypeError($"Expected separator of type string, character or character list, but got object of type \"{separatorObject.TypeName}\"", arguments.ExecutionContext, separatorObject.StartPosition, separatorObject.EndPosition)); + return; + } + } + + StringBuilder messageBuilder = new(); + int messagesCount = messageReferences.Count; + + for (int i = 0; i < messagesCount; i++) + { + string messagePart = messageReferences[i].Object.ToPureString(result); + if (result.ShouldReturn) + return; + + messageBuilder.Append(messagePart); + if (i < messagesCount - 1) + messageBuilder.Append(separator); + } string lineEnd = Environment.NewLine; if (arguments.ArgumentReferences.TryGetValue("line_end", out Reference? lineEndReference)) { IEzrObject lineEndObject = lineEndReference.Object; - if (lineEndObject is EzrString lineEndString) - lineEnd = lineEndString.Value; - else if (lineEndObject is EzrCharacter lineEndCharacter) - lineEnd = lineEndCharacter.Value.ToString(); - else if (lineEndObject is EzrCharacterList lineEndCharacterList) - lineEnd = lineEndCharacterList.StringValue; + if (lineEndObject is IEzrString lineEndString) + lineEnd = lineEndString.StringValue; else { result.Failure(new EzrUnexpectedTypeError($"Expected line ending of type string, character or character list, but got object of type \"{lineEndObject.TypeName}\"", arguments.ExecutionContext, lineEndObject.StartPosition, lineEndObject.EndPosition)); @@ -62,7 +95,7 @@ public static void Show(SharpMethodParameters arguments) } } - Console.Write($"{message}{lineEnd}"); + Console.Write(messageBuilder.Append(lineEnd).ToString()); result.Success(ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant)); } diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs index d38d43d..dffa865 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs @@ -1,4 +1,6 @@ -using EzrSquared.Runtime.Types.Core.Errors; +global using WrapperArgumentPopulationResult = (System.Collections.Generic.Dictionary Arguments, System.Collections.Generic.List? ExtraPositionalArguments); + +using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Util; using System; using System.Collections.Generic; @@ -28,7 +30,12 @@ public abstract class EzrSharpSourceExecutableWrapper(Context parentContext, Pos /// /// Does the executable accept extra keyword arguments? /// - public bool HasKeywordArguments; + public bool HasExtraKeywordArguments; + + /// + /// Does the executable accept extra positional arguments? + /// + public bool HasExtraPositionalArguments; /// /// Converts a string from PascalCase to lowecase plain text, seperated by spaces. @@ -58,13 +65,21 @@ internal protected static string PascalCaseToLowerCasePlainText(string text) /// The array of arguments. /// Runtime result for carrying any errors. /// The dictionary of all the arguments. - protected internal Dictionary CheckAndPopulateArguments(Reference[] arguments, RuntimeResult result) + protected internal WrapperArgumentPopulationResult CheckAndPopulateArguments(Reference[] arguments, RuntimeResult result) { + int totalRequiredArguments = 0; + foreach ((string Name, bool IsRequired) in Parameters) + { + if (IsRequired) + totalRequiredArguments++; + } + int calculatedParameterIndex = 0; int requiredKeywordArguments = 0; int flaggedRequiredArguments = -1; Dictionary argumentReferences = new(arguments.Length); + List? extraPositionalArgumentReferences = HasExtraPositionalArguments ? new() : null; for (int i = 0; i < arguments.Length; i++) { @@ -78,21 +93,16 @@ protected internal Dictionary CheckAndPopulateArguments(Refer if (argumentReferences.ContainsKey(name)) { result.Failure(new EzrIllegalOperationError($"Cannot override already defined argument \"{name}\"!", _executionContext, reference.Object.StartPosition, reference.Object.EndPosition)); - return argumentReferences; + return (argumentReferences, extraPositionalArgumentReferences); } - bool found = Array.Find(Parameters, (v) => - { - parameterIndex++; - return v.Name == name; - }) != default; - - if (found) + parameterIndex = Array.FindIndex(Parameters, (param) => param.Name == name); + if (parameterIndex > -1) { argumentReferences.Add(name, reference); requiredKeywordArguments++; } - else if (HasKeywordArguments) + else if (HasExtraKeywordArguments) { argumentReferences.Add(name, reference); parameterIndex = -1; @@ -100,13 +110,13 @@ protected internal Dictionary CheckAndPopulateArguments(Refer else { result.Failure(new EzrUnexpectedArgumentError($"Did not expect argument \"{name}\"!", _executionContext, reference.Object.StartPosition, reference.Object.EndPosition)); - return argumentReferences; + return (argumentReferences, extraPositionalArgumentReferences); } } else { IndexCheck: - if (Parameters.Length <= calculatedParameterIndex) + if (Parameters.Length <= calculatedParameterIndex && !HasExtraPositionalArguments) { result.Failure(new EzrUnexpectedArgumentError( requiredKeywordArguments > 0 @@ -115,6 +125,11 @@ protected internal Dictionary CheckAndPopulateArguments(Refer _executionContext, StartPosition, EndPosition)); break; } + else if (totalRequiredArguments <= calculatedParameterIndex && HasExtraPositionalArguments) + { + extraPositionalArgumentReferences!.Add(reference); + continue; + } string argumentName = Parameters[calculatedParameterIndex].Name; if (!argumentReferences.ContainsKey(argumentName)) @@ -145,11 +160,11 @@ protected internal Dictionary CheckAndPopulateArguments(Refer if (Parameters[i].IsRequired && (flaggedRequiredArguments < 0 || (flaggedRequiredArguments & parameterFlag) != parameterFlag)) { result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{Parameters[i].Name}\"!", _executionContext, StartPosition, EndPosition)); - return argumentReferences; + return (argumentReferences, extraPositionalArgumentReferences); } } - return argumentReferences; + return (argumentReferences, extraPositionalArgumentReferences); } /// diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs index 6cf23f2..3b0deb7 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs @@ -79,7 +79,7 @@ public EzrSharpSourceFieldWrapper(FieldInfo fieldInfo, object? instance, Context /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { - Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); + Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result).Arguments; if (result.ShouldReturn) return; diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs index 01a7548..9da1406 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs @@ -97,19 +97,21 @@ private void AddParameters(SharpMethodWrapperAttribute attribute) for (int j = 0; j < attribute.OptionalParameters.Length; j++) Parameters[j + requiredParameters] = new(attribute.OptionalParameters[j], false); - HasKeywordArguments = attribute.HasKeywordArguments; + HasExtraKeywordArguments = attribute.HasExtraKeywordArguments; + HasExtraPositionalArguments = attribute.HasExtraPositionalArguments; } /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { - Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); + WrapperArgumentPopulationResult argumentReferences = CheckAndPopulateArguments(arguments, result); if (result.ShouldReturn) return; SharpFunction.Invoke(new SharpMethodParameters ( - argumentReferences, + argumentReferences.Arguments, + argumentReferences.ExtraPositionalArguments, _executionContext, CreationContext, Context, diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs index 837429a..ae90a33 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs @@ -74,7 +74,7 @@ public EzrSharpSourcePropertyWrapper(PropertyInfo propertyInfo, object? instance /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { - Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); + Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result).Arguments; if (result.ShouldReturn) return; diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index 1f0fd7d..af90862 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -100,7 +100,8 @@ public EzrSharpSourceTypeWrapper( Parameters[j + requiredParameters] = new(constructor.Value.Attribute.OptionalParameters[j], false); // Set variables. - HasKeywordArguments = constructor.Value.Attribute.HasKeywordArguments; + HasExtraKeywordArguments = constructor.Value.Attribute.HasExtraKeywordArguments; + HasExtraPositionalArguments = constructor.Value.Attribute.HasExtraPositionalArguments; Constructor = constructor.Value.Info; // Get static methods to wrap. @@ -238,7 +239,7 @@ public EzrSharpSourceTypeWrapper( /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { - Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result); + WrapperArgumentPopulationResult argumentReferences = CheckAndPopulateArguments(arguments, result); if (result.ShouldReturn) return; @@ -246,7 +247,8 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run [ new SharpMethodParameters ( - argumentReferences, + argumentReferences.Arguments, + argumentReferences.ExtraPositionalArguments, _executionContext, CreationContext, Context, diff --git a/src/Runtime/WrapperAttributes/SharpMethodParameters.cs b/src/Runtime/WrapperAttributes/SharpMethodParameters.cs index 0d2e28d..07e48be 100644 --- a/src/Runtime/WrapperAttributes/SharpMethodParameters.cs +++ b/src/Runtime/WrapperAttributes/SharpMethodParameters.cs @@ -6,6 +6,7 @@ namespace EzrSquared.Runtime.WrapperAttributes; /// Class for the paramters of a wrapped C# method. /// /// See . +/// See . /// See . /// See . /// See . @@ -15,6 +16,7 @@ namespace EzrSquared.Runtime.WrapperAttributes; /// See . public class SharpMethodParameters( Dictionary argumentReferences, + List? extraPositionalArgumentReferences, Context executionContext, Context creationContext, Context methodContext, @@ -28,6 +30,11 @@ public class SharpMethodParameters( ///
public Dictionary ArgumentReferences = argumentReferences; + /// + /// The references to optional extra positional ezr² arguments. + /// + public List? ExtraPositionalArgumentReferences = extraPositionalArgumentReferences; + /// /// The context under which the method is being executed. /// diff --git a/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs index 0d33e1a..79898ff 100644 --- a/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs @@ -29,7 +29,12 @@ public class SharpMethodWrapperAttribute : Attribute /// /// Does this method support additional keyword arguments (kwargs)? /// - public bool HasKeywordArguments; + public bool HasExtraKeywordArguments; + + /// + /// Does this method support additional positional arguments (args)? + /// + public bool HasExtraPositionalArguments; /// /// Creates a new instance of with a name. From 091f30a26d8e8cb66d604777d2fca20c800f920c Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 1 Nov 2024 01:03:32 +0530 Subject: [PATCH 051/113] =?UTF-8?q?ezr=C2=B2=20v0.7.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 4 ++++ src/EzrSquared.csproj | 2 +- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index c52558d..aa6f340 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,10 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.7.0 [01-11-24] + * Added slightly jank implementation of EKAs for C# source wrappers. + * Improved "show" function with multiple message input and new optional "separator" parameter. + * ezr² RE - v0.6.0 [31-10-24] * [BREAKING CHANGE] EKAs (Extra Keyword Arguments) now use the following syntax: "function abc with more named as keyword_args do ..." * Added EPA (Extra Positional Arguments) support! You can define them like so: "function abc with more as epas do ...". Here, "epas" will be an `EzrList` of the extra arguments. diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 7f289cd..3c737b1 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.6.0 + 0.7.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 9727361..0905463 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.6.0"; + private const string Version = "0.7.0"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 7825328..d8b84b8 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.6.0" +#define MyAppVersion "0.7.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 79e9eb7..45157ab 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.6.0" +#define MyAppVersion "0.7.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 21ff33c..582043c 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.6.0 + 0.7.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From 5fe8679ef1958a6f5b5678b43d0f2406ea008993 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 1 Nov 2024 01:51:41 +0530 Subject: [PATCH 052/113] Code analysis and formatting fixes. --- .../CSharpWrappers/Builtins/EzrBuiltinFunctions.cs | 2 +- .../CompatWrappers/EzrSharpCompatibilityType.cs | 2 +- .../CompatWrappers/EzrSharpCompatibilityWrapper.cs | 4 ++-- .../Executables/EzrSharpCompatibilityExecutable.cs | 2 +- .../SourceWrappers/EzrSharpSourceFunctionWrapper.cs | 7 +++---- .../SourceWrappers/EzrSharpSourceTypeWrapper.cs | 3 +-- .../Core/RuntimeErrors/EzrIllegalOperationError.cs | 3 ++- .../Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs | 3 ++- src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs | 3 ++- .../RuntimeErrors/EzrMissingRequiredArgumentError.cs | 3 ++- .../RuntimeErrors/EzrPrivateMemberOperationError.cs | 3 ++- .../Types/Core/RuntimeErrors/EzrRuntimeError.cs | 3 ++- .../Types/Core/RuntimeErrors/EzrUndefinedValueError.cs | 3 ++- .../Core/RuntimeErrors/EzrUnexpectedArgumentError.cs | 3 ++- .../Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs | 3 ++- .../Core/RuntimeErrors/EzrUnsupportedWrappingError.cs | 3 ++- .../Core/RuntimeErrors/EzrValueOutOfRangeError.cs | 3 ++- .../Core/RuntimeErrors/EzrWrapperExecutionError.cs | 3 ++- src/Runtime/Types/Executables/EzrRuntimeExecutable.cs | 10 +++++----- .../SharpAutoCompatibilityWrapperAttribute.cs | 2 +- .../WrapperAttributes/SharpTypeWrapperAttribute.cs | 2 +- 21 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs index a7bef0a..2dbedf0 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs @@ -37,7 +37,7 @@ public static class EzrBuiltinFunctions /// ezr² return type: /// ///
- /// ezr² errors: + /// ezr² errors:
/// if no messages provided.
/// if "line_end" is not one of the specified types.
/// if "separator" is not one of the specified types. diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index f279e4d..e391673 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -24,7 +24,7 @@ public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper /// The type to wrap. ///
public readonly Type SharpType; - + /// /// The name of the type to wrap, in ezr² format (snake_case). /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 64a54d6..a975cfc 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -267,10 +267,10 @@ TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArgu /// The converted . protected internal void PrimitiveToEzrObject( object? value, - + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type? valueType, - + RuntimeResult result) { if (value is null || valueType is null) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index c1a91cd..40bd0ac 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -55,7 +55,7 @@ public EzrSharpCompatibilityExecutable(string name, MethodBase sharpMember, obje { SharpRuntimeExecutableName = name; Tag = $"{Tag}.{SharpRuntimeExecutableName}.{Utils.GetNextUniqueId()}"; - + Executable = sharpMember; Parameters = Executable.GetParameters(); ParameterNames = Array.ConvertAll(Parameters, p => Utils.PascalToSnakeCase(p.Name ?? string.Empty)); diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs index 9da1406..adeba05 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs @@ -1,7 +1,6 @@ using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; -using System.Collections.Generic; using System.Reflection; namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; @@ -42,7 +41,7 @@ public EzrSharpSourceFunctionWrapper(MethodInfo function, Context parentContext, SharpFunction = (EzrSharpSourceWrappableMethod)function.CreateDelegate(typeof(EzrSharpSourceWrappableMethod)); (SharpFunctionName, SharpMethodWrapperAttribute attribute) = GetFunctionInfo(function); - + AddParameters(attribute); } @@ -74,10 +73,10 @@ public EzrSharpSourceFunctionWrapper(EzrSharpSourceWrappableMethod function, Con { SharpMethodWrapperAttribute attribute = function.GetCustomAttribute(true) ?? throw new ArgumentException($"No \"{nameof(SharpMethodWrapperAttribute)}\" attribute found in function \"{function.Name}\"!", nameof(function)); - + if (string.IsNullOrEmpty(attribute.Name)) throw new ArgumentException($"Name not provided in {nameof(SharpMethodWrapperAttribute)} of function \"{function.Name}\"!", nameof(function)); - + Tag = $"{Tag}.{attribute.Name}.{Utils.GetNextUniqueId()}"; return (attribute.Name, attribute); } diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index af90862..d4c3fc0 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -3,7 +3,6 @@ using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -232,7 +231,7 @@ public EzrSharpSourceTypeWrapper( EzrSharpCompatibilityFunction wrapper = !string.IsNullOrEmpty(attribute.Name) ? new(attribute.Name, method, null, Context, StartPosition, EndPosition) : new(method, null, Context, StartPosition, EndPosition); - + return (wrapper, wrapper.SharpRuntimeExecutableName); } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs index 809a9cb..e43db1d 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs @@ -28,5 +28,6 @@ public EzrIllegalOperationError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs index f6c9452..303691d 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs @@ -28,5 +28,6 @@ public EzrKeyNotFoundError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs index f3696aa..1772dc2 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs @@ -30,5 +30,6 @@ public EzrMathError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs index b825b77..c2be2b9 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs @@ -28,5 +28,6 @@ public EzrMissingRequiredArgumentError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs index a832e27..a49ec2e 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs @@ -28,5 +28,6 @@ public EzrPrivateMemberOperationError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs index 3267bb8..8587ce8 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs @@ -65,7 +65,8 @@ public EzrRuntimeError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } /// /// Converts the given argument to a string. diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs index a45c301..60f6dc6 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs @@ -28,5 +28,6 @@ public EzrUndefinedValueError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs index ff39a8a..ed00270 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs @@ -28,5 +28,6 @@ public EzrUnexpectedArgumentError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs index b850961..71fc49f 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs @@ -28,5 +28,6 @@ public EzrUnexpectedTypeError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs index 8654d43..458e573 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs @@ -28,5 +28,6 @@ public EzrUnsupportedWrappingError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs index b048698..829e5e8 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs @@ -28,5 +28,6 @@ public EzrValueOutOfRangeError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs index 6782d40..811fbc3 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs @@ -28,5 +28,6 @@ public EzrWrapperExecutionError(SharpMethodParameters arguments) : this( arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition - ) { } + ) + { } } diff --git a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs index c97fbab..f72381a 100644 --- a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs +++ b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs @@ -156,7 +156,7 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context ? $"Did not expect argument \"{parameterName}\", as it is already specified!" : "Did not expect any more positional arguments!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); - + return; } @@ -173,11 +173,11 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context for (int i = currentIndexThroughParameters; i < Parameters.Length; i++) { (string parameterName, Node parameterCode) = Parameters[i]; - + // Check if it is defined as a kwarg: if (context.IsDefined(parameterName)) continue; // If so, continue to the next. - + // The accessibility modifiers for the execution. AccessMod operationAccessibilityModifiers = AccessMod.None; if (parameterCode is VariableAccessNode vaNode) @@ -191,7 +191,7 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context interpreter.VisitNode(parameterCode, context, null, operationAccessibilityModifiers, true); if (result.ShouldReturn) // Check for errors and return if necessary. return; - + // If the result is empty, i.e. there is no default value: if (result.Reference.IsEmpty) { @@ -199,7 +199,7 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{parameterName}\"!", _executionContext, StartPosition, EndPosition)); return; } - + // Otherwise, if it is still not defined due to strange assignment practises by the programmer: if (!context.IsDefined(parameterName)) context.Set(null, parameterName, ReferencePool.Get(result.Reference.Object, AccessMod.Private)); // Set it. diff --git a/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs index 06fafdd..a22eb8e 100644 --- a/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs @@ -56,7 +56,7 @@ public class SharpAutoCompatibilityWrapperAttribute : Attribute if (methodInfo.ReturnType != typeof(void) && !EzrSharpCompatibilityWrapper.IsSupportedReturnType(methodInfo.ReturnType)) return new($"Expected method \"{methodInfo.Name}\"'s return type to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\"", nameof(methodInfo)); - + foreach (ParameterInfo parameterInfo in methodInfo.GetParameters()) { if (!EzrSharpCompatibilityWrapper.IsSupportedPrimitiveType(parameterInfo.ParameterType)) diff --git a/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs index ff42e2e..89123e8 100644 --- a/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs @@ -26,7 +26,7 @@ public class SharpTypeWrapperAttribute(string name) : Attribute public static Exception? ValidateMethodParameters( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type typeInfo, - + out (ConstructorInfo Info, SharpMethodWrapperAttribute Attribute)? constructor) { constructor = null; From 6c800039cb216293fb273772946b98c50173b39d Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 1 Nov 2024 01:58:28 +0530 Subject: [PATCH 053/113] Updated docs for "show" function. --- .../Builtins/EzrBuiltinFunctions.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs index 2dbedf0..144999f 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs @@ -37,10 +37,17 @@ public static class EzrBuiltinFunctions /// ezr² return type: /// ///
- /// ezr² errors:
- /// if no messages provided.
- /// if "line_end" is not one of the specified types.
- /// if "separator" is not one of the specified types. + /// ezr² errors: + /// + /// + /// + /// Thrown if no messages are provided. + /// + /// + /// + /// Thrown if "line_end" or "separator" are not of the specified types. + /// + /// /// /// The constructor arguments. [SharpMethodWrapper("show", HasExtraPositionalArguments = true, OptionalParameters = ["line_end", "separator"])] From 1885fa9ac9903f085a95cc9318a533d705612869 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 1 Nov 2024 02:02:48 +0530 Subject: [PATCH 054/113] Fixed documentation reference. --- .../Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs index 144999f..9c8d3da 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs @@ -40,7 +40,7 @@ public static class EzrBuiltinFunctions /// ezr² errors: /// /// - /// + /// /// Thrown if no messages are provided. /// /// From 1c4b7056276b275cc6ce19fad00f20d550bf055d Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 1 Nov 2024 13:57:08 +0530 Subject: [PATCH 055/113] Added some built in functions for types. --- .../Collections/RuntimeEzrObjectDictionary.cs | 13 +++-- src/Runtime/Types/BaseTypes.cs | 33 +++++++++++ .../Builtins/EzrBuiltinFunctions.cs | 20 +++---- src/Runtime/Types/Collections/EzrArray.cs | 27 ++++++--- .../Types/Collections/EzrDictionary.cs | 58 +++++++++++++++++-- src/Runtime/Types/Collections/EzrList.cs | 23 ++++++-- .../Types/Core/Text/EzrCharacterList.cs | 26 +++++++-- src/Runtime/Types/Core/Text/EzrString.cs | 27 ++++++--- 8 files changed, 180 insertions(+), 47 deletions(-) diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index e9d0d2a..f21ffa6 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -1,4 +1,5 @@ using EzrSquared.Runtime.Types; +using EzrSquared.Runtime.WrapperAttributes; using System.Collections.Generic; namespace EzrSquared.Runtime.Collections; @@ -17,6 +18,12 @@ public class RuntimeEzrObjectDictionary : IMutable ///
private readonly IDictionary> _items; + /// + /// The number of s in the . + /// + [SharpAutoCompatibilityWrapper(IsReadOnly = true)] + public int Length => _items.Count; + /// /// Creates a new . /// @@ -33,11 +40,6 @@ public RuntimeEzrObjectDictionary(IDictionary - /// The number of s in the . - ///
- public int Length => _items.Count; - /// /// Updates the with a new value. /// @@ -101,6 +103,7 @@ public bool Remove(IEzrObject key, RuntimeResult result) ///
/// The key (hash) to be removed. /// if the operation was successful, if not. + [SharpAutoCompatibilityWrapper(Name = "remove_by_hash")] public bool RemoveHash(int key) { return _items.Remove(key); diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs index 1a012c1..0ecdf36 100644 --- a/src/Runtime/Types/BaseTypes.cs +++ b/src/Runtime/Types/BaseTypes.cs @@ -5,7 +5,10 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; +using System; +using System.Collections.Generic; using System.Numerics; +using System.Reflection; namespace EzrSquared.Runtime.Types; @@ -30,6 +33,36 @@ internal class EzrRuntimeInvalidObject : EzrObject /// public abstract class EzrObject : IEzrObject { + /// + /// Cache of reflection data for all types. + /// + internal static readonly Lazy> s_memberMap = new(); + + /// + /// Gets cached reflection data about a member of . + /// + /// + /// If there is no cached data, it gets it by reflection and caches the result. + /// + /// The type to return. + /// The type which the member is a part of. + /// The name of the member. + /// The cached member data or the first member with the given . if not found. + internal static TMemberInfo? GetMemberInfo(string name) where TMemberInfo : MemberInfo + { + (Type ParentType, string MemberName) key = (typeof(TParentType), name); + + if (s_memberMap.Value.TryGetValue(key, out MemberInfo? cachedMemberInfo)) + return (TMemberInfo)cachedMemberInfo; + + MemberInfo[] members = key.ParentType.GetMember(name); + if (members.Length == 0 || members[0] is not TMemberInfo memberInfo) + return default; + + s_memberMap.Value[key] = memberInfo; + return memberInfo; + } + /// public virtual string TypeName { get; protected internal set; } = string.Empty; diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs index 9c8d3da..f327877 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs @@ -49,7 +49,7 @@ public static class EzrBuiltinFunctions /// /// /// - /// The constructor arguments. + /// The method arguments. [SharpMethodWrapper("show", HasExtraPositionalArguments = true, OptionalParameters = ["line_end", "separator"])] public static void Show(SharpMethodParameters arguments) { @@ -130,7 +130,7 @@ public static void Show(SharpMethodParameters arguments) /// /// /// - /// The constructor arguments. + /// The method arguments. [SharpMethodWrapper("throw_error", RequiredParameters = ["error"])] public static void ThrowError(SharpMethodParameters arguments) { @@ -158,7 +158,7 @@ public static void ThrowError(SharpMethodParameters arguments) /// ezr² return type: /// /// - /// The constructor arguments. + /// The method arguments. [SharpMethodWrapper("get", OptionalParameters = ["message"])] public static void Get(SharpMethodParameters arguments) { @@ -182,7 +182,7 @@ public static void Get(SharpMethodParameters arguments) /// ezr² return type: /// /// - /// The constructor arguments. + /// The method arguments. [SharpMethodWrapper("clear")] public static void Clear(SharpMethodParameters arguments) { @@ -208,7 +208,7 @@ public static void Clear(SharpMethodParameters arguments) /// ezr² errors: /// if the condition is not met. /// - /// The constructor arguments. + /// The method arguments. [SharpMethodWrapper("assert", RequiredParameters = ["condition"])] public static void Assert(SharpMethodParameters arguments) { @@ -243,7 +243,7 @@ public static void Assert(SharpMethodParameters arguments) /// ezr² return type: /// /// - /// The constructor arguments. + /// The method arguments. [SharpMethodWrapper("hash", RequiredParameters = ["to_hash"])] public static void Hash(SharpMethodParameters arguments) { @@ -272,7 +272,7 @@ public static void Hash(SharpMethodParameters arguments) /// ezr² return type: /// /// - /// The constructor arguments. + /// The method arguments. [SharpMethodWrapper("type_of", RequiredParameters = ["to_check"])] public static void TypeOf(SharpMethodParameters arguments) { @@ -300,7 +300,7 @@ public static void TypeOf(SharpMethodParameters arguments) /// ezr² return type: /// /// - /// The constructor arguments. + /// The method arguments. [SharpMethodWrapper("type_name_of", RequiredParameters = ["to_check"])] public static void TypeNameOf(SharpMethodParameters arguments) { @@ -328,7 +328,7 @@ public static void TypeNameOf(SharpMethodParameters arguments) /// ezr² return type: /// /// - /// The constructor arguments. + /// The method arguments. [SharpMethodWrapper("type_hash_of", RequiredParameters = ["to_check"])] public static void TypeHashOf(SharpMethodParameters arguments) { @@ -359,7 +359,7 @@ public static void TypeHashOf(SharpMethodParameters arguments) /// ezr² errors: /// if "to_copy" is not of the expected type. /// - /// The constructor arguments. + /// The method arguments. [SharpMethodWrapper("copy", RequiredParameters = ["to_copy"])] public static void Copy(SharpMethodParameters arguments) { diff --git a/src/Runtime/Types/Collections/EzrArray.cs b/src/Runtime/Types/Collections/EzrArray.cs index 011d6d5..67b5983 100644 --- a/src/Runtime/Types/Collections/EzrArray.cs +++ b/src/Runtime/Types/Collections/EzrArray.cs @@ -1,20 +1,18 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using System; using System.Collections; using System.Collections.Generic; using System.Numerics; +using System.Reflection; namespace EzrSquared.Runtime.Types.Collections; /// /// The immutable, array type object. /// -/// The base value. -/// The parent context. -/// The starting position of the object. -/// The ending position of the object. -public class EzrArray(IEzrObject[] elements, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrIndexedCollection +public class EzrArray : EzrObject, IEzrIndexedCollection { /// public override string TypeName { get; protected internal set; } = "array"; @@ -25,10 +23,25 @@ public class EzrArray(IEzrObject[] elements, Context parentContext, Position sta /// /// The array value. /// - public readonly IEzrObject[] Value = elements; + public readonly IEzrObject[] Value; /// - public int Length => Value.Length; + public int Length { get; } + + /// + /// Creates a new . + /// + /// The base value. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrArray(IEzrObject[] elements, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + Value = elements; + Length = elements.Length; + + Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Length))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + } /// /// Compares the current array with another collection. diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index 95049a6..44b1fb0 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -1,19 +1,21 @@ using EzrSquared.Runtime.Collections; +using EzrSquared.Runtime.Types.Core; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +using EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; +using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections.Generic; +using System.Reflection; namespace EzrSquared.Runtime.Types.Collections; /// /// The mutable dictionary type object. /// -/// The base value. -/// The parent context. -/// The starting position of the object. -/// The ending position of the object. -public class EzrDictionary(RuntimeEzrObjectDictionary value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrMutableObject +public class EzrDictionary : EzrObject, IEzrMutableObject { /// public override string TypeName { get; protected internal set; } = "dictionary"; @@ -24,7 +26,51 @@ public class EzrDictionary(RuntimeEzrObjectDictionary value, Context parentConte /// /// The dictionary value. /// - public readonly RuntimeEzrObjectDictionary Value = value; + public readonly RuntimeEzrObjectDictionary Value; + + /// + /// Creates a new . + /// + /// The base value. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrDictionary(RuntimeEzrObjectDictionary value, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + Value = value; + + Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Value.Length))!, Value, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "remove_by_hash", ReferencePool.Get(new EzrSharpCompatibilityFunction(GetMemberInfo(nameof(Value.RemoveHash))!, Value, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "has_key", ReferencePool.Get(new EzrSharpSourceFunctionWrapper(DictionaryExists, Context, StartPosition, EndPosition), AccessMod.Constant)); + } + + /// + /// Basic key checking function. Implements . + /// + /// + /// ezr² parameters: + /// + /// + /// key + /// () The key to check for. + /// + /// + /// + /// ezr² return type: + /// + /// + /// The constructor arguments. + [SharpMethodWrapper("has_key", RequiredParameters = ["key"])] + private void DictionaryExists(SharpMethodParameters arguments) + { + Reference reference = arguments.ArgumentReferences["key"]; + + bool hasKey = Value.HasKey(reference.Object, arguments.Result); + if (arguments.Result.ShouldReturn) + return; + + arguments.Result.Success(ReferencePool.Get(hasKey ? EzrConstants.True : EzrConstants.False, AccessMod.PrivateConstant)); + } /// public override void ComparisonEqual(IEzrObject other, RuntimeResult result) diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index e7dd3a1..eb5d577 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -1,21 +1,20 @@ using EzrSquared.Runtime.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections; using System.Collections.Generic; using System.Numerics; +using System.Reflection; namespace EzrSquared.Runtime.Types.Collections; /// /// The mutable, list type object. /// -/// The base value. -/// The parent context. -/// The starting position of the object. -/// The ending position of the object. -public class EzrList(RuntimeEzrObjectList elements, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrMutableObject, IEzrIndexedCollection +public class EzrList : EzrObject, IEzrMutableObject, IEzrIndexedCollection { /// public override string TypeName { get; protected internal set; } = "list"; @@ -26,11 +25,23 @@ public class EzrList(RuntimeEzrObjectList elements, Context parentContext, Posit /// /// The list value. /// - public readonly RuntimeEzrObjectList Value = elements; + public readonly RuntimeEzrObjectList Value; /// + [SharpAutoCompatibilityWrapper(IsReadOnly = true)] public int Length => Value.Count; + /// The base value. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrList(RuntimeEzrObjectList elements, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + Value = elements; + + Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Length))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + } + /// /// Compares the current list with another collection. /// diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index 9cc81a3..8d1b343 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -1,10 +1,13 @@ using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections; using System.Collections.Generic; using System.Numerics; +using System.Reflection; using System.Text; namespace EzrSquared.Runtime.Types.Core.Text; @@ -12,11 +15,7 @@ namespace EzrSquared.Runtime.Types.Core.Text; /// /// The type object. /// -/// The base string value. -/// The parent context. -/// The starting position of the object. -/// The ending position of the object. -public class EzrCharacterList(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrMutableObject, IEzrString, IEzrIndexedCollection +public class EzrCharacterList : EzrObject, IEzrMutableObject, IEzrString, IEzrIndexedCollection { /// public override string TypeName { get; protected internal set; } = "character list"; @@ -27,7 +26,7 @@ public class EzrCharacterList(string value, Context parentContext, Position star /// /// The value. /// - public readonly StringBuilder Value = new(value); + public readonly StringBuilder Value; /// /// Calls and returns the value converted to a . @@ -35,8 +34,23 @@ public class EzrCharacterList(string value, Context parentContext, Position star public string StringValue => Value.ToString(); /// + [SharpAutoCompatibilityWrapper(IsReadOnly = true)] public int Length => Value.Length; + /// + /// Creates a new . + /// + /// The base string value. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrCharacterList(string value, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + Value = new(value); + + Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Length))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + } + /// /// Compares the current character list with another collection. /// diff --git a/src/Runtime/Types/Core/Text/EzrString.cs b/src/Runtime/Types/Core/Text/EzrString.cs index 81f7ecc..62bee3e 100644 --- a/src/Runtime/Types/Core/Text/EzrString.cs +++ b/src/Runtime/Types/Core/Text/EzrString.cs @@ -1,10 +1,12 @@ using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using System; using System.Collections; using System.Collections.Generic; using System.Numerics; +using System.Reflection; using System.Text; namespace EzrSquared.Runtime.Types.Core.Text; @@ -12,11 +14,7 @@ namespace EzrSquared.Runtime.Types.Core.Text; /// /// The string type object. /// -/// The base value. -/// The parent context. -/// The starting position of the object. -/// The ending position of the object. -public class EzrString(string value, Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition), IEzrString, IEzrIndexedCollection +public class EzrString : EzrObject, IEzrString, IEzrIndexedCollection { /// public override string TypeName { get; protected internal set; } = "string"; @@ -27,13 +25,28 @@ public class EzrString(string value, Context parentContext, Position startPositi /// /// The string value. /// - public readonly string Value = value; + public readonly string Value; /// public string StringValue => Value; /// - public int Length => Value.Length; + public int Length { get; } + + /// + /// Creates a new . + /// + /// The base value. + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrString(string value, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + Value = value; + Length = value.Length; + + Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Length))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + } /// /// Compares the current string with another collection. From 121833703aa1955541cc2e41d5e86854c868133d Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 1 Nov 2024 14:42:27 +0530 Subject: [PATCH 056/113] =?UTF-8?q?ezr=C2=B2=20v0.8.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/EzrSquared.csproj | 12 +++++++----- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 3c737b1..1b8fc4d 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -17,7 +17,7 @@ True True - true + True @@ -27,8 +27,8 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - - 0.7.0 + + 0.8.0-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED @@ -38,11 +38,13 @@ LICENSE.txt README.md + https://uralstech.github.io/ezrSquared/ programming language;portable;embeddable;compact;interpreted - ..\Binaries\ezrSquared\Package + See https://github.com/Uralstech/ezrSquared/releases. https://github.com/uralstech/ezrSquared + ezrSquared-re Icon (256x256).png @@ -70,7 +72,7 @@ - true + True MULTI_TARGETING_SUPPORT_ATTRIBUTES diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 0905463..c897cbe 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.7.0"; + private const string Version = "0.8.0"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index d8b84b8..cf4777b 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.7.0" +#define MyAppVersion "0.8.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 45157ab..2deef02 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.7.0" +#define MyAppVersion "0.8.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 582043c..a09574c 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.7.0 + 0.8.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From bd5a21b5997698d64ea5cca78b57756b7da3b0e8 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 1 Nov 2024 14:48:47 +0530 Subject: [PATCH 057/113] Updated README.md. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 70ecfe1..57e3428 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ More information, documentation and the reference manual for ezr² is available at ******! +ezr² is now up on NuGet! Check it out [***here!***](https://www.nuget.org/packages/ezrSquared/) + ## What's the 'ezrSquared-re' branch? ezr² is being rewritten from the ground up! Expect more features, better performance and better code documentation! From 97c2833f9266c6199682ab0710898b761a7626d7 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 1 Nov 2024 14:53:28 +0530 Subject: [PATCH 058/113] Updated changelog --- Changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.txt b/Changelog.txt index aa6f340..bcdbc24 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,9 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.8.0 [01-11-24] + * Added built-ins for `EzrString`, `EzrArray`, `EzrList`, `EzrDictionary` and `EzrCharacterList`. + * ezr² RE - v0.7.0 [01-11-24] * Added slightly jank implementation of EKAs for C# source wrappers. * Improved "show" function with multiple message input and new optional "separator" parameter. From b6946acfb406e85a92685773a4e05af79a530e5d Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 1 Nov 2024 15:51:25 +0530 Subject: [PATCH 059/113] =?UTF-8?q?ezr=C2=B2=20v0.8.1=20-=20Fixed=20shell?= =?UTF-8?q?=20printouts.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 5 ++++- README.md | 8 ++++---- src/EzrSquared.csproj | 2 +- src/Shell/EzrShell.cs | 4 ++-- src/Shell/EzrShellConsoleHelper.cs | 14 +++++++------- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 8 files changed, 21 insertions(+), 18 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index bcdbc24..ad75537 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,8 +3,11 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.8.1 [01-11-24] + * Fixed shell printouts. + * ezr² RE - v0.8.0 [01-11-24] - * Added built-ins for `EzrString`, `EzrArray`, `EzrList`, `EzrDictionary` and `EzrCharacterList`. + * Added some built-ins for `EzrString`, `EzrArray`, `EzrList`, `EzrDictionary` and `EzrCharacterList`. * ezr² RE - v0.7.0 [01-11-24] * Added slightly jank implementation of EKAs for C# source wrappers. diff --git a/README.md b/README.md index 57e3428..bc8840c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# The `ezr²` Programming Language -**ezr², or ezrSquared when you can't use the `²` symbol (or it's too inconvenient) - is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#!** +# The ezr² Programming Language +[![ezr² on NuGet](https://img.shields.io/nuget/v/ezrSquared?label=NuGet)](https://www.nuget.org/packages/ezrSquared) -More information, documentation and the reference manual for ezr² is available at ******! +**ezr², or ezrSquared when you can't use the ² symbol (or it's too inconvenient) - is an easy to learn and practical interpreted programming language for beginners and experts alike made in C#!** -ezr² is now up on NuGet! Check it out [***here!***](https://www.nuget.org/packages/ezrSquared/) +More information, documentation and the reference manual for ezr² is available at ******! ## What's the 'ezrSquared-re' branch? ezr² is being rewritten from the ground up! Expect more features, better performance and better code documentation! diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 1b8fc4d..e324df6 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.8.0-unstable + 0.8.1-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index c897cbe..e7ec3c5 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.8.0"; + private const string Version = "0.8.1"; private static bool s_showLexerOutput; private static bool s_showParserOutput; @@ -107,7 +107,7 @@ private static void ExecuteFile() private static void InteractiveMode() { - if (Console.WindowWidth > 100) + if (Console.WindowWidth > 110) EzrShellConsoleHelper.PrintBigConsoleGraphics(Version); else EzrShellConsoleHelper.PrintSmallConsoleGraphics(Version); diff --git a/src/Shell/EzrShellConsoleHelper.cs b/src/Shell/EzrShellConsoleHelper.cs index e272d86..84f6134 100644 --- a/src/Shell/EzrShellConsoleHelper.cs +++ b/src/Shell/EzrShellConsoleHelper.cs @@ -7,7 +7,7 @@ internal static class EzrShellConsoleHelper private const string ConsoleGraphicsInfo = """ ▋ ezr² v{0} ▋ Online documentation: - ▋ https://uralstech.github.io/ezrSquared/Introduction.html + ▋ https://uralstech.github.io/ezrSquared/docsrc/Learn-ezrSquared.html ▋ Feature requests and bug reports: ▋ https://github.com/Uralstech/ezrSquared/issues ▋ GitHub repository: @@ -70,10 +70,10 @@ internal static void PrintSmallConsoleGraphics(string version) { Console.Clear(); - ShowMessage("e", ConsoleColor.Green, true); - ShowMessage("z", ConsoleColor.Red); - ShowMessage("r", ConsoleColor.Blue); - ShowMessage("²", ConsoleColor.Yellow); + ShowMessage("e", ConsoleColor.Green, true, newLine: string.Empty); + ShowMessage("z", ConsoleColor.Red, newLine: string.Empty); + ShowMessage("r", ConsoleColor.Blue, newLine: string.Empty); + ShowMessage("²", ConsoleColor.Yellow, newLine: string.Empty); ShowMessage($" v{version}", ConsoleColor.White); } @@ -119,13 +119,13 @@ internal static void WaitForUser() Console.ReadKey(); } - private static void ShowMessage(string message, ConsoleColor color, bool resetPosition = false) + private static void ShowMessage(string message, ConsoleColor color, bool resetPosition = false, string? newLine = null) { if (resetPosition) Console.SetCursorPosition(0, 0); Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = color; - Console.WriteLine(message); + Console.Write(message + (newLine ?? Environment.NewLine)); } } diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index cf4777b..6723e94 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.0" +#define MyAppVersion "0.8.1" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 2deef02..f1cbf53 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.0" +#define MyAppVersion "0.8.1" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index a09574c..68bc241 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.8.0 + 0.8.1 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From d161fb80b8295c856cc9f30e231dc9483290cfda Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 2 Nov 2024 14:44:40 +0530 Subject: [PATCH 060/113] Updated index. --- docs/index.md | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/docs/index.md b/docs/index.md index 462190f..1fd7c82 100644 --- a/docs/index.md +++ b/docs/index.md @@ -19,7 +19,7 @@ For more information, check out the [*learn ezr² page*](docsrc/Learn-ezrSquared > ezr² is still in development, and with [ezr² ***REwrite***](https://github.com/Uralstech/ezrSquared/tree/ezrSquared-re) on the horizon, > there will be some breaking changes in syntax in upcoming versions. -To install ezr² on your PC, follow the steps for your Operating System: +To install ezr², follow the steps for your Operating System: # [Windows](#tab/windows) @@ -49,7 +49,7 @@ If you are interested in how ezr² was embedded to the portable interpreter (a U # [Other](#tab/other) -For other OSes you can clone the [***repository***](https://github.com/Uralstech/ezrSquared/), and compile your own build. If you're a contributor, feel free to add the build to the latest release. +For other OSes you can clone the [***repository***](https://github.com/Uralstech/ezrSquared/), and compile your own build. --- @@ -71,24 +71,35 @@ The documentation is packaged with the Windows installer. For other OSes, downlo [![ezr² Pre-release v1.5.1.3.0 Offline Documentation](https://img.shields.io/badge/ezr%C2%B2_Pre--release_v1.5.1.3.0_Offline_Documentation-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/prereleaseV1.5.1.3.0/ezrSquared.Offline.Documentation.zip) -## Latest Updates +## ezr² RE -More frequent development updates will be posted on [***my blog***](https://uralstech.github.io/). +ezr² is being rewritten, with better performance, more features and better compatibility with existing C# libraries! -### New website +ezr² RE still has a lot missing features, like the `include` expression and many built in type extension methods like `["list"].insert('2', 0)`. +It is also very unstable, and the API and syntax may change in updates. So, it is not recommended to use ezr² RE for scripting. If you want to try it +out, you can download it from the [***releases page on GitHub***](https://github.com/Uralstech/ezrSquared/releases/), or, from here: -The website has been updated! Now, this website also contains the reference documentation! Please note that the reference documentation is only for ezr² ***RE***, not for older versions. +# [Windows](#tab/windows) + +* Download the appropriate installer. +* Run the installer and go through the installation. +
+ +[![ezr² RE v0.8.1 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.1_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.1/ezrSquared.Shell.Setup.Win64.exe) +[![ezr² RE v0.8.1 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.1_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.1/ezrSquared.Shell.Setup.Win32.exe) + +# [NuGet](#tab/nuget) -### ezr² ***RE*** Release +You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! -The latest version of ezr² ***RE*** has been released! ezr² ***RE***, or ***REwrite***, is the project's initiative to rewrite ezr². The latest working version of ezr² ***RE*** -has many more features than the latest version of ezr²! But, it is still in development, has some essential features missing. Like the `include` expression, or any built-in object -methods like `"a string".length` or `["a", "list"].insert`. If you want to help in testing it out and fixing bugs, feel free to download the latest version of ezr² ***RE*** from -the ezr² GitHub releases page and compiling it using the .NET SDK and/or Visual Studio. +[![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) +[![ezr² RE v0.8.1 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.1_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.1/ezrSquared.0.8.1-unstable.nupkg) -### New Versioning Format +# [Other](#tab/other) -ezr² now uses [***Semantic Versioning 2.0.0***](https://semver.org/) for new releases. +For other OSes you can clone the [***branch***](https://github.com/Uralstech/ezrSquared/tree/ezrSquared-re), and compile your own build. + +--- ## Contributing From 0329402e233b2c941e6ffca4c99126fc96efc4ec Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 2 Nov 2024 14:48:18 +0530 Subject: [PATCH 061/113] Fixed downloads. --- docs/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/index.md b/docs/index.md index 1fd7c82..80a088d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -79,7 +79,7 @@ ezr² RE still has a lot missing features, like the `include` expression and man It is also very unstable, and the API and syntax may change in updates. So, it is not recommended to use ezr² RE for scripting. If you want to try it out, you can download it from the [***releases page on GitHub***](https://github.com/Uralstech/ezrSquared/releases/), or, from here: -# [Windows](#tab/windows) +# [Windows](#tab/REwindows) * Download the appropriate installer. * Run the installer and go through the installation. @@ -88,14 +88,14 @@ out, you can download it from the [***releases page on GitHub***](https://github [![ezr² RE v0.8.1 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.1_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.1/ezrSquared.Shell.Setup.Win64.exe) [![ezr² RE v0.8.1 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.1_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.1/ezrSquared.Shell.Setup.Win32.exe) -# [NuGet](#tab/nuget) +# [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! [![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) [![ezr² RE v0.8.1 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.1_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.1/ezrSquared.0.8.1-unstable.nupkg) -# [Other](#tab/other) +# [Other](#tab/REother) For other OSes you can clone the [***branch***](https://github.com/Uralstech/ezrSquared/tree/ezrSquared-re), and compile your own build. From 1b48bf1e1e988975aa46ed0c26c8b6dbf48a5c57 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 2 Nov 2024 18:44:50 +0530 Subject: [PATCH 062/113] =?UTF-8?q?ezr=C2=B2=20v0.8.2=20-=20Added=20portab?= =?UTF-8?q?le=20debug=20files.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 3 +++ docs/index.md | 6 +++--- src/EzrSquared.csproj | 7 ++++++- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 7 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index ad75537..2691edb 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,9 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.8.2 [02-11-24] + * Added portable debug files. + * ezr² RE - v0.8.1 [01-11-24] * Fixed shell printouts. diff --git a/docs/index.md b/docs/index.md index 80a088d..d6ab269 100644 --- a/docs/index.md +++ b/docs/index.md @@ -85,15 +85,15 @@ out, you can download it from the [***releases page on GitHub***](https://github * Run the installer and go through the installation.
-[![ezr² RE v0.8.1 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.1_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.1/ezrSquared.Shell.Setup.Win64.exe) -[![ezr² RE v0.8.1 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.1_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.1/ezrSquared.Shell.Setup.Win32.exe) +[![ezr² RE v0.8.2 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.2_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.2/ezrSquared.Shell.Setup.Win64.exe) +[![ezr² RE v0.8.2 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.2_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.2/ezrSquared.Shell.Setup.Win32.exe) # [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! [![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) -[![ezr² RE v0.8.1 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.1_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.1/ezrSquared.0.8.1-unstable.nupkg) +[![ezr² RE v0.8.2 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.2_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.2/ezrSquared.0.8.2-unstable.nupkg) # [Other](#tab/REother) diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index e324df6..487905e 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.8.1-unstable + 0.8.2-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED @@ -74,5 +74,10 @@ True MULTI_TARGETING_SUPPORT_ATTRIBUTES + portable + + + + portable diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index e7ec3c5..7a3621c 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; ///
internal class Shell { - private const string Version = "0.8.1"; + private const string Version = "0.8.2"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 6723e94..783fd7f 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.1" +#define MyAppVersion "0.8.2" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index f1cbf53..ec3ab39 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.1" +#define MyAppVersion "0.8.2" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 68bc241..c2980e7 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.8.1 + 0.8.2 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From a3cbd41460500372349ad2f4b93e35cce8296b21 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 2 Nov 2024 19:01:52 +0530 Subject: [PATCH 063/113] Added snupkg file build support. --- src/EzrSquared.csproj | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 487905e..ea05a86 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -16,6 +16,7 @@ True True + portable True @@ -50,6 +51,9 @@ True True + + true + snupkg @@ -74,10 +78,5 @@ True MULTI_TARGETING_SUPPORT_ATTRIBUTES - portable - - - - portable From c5bbb92299dac803f9225d4bdeabafe3252f4202 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 2 Nov 2024 19:36:03 +0530 Subject: [PATCH 064/113] =?UTF-8?q?ezr=C2=B2=20v0.8.3=20-=20Fixed=20warnin?= =?UTF-8?q?g=20in=20`EzrObject`=20caused=20by=20missing=20`DynamicallyAcce?= =?UTF-8?q?ssedMembers`=20attribute.=20-=20Fixed=20debug=20files.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 4 ++++ docs/index.md | 6 +++--- src/EzrSquared.csproj | 3 +-- src/Runtime/Types/BaseTypes.cs | 8 +++++--- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 8 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 2691edb..b5e0027 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,10 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.8.3 [02-11-24] + * Fixed warning in `EzrObject` caused by missing `DynamicallyAccessedMembers` attribute. + * Fixed debug files. + * ezr² RE - v0.8.2 [02-11-24] * Added portable debug files. diff --git a/docs/index.md b/docs/index.md index d6ab269..422e172 100644 --- a/docs/index.md +++ b/docs/index.md @@ -85,15 +85,15 @@ out, you can download it from the [***releases page on GitHub***](https://github * Run the installer and go through the installation.
-[![ezr² RE v0.8.2 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.2_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.2/ezrSquared.Shell.Setup.Win64.exe) -[![ezr² RE v0.8.2 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.2_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.2/ezrSquared.Shell.Setup.Win32.exe) +[![ezr² RE v0.8.3 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.3_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.3/ezrSquared.Shell.Setup.Win64.exe) +[![ezr² RE v0.8.3 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.3_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.3/ezrSquared.Shell.Setup.Win32.exe) # [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! [![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) -[![ezr² RE v0.8.2 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.2_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.2/ezrSquared.0.8.2-unstable.nupkg) +[![ezr² RE v0.8.3 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.3_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.3/ezrSquared.0.8.3-unstable.nupkg) # [Other](#tab/REother) diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index ea05a86..f5fe7dc 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -16,7 +16,6 @@ True True - portable True @@ -29,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.8.2-unstable + 0.8.3-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs index 0ecdf36..73905aa 100644 --- a/src/Runtime/Types/BaseTypes.cs +++ b/src/Runtime/Types/BaseTypes.cs @@ -7,6 +7,7 @@ using EzrSquared.Runtime.Types.Core.Text; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Reflection; @@ -48,14 +49,15 @@ public abstract class EzrObject : IEzrObject /// The type which the member is a part of. /// The name of the member. /// The cached member data or the first member with the given . if not found. - internal static TMemberInfo? GetMemberInfo(string name) where TMemberInfo : MemberInfo + internal static TMemberInfo? GetMemberInfo(string name) where TMemberInfo : MemberInfo { - (Type ParentType, string MemberName) key = (typeof(TParentType), name); + Type parentType = typeof(TParentType); + (Type, string) key = (parentType, name); if (s_memberMap.Value.TryGetValue(key, out MemberInfo? cachedMemberInfo)) return (TMemberInfo)cachedMemberInfo; - MemberInfo[] members = key.ParentType.GetMember(name); + MemberInfo[] members = parentType.GetMember(name); if (members.Length == 0 || members[0] is not TMemberInfo memberInfo) return default; diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 7a3621c..8c54809 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.8.2"; + private const string Version = "0.8.3"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 783fd7f..9fc6f13 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.2" +#define MyAppVersion "0.8.3" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index ec3ab39..7800515 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.2" +#define MyAppVersion "0.8.3" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index c2980e7..c35ff3c 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.8.2 + 0.8.3 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From 3877ce8f3935cfa715c0223bb858947751863a2f Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 2 Nov 2024 20:51:24 +0530 Subject: [PATCH 065/113] =?UTF-8?q?ezr=C2=B2=20v0.8.4=20-=20Fixed=20debug?= =?UTF-8?q?=20files,=20again.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 3 +++ docs/index.md | 6 +++--- src/EzrSquared.csproj | 4 ++-- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 7 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index b5e0027..d04f3d1 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,9 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.8.4 [02-11-24] + * Fixed debug files, again. + * ezr² RE - v0.8.3 [02-11-24] * Fixed warning in `EzrObject` caused by missing `DynamicallyAccessedMembers` attribute. * Fixed debug files. diff --git a/docs/index.md b/docs/index.md index 422e172..336146d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -85,15 +85,15 @@ out, you can download it from the [***releases page on GitHub***](https://github * Run the installer and go through the installation.
-[![ezr² RE v0.8.3 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.3_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.3/ezrSquared.Shell.Setup.Win64.exe) -[![ezr² RE v0.8.3 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.3_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.3/ezrSquared.Shell.Setup.Win32.exe) +[![ezr² RE v0.8.4 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.4_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.4/ezrSquared.Shell.Setup.Win64.exe) +[![ezr² RE v0.8.4 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.4_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.4/ezrSquared.Shell.Setup.Win32.exe) # [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! [![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) -[![ezr² RE v0.8.3 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.3_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.3/ezrSquared.0.8.3-unstable.nupkg) +[![ezr² RE v0.8.4 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.4_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.4/ezrSquared.0.8.4-unstable.nupkg) # [Other](#tab/REother) diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index f5fe7dc..690afe8 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -10,7 +10,7 @@ Enable EzrSquared - Full + portable True @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.8.3-unstable + 0.8.4-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 8c54809..a965a3c 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.8.3"; + private const string Version = "0.8.4"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 9fc6f13..fae2343 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.3" +#define MyAppVersion "0.8.4" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 7800515..d9d531b 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.3" +#define MyAppVersion "0.8.4" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index c35ff3c..1eae53b 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.8.3 + 0.8.4 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From 15a0d764c45b8ea459e343a9aa4dbcc44c3d8e2d Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 2 Nov 2024 22:40:55 +0530 Subject: [PATCH 066/113] =?UTF-8?q?ezr=C2=B2=20v0.8.5=20-=20`CodeExecutor.?= =?UTF-8?q?s=5FruntimeContext`=20is=20now=20public-access-only=20as=20`Cod?= =?UTF-8?q?eExecutor.RuntimeContext`.=20-=20Added=20option=20to=20exclude?= =?UTF-8?q?=20built-in=20I/O=20functions=20from=20`CodeExecutor.PopulateRu?= =?UTF-8?q?ntimeContext`.=20-=20Added=20`EzrBuiltinsUtility.AddBuiltinIOFu?= =?UTF-8?q?nctions`=20to=20explicitly=20add=20built-in=20I/O=20functions.?= =?UTF-8?q?=20-=20Fixed=20command=20line=20file=20input=20for=20shell.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 6 ++ docs/index.md | 6 +- samples/turing_machine_demo.ezr2 | 67 +++++++++---------- src/Executor/CodeExecutor.cs | 37 +++++----- src/EzrSquared.csproj | 2 +- .../Builtins/EzrBuiltinsUtility.cs | 23 +++++-- src/Shell/EzrShell.cs | 4 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 10 files changed, 85 insertions(+), 66 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index d04f3d1..09cb9a6 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,12 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.8.5 [02-11-24] + * [BREAKING CHANGE] `CodeExecutor.s_runtimeContext` is now public-access-only as `CodeExecutor.RuntimeContext`. + * Added option to exclude built-in I/O functions from `CodeExecutor.PopulateRuntimeContext`. + * Added `EzrBuiltinsUtility.AddBuiltinIOFunctions` to explicitly add built-in I/O functions. + * Fixed command line file input for shell. + * ezr² RE - v0.8.4 [02-11-24] * Fixed debug files, again. diff --git a/docs/index.md b/docs/index.md index 336146d..30fc548 100644 --- a/docs/index.md +++ b/docs/index.md @@ -85,15 +85,15 @@ out, you can download it from the [***releases page on GitHub***](https://github * Run the installer and go through the installation.
-[![ezr² RE v0.8.4 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.4_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.4/ezrSquared.Shell.Setup.Win64.exe) -[![ezr² RE v0.8.4 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.4_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.4/ezrSquared.Shell.Setup.Win32.exe) +[![ezr² RE v0.8.5 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.5_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.5/ezrSquared.Shell.Setup.Win64.exe) +[![ezr² RE v0.8.5 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.5_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.5/ezrSquared.Shell.Setup.Win32.exe) # [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! [![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) -[![ezr² RE v0.8.4 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.4_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.4/ezrSquared.0.8.4-unstable.nupkg) +[![ezr² RE v0.8.5 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.5_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.5/ezrSquared.0.8.5-unstable.nupkg) # [Other](#tab/REother) diff --git a/samples/turing_machine_demo.ezr2 b/samples/turing_machine_demo.ezr2 index 38fbdd4..708421f 100644 --- a/samples/turing_machine_demo.ezr2 +++ b/samples/turing_machine_demo.ezr2 @@ -1,37 +1,39 @@ -item string: get("Enter string:") -item length: string.length + 2 -item tape: ["B"] * length -item tapehead: 1 +string: get("Enter string:") +length: string.length() + 2 +tape: ["B"] +tape * length +tapehead: 1 -item i: 1 -count to string.length as j do - tape.set(i, string <= j) - item i:+ 1 +i: 1 +for each j in string do + tape < i : j + i:+ 1 end -item state: 0 -item a: "a" -item b: "b" -item X: "X" -item Z: "Z" -item U: "U" -item V: "V" -item R: "R" -item L: "L" -item B: "B" -item old_tapehead: -1 -item accept: false +state: 0 +a: "a" +b: "b" +X: "X" +Z: "Z" +U: "U" +V: "V" +R: "R" +L: "L" +B: "B" +old_tapehead: -1 +accept: false function action with input_char, replace_with, move, new_state do - if tapehead >= tape.length do return false + if tapehead >= tape.length() do return false - if tape <= tapehead = input_char do - tape.set(tapehead, replace_with) - global item state: new_state + if tape < tapehead = input_char do + global tape < tapehead : replace_with + global state: new_state + if move = "L" do - global item tapehead:- 1 + global tapehead:- 1 else do - global item tapehead:+ 1 + global tapehead:+ 1 end return true @@ -41,12 +43,9 @@ function action with input_char, replace_with, move, new_state do end while old_tapehead ! tapehead do - item old_tapehead: tapehead - simple_show(tape) - simple_show(" with tapehead at index ") - simple_show(tapehead) - simple_show(" on state ") - show(state) + old_tapehead: tapehead + + show(tape, " with tapehead at index ", tapehead, " on state ", state) if state = 0 do if action(a, X, R, 1) do 1 else if action(B, B, R, 10) do 1 else if action(Z, Z, R, 7) do 1 else if action(b, U, R, 4) do 1 @@ -84,7 +83,7 @@ while old_tapehead ! tapehead do end if accept do - show("String accepted on state = " + state.as_string()) + show("String accepted on state = ", state) else do - show("String not accepted on state = " + state.as_string()) + show("String not accepted on state = ", state) end \ No newline at end of file diff --git a/src/Executor/CodeExecutor.cs b/src/Executor/CodeExecutor.cs index 16f0a8f..293eb2d 100644 --- a/src/Executor/CodeExecutor.cs +++ b/src/Executor/CodeExecutor.cs @@ -18,9 +18,9 @@ public static class CodeExecutor public static readonly Interpreter Interpreter = new(); /// - /// The runtime context, may be null. + /// The runtime context, may be . /// - private static Context? s_runtimeContext; + public static Context? RuntimeContext { get; private set; } /// /// Creates the runtime context. @@ -28,7 +28,8 @@ public static class CodeExecutor /// The file path to the code file this context will be used to execute. public static void CreateRuntimeContext(string filePath) { - s_runtimeContext = new Context($"<\"{filePath}\" context>", true, new Position(0, 0, filePath, string.Empty)); + RuntimeContext?.Release(); + RuntimeContext = new Context($"<\"{filePath}\" context>", true, new Position(0, 0, filePath, string.Empty)); } /// @@ -38,14 +39,18 @@ public static void CreateRuntimeContext(string filePath) /// Thrown if the runtime context is . /// Use to initialize the runtime context. /// - public static void PopulateRuntimeContext() + /// Exclude built-in I/O functions like ? + public static void PopulateRuntimeContext(bool excludeIO=false) { - if (s_runtimeContext is null) - throw new NullReferenceException($"{nameof(s_runtimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); + if (RuntimeContext is null) + throw new NullReferenceException($"{nameof(RuntimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); - EzrBuiltinsUtility.AddBuiltinConstants(s_runtimeContext); - EzrBuiltinsUtility.AddBuiltinFunctions(s_runtimeContext); - EzrBuiltinsUtility.AddBuiltinTypes(s_runtimeContext); + EzrBuiltinsUtility.AddBuiltinConstants(RuntimeContext); + EzrBuiltinsUtility.AddBuiltinFunctions(RuntimeContext); + EzrBuiltinsUtility.AddBuiltinTypes(RuntimeContext); + + if (!excludeIO) + EzrBuiltinsUtility.AddBuiltinIOFunctions(RuntimeContext); } /// @@ -59,10 +64,10 @@ public static void PopulateRuntimeContext() /// The name of the new symbol. public static void AddToContext(Reference reference, string name) { - if (s_runtimeContext is null) - throw new NullReferenceException($"{nameof(s_runtimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); + if (RuntimeContext is null) + throw new NullReferenceException($"{nameof(RuntimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); - s_runtimeContext.Set(null, name, reference); + RuntimeContext.Set(null, name, reference); } /// @@ -76,11 +81,11 @@ public static void AddToContext(Reference reference, string name) /// public static ExecutionResult Execute(string script) { - if (s_runtimeContext is null) - throw new NullReferenceException($"{nameof(s_runtimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); + if (RuntimeContext is null) + throw new NullReferenceException($"{nameof(RuntimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); // Tokenize the script. - SyntaxError? lexerError = new Lexer(s_runtimeContext.StartPosition.File, script).Tokenize(out List tokens); + SyntaxError? lexerError = new Lexer(RuntimeContext.StartPosition.File, script).Tokenize(out List tokens); if (lexerError is not null) // Check for errors. return new ExecutionResult([.. tokens], lexerError); // Return tokens with lexing error. @@ -90,7 +95,7 @@ public static ExecutionResult Execute(string script) return new ExecutionResult([.. tokens], parseResult); // Return the tokens, with the parse error. // Interpret the Abstract Syntax Tree. - RuntimeResult result = Interpreter.Execute(parseResult.Node, s_runtimeContext); + RuntimeResult result = Interpreter.Execute(parseResult.Node, RuntimeContext); // Return result. return new ExecutionResult([.. tokens], parseResult.Node, result); diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 690afe8..688d8ac 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.8.4-unstable + 0.8.5-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs index c97591c..04c84a2 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs @@ -10,15 +10,12 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.Builtins; public static class EzrBuiltinsUtility { /// - /// Adds all built-in functions to the given context. + /// Adds all built-in functions to the given context, excluding I/O functions. /// /// The context to add to. public static void AddBuiltinFunctions(Context context) { - EzrSharpSourceFunctionWrapper show = new(EzrBuiltinFunctions.Show, context, Position.None, Position.None); EzrSharpSourceFunctionWrapper throwError = new(EzrBuiltinFunctions.ThrowError, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper get = new(EzrBuiltinFunctions.Get, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper clear = new(EzrBuiltinFunctions.Clear, context, Position.None, Position.None); EzrSharpSourceFunctionWrapper assert = new(EzrBuiltinFunctions.Assert, context, Position.None, Position.None); EzrSharpSourceFunctionWrapper hash = new(EzrBuiltinFunctions.Hash, context, Position.None, Position.None); EzrSharpSourceFunctionWrapper typeOf = new(EzrBuiltinFunctions.TypeOf, context, Position.None, Position.None); @@ -26,10 +23,7 @@ public static void AddBuiltinFunctions(Context context) EzrSharpSourceFunctionWrapper typeHashOf = new(EzrBuiltinFunctions.TypeHashOf, context, Position.None, Position.None); EzrSharpSourceFunctionWrapper copy = new(EzrBuiltinFunctions.Copy, context, Position.None, Position.None); - context.Set(null, show.SharpFunctionName, ReferencePool.Get(show, AccessMod.Constant)); context.Set(null, throwError.SharpFunctionName, ReferencePool.Get(throwError, AccessMod.Constant)); - context.Set(null, get.SharpFunctionName, ReferencePool.Get(get, AccessMod.Constant)); - context.Set(null, clear.SharpFunctionName, ReferencePool.Get(clear, AccessMod.Constant)); context.Set(null, assert.SharpFunctionName, ReferencePool.Get(assert, AccessMod.Constant)); context.Set(null, hash.SharpFunctionName, ReferencePool.Get(hash, AccessMod.Constant)); context.Set(null, typeOf.SharpFunctionName, ReferencePool.Get(typeOf, AccessMod.Constant)); @@ -38,6 +32,21 @@ public static void AddBuiltinFunctions(Context context) context.Set(null, copy.SharpFunctionName, ReferencePool.Get(copy, AccessMod.Constant)); } + /// + /// Adds all built-in I/O functions to the given context. + /// + /// The context to add to. + public static void AddBuiltinIOFunctions(Context context) + { + EzrSharpSourceFunctionWrapper show = new(EzrBuiltinFunctions.Show, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper get = new(EzrBuiltinFunctions.Get, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper clear = new(EzrBuiltinFunctions.Clear, context, Position.None, Position.None); + + context.Set(null, show.SharpFunctionName, ReferencePool.Get(show, AccessMod.Constant)); + context.Set(null, get.SharpFunctionName, ReferencePool.Get(get, AccessMod.Constant)); + context.Set(null, clear.SharpFunctionName, ReferencePool.Get(clear, AccessMod.Constant)); + } + /// /// Adds all built-in types to the given context. /// diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index a965a3c..b7d9982 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.8.4"; + private const string Version = "0.8.5"; private static bool s_showLexerOutput; private static bool s_showParserOutput; @@ -68,7 +68,7 @@ private static bool ParseCommandLineArguments(string[] arguments) Console.ResetColor(); return false; default: - if (!string.IsNullOrEmpty(s_filePath) && File.Exists(arguments[i])) + if (string.IsNullOrEmpty(s_filePath) && File.Exists(arguments[i])) s_filePath = arguments[i]; else { diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index fae2343..397cb82 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.4" +#define MyAppVersion "0.8.5" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index d9d531b..8b5b1a3 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.4" +#define MyAppVersion "0.8.5" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 1eae53b..b3f9494 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.8.4 + 0.8.5 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From 0394832bd6642be4f1ec65ab2e2adb96a85284ae Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sun, 3 Nov 2024 22:23:45 +0530 Subject: [PATCH 067/113] MASSIVE overhaul for the wrapper systems. --- src/EzrSquared.csproj | 2 +- .../Collections/RuntimeEzrObjectDictionary.cs | 4 +- .../EzrSharpCompatibilityObjectInstance.cs | 71 ++++------ .../EzrSharpCompatibilityType.cs | 107 ++++++++------- .../EzrSharpCompatibilityWrapper.cs | 109 ++++++++++----- .../EzrSharpCompatibilityConstructor.cs | 65 ++------- .../EzrSharpCompatibilityExecutable.cs | 29 ++-- .../EzrSharpCompatibilityFunction.cs | 37 ++---- .../EzrSharpCompatibilityField.cs | 87 ++++++------ .../EzrSharpCompatibilityProperty.cs | 51 +++---- .../EzrSharpSourceFieldWrapper.cs | 124 ------------------ .../EzrSharpSourcePropertyWrapper.cs | 117 ----------------- .../EzrSharpSourceTypeWrapper.cs | 80 +++-------- src/Runtime/Types/Collections/EzrList.cs | 2 +- .../Types/Core/Text/EzrCharacterList.cs | 2 +- .../SharpAutoCompatibilityWrapperAttribute.cs | 68 ---------- .../SharpAutoWrapperAttribute.cs | 89 +++++++++++++ .../SharpFieldWrapperAttribute.cs | 47 ------- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 22 files changed, 361 insertions(+), 738 deletions(-) delete mode 100644 src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs delete mode 100644 src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs delete mode 100644 src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs create mode 100644 src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs delete mode 100644 src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 688d8ac..b2c58da 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.8.5-unstable + 0.9.0-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index f21ffa6..71c28c8 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -21,7 +21,7 @@ public class RuntimeEzrObjectDictionary : IMutable /// /// The number of s in the . /// - [SharpAutoCompatibilityWrapper(IsReadOnly = true)] + [SharpAutoWrapper(IsReadOnly = true)] public int Length => _items.Count; /// @@ -103,7 +103,7 @@ public bool Remove(IEzrObject key, RuntimeResult result) /// /// The key (hash) to be removed. /// if the operation was successful, if not. - [SharpAutoCompatibilityWrapper(Name = "remove_by_hash")] + [SharpAutoWrapper(Name = "remove_by_hash")] public bool RemoveHash(int key) { return _items.Remove(key); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index 4e25a46..af17d7e 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -1,5 +1,4 @@ -using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; using EzrSquared.Util; using System; @@ -25,45 +24,37 @@ public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper /// public readonly object Instance; - /// - /// The name of the type of the wrapped instance, in ezr² (snake_case) format. - /// - public readonly string InstanceTypeName; - /// /// Creates a new . /// - /// The name of the type of the wrapped instance, in ezr² (snake_case) format. /// The object to wrap. - /// The type of the wrapped instance + /// The C# object's type. /// Runtime result for carrying any errors. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. public EzrSharpCompatibilityObjectInstance( - string typeName, object instance, - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.NonPublicMethods + | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.NonPublicProperties + | DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.NonPublicFields)] Type instanceType, - - RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + + RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(instanceType, parentContext, startPosition, endPosition) { Instance = instance; - InstanceTypeName = typeName; - Tag = $"{Tag}.{InstanceTypeName}.{Utils.GetNextUniqueId()}"; + Tag = $"{Tag}.{SharpMemberName}.{Utils.GetNextUniqueId()}"; - MethodInfo[] publicMethods = instanceType.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + MethodInfo[] publicMethods = instanceType.GetMethods(BindingFlags.Public | BindingFlags.Instance); Dictionary duplicateNames = new(publicMethods.Length); for (int i = 0; i < publicMethods.Length; i++) { MethodInfo method = publicMethods[i]; - if (method.ContainsGenericParameters || method.IsGenericMethod) - { - result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap CSharp method \"{method.Name}\" of instance \"{instanceType.Name}\"! Reasons can include the method being generic or containing generic parameters.", Context, StartPosition, EndPosition)); - return; - } - if (method.IsAbstract) continue; @@ -77,41 +68,33 @@ public EzrSharpCompatibilityObjectInstance( duplicateNames.Add(method.Name, 1); EzrSharpCompatibilityFunction methodObject = new(method, Instance, Context, StartPosition, EndPosition); + if (methodObject.Validate(result)) + return; + Context.Set(null, methodObjectName, ReferencePool.Get(methodObject, AccessMod.Constant)); } - PropertyInfo[] publicProperties = instanceType.GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + PropertyInfo[] publicProperties = instanceType.GetProperties(BindingFlags.Public | BindingFlags.Instance); for (int i = 0; i < publicProperties.Length; i++) { EzrSharpCompatibilityProperty property = new(publicProperties[i], Instance, Context, StartPosition, EndPosition); - Context.Set(null, property.SharpPropertyName, ReferencePool.Get(property, AccessMod.Constant)); + if (property.Validate(result)) + return; + + Context.Set(null, property.SharpMemberName, ReferencePool.Get(property, AccessMod.Constant)); } - FieldInfo[] publicFields = instanceType.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + FieldInfo[] publicFields = instanceType.GetFields(BindingFlags.Public | BindingFlags.Instance); for (int i = 0; i < publicFields.Length; i++) { EzrSharpCompatibilityField field = new(publicFields[i], Instance, Context, StartPosition, EndPosition); - Context.Set(null, field.SharpFieldName, ReferencePool.Get(field, AccessMod.Constant)); + if (field.Validate(result)) + return; + + Context.Set(null, field.SharpMemberName, ReferencePool.Get(field, AccessMod.Constant)); } } - /// - /// Creates a new . Infers the type's name by converting it to snake_case. - /// - /// The object to wrap. - /// The type of the wrapped instance - /// Runtime result for carrying any errors. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - public EzrSharpCompatibilityObjectInstance(object instance, - - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] - Type instanceType, - - RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) - : this(Utils.PascalToSnakeCase(instanceType.Name), instance, instanceType, result, parentContext, startPosition, endPosition) { } - /// public override int ComputeHashCode(RuntimeResult result) { @@ -127,6 +110,6 @@ public override bool StrictEquals(IEzrObject other, RuntimeResult result) /// public override string ToString(RuntimeResult result) { - return $"<{TypeName} of type \"{InstanceTypeName}\">"; + return $"<{TypeName} of type \"{SharpMemberName}\">"; } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index e391673..6c4e197 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -1,6 +1,7 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; using System.Collections.Generic; @@ -23,38 +24,41 @@ public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper /// /// The type to wrap. /// + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.NonPublicFields + | DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.NonPublicMethods + | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.NonPublicProperties + | DynamicallyAccessedMemberTypes.PublicConstructors + | DynamicallyAccessedMemberTypes.NonPublicConstructors)] public readonly Type SharpType; - /// - /// The name of the type to wrap, in ezr² format (snake_case). - /// - public readonly string SharpTypeName; - /// /// Creates a new . /// - /// The name of the type to wrap, in ezr² format (snake_case). /// The type to wrap. /// Runtime result for carrying any errors. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. public EzrSharpCompatibilityType( - string name, - [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.NonPublicFields | DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.NonPublicProperties | DynamicallyAccessedMemberTypes.PublicConstructors - | DynamicallyAccessedMemberTypes.NonPublicConstructors - )] Type type, + | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type type, - RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(type, parentContext, startPosition, endPosition) { SharpType = type; - SharpTypeName = name; - Tag = $"{Tag}.{SharpTypeName}.{Utils.GetNextUniqueId()}"; + Tag = $"{Tag}.{SharpMemberName}.{Utils.GetNextUniqueId()}"; if (SharpType.IsGenericType) { @@ -62,18 +66,12 @@ public EzrSharpCompatibilityType( return; } - MethodInfo[] publicStaticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public); - Dictionary duplicateNames = new(publicStaticMethods.Length); - for (int i = 0; i < publicStaticMethods.Length; i++) + MethodInfo[] allStaticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + Dictionary duplicateNames = new(allStaticMethods.Length); + for (int i = 0; i < allStaticMethods.Length; i++) { - MethodInfo method = publicStaticMethods[i]; - if (method.ContainsGenericParameters || method.IsGenericMethod) - { - result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap CSharp static method \"{method.Name}\" of type \"{SharpType.Name}\"! Reasons can include the method being generic or containing generic parameters.", Context, StartPosition, EndPosition)); - return; - } - - if (method.IsAbstract) + MethodInfo method = allStaticMethods[i]; + if (method.IsAbstract || (!method.IsPublic && method.GetCustomAttribute() is null)) continue; string methodObjectName = Utils.PascalToSnakeCase(method.Name); @@ -86,21 +84,38 @@ public EzrSharpCompatibilityType( duplicateNames.Add(method.Name, 1); EzrSharpCompatibilityFunction methodObject = new(method, null, Context, StartPosition, EndPosition); + if (!methodObject.Validate(result)) + return; + Context.Set(null, methodObjectName, ReferencePool.Get(methodObject, AccessMod.Constant)); } - PropertyInfo[] publicStaticProperties = type.GetProperties(BindingFlags.Static | BindingFlags.Public); - for (int i = 0; i < publicStaticProperties.Length; i++) + PropertyInfo[] allStaticProperties = type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + for (int i = 0; i < allStaticProperties.Length; i++) { - EzrSharpCompatibilityProperty property = new(publicStaticProperties[i], null, Context, StartPosition, EndPosition); - Context.Set(null, property.SharpPropertyName, ReferencePool.Get(property, AccessMod.Constant)); + PropertyInfo property = allStaticProperties[i]; + if (property.GetMethod?.IsPublic != true && property.SetMethod?.IsPublic != true && property.GetCustomAttribute() is null) + continue; + + EzrSharpCompatibilityProperty propertyObject = new(property, null, Context, StartPosition, EndPosition); + if (!propertyObject.Validate(result)) + return; + + Context.Set(null, propertyObject.SharpMemberName, ReferencePool.Get(propertyObject, AccessMod.Constant)); } - FieldInfo[] publicStaticFields = type.GetFields(BindingFlags.Static | BindingFlags.Public); - for (int i = 0; i < publicStaticFields.Length; i++) + FieldInfo[] allStaticFields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + for (int i = 0; i < allStaticFields.Length; i++) { - EzrSharpCompatibilityField field = new(publicStaticFields[i], null, Context, StartPosition, EndPosition); - Context.Set(null, field.SharpFieldName, ReferencePool.Get(field, AccessMod.Constant)); + FieldInfo field = allStaticFields[i]; + if (!field.IsPublic && field.GetCustomAttribute() is null) + continue; + + EzrSharpCompatibilityField fieldObject = new(field, null, Context, StartPosition, EndPosition); + if (!fieldObject.Validate(result)) + return; + + Context.Set(null, fieldObject.SharpMemberName, ReferencePool.Get(fieldObject, AccessMod.Constant)); } ConstructorInfo[] publicConstructors = type.GetConstructors(); @@ -110,32 +125,14 @@ public EzrSharpCompatibilityType( if (!constructor.IsPublic) continue; - IEzrObject constructorObject = new EzrSharpCompatibilityConstructor(SharpTypeName, constructor, type, Context, StartPosition, EndPosition); + EzrSharpCompatibilityConstructor constructorObject = new(this, constructor, Context, StartPosition, EndPosition); + if (constructorObject.Validate(result)) + return; + Context.Set(null, $"make_{i}", ReferencePool.Get(constructorObject, AccessMod.Constant)); } } - /// - /// Creates a new . Infers the name by converting the member's name to snake_case. - /// - /// The type to wrap. - /// Runtime result for carrying any errors. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - public EzrSharpCompatibilityType( - - [DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields - | DynamicallyAccessedMemberTypes.PublicMethods - | DynamicallyAccessedMemberTypes.PublicProperties - | DynamicallyAccessedMemberTypes.PublicConstructors - | DynamicallyAccessedMemberTypes.NonPublicConstructors - )] Type type, - - RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) - : this(Utils.PascalToSnakeCase(type.Name), type, result, parentContext, startPosition, endPosition) { } - /// public override int ComputeHashCode(RuntimeResult result) { @@ -151,6 +148,6 @@ public override bool StrictEquals(IEzrObject other, RuntimeResult result) /// public override string ToString(RuntimeResult result) { - return $"<{TypeName} \"{SharpTypeName}\">"; + return $"<{TypeName} \"{SharpMemberName}\">"; } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index a975cfc..7ed8db3 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -2,6 +2,8 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; +using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Util; using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -12,10 +14,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; /// /// Parent class for all automatic wrappers which wrap existing C# objects and members so that they can be used in ezr². /// -/// The context in which this object was created. -/// The starting position of the object. -/// The ending position of the object. -public abstract class EzrSharpCompatibilityWrapper(Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) +public abstract class EzrSharpCompatibilityWrapper : EzrObject { /// public override string TypeName { get; protected internal set; } = "csharp wrapper"; @@ -24,15 +23,60 @@ public abstract class EzrSharpCompatibilityWrapper(Context parentContext, Positi public override string Tag { get; protected internal set; } = "ezrSquared.CSharpWrapper"; /// - /// Checks if the given type is supported by the primitive compatibility wrappers. + /// The of the wrapped object, if defined. + /// + public readonly SharpAutoWrapperAttribute? AutoWrapperAttribute; + + /// + /// The name of the wrapped member in snake_case. + /// + public readonly string SharpMemberName; + + /// + /// Reflection info for the current object being wrapped. + /// + public readonly MemberInfo SharpMember; + + /// + /// Creates a new . + /// + /// Reflection info on the wrapped C# member. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. + public EzrSharpCompatibilityWrapper(MemberInfo wrappedMember, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + { + SharpMember = wrappedMember; + AutoWrapperAttribute = wrappedMember.GetCustomAttribute(); + SharpMemberName = !string.IsNullOrEmpty(AutoWrapperAttribute?.Name) ? AutoWrapperAttribute.Name : Utils.PascalToSnakeCase(wrappedMember.Name); + } + + /// + /// Validates the the current object for wrapping. + /// + /// Optional runtime result for carrying runtime errors. + /// if the member can be wrapped, otherwise. + public bool Validate(RuntimeResult? result=null) + { + Exception? validationException = SharpAutoWrapperAttribute.Validate(SharpMember); + if (validationException is null) + return true; + + if (AutoWrapperAttribute is not null) + throw validationException; + + result?.Failure(new EzrUnsupportedWrappingError($"C# type member \"{SharpMemberName}\" cannot be wrapped into an ezr² type!", Context, StartPosition, EndPosition)); + return false; + } + + /// + /// Checks if the given type is supported by the compatibility wrappers. /// /// The type to check. /// if yes, otherwise. - public static bool IsSupportedPrimitiveType(Type type) + public static bool IsSupportedType(Type type) { - TypeCode typeCode = Type.GetTypeCode(type); - - return typeCode is TypeCode.Empty + return typeof(IEzrObject).IsAssignableFrom(type) || Type.GetTypeCode(type) is TypeCode.Empty or TypeCode.Int16 or TypeCode.Int32 or TypeCode.Int64 @@ -50,7 +94,7 @@ or TypeCode.Char } /// - /// Checks if the given type is supported by the primitive compatibility wrappers, including generic objects. + /// Checks if the given type is supported by the compatibility wrappers, including generic objects. /// /// The type to check. /// if yes, otherwise. @@ -58,21 +102,29 @@ public static bool IsSupportedReturnType(Type type) { return Type.GetTypeCode(type) switch { - TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArguments.Length == 0 || IsSupportedPrimitiveType(type.GenericTypeArguments[0]), - _ => IsSupportedPrimitiveType(type), + TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArguments.Length == 0 || IsSupportedType(type.GenericTypeArguments[0]), + _ => IsSupportedType(type), }; } /// - /// Converts an ezr² type to a C# primitive type. + /// Converts an ezr² type to a C# type. /// /// The to convert. - /// The primitive type to convert it to. + /// The type to convert it to. /// Runtime result for carrying any errors. /// The converted object. - protected internal object? EzrObjectToPrimitive(IEzrObject value, TypeCode typeCode, RuntimeResult result) + protected internal object? EzrObjectToCSharp(IEzrObject value, Type targetType, RuntimeResult result) { - switch (typeCode) + if (targetType.IsAssignableFrom(value.GetType())) + return value; + else if (typeof(IEzrObject).IsAssignableFrom(targetType)) + { + result.Failure(new EzrUnexpectedTypeError($"Expected ezr² object of type \"{targetType.Name}\" (this is the name of the object in C#), but got object of type \"{value.TypeName}\".", Context, value.StartPosition, value.EndPosition)); + return null; + } + + switch (Type.GetTypeCode(targetType)) { case TypeCode.Int16: if (value is EzrInteger integer16Value) @@ -235,12 +287,8 @@ TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArgu result.Failure(new EzrUnexpectedTypeError($"Expected character, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; case TypeCode.String: - if (value is EzrString stringValue) - return stringValue.Value; - else if (value is EzrCharacterList characterListValue) - return characterListValue.StringValue; - else if (value is EzrCharacter stringCharacterValue) - return stringCharacterValue.Value.ToString(); + if (value is IEzrString ezrString) + return ezrString.StringValue; result.Failure(new EzrUnexpectedTypeError($"Expected string, character or character list, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; @@ -251,7 +299,7 @@ TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArgu result.Failure(new EzrUnexpectedTypeError($"Expected type nothing, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; default: - result.Failure(new EzrUnsupportedWrappingError($"Object of type \"{value.TypeName}\" cannot be converted to CSharp type \"{typeCode}\"!", Context, value.StartPosition, value.EndPosition)); + result.Failure(new EzrUnsupportedWrappingError($"Object of type \"{value.TypeName}\" cannot be converted to CSharp type \"{targetType.Name}\"!", Context, value.StartPosition, value.EndPosition)); break; } @@ -262,17 +310,11 @@ TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArgu /// Converts a C# primitive type object or a task which returns a C# primitive type object to an ezr² object. /// /// The C# object to convert. - /// The type to convert from. /// Runtime result for carrying the result and any errors. /// The converted . - protected internal void PrimitiveToEzrObject( - object? value, - - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] - Type? valueType, - - RuntimeResult result) + protected internal void CSharpToEzrObject(object? value, RuntimeResult result) { + Type? valueType = value?.GetType(); if (value is null || valueType is null) { result.Success(NewNothingConstant()); @@ -323,6 +365,9 @@ protected internal void PrimitiveToEzrObject( case TypeCode.String: result.Success(NewStringConstant((string)value)); break; + case TypeCode.Object when typeof(IEzrObject).IsAssignableFrom(valueType): + result.Success(ReferencePool.Get((IEzrObject)value, AccessMod.PrivateConstant)); + break; case TypeCode.Object when typeof(Task).IsAssignableFrom(valueType): HandleAsynchronousObject(value, valueType, result); break; @@ -359,7 +404,7 @@ protected internal void HandleAsynchronousObject( // Get the value of the Result property object taskResult = resultProperty.GetValue(value)!; - PrimitiveToEzrObject(taskResult, taskResult.GetType(), result); + CSharpToEzrObject(taskResult, result); } else result.Success(NewNothingConstant()); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index 04d39c5..8b64938 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -1,8 +1,6 @@ using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Util; using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; @@ -10,57 +8,18 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.E /// /// Class to automatically wrap C# constructors so that they can be used in ezr². /// -public class EzrSharpCompatibilityConstructor : EzrSharpCompatibilityExecutable +/// The wrapper for this C# constructor's class. +/// The constructor to wrap. +/// The context in which this object was created. +/// The starting position of the object. +/// The ending position of the object. +/// Skip method signature validation? +public class EzrSharpCompatibilityConstructor(EzrSharpCompatibilityType constructingTypeWrapper, ConstructorInfo sharpConstructor, Context parentContext, Position startPosition, Position endPosition, bool skipValidation=false) : EzrSharpCompatibilityExecutable(sharpConstructor, null, parentContext, startPosition, endPosition, skipValidation) { /// - /// Reflection information about the type which is constructed by the wrapped constructor. + /// The wrapper for this C# constructor's class. /// - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] - public readonly Type ConstructingType; - - /// - /// The name of the constructor's constructing type, in ezr² format (snake_case). - /// - public readonly string ConstructingTypeName; - - /// - /// Creates a new . - /// - /// The name of the constructor's constructing type, in ezr² format (snake_case). - /// The constructor to wrap. - /// The type which is constructed by the constructor. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - public EzrSharpCompatibilityConstructor( - string constructTypeName, - ConstructorInfo sharpConstructor, - - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] - Type constructType, - - Context parentContext, Position startPosition, Position endPosition) : base(sharpConstructor, null, parentContext, startPosition, endPosition) - { - ConstructingType = constructType; - ConstructingTypeName = constructTypeName; - } - - /// - /// Creates a new . Infers the constructing type's name by converting it to snake_case. - /// - /// The constructor to wrap. - /// The type which is constructed by the constructor. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - public EzrSharpCompatibilityConstructor( - ConstructorInfo sharpConstructor, - - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] - Type constructType, - - Context parentContext, Position startPosition, Position endPosition) - : this(Utils.PascalToSnakeCase(constructType.Name), sharpConstructor, constructType, parentContext, startPosition, endPosition) { } + public readonly EzrSharpCompatibilityType ConstructingTypeWrapper = constructingTypeWrapper; /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) @@ -81,7 +40,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run result.Success(NewNothingConstant()); else { - IEzrObject wrapper = new EzrSharpCompatibilityObjectInstance(ConstructingTypeName, output, ConstructingType, result, _executionContext, StartPosition, EndPosition); + IEzrObject wrapper = new EzrSharpCompatibilityObjectInstance(output, ConstructingTypeWrapper.SharpType, result, _executionContext, StartPosition, EndPosition); if (result.ShouldReturn) return; @@ -98,7 +57,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run public override string ToString(RuntimeResult result) { return ParameterNames.Length > 0 - ? $"<{TypeName} for type \"{ConstructingTypeName}\", with \"{string.Join("\", \"", ParameterNames)}\">" - : $"<{TypeName} for \"{ConstructingTypeName}\">"; + ? $"<{TypeName} for type \"{ConstructingTypeWrapper.SharpMemberName}\", with \"{string.Join("\", \"", ParameterNames)}\">" + : $"<{TypeName} for \"{ConstructingTypeWrapper.SharpMemberName}\">"; } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index 40bd0ac..c1de8a2 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -1,4 +1,5 @@ using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; using System.Collections.Generic; @@ -37,41 +38,27 @@ public abstract class EzrSharpCompatibilityExecutable : EzrSharpCompatibilityWra /// public readonly object? Instance; - /// - /// The name of the executable to wrap, in ezr² (snake_case) format. - /// - public readonly string SharpRuntimeExecutableName; - /// /// Creates a new . /// - /// The name of the executable to wrap, in ezr² format (snake_case). /// The executable to wrap. /// The object which contains the executable, if static. /// The parent context. /// The starting position of the object. /// The ending position of the object. - public EzrSharpCompatibilityExecutable(string name, MethodBase sharpMember, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + /// Skip method signature validation? + public EzrSharpCompatibilityExecutable(MethodBase sharpMember, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation) : base(sharpMember, parentContext, startPosition, endPosition) { - SharpRuntimeExecutableName = name; - Tag = $"{Tag}.{SharpRuntimeExecutableName}.{Utils.GetNextUniqueId()}"; + Tag = $"{Tag}.{SharpMemberName}.{Utils.GetNextUniqueId()}"; Executable = sharpMember; Parameters = Executable.GetParameters(); ParameterNames = Array.ConvertAll(Parameters, p => Utils.PascalToSnakeCase(p.Name ?? string.Empty)); Instance = instance; - } - /// - /// Creates a new . Infers the name by converting the member's name to snake_case. - /// - /// The executable to wrap. - /// The object which contains the executable, if static. - /// The parent context. - /// The starting position of the object. - /// The ending position of the object. - public EzrSharpCompatibilityExecutable(MethodBase sharpMember, object? instance, Context parentContext, Position startPosition, Position endPosition) - : this(Utils.PascalToSnakeCase(sharpMember.Name), sharpMember, instance, parentContext, startPosition, endPosition) { } + if (!skipValidation) + Validate(); + } /// /// Converts an array of arguments from ezr² code to an ordered dictionary. @@ -146,7 +133,7 @@ protected internal Dictionary ArgumentsArrayToDictionary(Ref ParameterInfo parameter = Parameters[i]; if (!string.IsNullOrEmpty(parameter.Name) && arguments.TryGetValue(ParameterNames[i], out IEzrObject? argument)) { - object? primitiveArgument = EzrObjectToPrimitive(argument, Type.GetTypeCode(parameter.ParameterType), result); + object? primitiveArgument = EzrObjectToCSharp(argument, parameter.ParameterType, result); if (result.ShouldReturn) return []; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs index 3e4fafe..b8acd3e 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs @@ -8,7 +8,13 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.E /// /// Class to automatically wrap C# methods so that they can be used in ezr². /// -public class EzrSharpCompatibilityFunction : EzrSharpCompatibilityExecutable +/// The method to wrap. +/// The object which contains the method, if static. +/// The context in which this object was created. +/// The starting position of the object. +/// The ending position of the object. +/// Skip method signature validation? +public class EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation=false) : EzrSharpCompatibilityExecutable(sharpFunction, instance, parentContext, startPosition, endPosition, skipValidation) { /// public override string TypeName { get; protected internal set; } = "csharp function"; @@ -16,29 +22,6 @@ public class EzrSharpCompatibilityFunction : EzrSharpCompatibilityExecutable /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpFunction"; - /// - /// Creates a new . Infers the name by converting the member's name to snake_case. - /// - /// The name of the method to wrap, in ezr² format (snake_case). - /// The method to wrap. - /// The object which contains the method, if static. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - public EzrSharpCompatibilityFunction(string name, MethodInfo sharpFunction, object? instance, Context parentContext, Position startPosition, Position endPosition) - : base(name, sharpFunction, instance, parentContext, startPosition, endPosition) { } - - /// - /// Creates a new . - /// - /// The method to wrap. - /// The object which contains the method, if static. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - public EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context parentContext, Position startPosition, Position endPosition) - : base(sharpFunction, instance, parentContext, startPosition, endPosition) { } - /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { @@ -57,7 +40,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run if (output is null) result.Success(NewNothingConstant()); else - PrimitiveToEzrObject(output, output.GetType(), result); + CSharpToEzrObject(output, result); } catch (Exception error) { @@ -69,7 +52,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run public override string ToString(RuntimeResult result) { return ParameterNames.Length > 0 - ? $"<{TypeName} \"{SharpRuntimeExecutableName}\", with \"{string.Join("\", \"", ParameterNames)}\">" - : $"<{TypeName} \"{SharpRuntimeExecutableName}\">"; + ? $"<{TypeName} \"{SharpMemberName}\", with \"{string.Join("\", \"", ParameterNames)}\">" + : $"<{TypeName} \"{SharpMemberName}\">"; } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index 5c8dc8f..b373093 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -1,4 +1,5 @@ using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; using System.Reflection; @@ -26,38 +27,24 @@ public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper /// public readonly object? Instance; - /// - /// The name of the field to wrap, in ezr² format (snake_case). - /// - public readonly string SharpFieldName; - /// /// Creates a new . /// - /// The name of the field to wrap, in ezr² format (snake_case). /// The field to wrap. /// The object which contains the field, if static. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrSharpCompatibilityField(string name, FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + /// Skip field type validation? + public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation=false) : base(sharpField, parentContext, startPosition, endPosition) { SharpField = sharpField; Instance = instance; - SharpFieldName = name; - Tag = $"{Tag}.{SharpFieldName}.{Utils.GetNextUniqueId()}"; - } + Tag = $"{Tag}.{SharpMemberName}.{Utils.GetNextUniqueId()}"; - /// - /// Creates a new . Infers the name by converting the member's name to snake_case. - /// - /// The field to wrap. - /// The object which contains the field, if static. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition) - : this(Utils.PascalToSnakeCase(sharpField.Name), sharpField, instance, parentContext, startPosition, endPosition) { } + if (!skipValidation) + Validate(); + } /// /// If there are no arguments, accesses the field's value. If the field is not read-only and there is an arguments, sets the field's value. @@ -65,33 +52,43 @@ public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Contex /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { - if (arguments.Length > 1) + switch (arguments) { - result.Failure(new EzrUnexpectedArgumentError($"Only expected 0 (for getting the value) or 1 (for setting the value) argument(s) for CSharp field wrapper \"{SharpFieldName}\"!", Context, StartPosition, EndPosition)); - return; - } + case { Length: > 1 }: + result.Failure(new EzrUnexpectedArgumentError($"Only expected 0 (for getting the value) or 1 (for setting the value) argument(s) for CSharp field wrapper \"{SharpMemberName}\"!", Context, StartPosition, EndPosition)); + break; - if (arguments.Length == 0) - { - object? value = SharpField.GetValue(Instance); - PrimitiveToEzrObject(value, value?.GetType(), result); - } - else - { - object? value = EzrObjectToPrimitive(arguments[0].Object, Type.GetTypeCode(SharpField.FieldType), result); - if (result.ShouldReturn) - return; + case { Length: 1 } when AutoWrapperAttribute?.IsReadOnly == true: + result.Failure(new EzrIllegalOperationError($"Cannot set value to CSharp field wrapper \"{SharpMemberName}\" as it is read-only!", Context, StartPosition, EndPosition)); + break; + + case { Length: 1 }: + object? argumentAsPrimitive = EzrObjectToCSharp(arguments[0].Object, SharpField.FieldType, result); + if (result.ShouldReturn) + break; + + try + { + SharpField.SetValue(Instance, argumentAsPrimitive); + result.Success(NewNothingConstant()); + } + catch (Exception error) + { + result.Failure(new EzrWrapperExecutionError(error.Message, Context, StartPosition, EndPosition)); + break; + } + break; - try - { - SharpField.SetValue(Instance, value); - result.Success(NewNothingConstant()); - } - catch (Exception error) - { - result.Failure(new EzrWrapperExecutionError(error.Message, Context, StartPosition, EndPosition)); - return; - } + default: + if (AutoWrapperAttribute?.IsWriteOnly == true) + { + result.Failure(new EzrIllegalOperationError($"Cannot get value from CSharp field wrapper \"{SharpMemberName}\" as it is write-only!", Context, StartPosition, EndPosition)); + break; + } + + object? value = SharpField.GetValue(Instance); + CSharpToEzrObject(value, result); + break; } } @@ -113,6 +110,6 @@ public override int ComputeHashCode(RuntimeResult result) /// public override string ToString(RuntimeResult result) { - return $"<{TypeName} \"{SharpFieldName}\">"; + return $"<{TypeName} \"{SharpMemberName}\">"; } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs index f9ef16d..f4eebfe 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -1,4 +1,5 @@ using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; using System.Reflection; @@ -26,38 +27,24 @@ public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper /// public readonly object? Instance; - /// - /// The name of the property to wrap, in ezr² format (snake_case). - /// - public readonly string SharpPropertyName; - /// /// Creates a new . /// - /// The name of the property to wrap, in ezr² format (snake_case). /// The property to wrap. /// The object which contains the property, if static. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrSharpCompatibilityProperty(string name, PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + /// Skip property type validation? + public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation=false) : base(sharpProperty, parentContext, startPosition, endPosition) { SharpProperty = sharpProperty; Instance = instance; - SharpPropertyName = name; - Tag = $"{Tag}.{SharpPropertyName}.{Utils.GetNextUniqueId()}"; - } + Tag = $"{Tag}.{SharpMemberName}.{Utils.GetNextUniqueId()}"; - /// - /// Creates a new . Infers the name by converting the member's name to snake_case. - /// - /// The property to wrap. - /// The object which contains the property, if static. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition) - : this(Utils.PascalToSnakeCase(sharpProperty.Name), sharpProperty, instance, parentContext, startPosition, endPosition) { } + if (!skipValidation) + Validate(); + } /// /// If there are no arguments, accesses the property's value. If the property is not read-only and there is an arguments, sets the property's value. @@ -67,30 +54,30 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run { if (arguments.Length > 1) { - result.Failure(new EzrUnexpectedArgumentError($"Only expected 0 (for getting the value) or 1 (for setting the value) argument(s) for CSharp property wrapper \"{SharpPropertyName}\"!", Context, StartPosition, EndPosition)); + result.Failure(new EzrUnexpectedArgumentError($"Only expected 0 (for getting the value) or 1 (for setting the value) argument(s) for CSharp property wrapper \"{SharpMemberName}\"!", Context, StartPosition, EndPosition)); return; } if (arguments.Length == 0) { + if (AutoWrapperAttribute?.IsWriteOnly == true || SharpProperty.GetMethod is null || (AutoWrapperAttribute == null && !SharpProperty.GetMethod.IsPublic)) + { + result.Failure(new EzrIllegalOperationError($"Cannot get value from CSharp property wrapper \"{SharpMemberName}\" as it is write-only!", Context, StartPosition, EndPosition)); + return; + } + object? value = SharpProperty.GetValue(Instance); - PrimitiveToEzrObject(value, value?.GetType(), result); + CSharpToEzrObject(value, result); } else { - object? value = EzrObjectToPrimitive(arguments[0].Object, Type.GetTypeCode(SharpProperty.PropertyType), result); + object? value = EzrObjectToCSharp(arguments[0].Object, SharpProperty.PropertyType, result); if (result.ShouldReturn) return; - if (!SharpProperty.CanWrite || SharpProperty.SetMethod is null) - { - result.Failure(new EzrIllegalOperationError($"Cannot set value to CSharp property wrapper \"{SharpPropertyName}\" as it is read-only!", Context, StartPosition, EndPosition)); - return; - } - - if (!SharpProperty.SetMethod.IsPublic) + if (AutoWrapperAttribute?.IsReadOnly == true || SharpProperty.SetMethod is null || (AutoWrapperAttribute == null && !SharpProperty.SetMethod.IsPublic)) { - result.Failure(new EzrIllegalOperationError($"Cannot set value to CSharp property wrapper \"{SharpPropertyName}\" as it does not have a public setter method!", Context, StartPosition, EndPosition)); + result.Failure(new EzrIllegalOperationError($"Cannot set value to CSharp property wrapper \"{SharpMemberName}\" as it is read-only!", Context, StartPosition, EndPosition)); return; } @@ -125,6 +112,6 @@ public override bool StrictEquals(IEzrObject other, RuntimeResult result) /// public override string ToString(RuntimeResult result) { - return $"<{TypeName} \"{SharpPropertyName}\">"; + return $"<{TypeName} \"{SharpMemberName}\">"; } } diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs deleted file mode 100644 index 3b0deb7..0000000 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFieldWrapper.cs +++ /dev/null @@ -1,124 +0,0 @@ -using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.WrapperAttributes; -using EzrSquared.Util; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; - -/// -/// A class to wrap fields written in C# so that they can be used in ezr². -/// -public class EzrSharpSourceFieldWrapper : EzrSharpSourceExecutableWrapper -{ - /// - public override string TypeName { get; protected internal set; } = "csharp source field wrapper"; - - /// - public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceFieldWrapper"; - - /// - /// The object which the field is a part of, if static. - /// - public readonly object? SharpInstance; - - /// - /// Reflection information about the field. - /// - public readonly FieldInfo SharpField; - - /// - /// The type of the field's value. - /// - public readonly Type SharpFieldType; - - /// - /// The name of the field, in snake_case. - /// - public readonly string SharpFieldName; - - /// - /// Is the field read-only? - /// - public readonly bool IsReadOnlyField; - - /// - /// Creates a new . - /// - /// The field to wrap. - /// The object which the field is a part of, if static. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - /// Thrown if is not found in the field. - public EzrSharpSourceFieldWrapper(FieldInfo fieldInfo, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) - { - SharpInstance = instance; - SharpField = fieldInfo; - - SharpFieldWrapperAttribute attribute = SharpField.GetCustomAttribute(true) ?? throw new ArgumentException($"No \"{nameof(SharpFieldWrapperAttribute)}\" attribute found!", nameof(fieldInfo)); - - ArgumentException? fieldTypeException = SharpFieldWrapperAttribute.ValidateField(SharpField); - if (fieldTypeException is not null) - throw fieldTypeException; - - SharpFieldName = attribute.Name; - SharpFieldType = fieldInfo.FieldType; - IsReadOnlyField = attribute.IsReadOnly; - - if (!IsReadOnlyField && !SharpField.IsLiteral && !SharpField.IsInitOnly) - Parameters = [("value", false)]; - - Tag = $"{Tag}.{SharpFieldName}.{Utils.GetNextUniqueId()}"; - } - - /// - /// If there are no arguments, accesses the field's value. If the field is not read-only and there is an arguments, sets the field's value. - /// - /// - public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) - { - Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result).Arguments; - if (result.ShouldReturn) - return; - - if (argumentReferences.TryGetValue("value", out Reference? newValue)) - { - if (!SharpFieldType.IsAssignableFrom(newValue.Object.GetType())) - { - string sharpFieldType = SharpFieldType.Name; - if (sharpFieldType.StartsWith("Ezr")) - sharpFieldType = sharpFieldType[3..]; - - result.Failure(new EzrUnexpectedTypeError($"Expected object of type \"{PascalCaseToLowerCasePlainText(sharpFieldType)}\", but got object of type \"{newValue.Object.TypeName}\"!", _executionContext, StartPosition, EndPosition)); - return; - } - - SharpField.SetValue(SharpInstance, newValue.Object); - } - - IEzrObject? fieldValue = (IEzrObject?)SharpField.GetValue(SharpInstance); - Reference fieldReference = fieldValue is null ? NewNothingConstant() : ReferencePool.Get(fieldValue, AccessMod.PrivateConstant); - - result.Success(fieldReference); - } - - /// - public override int ComputeHashCode(RuntimeResult result) - { - return HashCode.Combine(HashTag, SharpField); - } - - /// - public override bool StrictEquals(IEzrObject other, RuntimeResult result) - { - return (other as EzrSharpSourceFieldWrapper)?.SharpField == SharpField && other.HashTag == HashTag; - } - - /// - public override string ToString(RuntimeResult result) - { - return $"<{TypeName} \"{SharpFieldName}\">"; - } -} diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs deleted file mode 100644 index ae90a33..0000000 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourcePropertyWrapper.cs +++ /dev/null @@ -1,117 +0,0 @@ -using EzrSquared.Runtime.Types.Core; -using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.WrapperAttributes; -using EzrSquared.Util; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; - -/// -/// A class to wrap properties written in C# so that they can be used in ezr². -/// -public class EzrSharpSourcePropertyWrapper : EzrSharpSourceExecutableWrapper -{ - /// - public override string TypeName { get; protected internal set; } = "csharp source field wrapper"; - - /// - public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceFieldWrapper"; - - /// - /// The object which the property is a part of, if static. - /// - public readonly object? SharpInstance; - - /// - /// Reflection information about the property. - /// - public readonly PropertyInfo SharpProperty; - - /// - /// The type of the property's value. - /// - public readonly Type SharpPropertyType; - - /// - /// The name of the property, in snake_case. - /// - public readonly string SharpPropertyName; - - /// - /// Creates a new . - /// - /// The property to wrap. - /// The object which the property is a part of, if static. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - /// Thrown if is not found in the property. - public EzrSharpSourcePropertyWrapper(PropertyInfo propertyInfo, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) - { - SharpInstance = instance; - SharpProperty = propertyInfo; - - SharpFieldWrapperAttribute attribute = SharpProperty.GetCustomAttribute(true) ?? throw new ArgumentException($"No \"{nameof(SharpFieldWrapperAttribute)}\" attribute found!", nameof(propertyInfo)); - - Exception? propertyTypeException = SharpFieldWrapperAttribute.ValidateProperty(SharpProperty); - if (propertyTypeException is not null) - throw propertyTypeException; - - SharpPropertyName = attribute.Name; - SharpPropertyType = propertyInfo.PropertyType; - - if (SharpProperty.CanWrite && !attribute.IsReadOnly) - Parameters = [("value", false)]; - - Tag = $"{Tag}.{SharpPropertyName}.{Utils.GetNextUniqueId()}"; - } - - /// - /// If there are no arguments, accesses the property's value. If the property is not read-only and there is an arguments, sets the property's value. - /// - /// - public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) - { - Dictionary argumentReferences = CheckAndPopulateArguments(arguments, result).Arguments; - if (result.ShouldReturn) - return; - - if (argumentReferences.TryGetValue("value", out Reference? newValue)) - { - if (!SharpPropertyType.IsAssignableFrom(newValue.Object.GetType())) - { - string sharpFieldType = SharpPropertyType.Name; - if (sharpFieldType.StartsWith("Ezr")) - sharpFieldType = sharpFieldType[3..]; - - result.Failure(new EzrUnexpectedTypeError($"Expected object of type \"{PascalCaseToLowerCasePlainText(sharpFieldType)}\", but got object of type \"{newValue.Object.TypeName}\"!", _executionContext, StartPosition, EndPosition)); - return; - } - - SharpProperty.SetValue(SharpInstance, newValue.Object); - } - - IEzrObject value = (IEzrObject?)SharpProperty.GetValue(SharpInstance) ?? EzrConstants.Nothing; - result.Success(ReferencePool.Get(value, AccessMod.PrivateConstant)); - } - - /// - public override int ComputeHashCode(RuntimeResult result) - { - return HashCode.Combine(HashTag, SharpProperty); - } - - /// - public override bool StrictEquals(IEzrObject other, RuntimeResult result) - { - return (other as EzrSharpSourceFieldWrapper)?.SharpField == SharpProperty && other.HashTag == HashTag; - } - - /// - public override string ToString(RuntimeResult result) - { - return $"<{TypeName} \"{SharpPropertyName}\">"; - } -} diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index d4c3fc0..0f1f17a 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -117,10 +117,16 @@ public EzrSharpSourceTypeWrapper( string methodName; // Check if method can be wrapped. - if (method.GetCustomAttribute(false) is SharpMethodWrapperAttribute methodAttribute) - (wrappedMethod, methodName) = GetWrappedMethod(method); - else if (method.GetCustomAttribute(false) is SharpAutoCompatibilityWrapperAttribute autoWrapAttribute) - (wrappedMethod, methodName) = GetAutoWrappedMethod(method, autoWrapAttribute); + if (method.GetCustomAttribute(false) is not null) + { + EzrSharpSourceFunctionWrapper sourceMethod = new(method, Context, StartPosition, EndPosition); + (wrappedMethod, methodName) = (sourceMethod, sourceMethod.SharpFunctionName); + } + else if (method.GetCustomAttribute(false) is not null) + { + EzrSharpCompatibilityFunction compatMethod = new(method, null, Context, StartPosition, EndPosition); + (wrappedMethod, methodName) = (compatMethod, compatMethod.SharpMemberName); + } else continue; @@ -141,18 +147,10 @@ public EzrSharpSourceTypeWrapper( string propertyName; // Check if property can be wrapped. - if (property.GetCustomAttribute(false) is SharpFieldWrapperAttribute propertyAttribute) + if (property.GetCustomAttribute(false) is not null) { - EzrSharpSourcePropertyWrapper sourceWrapper = new(property, null, Context, StartPosition, EndPosition); - (wrappedProperty, propertyName) = (sourceWrapper, sourceWrapper.SharpPropertyName); - } - else if (property.GetCustomAttribute(false) is SharpAutoCompatibilityWrapperAttribute autoWrapAttribute) - { - EzrSharpCompatibilityProperty compatWrapper = !string.IsNullOrEmpty(autoWrapAttribute.Name) - ? new(autoWrapAttribute.Name, property, null, Context, StartPosition, EndPosition) - : new(property, null, Context, StartPosition, EndPosition); - - (wrappedProperty, propertyName) = (compatWrapper, compatWrapper.SharpPropertyName); + EzrSharpCompatibilityProperty compatWrapper = new(property, null, Context, StartPosition, EndPosition); + (wrappedProperty, propertyName) = (compatWrapper, compatWrapper.SharpMemberName); } else continue; @@ -173,18 +171,10 @@ public EzrSharpSourceTypeWrapper( string fieldName; // Check if property can be wrapped. - if (field.GetCustomAttribute(false) is SharpFieldWrapperAttribute fieldAttribute) + if (field.GetCustomAttribute(false) is not null) { - EzrSharpSourceFieldWrapper sourceWrapper = new(field, null, Context, StartPosition, EndPosition); - (wrappedField, fieldName) = (sourceWrapper, sourceWrapper.SharpFieldName); - } - else if (field.GetCustomAttribute(false) is SharpAutoCompatibilityWrapperAttribute autoWrapAttribute) - { - EzrSharpCompatibilityField compatWrapper = !string.IsNullOrEmpty(autoWrapAttribute.Name) - ? new(autoWrapAttribute.Name, field, null, Context, StartPosition, EndPosition) - : new(field, null, Context, StartPosition, EndPosition); - - (wrappedField, fieldName) = (compatWrapper, compatWrapper.SharpFieldName); + EzrSharpCompatibilityField compatWrapper = new(field, null, Context, StartPosition, EndPosition); + (wrappedField, fieldName) = (compatWrapper, compatWrapper.SharpMemberName); } else continue; @@ -197,44 +187,6 @@ public EzrSharpSourceTypeWrapper( } } - /// - /// Creates a from a -decorated method. - /// - /// The method to wrap. - /// The method wrapper and its ezr² (snake_case) formatted name. - private (IEzrObject, string) GetWrappedMethod(MethodInfo method) - { - // Check if parameters of the method are valid. - Exception? parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(method); - if (parameterException is not null) - throw parameterException; - - // Create the wrapper object. - EzrSharpSourceFunctionWrapper wrapper = new(method, Context, StartPosition, EndPosition); - return (wrapper, wrapper.SharpFunctionName); - } - - /// - /// Creates a from a -decorated method. - /// - /// The method to wrap. - /// The wrapper attribute. - /// The method wrapper and its ezr² (snake_case) formatted name. - private (IEzrObject, string) GetAutoWrappedMethod(MethodInfo method, SharpAutoCompatibilityWrapperAttribute attribute) - { - // Check if the method is eligible for automatic wrapping. - ArgumentException? formatException = SharpAutoCompatibilityWrapperAttribute.ValidateMethod(method); - if (formatException is not null) - throw formatException; - - // Create the wrapper object. - EzrSharpCompatibilityFunction wrapper = !string.IsNullOrEmpty(attribute.Name) - ? new(attribute.Name, method, null, Context, StartPosition, EndPosition) - : new(method, null, Context, StartPosition, EndPosition); - - return (wrapper, wrapper.SharpRuntimeExecutableName); - } - /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index eb5d577..3ebfd6d 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -28,7 +28,7 @@ public class EzrList : EzrObject, IEzrMutableObject, IEzrIndexedCollection public readonly RuntimeEzrObjectList Value; /// - [SharpAutoCompatibilityWrapper(IsReadOnly = true)] + [SharpAutoWrapper(IsReadOnly = true)] public int Length => Value.Count; /// The base value. diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index 8d1b343..30d6b30 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -34,7 +34,7 @@ public class EzrCharacterList : EzrObject, IEzrMutableObject, IEzrString, IEzrIn public string StringValue => Value.ToString(); /// - [SharpAutoCompatibilityWrapper(IsReadOnly = true)] + [SharpAutoWrapper(IsReadOnly = true)] public int Length => Value.Length; /// diff --git a/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs deleted file mode 100644 index a22eb8e..0000000 --- a/src/Runtime/WrapperAttributes/SharpAutoCompatibilityWrapperAttribute.cs +++ /dev/null @@ -1,68 +0,0 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; -using System; -using System.Reflection; - -namespace EzrSquared.Runtime.WrapperAttributes; - -/// -/// Attribute for C# type members which to be automatically wrapped from primitive C# types into ezr² types. -/// -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] -public class SharpAutoCompatibilityWrapperAttribute : Attribute -{ - /// - /// The ezr² name for the member. - /// - public string Name = string.Empty; - - /// - /// Is the member read-only? Only for properties and fields. - /// - public bool IsReadOnly; - - /// - /// Checks if the given field is a supported primitive type. - /// - /// The field. - /// if the check was successful, an otherwise. - public static ArgumentException? ValidateField(FieldInfo fieldInfo) - { - return !EzrSharpCompatibilityWrapper.IsSupportedPrimitiveType(fieldInfo.FieldType) - ? new($"Expected field \"{fieldInfo.Name}\" to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\"", nameof(fieldInfo)) - : null; - } - - /// - /// Checks if the given property is a supported primitive type. - /// - /// The property. - /// if the check was successful, an otherwise. - public static ArgumentException? ValidateProperty(PropertyInfo propertyInfo) - { - return !EzrSharpCompatibilityWrapper.IsSupportedPrimitiveType(propertyInfo.PropertyType) - ? new($"Expected property \"{propertyInfo.Name}\" to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\"", nameof(propertyInfo)) - : null; - } - - /// - /// Checks if the given method has the supported signature. - /// - /// The method. - /// if the check was successful, an otherwise. - public static ArgumentException? ValidateMethod(MethodInfo methodInfo) - { - if (methodInfo.IsGenericMethod) - return new($"The \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\" attribute does not support generic method \"{methodInfo.Name}\".", nameof(methodInfo)); - - if (methodInfo.ReturnType != typeof(void) && !EzrSharpCompatibilityWrapper.IsSupportedReturnType(methodInfo.ReturnType)) - return new($"Expected method \"{methodInfo.Name}\"'s return type to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\"", nameof(methodInfo)); - - foreach (ParameterInfo parameterInfo in methodInfo.GetParameters()) - { - if (!EzrSharpCompatibilityWrapper.IsSupportedPrimitiveType(parameterInfo.ParameterType)) - return new($"Expected all of method \"{methodInfo.Name}\"'s parameters to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoCompatibilityWrapperAttribute)}\", but found parameter \"{parameterInfo.Name}\" of type \"{parameterInfo.ParameterType.Name}\"", nameof(methodInfo)); - } - - return null; - } -} diff --git a/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs new file mode 100644 index 0000000..5634dae --- /dev/null +++ b/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs @@ -0,0 +1,89 @@ +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; +using System; +using System.Reflection; + +namespace EzrSquared.Runtime.WrapperAttributes; + +/// +/// Attribute for C# type members which to be automatically wrapped from primitive C# types into ezr² types. +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] +public class SharpAutoWrapperAttribute : Attribute +{ + /// + /// The ezr² name for the member. + /// + public string Name = string.Empty; + + /// + /// Is the member read-only? Only for properties and fields. + /// + public bool IsReadOnly; + + /// + /// Is the member write-only? Only for properties and fields. + /// + public bool IsWriteOnly; + + /// + /// Checks if the given member is supported for wrapping. + /// + /// The member. + /// if the check was successful, an otherwise. + public static Exception? Validate(MemberInfo memberInfo) + { + return memberInfo switch + { + FieldInfo field => ValidateField(field), + PropertyInfo property => ValidateProperty(property), + MethodBase method => ValidateMethod(method), + _ => throw new ArgumentException($"Unsupported {nameof(MemberInfo)} type {memberInfo.GetType().Name} for validation!", nameof(memberInfo)) + }; + } + + /// + /// Checks if the given field is a supported type for wrapping. + /// + /// The field. + /// if the check was successful, an otherwise. + public static ArgumentException? ValidateField(FieldInfo fieldInfo) + { + return !EzrSharpCompatibilityWrapper.IsSupportedType(fieldInfo.FieldType) + ? new($"Expected field \"{fieldInfo.Name}\" to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\"", nameof(fieldInfo)) + : null; + } + + /// + /// Checks if the given property is a supported type for wrapping. + /// + /// The property. + /// if the check was successful, an otherwise. + public static ArgumentException? ValidateProperty(PropertyInfo propertyInfo) + { + return !EzrSharpCompatibilityWrapper.IsSupportedType(propertyInfo.PropertyType) + ? new($"Expected property \"{propertyInfo.Name}\" to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\"", nameof(propertyInfo)) + : null; + } + + /// + /// Checks if the given method has the supported signature for wrapping. + /// + /// The method. + /// if the check was successful, an otherwise. + public static ArgumentException? ValidateMethod(MethodBase methodBase) + { + if (methodBase.IsGenericMethod || methodBase.ContainsGenericParameters) + return new($"The \"{nameof(SharpAutoWrapperAttribute)}\" attribute does not support generic method/constructor \"{methodBase.Name}\".", nameof(methodBase)); + + if (methodBase is MethodInfo methodInfo && methodInfo.ReturnType != typeof(void) && !EzrSharpCompatibilityWrapper.IsSupportedReturnType(methodInfo.ReturnType)) + return new($"Expected method \"{methodBase.Name}\"'s return type to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\"", nameof(methodBase)); + + foreach (ParameterInfo parameterInfo in methodBase.GetParameters()) + { + if (!EzrSharpCompatibilityWrapper.IsSupportedType(parameterInfo.ParameterType)) + return new($"Expected all of method/constructor \"{methodBase.Name}\"'s parameters to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\", but found parameter \"{parameterInfo.Name}\" of type \"{parameterInfo.ParameterType.Name}\"", nameof(methodBase)); + } + + return null; + } +} diff --git a/src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs deleted file mode 100644 index 298e509..0000000 --- a/src/Runtime/WrapperAttributes/SharpFieldWrapperAttribute.cs +++ /dev/null @@ -1,47 +0,0 @@ -using EzrSquared.Runtime.Types; -using System; -using System.Reflection; - -namespace EzrSquared.Runtime.WrapperAttributes; - -/// -/// Attribute for C# fields and properties which will be wrapped into ezr². -/// -/// The ezr² name for the property or field. -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] -public class SharpFieldWrapperAttribute(string name) : Attribute -{ - /// - /// The ezr² name for the property or field. - /// - public string Name = name; - - /// - /// Is the property or field read-only? - /// - public bool IsReadOnly; - - /// - /// Checks if the given field is of type . - /// - /// The field. - /// if the check was successful, an otherwise. - public static ArgumentException? ValidateField(FieldInfo fieldInfo) - { - return !typeof(IEzrObject).IsAssignableFrom(fieldInfo.FieldType) - ? new($"Expected field \"{fieldInfo.Name}\" to be of type {nameof(IEzrObject)}, as it uses the attribute \"{nameof(SharpFieldWrapperAttribute)}\"", nameof(fieldInfo)) - : null; - } - - /// - /// Checks if the given property is of type . - /// - /// The property. - /// if the check was successful, an otherwise. - public static ArgumentException? ValidateProperty(PropertyInfo propertyInfo) - { - return !typeof(IEzrObject).IsAssignableFrom(propertyInfo.PropertyType) - ? new($"Expected property \"{propertyInfo.Name}\" to be of type {nameof(IEzrObject)}, as it uses the attribute \"{nameof(SharpFieldWrapperAttribute)}\"", nameof(propertyInfo)) - : null; - } -} diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index b7d9982..cc76c3b 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.8.5"; + private const string Version = "0.9.0"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 397cb82..5544b78 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.5" +#define MyAppVersion "0.9.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 8b5b1a3..22198ce 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.8.5" +#define MyAppVersion "0.9.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index b3f9494..ab32e27 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.8.5 + 0.9.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From 5ed4199f791032e4e39051485d4eb66297bf5546 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Mon, 4 Nov 2024 00:32:24 +0530 Subject: [PATCH 068/113] Bugfixes and improvements for the previous commit. --- src/Executor/CodeExecutor.cs | 7 ++- src/GlobalSuppressions.cs | 1 + .../Collections/RuntimeEzrObjectDictionary.cs | 4 +- .../EzrSharpCompatibilityObjectInstance.cs | 56 +++++++++++-------- .../EzrSharpCompatibilityType.cs | 30 +++++----- .../EzrSharpCompatibilityWrapper.cs | 32 ++++++++--- .../EzrSharpCompatibilityConstructor.cs | 4 +- .../EzrSharpCompatibilityExecutable.cs | 8 ++- .../EzrSharpCompatibilityFunction.cs | 2 +- .../EzrSharpCompatibilityField.cs | 5 +- .../EzrSharpCompatibilityProperty.cs | 3 +- .../Types/Collections/EzrDictionary.cs | 2 +- src/Runtime/Types/Collections/EzrList.cs | 2 +- .../Types/Core/Text/EzrCharacterList.cs | 2 +- .../SharpAutoWrapperAttribute.cs | 36 ++++++++++-- src/Util/Utils.cs | 22 -------- 16 files changed, 128 insertions(+), 88 deletions(-) diff --git a/src/Executor/CodeExecutor.cs b/src/Executor/CodeExecutor.cs index 293eb2d..998c96e 100644 --- a/src/Executor/CodeExecutor.cs +++ b/src/Executor/CodeExecutor.cs @@ -17,6 +17,11 @@ public static class CodeExecutor /// public static readonly Interpreter Interpreter = new(); + /// + /// The static of . + /// + public static RuntimeResult RuntimeResult => Interpreter.RuntimeResult; + /// /// The runtime context, may be . /// @@ -40,7 +45,7 @@ public static void CreateRuntimeContext(string filePath) /// Use to initialize the runtime context. /// /// Exclude built-in I/O functions like ? - public static void PopulateRuntimeContext(bool excludeIO=false) + public static void PopulateRuntimeContext(bool excludeIO = false) { if (RuntimeContext is null) throw new NullReferenceException($"{nameof(RuntimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); diff --git a/src/GlobalSuppressions.cs b/src/GlobalSuppressions.cs index 3cb47e8..c5e947a 100644 --- a/src/GlobalSuppressions.cs +++ b/src/GlobalSuppressions.cs @@ -10,3 +10,4 @@ [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrCharacterList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Collections.EzrList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrString.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] +[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "That's too many ternary operations.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.EzrSharpCompatibilityWrapper.Validate~System.Boolean")] diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index 71c28c8..64589a4 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -21,7 +21,7 @@ public class RuntimeEzrObjectDictionary : IMutable /// /// The number of s in the . /// - [SharpAutoWrapper(IsReadOnly = true)] + [SharpAutoWrapper(isReadOnly: true)] public int Length => _items.Count; /// @@ -103,7 +103,7 @@ public bool Remove(IEzrObject key, RuntimeResult result) /// /// The key (hash) to be removed. /// if the operation was successful, if not. - [SharpAutoWrapper(Name = "remove_by_hash")] + [SharpAutoWrapper("remove_by_hash")] public bool RemoveHash(int key) { return _items.Remove(key); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index af17d7e..94f72f1 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -1,5 +1,6 @@ using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; using System.Collections.Generic; @@ -29,7 +30,6 @@ public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper /// /// The object to wrap. /// The C# object's type. - /// Runtime result for carrying any errors. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. @@ -45,20 +45,24 @@ public EzrSharpCompatibilityObjectInstance( | DynamicallyAccessedMemberTypes.NonPublicFields)] Type instanceType, - RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(instanceType, parentContext, startPosition, endPosition) + Context parentContext, Position startPosition, Position endPosition) : base(instanceType, parentContext, startPosition, endPosition) { Instance = instance; Tag = $"{Tag}.{SharpMemberName}.{Utils.GetNextUniqueId()}"; - MethodInfo[] publicMethods = instanceType.GetMethods(BindingFlags.Public | BindingFlags.Instance); - Dictionary duplicateNames = new(publicMethods.Length); - for (int i = 0; i < publicMethods.Length; i++) + MethodInfo[] allMethods = instanceType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + Dictionary duplicateNames = new(allMethods.Length); + for (int i = 0; i < allMethods.Length; i++) { - MethodInfo method = publicMethods[i]; - if (method.IsAbstract) + MethodInfo method = allMethods[i]; + if (method.IsAbstract || (!method.IsPublic && method.GetCustomAttribute() is null)) continue; - string methodObjectName = Utils.PascalToSnakeCase(method.Name); + EzrSharpCompatibilityFunction methodObject = new(method, Instance, Context, StartPosition, EndPosition, skipValidation: true); + if (!methodObject.Validate()) + continue; + + string methodObjectName = methodObject.SharpMemberName; if (duplicateNames.TryGetValue(method.Name, out int duplicates)) { methodObjectName += $"_{duplicates}"; @@ -67,31 +71,35 @@ public EzrSharpCompatibilityObjectInstance( else duplicateNames.Add(method.Name, 1); - EzrSharpCompatibilityFunction methodObject = new(method, Instance, Context, StartPosition, EndPosition); - if (methodObject.Validate(result)) - return; - Context.Set(null, methodObjectName, ReferencePool.Get(methodObject, AccessMod.Constant)); } - PropertyInfo[] publicProperties = instanceType.GetProperties(BindingFlags.Public | BindingFlags.Instance); - for (int i = 0; i < publicProperties.Length; i++) + PropertyInfo[] allProperties = instanceType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + for (int i = 0; i < allProperties.Length; i++) { - EzrSharpCompatibilityProperty property = new(publicProperties[i], Instance, Context, StartPosition, EndPosition); - if (property.Validate(result)) - return; + PropertyInfo property = allProperties[i]; + if (property.GetMethod?.IsPublic != true && property.SetMethod?.IsPublic != true && property.GetCustomAttribute() is null) + continue; - Context.Set(null, property.SharpMemberName, ReferencePool.Get(property, AccessMod.Constant)); + EzrSharpCompatibilityProperty propertyObject = new(property, Instance, Context, StartPosition, EndPosition, skipValidation: true); + if (!propertyObject.Validate()) + continue; + + Context.Set(null, propertyObject.SharpMemberName, ReferencePool.Get(propertyObject, AccessMod.Constant)); } - FieldInfo[] publicFields = instanceType.GetFields(BindingFlags.Public | BindingFlags.Instance); - for (int i = 0; i < publicFields.Length; i++) + FieldInfo[] allFields = instanceType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + for (int i = 0; i < allFields.Length; i++) { - EzrSharpCompatibilityField field = new(publicFields[i], Instance, Context, StartPosition, EndPosition); - if (field.Validate(result)) - return; + FieldInfo field = allFields[i]; + if (!field.IsPublic && field.GetCustomAttribute() is null) + continue; + + EzrSharpCompatibilityField fieldObject = new(field, Instance, Context, StartPosition, EndPosition, skipValidation: true); + if (!fieldObject.Validate()) + continue; - Context.Set(null, field.SharpMemberName, ReferencePool.Get(field, AccessMod.Constant)); + Context.Set(null, fieldObject.SharpMemberName, ReferencePool.Get(fieldObject, AccessMod.Constant)); } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index 6c4e197..1323c39 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -74,7 +74,11 @@ public EzrSharpCompatibilityType( if (method.IsAbstract || (!method.IsPublic && method.GetCustomAttribute() is null)) continue; - string methodObjectName = Utils.PascalToSnakeCase(method.Name); + EzrSharpCompatibilityFunction methodObject = new(method, null, Context, StartPosition, EndPosition, skipValidation: true); + if (!methodObject.Validate()) + continue; + + string methodObjectName = methodObject.SharpMemberName; if (duplicateNames.TryGetValue(method.Name, out int duplicates)) { methodObjectName += $"_{duplicates}"; @@ -83,10 +87,6 @@ public EzrSharpCompatibilityType( else duplicateNames.Add(method.Name, 1); - EzrSharpCompatibilityFunction methodObject = new(method, null, Context, StartPosition, EndPosition); - if (!methodObject.Validate(result)) - return; - Context.Set(null, methodObjectName, ReferencePool.Get(methodObject, AccessMod.Constant)); } @@ -97,9 +97,9 @@ public EzrSharpCompatibilityType( if (property.GetMethod?.IsPublic != true && property.SetMethod?.IsPublic != true && property.GetCustomAttribute() is null) continue; - EzrSharpCompatibilityProperty propertyObject = new(property, null, Context, StartPosition, EndPosition); - if (!propertyObject.Validate(result)) - return; + EzrSharpCompatibilityProperty propertyObject = new(property, null, Context, StartPosition, EndPosition, skipValidation: true); + if (!propertyObject.Validate()) + continue; Context.Set(null, propertyObject.SharpMemberName, ReferencePool.Get(propertyObject, AccessMod.Constant)); } @@ -111,9 +111,9 @@ public EzrSharpCompatibilityType( if (!field.IsPublic && field.GetCustomAttribute() is null) continue; - EzrSharpCompatibilityField fieldObject = new(field, null, Context, StartPosition, EndPosition); - if (!fieldObject.Validate(result)) - return; + EzrSharpCompatibilityField fieldObject = new(field, null, Context, StartPosition, EndPosition, skipValidation: true); + if (!fieldObject.Validate()) + continue; Context.Set(null, fieldObject.SharpMemberName, ReferencePool.Get(fieldObject, AccessMod.Constant)); } @@ -122,12 +122,12 @@ public EzrSharpCompatibilityType( for (int i = 0; i < publicConstructors.Length; i++) { ConstructorInfo constructor = publicConstructors[i]; - if (!constructor.IsPublic) + if (!constructor.IsPublic && constructor.GetCustomAttribute() is null) continue; - EzrSharpCompatibilityConstructor constructorObject = new(this, constructor, Context, StartPosition, EndPosition); - if (constructorObject.Validate(result)) - return; + EzrSharpCompatibilityConstructor constructorObject = new(this, constructor, Context, StartPosition, EndPosition, skipValidation: true); + if (!constructorObject.Validate()) + continue; Context.Set(null, $"make_{i}", ReferencePool.Get(constructorObject, AccessMod.Constant)); } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 7ed8db3..5a46ba6 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -7,6 +7,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Text; using System.Threading.Tasks; namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; @@ -48,25 +49,42 @@ public EzrSharpCompatibilityWrapper(MemberInfo wrappedMember, Context parentCont { SharpMember = wrappedMember; AutoWrapperAttribute = wrappedMember.GetCustomAttribute(); - SharpMemberName = !string.IsNullOrEmpty(AutoWrapperAttribute?.Name) ? AutoWrapperAttribute.Name : Utils.PascalToSnakeCase(wrappedMember.Name); + SharpMemberName = !string.IsNullOrEmpty(AutoWrapperAttribute?.Name) ? AutoWrapperAttribute.Name : PascalToSnakeCase(wrappedMember.Name); } /// /// Validates the the current object for wrapping. /// - /// Optional runtime result for carrying runtime errors. /// if the member can be wrapped, otherwise. - public bool Validate(RuntimeResult? result=null) + public bool Validate() { Exception? validationException = SharpAutoWrapperAttribute.Validate(SharpMember); if (validationException is null) return true; - if (AutoWrapperAttribute is not null) - throw validationException; + return AutoWrapperAttribute is not null ? throw validationException : false; + } + + /// + /// Converts a string from PascalCase to snake_case. + /// + /// The text to convert in PascalCase. + /// The converted text in snake_case. + internal protected static string PascalToSnakeCase(string text) + { + StringBuilder result = new(); + result.Append(char.ToLowerInvariant(text[0])); + + for (int i = 1; i < text.Length; ++i) + { + char c = text[i]; + if (char.IsUpper(c)) + result.Append('_').Append(char.ToLowerInvariant(c)); + else + result.Append(c); + } - result?.Failure(new EzrUnsupportedWrappingError($"C# type member \"{SharpMemberName}\" cannot be wrapped into an ezr² type!", Context, StartPosition, EndPosition)); - return false; + return result.ToString(); } /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index 8b64938..29beb55 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -14,7 +14,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.E /// The starting position of the object. /// The ending position of the object. /// Skip method signature validation? -public class EzrSharpCompatibilityConstructor(EzrSharpCompatibilityType constructingTypeWrapper, ConstructorInfo sharpConstructor, Context parentContext, Position startPosition, Position endPosition, bool skipValidation=false) : EzrSharpCompatibilityExecutable(sharpConstructor, null, parentContext, startPosition, endPosition, skipValidation) +public class EzrSharpCompatibilityConstructor(EzrSharpCompatibilityType constructingTypeWrapper, ConstructorInfo sharpConstructor, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : EzrSharpCompatibilityExecutable(sharpConstructor, null, parentContext, startPosition, endPosition, skipValidation) { /// /// The wrapper for this C# constructor's class. @@ -40,7 +40,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run result.Success(NewNothingConstant()); else { - IEzrObject wrapper = new EzrSharpCompatibilityObjectInstance(output, ConstructingTypeWrapper.SharpType, result, _executionContext, StartPosition, EndPosition); + IEzrObject wrapper = new EzrSharpCompatibilityObjectInstance(output, ConstructingTypeWrapper.SharpType, _executionContext, StartPosition, EndPosition); if (result.ShouldReturn) return; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index c1de8a2..fe20943 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -53,7 +53,13 @@ public EzrSharpCompatibilityExecutable(MethodBase sharpMember, object? instance, Executable = sharpMember; Parameters = Executable.GetParameters(); - ParameterNames = Array.ConvertAll(Parameters, p => Utils.PascalToSnakeCase(p.Name ?? string.Empty)); + + ParameterNames = Array.ConvertAll(Parameters, p => + { + string? definedName = p.GetCustomAttribute()?.Name; + return string.IsNullOrEmpty(definedName) ? PascalToSnakeCase(p.Name ?? string.Empty) : definedName; + }); + Instance = instance; if (!skipValidation) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs index b8acd3e..bd87ef8 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs @@ -14,7 +14,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.E /// The starting position of the object. /// The ending position of the object. /// Skip method signature validation? -public class EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation=false) : EzrSharpCompatibilityExecutable(sharpFunction, instance, parentContext, startPosition, endPosition, skipValidation) +public class EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : EzrSharpCompatibilityExecutable(sharpFunction, instance, parentContext, startPosition, endPosition, skipValidation) { /// public override string TypeName { get; protected internal set; } = "csharp function"; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index b373093..70d1a64 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; using System.Reflection; @@ -36,7 +35,7 @@ public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper /// The starting position of the object. /// The ending position of the object. /// Skip field type validation? - public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation=false) : base(sharpField, parentContext, startPosition, endPosition) + public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : base(sharpField, parentContext, startPosition, endPosition) { SharpField = sharpField; Instance = instance; @@ -85,7 +84,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run result.Failure(new EzrIllegalOperationError($"Cannot get value from CSharp field wrapper \"{SharpMemberName}\" as it is write-only!", Context, StartPosition, EndPosition)); break; } - + object? value = SharpField.GetValue(Instance); CSharpToEzrObject(value, result); break; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs index f4eebfe..3e2e3b0 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -1,5 +1,4 @@ using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; using System.Reflection; @@ -36,7 +35,7 @@ public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper /// The starting position of the object. /// The ending position of the object. /// Skip property type validation? - public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation=false) : base(sharpProperty, parentContext, startPosition, endPosition) + public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : base(sharpProperty, parentContext, startPosition, endPosition) { SharpProperty = sharpProperty; Instance = instance; diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index 44b1fb0..f9a1e0a 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -64,7 +64,7 @@ public EzrDictionary(RuntimeEzrObjectDictionary value, Context parentContext, Po private void DictionaryExists(SharpMethodParameters arguments) { Reference reference = arguments.ArgumentReferences["key"]; - + bool hasKey = Value.HasKey(reference.Object, arguments.Result); if (arguments.Result.ShouldReturn) return; diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index 3ebfd6d..2389e3e 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -28,7 +28,7 @@ public class EzrList : EzrObject, IEzrMutableObject, IEzrIndexedCollection public readonly RuntimeEzrObjectList Value; /// - [SharpAutoWrapper(IsReadOnly = true)] + [SharpAutoWrapper(isReadOnly: true)] public int Length => Value.Count; /// The base value. diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index 30d6b30..15d1d38 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -34,7 +34,7 @@ public class EzrCharacterList : EzrObject, IEzrMutableObject, IEzrString, IEzrIn public string StringValue => Value.ToString(); /// - [SharpAutoWrapper(IsReadOnly = true)] + [SharpAutoWrapper(isReadOnly: true)] public int Length => Value.Length; /// diff --git a/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs index 5634dae..0a25407 100644 --- a/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs @@ -5,25 +5,51 @@ namespace EzrSquared.Runtime.WrapperAttributes; /// -/// Attribute for C# type members which to be automatically wrapped from primitive C# types into ezr² types. +/// Attribute for C# type members which to be automatically wrapped from C# types into ezr² types. /// -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] public class SharpAutoWrapperAttribute : Attribute { /// /// The ezr² name for the member. /// - public string Name = string.Empty; + public readonly string Name = string.Empty; /// /// Is the member read-only? Only for properties and fields. /// - public bool IsReadOnly; + public readonly bool IsReadOnly; /// /// Is the member write-only? Only for properties and fields. /// - public bool IsWriteOnly; + public readonly bool IsWriteOnly; + + /// + /// Creates a new . + /// + /// Is the member read-only? Only for properties and fields. + /// Is the member write-only? Only for properties and fields. + /// Thrown if both and are set to . + public SharpAutoWrapperAttribute(bool isReadOnly = false, bool isWriteOnly = false) + { + IsReadOnly = isReadOnly; + IsWriteOnly = isWriteOnly; + + if (IsWriteOnly && IsReadOnly) + throw new ArgumentException("You can't make a property or field both read-only and write-only."); + } + + /// + /// Creates a new . + /// + /// The ezr² name for the member. + /// Is the member read-only? Only for properties and fields. + /// Is the member write-only? Only for properties and fields. + public SharpAutoWrapperAttribute(string name, bool isReadOnly = false, bool isWriteOnly = false) : this(isReadOnly, isWriteOnly) + { + Name = name; + } /// /// Checks if the given member is supported for wrapping. diff --git a/src/Util/Utils.cs b/src/Util/Utils.cs index e070d2d..8632e01 100644 --- a/src/Util/Utils.cs +++ b/src/Util/Utils.cs @@ -98,26 +98,4 @@ public static (int AdjustedLineNumber, string SourceWithUnderline) SourceWithUnd return (line, result.ToString()); } - - /// - /// Converts a string from PascalCase to snake_case. - /// - /// The text to convert in PascalCase. - /// The converted text in snake_case. - public static string PascalToSnakeCase(string text) - { - StringBuilder result = new(); - result.Append(char.ToLowerInvariant(text[0])); - - for (int i = 1; i < text.Length; ++i) - { - char c = text[i]; - if (char.IsUpper(c)) - result.Append('_').Append(char.ToLowerInvariant(c)); - else - result.Append(c); - } - - return result.ToString(); - } } From 27d0075eff19d51a5bf2cc0af33c37210ef3a585 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Mon, 4 Nov 2024 01:49:44 +0530 Subject: [PATCH 069/113] Overhaul of error types and `Utils` class. --- src/Executor/CodeExecutor.cs | 2 +- src/Executor/ExecutionResult.cs | 6 +- src/{Util/Utils.cs => IEzrError.cs} | 43 ++--- src/Runtime/Context.cs | 2 +- src/Runtime/Nodes/BaseNodes.cs | 2 +- .../EzrSharpCompatibilityObjectInstance.cs | 2 +- .../EzrSharpCompatibilityType.cs | 2 +- .../EzrSharpCompatibilityExecutable.cs | 2 +- .../EzrSharpCompatibilityField.cs | 2 +- .../EzrSharpCompatibilityProperty.cs | 2 +- .../EzrSharpSourceExecutableWrapper.cs | 22 ++- .../EzrSharpSourceFunctionWrapper.cs | 2 +- .../EzrSharpSourceTypeWrapper.cs | 2 +- .../Core/RuntimeErrors/EzrRuntimeError.cs | 3 +- .../Core/RuntimeErrors/IEzrRuntimeError.cs | 22 +-- .../Types/Executables/EzrRuntimeExecutable.cs | 4 +- src/Syntax/Errors/EzrStackedSyntaxError.cs | 18 ++ src/Syntax/Errors/EzrSyntaxError.cs | 42 ++++ src/Syntax/Errors/StackedSyntaxError.cs | 18 -- src/Syntax/Errors/SyntaxError.cs | 53 ----- src/Syntax/Lexer.cs | 36 ++-- src/Syntax/Parser/ParseResult.cs | 8 +- src/Syntax/Parser/Parser.cs | 182 +++++++++--------- src/Util/UIDProvider.cs | 23 +++ 24 files changed, 248 insertions(+), 252 deletions(-) rename src/{Util/Utils.cs => IEzrError.cs} (62%) create mode 100644 src/Syntax/Errors/EzrStackedSyntaxError.cs create mode 100644 src/Syntax/Errors/EzrSyntaxError.cs delete mode 100644 src/Syntax/Errors/StackedSyntaxError.cs delete mode 100644 src/Syntax/Errors/SyntaxError.cs create mode 100644 src/Util/UIDProvider.cs diff --git a/src/Executor/CodeExecutor.cs b/src/Executor/CodeExecutor.cs index 998c96e..b8f62b2 100644 --- a/src/Executor/CodeExecutor.cs +++ b/src/Executor/CodeExecutor.cs @@ -90,7 +90,7 @@ public static ExecutionResult Execute(string script) throw new NullReferenceException($"{nameof(RuntimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); // Tokenize the script. - SyntaxError? lexerError = new Lexer(RuntimeContext.StartPosition.File, script).Tokenize(out List tokens); + EzrSyntaxError? lexerError = new Lexer(RuntimeContext.StartPosition.File, script).Tokenize(out List tokens); if (lexerError is not null) // Check for errors. return new ExecutionResult([.. tokens], lexerError); // Return tokens with lexing error. diff --git a/src/Executor/ExecutionResult.cs b/src/Executor/ExecutionResult.cs index 18f9ed4..3933368 100644 --- a/src/Executor/ExecutionResult.cs +++ b/src/Executor/ExecutionResult.cs @@ -19,7 +19,7 @@ public class ExecutionResult /// /// Any error that occurred during lexing. /// - public readonly SyntaxError? LexerError; + public readonly EzrSyntaxError? LexerError; /// /// The Abstract Syntax Tree of the executed script. @@ -29,7 +29,7 @@ public class ExecutionResult /// /// Any error that occurred during parsing. /// - public readonly SyntaxError? ParseError; + public readonly EzrSyntaxError? ParseError; /// /// The result of the execution. @@ -46,7 +46,7 @@ public class ExecutionResult /// /// The tokens returned by the lexer. /// The error. - public ExecutionResult(Token[] tokens, SyntaxError error) + public ExecutionResult(Token[] tokens, EzrSyntaxError error) { Tokens = tokens; LexerError = error; diff --git a/src/Util/Utils.cs b/src/IEzrError.cs similarity index 62% rename from src/Util/Utils.cs rename to src/IEzrError.cs index 8632e01..e77f10d 100644 --- a/src/Util/Utils.cs +++ b/src/IEzrError.cs @@ -1,41 +1,32 @@ -using System; -using System.Text; +using System.Text; +using System; -namespace EzrSquared.Util; +namespace EzrSquared; /// -/// Utilities functions used in ezrSquared. +/// Error interface for all errors. /// -public static class Utils +public interface IEzrError { /// - /// value for the last generated unique identifier. + /// The name of the . /// - private static long s_currentId = 0; + public string Title { get; } /// - /// Generates an incremental unique identifier. + /// The reason why the occurred. /// - /// A new unique identifier. - public static long GetNextUniqueId() - { - return System.Threading.Interlocked.Increment(ref s_currentId); - } + public string Details { get; } /// - /// Converts an index to a power of two, so that the index can be used like an enum flag. + /// The starting of the . /// - /// - /// This function is used to check if all arguments have been provided to and types.
- /// The indices of the given arguments are converted to powers of two and bitwise-ored together, then bitwise-anded with the index of a defined parameter which is also converted to a power of two.
- /// Finally, if the result is the same as the power of two of the parameter's index, this tells the interpreter that the particular required parameter has been provided. - ///
- /// The index to be converted. - /// The power of two. - public static int IndexToFlag(int index) - { - return (index++ < 3) ? index : (4 * index) - 8; - } + public Position ErrorStartPosition { get; } + + /// + /// The ending of the . + /// + public Position ErrorEndPosition { get; } /// /// Creates formatted text which contains the text between and , underlined with tilde (~) symbols. @@ -43,7 +34,7 @@ public static int IndexToFlag(int index) /// The starting position of the underlining. /// The ending position of the underlining. /// The formatted text and the actual starting line number of the error. - public static (int AdjustedLineNumber, string SourceWithUnderline) SourceWithUnderline(Position startPosition, Position endPosition) + internal protected static (int AdjustedLineNumber, string SourceWithUnderline) SourceWithUnderline(Position startPosition, Position endPosition) { string text = startPosition.Script; int textLength = text.Length; diff --git a/src/Runtime/Context.cs b/src/Runtime/Context.cs index 3b5c17b..e99cff6 100644 --- a/src/Runtime/Context.cs +++ b/src/Runtime/Context.cs @@ -156,7 +156,7 @@ public enum SetStatus public Context(string name, bool isStatic, Position startPosition, Context? parent = null, Context? staticContext = null, int linkedContexts = 0) { Name = name; - Id = Utils.GetNextUniqueId(); + Id = UIDProvider.Get(); LinkedContexts = linkedContexts == 0 ? [] : new Context[linkedContexts]; if (isStatic && StaticContext != null) diff --git a/src/Runtime/Nodes/BaseNodes.cs b/src/Runtime/Nodes/BaseNodes.cs index 6fe43b9..f80134b 100644 --- a/src/Runtime/Nodes/BaseNodes.cs +++ b/src/Runtime/Nodes/BaseNodes.cs @@ -30,7 +30,7 @@ public override string ToString() } /// -/// The dummy invalid structure. For returning instead of if an occurs during parsing. +/// The dummy invalid structure. For returning instead of if an occurs during parsing. /// public class InvalidNode : Node { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index 94f72f1..ae8d4f5 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -48,7 +48,7 @@ public EzrSharpCompatibilityObjectInstance( Context parentContext, Position startPosition, Position endPosition) : base(instanceType, parentContext, startPosition, endPosition) { Instance = instance; - Tag = $"{Tag}.{SharpMemberName}.{Utils.GetNextUniqueId()}"; + Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; MethodInfo[] allMethods = instanceType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); Dictionary duplicateNames = new(allMethods.Length); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index 1323c39..48290f3 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -58,7 +58,7 @@ public EzrSharpCompatibilityType( RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(type, parentContext, startPosition, endPosition) { SharpType = type; - Tag = $"{Tag}.{SharpMemberName}.{Utils.GetNextUniqueId()}"; + Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; if (SharpType.IsGenericType) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index fe20943..1dfbe47 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -49,7 +49,7 @@ public abstract class EzrSharpCompatibilityExecutable : EzrSharpCompatibilityWra /// Skip method signature validation? public EzrSharpCompatibilityExecutable(MethodBase sharpMember, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation) : base(sharpMember, parentContext, startPosition, endPosition) { - Tag = $"{Tag}.{SharpMemberName}.{Utils.GetNextUniqueId()}"; + Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; Executable = sharpMember; Parameters = Executable.GetParameters(); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index 70d1a64..d1b104e 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -39,7 +39,7 @@ public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Contex { SharpField = sharpField; Instance = instance; - Tag = $"{Tag}.{SharpMemberName}.{Utils.GetNextUniqueId()}"; + Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; if (!skipValidation) Validate(); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs index 3e2e3b0..d8d2707 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -39,7 +39,7 @@ public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instanc { SharpProperty = sharpProperty; Instance = instance; - Tag = $"{Tag}.{SharpMemberName}.{Utils.GetNextUniqueId()}"; + Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; if (!skipValidation) Validate(); diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs index dffa865..daf9078 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs @@ -1,7 +1,6 @@ global using WrapperArgumentPopulationResult = (System.Collections.Generic.Dictionary Arguments, System.Collections.Generic.List? ExtraPositionalArguments); using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Util; using System; using System.Collections.Generic; using System.Text; @@ -59,6 +58,21 @@ internal protected static string PascalCaseToLowerCasePlainText(string text) return result.ToString(); } + /// + /// Converts an index to a power of two, so that the index can be used like an enum flag. + /// + /// + /// This function is used to check if all arguments have been provided to and types.
+ /// The indices of the given arguments are converted to powers of two and bitwise-ored together, then bitwise-anded with the index of a defined parameter which is also converted to a power of two.
+ /// Finally, if the result is the same as the power of two of the parameter's index, this tells the interpreter that the particular required parameter has been provided. + ///
+ /// The index to be converted. + /// The power of two. + protected internal static int IndexToFlag(int index) + { + return (index++ < 3) ? index : (4 * index) - 8; + } + /// /// Checks and populates the arguments given by the user's ezr² code into a dictionary. /// @@ -149,14 +163,14 @@ protected internal WrapperArgumentPopulationResult CheckAndPopulateArguments(Ref if (parameterIndex > -1) if (flaggedRequiredArguments < 0) - flaggedRequiredArguments = Utils.IndexToFlag(parameterIndex); + flaggedRequiredArguments = IndexToFlag(parameterIndex); else - flaggedRequiredArguments |= Utils.IndexToFlag(parameterIndex); + flaggedRequiredArguments |= IndexToFlag(parameterIndex); } for (int i = 0; i < Parameters.Length; i++) { - int parameterFlag = Utils.IndexToFlag(i); + int parameterFlag = IndexToFlag(i); if (Parameters[i].IsRequired && (flaggedRequiredArguments < 0 || (flaggedRequiredArguments & parameterFlag) != parameterFlag)) { result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{Parameters[i].Name}\"!", _executionContext, StartPosition, EndPosition)); diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs index adeba05..bbb3443 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs @@ -77,7 +77,7 @@ public EzrSharpSourceFunctionWrapper(EzrSharpSourceWrappableMethod function, Con if (string.IsNullOrEmpty(attribute.Name)) throw new ArgumentException($"Name not provided in {nameof(SharpMethodWrapperAttribute)} of function \"{function.Name}\"!", nameof(function)); - Tag = $"{Tag}.{attribute.Name}.{Utils.GetNextUniqueId()}"; + Tag = $"{Tag}.{attribute.Name}.{UIDProvider.Get()}"; return (attribute.Name, attribute); } diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index 0f1f17a..78f8850 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -74,7 +74,7 @@ public EzrSharpSourceTypeWrapper( // Set name and tag. SharpTypeName = typeAttribute.Name; - Tag = $"{Tag}.{SharpTypeName}.{Utils.GetNextUniqueId()}"; + Tag = $"{Tag}.{SharpTypeName}.{UIDProvider.Get()}"; Exception? typeAttributeException = SharpTypeWrapperAttribute.ValidateMethodParameters(type, out (ConstructorInfo Info, SharpMethodWrapperAttribute Attribute)? constructor); diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs index 8587ce8..f1eb24e 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs @@ -1,6 +1,5 @@ using EzrSquared.Runtime.Types.Core.Text; using EzrSquared.Runtime.WrapperAttributes; -using EzrSquared.Util; using System; using System.Text; @@ -153,7 +152,7 @@ public override string ToString(RuntimeResult result) /// public override string ToPureString(RuntimeResult result) { - (int adjustedLineNumber, string sourceWithUnderline) = Utils.SourceWithUnderline(ErrorStartPosition, ErrorEndPosition); + (int adjustedLineNumber, string sourceWithUnderline) = IEzrError.SourceWithUnderline(ErrorStartPosition, ErrorEndPosition); return $"{GenerateTraceback(adjustedLineNumber)}\n{Title}: {Details}\n{sourceWithUnderline}"; } diff --git a/src/Runtime/Types/Core/RuntimeErrors/IEzrRuntimeError.cs b/src/Runtime/Types/Core/RuntimeErrors/IEzrRuntimeError.cs index 8e1cb18..e49683c 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/IEzrRuntimeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/IEzrRuntimeError.cs @@ -3,30 +3,10 @@ /// /// Base of all error types. /// -public interface IEzrRuntimeError : IEzrObject +public interface IEzrRuntimeError : IEzrObject, IEzrError { - /// - /// The title of the error. - /// - public string Title { get; } - - /// - /// The reason why the error occurred. - /// - public string Details { get; } - /// /// The context where the error occurred. /// public Context ErrorContext { get; } - - /// - /// The starting position of the error. - /// - public Position ErrorStartPosition { get; } - - /// - /// The ending position of the error. - /// - public Position ErrorEndPosition { get; } } diff --git a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs index f72381a..019d65d 100644 --- a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs +++ b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs @@ -60,8 +60,8 @@ public abstract class EzrRuntimeExecutable : EzrObject public EzrRuntimeExecutable(string? name, Node body, (string Name, Node Node)[] parameters, OptionalExtraArguments extraKeywordArguments, OptionalExtraArguments extraPositionalArguments, Context parentContext, Position startPosition, Position endPosition, Context? initializationContext = null) : base(initializationContext, parentContext, startPosition, endPosition) { Tag = name is not null - ? $"{Tag}.{name}.{Utils.GetNextUniqueId()}" - : $"{Tag}.{Utils.GetNextUniqueId()}"; + ? $"{Tag}.{name}.{UIDProvider.Get()}" + : $"{Tag}.{UIDProvider.Get()}"; ExecutableName = name ?? $""; Body = body; diff --git a/src/Syntax/Errors/EzrStackedSyntaxError.cs b/src/Syntax/Errors/EzrStackedSyntaxError.cs new file mode 100644 index 0000000..b457a5c --- /dev/null +++ b/src/Syntax/Errors/EzrStackedSyntaxError.cs @@ -0,0 +1,18 @@ +namespace EzrSquared.Syntax.Errors; + +/// +/// The returned when multiple objects need to be returned to the user. +/// +/// The 'parent' error, or the error that occurred first. +/// The 'child' error, or the error that occurred because of the . +internal class EzrStackedSyntaxError(EzrSyntaxError parent, EzrSyntaxError child) : EzrSyntaxError("Multiple errors", $"{parent}\n\nDue to the above error, another one occurred:\n{child}", parent.ErrorStartPosition, parent.ErrorEndPosition) +{ + /// + /// Creates the formatted text representation of the , which shows all child objects as the 'details'. + /// + /// The formatted text. + public override string ToString() + { + return Details; + } +} diff --git a/src/Syntax/Errors/EzrSyntaxError.cs b/src/Syntax/Errors/EzrSyntaxError.cs new file mode 100644 index 0000000..1c1a35f --- /dev/null +++ b/src/Syntax/Errors/EzrSyntaxError.cs @@ -0,0 +1,42 @@ +namespace EzrSquared.Syntax.Errors; + +/// +/// Error class for all syntax errors. +/// +/// The title of the . +/// The reason why the occurred. +/// The starting of the . +/// The ending of the . +public class EzrSyntaxError(string title, string details, Position startPosition, Position endPosition) : IEzrError +{ + /// An unexpected character was encountered. + public const string UnexpectedCharacter = "Unexpected character"; + + /// An invalid hexadecimal value was encountered. + public const string InvalidHexValue = "Invalid hexadecimal value"; + + /// Invalid grammar was encountered. + public const string InvalidGrammar = "Invalid grammar"; + + /// + public string Title { get; } = title; + + /// + public string Details { get; } = details; + + /// + public Position ErrorStartPosition { get; } = startPosition; + + /// + public Position ErrorEndPosition { get; } = endPosition; + + /// + /// Creates the formatted text representation of the . + /// + /// The formatted text. + public override string ToString() + { + (int adjustedLineNumber, string sourceWithUnderline) = IEzrError.SourceWithUnderline(ErrorStartPosition, ErrorEndPosition); + return $"{Title} in {ErrorStartPosition.File}, line {adjustedLineNumber}: {Details}\n{sourceWithUnderline}"; + } +} diff --git a/src/Syntax/Errors/StackedSyntaxError.cs b/src/Syntax/Errors/StackedSyntaxError.cs deleted file mode 100644 index 4d3d0a9..0000000 --- a/src/Syntax/Errors/StackedSyntaxError.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace EzrSquared.Syntax.Errors; - -/// -/// The returned when multiple objects need to be returned to the user. -/// -/// The 'parent' error, or the error that occurred first. -/// The 'child' error, or the error that occurred because of the . -internal class StackedSyntaxError(SyntaxError parent, SyntaxError child) : SyntaxError("Multiple errors", $"{parent}\n\nDue to the above error, another one occurred:\n{child}", parent._startPosition, parent._endPosition) -{ - /// - /// Creates the formatted text representation of the , which shows all child objects as the 'details'. - /// - /// The formatted text. - public override string ToString() - { - return _details; - } -} diff --git a/src/Syntax/Errors/SyntaxError.cs b/src/Syntax/Errors/SyntaxError.cs deleted file mode 100644 index d61a249..0000000 --- a/src/Syntax/Errors/SyntaxError.cs +++ /dev/null @@ -1,53 +0,0 @@ -using EzrSquared.Util; - -namespace EzrSquared.Syntax.Errors; - -/// -/// Error class for all syntax error. -/// -/// The title of the . -/// The reason why the occurred. -/// The starting of the . -/// The ending of the . -public class SyntaxError(string title, string details, Position startPosition, Position endPosition) -{ - /// An unexpected character was encountered. - public const string UnexpectedCharacter = "Unexpected character"; - - /// An invalid hexadecimal value was encountered. - public const string InvalidHexValue = "Invalid hexadecimal value"; - - /// Invalid grammar was encountered. - public const string InvalidGrammar = "Invalid grammar"; - - /// - /// The name of the . - /// - protected internal readonly string _title = title; - - /// - /// The reason why the occurred. - /// - protected internal readonly string _details = details; - - /// - /// The starting of the . - /// - protected internal readonly Position _startPosition = startPosition; - - /// - /// The ending of the . - /// - protected internal readonly Position _endPosition = endPosition; - - /// - /// Creates the formatted text representation of the . - /// - /// The formatted text. - public override string ToString() - { - (int adjustedLineNumber, string sourceWithUnderline) = Utils.SourceWithUnderline(_startPosition, _endPosition); - - return $"{_title} in {_startPosition.File}, line {adjustedLineNumber}: {_details}\n{sourceWithUnderline}"; - } -} diff --git a/src/Syntax/Lexer.cs b/src/Syntax/Lexer.cs index 9199b0a..f724a90 100644 --- a/src/Syntax/Lexer.cs +++ b/src/Syntax/Lexer.cs @@ -85,10 +85,10 @@ private void ReverseTo(int index) /// Creates a of objects from the given script. ///
/// The created of objects. - /// Any that occurred in the lexing; if none occurred. - public SyntaxError? Tokenize(out List tokens) + /// Any that occurred in the lexing; if none occurred. + public EzrSyntaxError? Tokenize(out List tokens) { - SyntaxError? error; + EzrSyntaxError? error; tokens = []; while (!_reachedEnd) { @@ -251,7 +251,7 @@ private void ReverseTo(int index) char unknownCharacter = _currentChar; Advance(); - return new SyntaxError(SyntaxError.UnexpectedCharacter, unknownCharacter.ToString(), errorStartPosition, _position); + return new EzrSyntaxError(EzrSyntaxError.UnexpectedCharacter, unknownCharacter.ToString(), errorStartPosition, _position); } } @@ -339,9 +339,9 @@ private Token CompileNewLines() /// /// Creates a of types , or , depending on the enclosing character. /// - /// Any that occurred in creating the stringlike; if none occurred. + /// Any that occurred in creating the stringlike; if none occurred. /// The created . - private Token CompileStringLike(out SyntaxError? error) + private Token CompileStringLike(out EzrSyntaxError? error) { char enclosingChar = _currentChar; @@ -371,14 +371,14 @@ private Token CompileStringLike(out SyntaxError? error) Position errorStartPosition = _position.Copy(); _position.Advance(); - error = new SyntaxError(SyntaxError.InvalidGrammar, $"Expected '{enclosingChar}'!", errorStartPosition, _position); + error = new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, $"Expected '{enclosingChar}'!", errorStartPosition, _position); return Token.Empty; } Advance(); if (enclosingChar == '`' && ((toReturn.Length > 1 is bool tooLong && tooLong) || toReturn.Length == 0)) { - error = new SyntaxError(SyntaxError.InvalidGrammar, + error = new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, tooLong ? "Value too long to be a character!" : "A character cannot be empty!", startPosition, _position); @@ -403,8 +403,8 @@ private Token CompileStringLike(out SyntaxError? error) /// Processes an escape sequence in a stringlike. ///
/// The to append the special character to. - /// Any that occurred in the process; if none occurred. - private void ProcessEscapeSequence(StringBuilder builder, ref SyntaxError? error) + /// Any that occurred in the process; if none occurred. + private void ProcessEscapeSequence(StringBuilder builder, ref EzrSyntaxError? error) { Position startPosition = _position.Copy(); Advance(); @@ -453,7 +453,7 @@ private void ProcessEscapeSequence(StringBuilder builder, ref SyntaxError? error Advance(); break; default: - error = new SyntaxError(SyntaxError.UnexpectedCharacter, $"Unknown escape sequence '\\{_currentChar}'.", startPosition, _position); + error = new EzrSyntaxError(EzrSyntaxError.UnexpectedCharacter, $"Unknown escape sequence '\\{_currentChar}'.", startPosition, _position); break; } } @@ -461,9 +461,9 @@ private void ProcessEscapeSequence(StringBuilder builder, ref SyntaxError? error /// /// Processes a UTF-16 escaped sequence in a stringlike. /// - /// Any that occurred in the process; if none occurred. + /// Any that occurred in the process; if none occurred. /// The UTF-16 character. - private char[] ProcessUtf16Sequence(ref SyntaxError? error) + private char[] ProcessUtf16Sequence(ref EzrSyntaxError? error) { int characterCount = 0; string hexValue = string.Empty; @@ -483,7 +483,7 @@ private char[] ProcessUtf16Sequence(ref SyntaxError? error) Position endPosition = _position.Copy(); endPosition.Advance(); - error = new SyntaxError(SyntaxError.InvalidHexValue, "UTF-16 hexadecimal values must be 4 characters long and only contain digits and the letters A to F!", startPosition, endPosition); + error = new EzrSyntaxError(EzrSyntaxError.InvalidHexValue, "UTF-16 hexadecimal values must be 4 characters long and only contain digits and the letters A to F!", startPosition, endPosition); return []; } } @@ -494,9 +494,9 @@ private char[] ProcessUtf16Sequence(ref SyntaxError? error) /// /// Processes a UTF-32 escaped sequence in a stringlike. /// - /// Any that occurred in the process; if none occurred. + /// Any that occurred in the process; if none occurred. /// The UTF-32 character. - private string ProcessUtf32Sequence(ref SyntaxError? error) + private string ProcessUtf32Sequence(ref EzrSyntaxError? error) { int characterCount = 0; string hexValue = string.Empty; @@ -516,7 +516,7 @@ private string ProcessUtf32Sequence(ref SyntaxError? error) Position endPosition = _position.Copy(); endPosition.Advance(); - error = new SyntaxError(SyntaxError.InvalidHexValue, "UTF-32 hexadecimal values must be 6 characters long and only contain digits and the letters A to F!", startPosition, endPosition); + error = new EzrSyntaxError(EzrSyntaxError.InvalidHexValue, "UTF-32 hexadecimal values must be 6 characters long and only contain digits and the letters A to F!", startPosition, endPosition); return string.Empty; } } @@ -524,7 +524,7 @@ private string ProcessUtf32Sequence(ref SyntaxError? error) int unicodePoint = Convert.ToInt32(hexValue, 16); if (unicodePoint > 0x10FFFF) { - error = new SyntaxError(SyntaxError.InvalidHexValue, "UTF-32 hexadecimal values must be in range 000000 - 10FFFF!", startPosition, _position); + error = new EzrSyntaxError(EzrSyntaxError.InvalidHexValue, "UTF-32 hexadecimal values must be in range 000000 - 10FFFF!", startPosition, _position); return string.Empty; } diff --git a/src/Syntax/Parser/ParseResult.cs b/src/Syntax/Parser/ParseResult.cs index 0e18761..ca50b2a 100644 --- a/src/Syntax/Parser/ParseResult.cs +++ b/src/Syntax/Parser/ParseResult.cs @@ -9,9 +9,9 @@ namespace EzrSquared.Syntax; public class ParseResult { /// - /// The that occurred while parsing, if any. + /// The that occurred while parsing, if any. /// - public SyntaxError? Error = null; + public EzrSyntaxError? Error = null; /// /// The which is the result of the parsing. @@ -45,8 +45,8 @@ public void Success(Node node) /// then will override . /// /// The priority/fatality of the failure. - /// The that occurred in parsing. - public void Failure(int priority, SyntaxError error) + /// The that occurred in parsing. + public void Failure(int priority, EzrSyntaxError error) { if (Error is null || _errorPriority < priority) { diff --git a/src/Syntax/Parser/Parser.cs b/src/Syntax/Parser/Parser.cs index 9b4b568..ac96a35 100644 --- a/src/Syntax/Parser/Parser.cs +++ b/src/Syntax/Parser/Parser.cs @@ -123,7 +123,7 @@ public ParseResult Parse() { ParseStatements(); if (_result.Error is null && _currentToken.Type != TokenType.EndOfFile) - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Did not expect this!", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Did not expect this!", _currentToken.StartPosition, _currentToken.EndPosition)); return _result; } @@ -282,7 +282,7 @@ or TokenType.KeywordElse ParseExpression(); if (_result.Error is not null) - _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a statement!", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(4, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a statement!", _currentToken.StartPosition, _currentToken.EndPosition)); } /// @@ -307,7 +307,7 @@ private void ParseExpression(bool itemKeywordRequired = false) { if ((accessibilityModifiers & AccessMod.Global) == AccessMod.Global) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "A variable, function or class cannot be declared 'global' and 'private' at the same time! It must be either 'global' , which means it is accessible to any code, or 'private' , which means it is only accessible to the current context.", startPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "A variable, function or class cannot be declared 'global' and 'private' at the same time! It must be either 'global' , which means it is accessible to any code, or 'private' , which means it is only accessible to the current context.", startPosition, _currentToken.EndPosition)); return; } @@ -336,7 +336,7 @@ private void ParseExpression(bool itemKeywordRequired = false) { ParseQuickExpression(true); if (_result.Error is not null) - _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(4, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -362,7 +362,7 @@ private void ParseExpression(bool itemKeywordRequired = false) } else if (usedItemKeyword || ((accessibilityModifiers & AccessMod.PrivateConstant) != 0)) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } else @@ -370,7 +370,7 @@ private void ParseExpression(bool itemKeywordRequired = false) } else if (usedItemKeyword) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a variable name! The variable name is where the value will be assigned.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a variable name! The variable name is where the value will be assigned.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } else @@ -378,7 +378,7 @@ private void ParseExpression(bool itemKeywordRequired = false) ParseQuickExpression(); if (_result.Error is not null) - _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(4, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected an expression!", _currentToken.StartPosition, _currentToken.EndPosition)); } /// @@ -408,7 +408,7 @@ private void ParseQuickExpression(bool itemKeywordRequired = false) Position errorStartPosition = startPosition.Copy(); errorStartPosition.Advance(); - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "A variable, function or class cannot be declared 'global' and 'private' at the same time! It must be either 'global' , which means it is accessible to any code, or 'private' , which means it is only accessible to the current context.", errorStartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "A variable, function or class cannot be declared 'global' and 'private' at the same time! It must be either 'global' , which means it is accessible to any code, or 'private' , which means it is only accessible to the current context.", errorStartPosition, _currentToken.EndPosition)); return; } @@ -437,7 +437,7 @@ private void ParseQuickExpression(bool itemKeywordRequired = false) { ParseJunction(); if (_result.Error is not null) - _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a QuickSyntax expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(4, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a QuickSyntax expression!", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -463,7 +463,7 @@ private void ParseQuickExpression(bool itemKeywordRequired = false) } else if (usedItemKeyword || ((accessibilityModifiers & AccessMod.PrivateConstant) != 0)) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected an assignment symbol! The assignment symbol seperates the variable name and value, and declares how to handle any existing values in the variable, in a variable assignment expression. A few examples of assignment symbols are: (':') - normal assignment, (':+') - adds existing value in variable to new value, assigns the result, (':*') - multiplies existing value with new value, assigns the result, and (':&') - does a bitwise and operation between the existing and new value, assigns the result. There are equivalent symbols for all binary mathematical and bitwise operations.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } else @@ -471,7 +471,7 @@ private void ParseQuickExpression(bool itemKeywordRequired = false) } else if (usedItemKeyword) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a variable name! The variable name is where the value will be assigned.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a variable name! The variable name is where the value will be assigned.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } else @@ -480,7 +480,7 @@ private void ParseQuickExpression(bool itemKeywordRequired = false) ParseJunction(); if (_result.Error is not null) - _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a QuickSyntax expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(4, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a QuickSyntax expression!", _currentToken.StartPosition, _currentToken.EndPosition)); } /// @@ -535,7 +535,7 @@ private void ParseInversion() ParseContainsCheck(); if (_result.Error is not null) - _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an inversion expression!", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(4, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected an inversion expression!", _currentToken.StartPosition, _currentToken.EndPosition)); } /// @@ -552,7 +552,7 @@ private void ParseContainsCheck() { if (_currentToken.Type != TokenType.KeywordIn) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'in' keyword! The 'in' keyword is the second part of a check-not-in operation.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'in' keyword! The 'in' keyword is the second part of a check-not-in operation.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -700,7 +700,7 @@ private void ParseCall() ParseExpression(); if (_result.Error is not null) { - _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + _result.Failure(10, new EzrStackedSyntaxError(_result.Error, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); return; } @@ -719,7 +719,7 @@ private void ParseCall() ParseExpression(); if (_result.Error is not null) { - _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + _result.Failure(10, new EzrStackedSyntaxError(_result.Error, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! The function/object call expression must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); return; } arguments.Add(_result.Node); @@ -730,7 +730,7 @@ private void ParseCall() if (_currentToken.Type != TokenType.RightParenthesis) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma or right-parenthesis symbol! Commas are used to seperate the arguments of the function/object call expression, and the right-parenthesis is used to end it.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a comma or right-parenthesis symbol! Commas are used to seperate the arguments of the function/object call expression, and the right-parenthesis is used to end it.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -810,7 +810,7 @@ private void ParseAtom() (false, false) => $"Expected a variable assignment expression, variable access expression or the 'function' or 'object' keywords! In this case, a variable assignment expression will assign a global {onStatic}variable, a variable access expression references a global {onStatic}variable and the 'function' or 'object' keywords will declare a global {onStatic}function or class, respectively.", }; - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); break; case TokenType.KeywordPrivate: nextToken = PeekNext(); @@ -858,7 +858,7 @@ private void ParseAtom() ? $"Expected the 'object' keyword! In this case, the 'object' keyword is used to declare a private {onStatic}{onConstant}read-only class." : $"Expected a variable assignment expression or the 'function' or 'object' keywords! In this case, a variable assignment expression will assign a private {onStatic}{onConstant}{onVariable}and the 'function' or 'object' keywords will declare a private {onStatic}{onConstant}function or class, respectively."; - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); break; case TokenType.KeywordStatic: nextToken = PeekNext(); @@ -913,7 +913,7 @@ private void ParseAtom() (false, false) => $"Expected a variable assignment expression, variable access expression or the 'function' or 'object' keywords! In this case, a variable assignment expression will assign a static variable, a variable access expression references a static variable and the 'function' or 'object' keywords will declare a static function or class, respectively.", }; - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); break; case TokenType.KeywordConstant: nextToken = PeekNext(); @@ -940,14 +940,14 @@ private void ParseAtom() ? "Expected the 'object' keyword! In this case, the 'object' keyword is used to declare a constant read-only class." : "Expected a variable assignment expression or the 'function' or 'object' keywords! In this case, a variable assignment expression will assign a constant, while the 'function' or 'object' keywords will declare a constant function or class, respectively."; - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, errorMessage, nextToken.StartPosition, nextToken.EndPosition)); break; case TokenType.KeywordReadonly: nextToken = PeekNext(); if (nextToken.Type != TokenType.KeywordObject) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'object' keyword! In this case, the 'object' keyword is used to declare a read-only class.", nextToken.StartPosition, nextToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'object' keyword! In this case, the 'object' keyword is used to declare a read-only class.", nextToken.StartPosition, nextToken.EndPosition)); return; } @@ -992,7 +992,7 @@ private void ParseAtom() #pragma warning disable CS0618 case TokenType.KeywordSpecial: - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "The \"special function\" structure has been removed from ezr². Please use normal functions with dedicated names for operator overloading. Check [DOCUMENTATION LINK HERE] for more info.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "The \"special function\" structure has been removed from ezr². Please use normal functions with dedicated names for operator overloading. Check [DOCUMENTATION LINK HERE] for more info.", _currentToken.StartPosition, _currentToken.EndPosition)); break; #pragma warning restore CS0618 @@ -1012,7 +1012,7 @@ private void ParseAtom() return; } - _result.Failure(4, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an integer, float, string, character, character list, identifier, 'if' expression, 'count' expression, 'while' expression...", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(4, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected an integer, float, string, character, character list, identifier, 'if' expression, 'count' expression, 'while' expression...", _currentToken.StartPosition, _currentToken.EndPosition)); break; } } @@ -1043,7 +1043,7 @@ private void ParseArrayOrParentheticalExpression() ParseExpression(); if (_result.Error is not null) { - _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! An array/parenthetical expression must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + _result.Failure(10, new EzrStackedSyntaxError(_result.Error, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! An array/parenthetical expression must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); return; } @@ -1067,7 +1067,7 @@ private void ParseArrayOrParentheticalExpression() ParseExpression(); if (_result.Error is not null) { - _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! An array must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + _result.Failure(10, new EzrStackedSyntaxError(_result.Error, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a right-parenthesis symbol! An array must end with a right-parenthesis.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); return; } @@ -1079,9 +1079,9 @@ private void ParseArrayOrParentheticalExpression() if (_currentToken.Type != TokenType.RightParenthesis) { if (isArray) - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma or a right-parenthesis symbol! Commas seperate the elements of the array, while the right-parenthesis ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a comma or a right-parenthesis symbol! Commas seperate the elements of the array, while the right-parenthesis ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); else - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma or a right-parenthesis symbol! The comma is used to create an array and seperate its elements, while the right-parenthesis declares the end of a parenthetical expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a comma or a right-parenthesis symbol! The comma is used to create an array and seperate its elements, while the right-parenthesis declares the end of a parenthetical expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1123,7 +1123,7 @@ private void ParseList() ParseExpression(); if (_result.Error is not null) { - _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + _result.Failure(10, new EzrStackedSyntaxError(_result.Error, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); return; } elements.Add(_result.Node); @@ -1142,7 +1142,7 @@ private void ParseList() ParseExpression(); if (_result.Error is not null) { - _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + _result.Failure(10, new EzrStackedSyntaxError(_result.Error, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a right-square-bracket symbol! A list expression must end with a right-square-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); return; } elements.Add(_result.Node); @@ -1153,7 +1153,7 @@ private void ParseList() if (_currentToken.Type != TokenType.RightSquareBracket) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma or a right-square-bracket symbol! Commas are used to seperate elements in the list, while the right-square-bracket ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a comma or a right-square-bracket symbol! Commas are used to seperate elements in the list, while the right-square-bracket ends it.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1189,7 +1189,7 @@ private void ParseDictionary() ParseExpression(true); if (_result.Error is not null) { - _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + _result.Failure(10, new EzrStackedSyntaxError(_result.Error, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); return; } @@ -1199,7 +1199,7 @@ private void ParseDictionary() if (_currentToken.Type != TokenType.Colon) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1228,7 +1228,7 @@ private void ParseDictionary() ParseExpression(true); if (_result.Error is not null) { - _result.Failure(10, new StackedSyntaxError(_result.Error, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); + _result.Failure(10, new EzrStackedSyntaxError(_result.Error, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a right-curly-bracket symbol! A dictionary expression must end with a right-curly-bracket.", possibleErrorToken.StartPosition, possibleErrorToken.EndPosition))); return; } @@ -1238,7 +1238,7 @@ private void ParseDictionary() if (_currentToken.Type != TokenType.Colon) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a colon symbol! The colon is the seperator between a key and its value in a dictionary.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1259,7 +1259,7 @@ private void ParseDictionary() if (_currentToken.Type != TokenType.RightCurlyBracket) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma or right-curly-bracket symbol! Commas are used to seperate key-value pairs in the dictionary, and the right-curly-bracket declares its end.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a comma or right-curly-bracket symbol! Commas are used to seperate key-value pairs in the dictionary, and the right-curly-bracket declares its end.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1288,7 +1288,7 @@ private void ParseIfExpression() Node condition = _result.Node; if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1322,7 +1322,7 @@ private void ParseIfExpression() { if (elseCase is not null) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; } @@ -1335,7 +1335,7 @@ private void ParseIfExpression() condition = _result.Node; if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1350,14 +1350,14 @@ private void ParseIfExpression() } else if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } else { if (elseCase is not null) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; } @@ -1374,9 +1374,9 @@ private void ParseIfExpression() if (_currentToken.Type != TokenType.KeywordEnd) { if (elseCase is null) - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); else - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1385,7 +1385,7 @@ private void ParseIfExpression() } else { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'else' or 'end' keywords! The 'else' keyword defines the start of an \"else\" or \"else if\" expression, and the 'end' keyword declares the end of the whole \"if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1408,7 +1408,7 @@ private void ParseIfExpression() { if (elseCase is not null) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "The \"else-if\" expression cannot be declared before the \"else\" expression! You cannot have \"else\" expressions before or in-between \"else if\" expressions.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; } @@ -1421,7 +1421,7 @@ private void ParseIfExpression() condition = _result.Node; if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"else if\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1436,14 +1436,14 @@ private void ParseIfExpression() } else if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'if' or 'do' keywords! The 'if' keyword declares the start of an \"else if\" expression, and the 'do' keyword declares the start of the body of an \"else\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } else { if (elseCase is not null) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "There should only be one \"else\" expression! You cannot have multiple \"else\" expressions in an \"if\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; } @@ -1486,9 +1486,9 @@ private void ParseCountExpression() if (_currentToken.Type != TokenType.KeywordTo) { if (from is null) - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'to' or 'from' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop, and the optional 'from' keyword and the following expression is the amount to count from.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'to' or 'from' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop, and the optional 'from' keyword and the following expression is the amount to count from.", _currentToken.StartPosition, _currentToken.EndPosition)); else - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'to' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'to' keyword! The 'to' keyword and the following expression is the amount to count to in the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1522,11 +1522,11 @@ private void ParseCountExpression() if (_currentToken.Type != TokenType.KeywordDo) { if (step is null && iterationVariable is null) - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do', 'step' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, the optional 'step' keyword and the following expression is the increment, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'do', 'step' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, the optional 'step' keyword and the following expression is the increment, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); else if (iterationVariable is null) - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'do' or 'as' keyword! The 'do' keyword declares the start of the body of the count loop, and the optional 'as' keyword and the following expression is where the iterations are stored.", _currentToken.StartPosition, _currentToken.EndPosition)); else - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1545,7 +1545,7 @@ private void ParseCountExpression() body = _result.Node; if (_currentToken.Type != TokenType.KeywordEnd) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the count loop.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1575,7 +1575,7 @@ private void ParseForEachExpression() if (_currentToken.Type != TokenType.KeywordEach) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'each' keyword! The 'each' keyword is essential for forming a \"for each\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'each' keyword! The 'each' keyword is essential for forming a \"for each\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1586,13 +1586,13 @@ private void ParseForEachExpression() if (_result.Node is not BinaryOperationNode expression || expression.Operator != TokenType.KeywordIn) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a binary expression in the format \"[iteration variable] in [iterable collection]\".", _result.Node.StartPosition, _result.Node.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a binary expression in the format \"[iteration variable] in [iterable collection]\".", _result.Node.StartPosition, _result.Node.EndPosition)); return; } if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"for each\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"for each\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1607,7 +1607,7 @@ private void ParseForEachExpression() return; else if (_currentToken.Type != TokenType.KeywordEnd) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"for each\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"for each\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1643,7 +1643,7 @@ private void ParseWhileExpression() Node condition = _result.Node; if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1662,7 +1662,7 @@ private void ParseWhileExpression() body = _result.Node; if (_currentToken.Type != TokenType.KeywordEnd) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the while loop.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1696,7 +1696,7 @@ private void ParseTryExpression() if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1733,7 +1733,7 @@ private void ParseTryExpression() { if (emptyCase is not null) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There should only be one empty \"catch\" expression! You cannot have multiple empty \"catch\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "There should only be one empty \"catch\" expression! You cannot have multiple empty \"catch\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; } @@ -1748,7 +1748,7 @@ private void ParseTryExpression() @as = _result.Node; if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } } @@ -1770,7 +1770,7 @@ private void ParseTryExpression() if (emptyCase is not null) { Token previous = PeekPrevious(); - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There can't be any \"catch\" expressions after an empty \"catch\" expression!", previous.StartPosition, previous.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "There can't be any \"catch\" expressions after an empty \"catch\" expression!", previous.StartPosition, previous.EndPosition)); return; } @@ -1784,12 +1784,12 @@ private void ParseTryExpression() } else if (isErrorNull) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an expression or the 'as' or 'do' keywords! An expression after the 'catch' keyword defines what error(s) will lead to the \"catch\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected an expression or the 'as' or 'do' keywords! An expression after the 'catch' keyword defines what error(s) will lead to the \"catch\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } else { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } } @@ -1797,9 +1797,9 @@ private void ParseTryExpression() if (_currentToken.Type != TokenType.KeywordEnd) { if (emptyCase is null) - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'catch' or 'end' keywords! The 'catch' keyword defines the start of an \"catch\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'catch' or 'end' keywords! The 'catch' keyword defines the start of an \"catch\" expression, and the 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); else - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"try\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1808,7 +1808,7 @@ private void ParseTryExpression() } else { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'catch' or 'end' keywords! The 'catch' keyword defines the start of an \"catch\" expression, and the 'end' keyword declares the end of the whole \"try\" expression. Note: In newer versions of ezr², 'error' has been replaced by 'catch' and is now recognized as an identifier. Check [DOCUMENTATION LINK HERE] for more info.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'catch' or 'end' keywords! The 'catch' keyword defines the start of an \"catch\" expression, and the 'end' keyword declares the end of the whole \"try\" expression. Note: In newer versions of ezr², 'error' has been replaced by 'catch' and is now recognized as an identifier. Check [DOCUMENTATION LINK HERE] for more info.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1834,7 +1834,7 @@ private void ParseTryExpression() { if (emptyCase is not null) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There should only be one empty \"catch\" expression! You cannot have multiple empty \"catch\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "There should only be one empty \"catch\" expression! You cannot have multiple empty \"catch\" expressions in a \"try\" expression.", PeekPrevious().StartPosition, _currentToken.EndPosition)); return; } @@ -1849,7 +1849,7 @@ private void ParseTryExpression() @as = _result.Node; if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'do' keyword! The 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } } @@ -1871,7 +1871,7 @@ private void ParseTryExpression() if (emptyCase is not null) { Token previous = PeekPrevious(); - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "There can't be any \"catch\" expressions after an empty \"catch\" expression!", previous.StartPosition, previous.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "There can't be any \"catch\" expressions after an empty \"catch\" expression!", previous.StartPosition, previous.EndPosition)); return; } @@ -1885,12 +1885,12 @@ private void ParseTryExpression() } else if (isErrorNull) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an expression or the 'as' or 'do' keywords! An expression after the 'catch' keyword defines what error(s) will lead to the \"catch\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected an expression or the 'as' or 'do' keywords! An expression after the 'catch' keyword defines what error(s) will lead to the \"catch\" expression, the 'as' keyword and the following expression declares where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } else { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'as' or 'do' keywords! The 'as' keyword and the following expression tells the interpreter where the error will be stored and the 'do' keyword declares the start of the body of the \"catch\" expression.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } } @@ -1968,9 +1968,9 @@ private void ParseFunctionDefinitionExpression() if (_currentToken.Type != TokenType.KeywordAs) { if (isNamedExtraParamters) - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'as' keyword! The 'as' keyword comes in-between the 'named' keyword and an expression when declaring extra keyword parameters for an object.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'as' keyword! The 'as' keyword comes in-between the 'named' keyword and an expression when declaring extra keyword parameters for an object.", _currentToken.StartPosition, _currentToken.EndPosition)); else - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'as' or 'named' keywords! The 'named' keyword starts the definition of extra keyword parameters and the 'as' keyword comes in-between the 'from' or 'named' keyword and an expression when declaring extra positional or keyword parameters for an object.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'as' or 'named' keywords! The 'named' keyword starts the definition of extra keyword parameters and the 'as' keyword comes in-between the 'from' or 'named' keyword and an expression when declaring extra positional or keyword parameters for an object.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -1982,12 +1982,12 @@ private void ParseFunctionDefinitionExpression() if (isNamedExtraParamters && extraKeywordArguments is not null) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Only one extra keyword parameter dictionary can be defined per function!", paramStartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Only one extra keyword parameter dictionary can be defined per function!", paramStartPosition, _currentToken.EndPosition)); return; } else if (!isNamedExtraParamters && extraPositionalArguments is not null) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Only one extra positional parameter list can be defined per function!", paramStartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Only one extra positional parameter list can be defined per function!", paramStartPosition, _currentToken.EndPosition)); return; } @@ -2003,7 +2003,7 @@ private void ParseFunctionDefinitionExpression() } else if (extraKeywordArguments is not null || extraPositionalArguments is not null) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Normal mixed parameters must come before extra positional/keyword parameter list/dictionary definitions.", paramStartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Normal mixed parameters must come before extra positional/keyword parameter list/dictionary definitions.", paramStartPosition, _currentToken.EndPosition)); return; } @@ -2018,14 +2018,14 @@ private void ParseFunctionDefinitionExpression() if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parameter and the 'do' keyword declares the start of the body of the \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parameter and the 'do' keyword declares the start of the body of the \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } } if (name is null && accessibilityModifiers != AccessMod.None) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "The accessibility of an anonymous function cannot be declared in the definition! Anonymous functions are meant to be stored in variables or constants, where the accessibility is determined.", startPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "The accessibility of an anonymous function cannot be declared in the definition! Anonymous functions are meant to be stored in variables or constants, where the accessibility is determined.", startPosition, _currentToken.EndPosition)); return; } @@ -2042,7 +2042,7 @@ private void ParseFunctionDefinitionExpression() body = _result.Node; if (_currentToken.Type != TokenType.KeywordEnd) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"function\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -2072,12 +2072,12 @@ private void ParseFunctionDefinitionExpression() } else if (isNameNull) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected an expression or the 'with' or 'do' keywords! An expression after the 'function' keyword defines the name, the 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected an expression or the 'with' or 'do' keywords! An expression after the 'function' keyword defines the name, the 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); return; } else { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'with' or 'do' keywords! The 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'with' or 'do' keywords! The 'with' keyword and the following expression(s, seperated by commas) declare(s) the paramenters and the 'do' keyword declares the start of the body of the \"function\".", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -2138,7 +2138,7 @@ private void ParseClassDefinitionExpression() } else if (accessibilityModifiers != AccessMod.None) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "The accessibility of an anonymous class cannot be declared in the definition! Anonymous classes are meant to be stored in variables or constants, where the accessibility is determined.", startPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "The accessibility of an anonymous class cannot be declared in the definition! Anonymous classes are meant to be stored in variables or constants, where the accessibility is determined.", startPosition, _currentToken.EndPosition)); return; } @@ -2162,7 +2162,7 @@ private void ParseClassDefinitionExpression() if (_currentToken.Type != TokenType.KeywordDo) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parent and the 'do' keyword declares the start of the body of the class definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected a comma symbol or the 'do' keyword! The comma symbol and the following expression defines another parent and the 'do' keyword declares the start of the body of the class definition.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } } @@ -2182,7 +2182,7 @@ private void ParseClassDefinitionExpression() if (_currentToken.Type != TokenType.KeywordEnd) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole class definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole class definition.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -2203,7 +2203,7 @@ private void ParseClassDefinitionExpression() return; } - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, (name is null && parents.Count == 0) ? "Expected an expression or the 'from' or 'do' keywords! An expression after the 'object' keyword defines the name, the 'from' keyword and the following expression(s, seperated by commas) define(s) the parents and the 'do' keyword declares the start of the body of the class." : (parents.Count == 0) @@ -2254,7 +2254,7 @@ private void ParseIncludeExpression() } else { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'from' keyword! If a specific object being included from a script (when the object's name is provided after the 'include' keyword) or if the whole script is added to the script (using the 'all' keyword or a comma symbol after the 'include' keyword), the 'from' keyword followed by an expression declaring the script's name or path must be provided.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'from' keyword! If a specific object being included from a script (when the object's name is provided after the 'include' keyword) or if the whole script is added to the script (using the 'all' keyword or a comma symbol after the 'include' keyword), the 'from' keyword followed by an expression declaring the script's name or path must be provided.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -2305,7 +2305,7 @@ private void ParseDefineBlockExpression() if (accessibilityModifiers == AccessMod.None) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'private', 'global', 'static' or 'constant' keywords! The \"define block\" needs at least one accessibility modifier. The 'private' or 'global' keywords declare all variables, constants, functions and classes defined in the block as private or global - not both, the 'static' or 'constant' keywords declare them as statically bound or constants - can be both.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'private', 'global', 'static' or 'constant' keywords! The \"define block\" needs at least one accessibility modifier. The 'private' or 'global' keywords declare all variables, constants, functions and classes defined in the block as private or global - not both, the 'static' or 'constant' keywords declare them as statically bound or constants - can be both.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } @@ -2316,7 +2316,7 @@ private void ParseDefineBlockExpression() Node body = _result.Node; if (_currentToken.Type != TokenType.KeywordEnd) { - _result.Failure(10, new SyntaxError(SyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"define block\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "Expected the 'end' keyword! The 'end' keyword declares the end of the whole \"define block\" definition.", _currentToken.StartPosition, _currentToken.EndPosition)); return; } diff --git a/src/Util/UIDProvider.cs b/src/Util/UIDProvider.cs new file mode 100644 index 0000000..6b6797c --- /dev/null +++ b/src/Util/UIDProvider.cs @@ -0,0 +1,23 @@ +using System.Threading; + +namespace EzrSquared.Util; + +/// +/// Generates unique IDs for objects. +/// +public static class UIDProvider +{ + /// + /// value for the last generated unique identifier. + /// + private static long s_currentId = 0; + + /// + /// Generates an incremental unique identifier. + /// + /// A new unique identifier. + public static long Get() + { + return Interlocked.Increment(ref s_currentId); + } +} From c11981bd0919cf671811a3d04651e6d249046981 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Mon, 4 Nov 2024 13:54:38 +0530 Subject: [PATCH 070/113] Made `EzrSharpCompatibilityWrapper` more generic. --- src/GlobalSuppressions.cs | 2 +- .../EzrSharpCompatibilityObjectInstance.cs | 26 ++------ .../EzrSharpCompatibilityType.cs | 49 ++++----------- .../EzrSharpCompatibilityWrapper.cs | 35 +++++++++-- .../EzrSharpCompatibilityConstructor.cs | 61 +++++++++++++++---- .../EzrSharpCompatibilityExecutable.cs | 39 ++---------- .../EzrSharpCompatibilityFunction.cs | 4 +- .../EzrSharpCompatibilityField.cs | 37 ++--------- .../EzrSharpCompatibilityProperty.cs | 41 +++---------- .../SharpAutoWrapperAttribute.cs | 8 +-- 10 files changed, 118 insertions(+), 184 deletions(-) diff --git a/src/GlobalSuppressions.cs b/src/GlobalSuppressions.cs index c5e947a..7a40ed1 100644 --- a/src/GlobalSuppressions.cs +++ b/src/GlobalSuppressions.cs @@ -10,4 +10,4 @@ [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrCharacterList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Collections.EzrList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrString.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "That's too many ternary operations.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.EzrSharpCompatibilityWrapper.Validate~System.Boolean")] +[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "That's too many ternary operations.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.EzrSharpCompatibilityWrapper`1.Validate~System.Boolean")] diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index ae8d4f5..df82932 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -10,9 +10,9 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; /// -/// Class to automatically wrap instances of already-wrapped C# types so that they can be used in ezr². +/// Class to automatically wrap instances of C# types so that they can be used in ezr². /// -public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper +public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper { /// public override string TypeName { get; protected internal set; } = "csharp object instance"; @@ -20,11 +20,6 @@ public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpObjectInstance"; - /// - /// The object to wrap. - /// - public readonly object Instance; - /// /// Creates a new . /// @@ -45,10 +40,9 @@ public EzrSharpCompatibilityObjectInstance( | DynamicallyAccessedMemberTypes.NonPublicFields)] Type instanceType, - Context parentContext, Position startPosition, Position endPosition) : base(instanceType, parentContext, startPosition, endPosition) + Context parentContext, Position startPosition, Position endPosition) : base(instanceType, instance, parentContext, startPosition, endPosition) { - Instance = instance; - Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; + Tag = $"{Tag}.{SharpMemberName}.{SharpMember.GetHashCode()}"; MethodInfo[] allMethods = instanceType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); Dictionary duplicateNames = new(allMethods.Length); @@ -103,18 +97,6 @@ public EzrSharpCompatibilityObjectInstance( } } - /// - public override int ComputeHashCode(RuntimeResult result) - { - return HashCode.Combine(HashTag, Instance); - } - - /// - public override bool StrictEquals(IEzrObject other, RuntimeResult result) - { - return (other as EzrSharpCompatibilityObjectInstance)?.Instance.GetHashCode() == Instance.GetHashCode() && other.HashTag == HashTag; - } - /// public override string ToString(RuntimeResult result) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index 48290f3..9f12b05 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -13,7 +13,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; /// /// Class to automatically wrap C# types so that they can be used in ezr². /// -public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper +public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper { /// public override string TypeName { get; protected internal set; } = "csharp type"; @@ -21,24 +21,10 @@ public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpType"; - /// - /// The type to wrap. - /// - [DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicFields - | DynamicallyAccessedMemberTypes.NonPublicFields - | DynamicallyAccessedMemberTypes.PublicMethods - | DynamicallyAccessedMemberTypes.NonPublicMethods - | DynamicallyAccessedMemberTypes.PublicProperties - | DynamicallyAccessedMemberTypes.NonPublicProperties - | DynamicallyAccessedMemberTypes.PublicConstructors - | DynamicallyAccessedMemberTypes.NonPublicConstructors)] - public readonly Type SharpType; - /// /// Creates a new . /// - /// The type to wrap. + /// The type to wrap. /// Runtime result for carrying any errors. /// The context in which this object was created. /// The starting position of the object. @@ -53,20 +39,19 @@ public EzrSharpCompatibilityType( | DynamicallyAccessedMemberTypes.NonPublicProperties | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] - Type type, + Type sharpType, - RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(type, parentContext, startPosition, endPosition) + RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(sharpType, null, parentContext, startPosition, endPosition) { - SharpType = type; Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; - if (SharpType.IsGenericType) + if (sharpType.IsGenericType) { - result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap generic CSharp type \"{SharpType.Name}\"!", Context, StartPosition, EndPosition)); + result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap generic CSharp type \"{SharpMember.Name}\"!", Context, StartPosition, EndPosition)); return; } - MethodInfo[] allStaticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + MethodInfo[] allStaticMethods = sharpType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); Dictionary duplicateNames = new(allStaticMethods.Length); for (int i = 0; i < allStaticMethods.Length; i++) { @@ -90,7 +75,7 @@ public EzrSharpCompatibilityType( Context.Set(null, methodObjectName, ReferencePool.Get(methodObject, AccessMod.Constant)); } - PropertyInfo[] allStaticProperties = type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + PropertyInfo[] allStaticProperties = sharpType.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < allStaticProperties.Length; i++) { PropertyInfo property = allStaticProperties[i]; @@ -104,7 +89,7 @@ public EzrSharpCompatibilityType( Context.Set(null, propertyObject.SharpMemberName, ReferencePool.Get(propertyObject, AccessMod.Constant)); } - FieldInfo[] allStaticFields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + FieldInfo[] allStaticFields = sharpType.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < allStaticFields.Length; i++) { FieldInfo field = allStaticFields[i]; @@ -118,14 +103,14 @@ public EzrSharpCompatibilityType( Context.Set(null, fieldObject.SharpMemberName, ReferencePool.Get(fieldObject, AccessMod.Constant)); } - ConstructorInfo[] publicConstructors = type.GetConstructors(); + ConstructorInfo[] publicConstructors = sharpType.GetConstructors(); for (int i = 0; i < publicConstructors.Length; i++) { ConstructorInfo constructor = publicConstructors[i]; if (!constructor.IsPublic && constructor.GetCustomAttribute() is null) continue; - EzrSharpCompatibilityConstructor constructorObject = new(this, constructor, Context, StartPosition, EndPosition, skipValidation: true); + EzrSharpCompatibilityConstructor constructorObject = new(sharpType, constructor, Context, StartPosition, EndPosition, skipValidation: true); if (!constructorObject.Validate()) continue; @@ -133,18 +118,6 @@ public EzrSharpCompatibilityType( } } - /// - public override int ComputeHashCode(RuntimeResult result) - { - return HashCode.Combine(HashTag, SharpType); - } - - /// - public override bool StrictEquals(IEzrObject other, RuntimeResult result) - { - return (other as EzrSharpCompatibilityType)?.SharpType == SharpType && other.HashTag == HashTag; - } - /// public override string ToString(RuntimeResult result) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 5a46ba6..c4b3be5 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -3,7 +3,6 @@ using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; using EzrSquared.Runtime.WrapperAttributes; -using EzrSquared.Util; using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -15,7 +14,9 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; /// /// Parent class for all automatic wrappers which wrap existing C# objects and members so that they can be used in ezr². /// -public abstract class EzrSharpCompatibilityWrapper : EzrObject +/// The type for the C# member being wrapped. +public abstract class EzrSharpCompatibilityWrapper : EzrObject + where TMemberInfo : MemberInfo { /// public override string TypeName { get; protected internal set; } = "csharp wrapper"; @@ -36,20 +37,27 @@ public abstract class EzrSharpCompatibilityWrapper : EzrObject /// /// Reflection info for the current object being wrapped. /// - public readonly MemberInfo SharpMember; + public readonly TMemberInfo SharpMember; /// - /// Creates a new . + /// The object which contains the wrapped member, if static. + /// + public readonly object? Instance; + + /// + /// Creates a new . /// /// Reflection info on the wrapped C# member. + /// The object which contains the wrapped member, if static. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrSharpCompatibilityWrapper(MemberInfo wrappedMember, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpMember = wrappedMember; AutoWrapperAttribute = wrappedMember.GetCustomAttribute(); SharpMemberName = !string.IsNullOrEmpty(AutoWrapperAttribute?.Name) ? AutoWrapperAttribute.Name : PascalToSnakeCase(wrappedMember.Name); + Instance = instance; } /// @@ -458,4 +466,21 @@ public override bool EvaluateBoolean(RuntimeResult result) { return true; } + + /// + public override bool StrictEquals(IEzrObject other, RuntimeResult result) + { + return other is EzrSharpCompatibilityWrapper otherWrapper + && otherWrapper.SharpMember == SharpMember + && otherWrapper.Instance?.GetHashCode() == Instance?.GetHashCode() + && other.HashTag == HashTag; + } + + /// + public override int ComputeHashCode(RuntimeResult result) + { + return Instance is not null + ? HashCode.Combine(HashTag, SharpMember, Instance) + : HashCode.Combine(HashTag, SharpMember); + } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index 29beb55..5cb734d 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -1,6 +1,8 @@ using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; @@ -8,18 +10,51 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.E /// /// Class to automatically wrap C# constructors so that they can be used in ezr². /// -/// The wrapper for this C# constructor's class. -/// The constructor to wrap. -/// The context in which this object was created. -/// The starting position of the object. -/// The ending position of the object. -/// Skip method signature validation? -public class EzrSharpCompatibilityConstructor(EzrSharpCompatibilityType constructingTypeWrapper, ConstructorInfo sharpConstructor, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : EzrSharpCompatibilityExecutable(sharpConstructor, null, parentContext, startPosition, endPosition, skipValidation) +public class EzrSharpCompatibilityConstructor : EzrSharpCompatibilityExecutable { /// - /// The wrapper for this C# constructor's class. + /// This C# constructor's class. /// - public readonly EzrSharpCompatibilityType ConstructingTypeWrapper = constructingTypeWrapper; + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.NonPublicMethods + | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.NonPublicProperties + | DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.NonPublicFields)] + public readonly Type ConstructingType; + + /// + /// The name of the constructing type in snake_case. + /// + public readonly string ConstructingTypeName; + + /// + /// Creates a new . + /// + /// This C# constructor's class. + /// The constructor to wrap. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. + /// Skip method signature validation? + public EzrSharpCompatibilityConstructor( + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.NonPublicMethods + | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.NonPublicProperties + | DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.NonPublicFields)] + Type constructingType, + + ConstructorInfo sharpConstructor, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : base(sharpConstructor, null, parentContext, startPosition, endPosition, skipValidation) + { + ConstructingType = constructingType; + + SharpAutoWrapperAttribute? autoWrapperAttribute = constructingType.GetCustomAttribute(); + ConstructingTypeName = !string.IsNullOrEmpty(autoWrapperAttribute?.Name) ? autoWrapperAttribute.Name : PascalToSnakeCase(constructingType.Name); + } /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) @@ -34,13 +69,13 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run try { - object? output = ((ConstructorInfo)Executable).Invoke(mappedArguments); + object? output = SharpMember.Invoke(mappedArguments); if (output is null) result.Success(NewNothingConstant()); else { - IEzrObject wrapper = new EzrSharpCompatibilityObjectInstance(output, ConstructingTypeWrapper.SharpType, _executionContext, StartPosition, EndPosition); + IEzrObject wrapper = new EzrSharpCompatibilityObjectInstance(output, ConstructingType, _executionContext, StartPosition, EndPosition); if (result.ShouldReturn) return; @@ -57,7 +92,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run public override string ToString(RuntimeResult result) { return ParameterNames.Length > 0 - ? $"<{TypeName} for type \"{ConstructingTypeWrapper.SharpMemberName}\", with \"{string.Join("\", \"", ParameterNames)}\">" - : $"<{TypeName} for \"{ConstructingTypeWrapper.SharpMemberName}\">"; + ? $"<{TypeName} for type \"{ConstructingTypeName}\", with \"{string.Join("\", \"", ParameterNames)}\">" + : $"<{TypeName} for \"{ConstructingTypeName}\">"; } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index 1dfbe47..4846b49 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -10,7 +10,8 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.E /// /// Base class for all automatic wrappers which wrap C# executables so that they can be used in ezr². /// -public abstract class EzrSharpCompatibilityExecutable : EzrSharpCompatibilityWrapper +public abstract class EzrSharpCompatibilityExecutable : EzrSharpCompatibilityWrapper + where TMethodBase : MethodBase { /// public override string TypeName { get; protected internal set; } = "csharp runtime executable"; @@ -29,30 +30,19 @@ public abstract class EzrSharpCompatibilityExecutable : EzrSharpCompatibilityWra public readonly string[] ParameterNames; /// - /// The executable to wrap. + /// Creates a new . /// - public readonly MethodBase Executable; - - /// - /// The object which contains the executable, if static. - /// - public readonly object? Instance; - - /// - /// Creates a new . - /// - /// The executable to wrap. + /// The executable to wrap. /// The object which contains the executable, if static. /// The parent context. /// The starting position of the object. /// The ending position of the object. /// Skip method signature validation? - public EzrSharpCompatibilityExecutable(MethodBase sharpMember, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation) : base(sharpMember, parentContext, startPosition, endPosition) + public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation) : base(sharpMethodBase, instance, parentContext, startPosition, endPosition) { Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; - Executable = sharpMember; - Parameters = Executable.GetParameters(); + Parameters = SharpMember.GetParameters(); ParameterNames = Array.ConvertAll(Parameters, p => { @@ -60,8 +50,6 @@ public EzrSharpCompatibilityExecutable(MethodBase sharpMember, object? instance, return string.IsNullOrEmpty(definedName) ? PascalToSnakeCase(p.Name ?? string.Empty) : definedName; }); - Instance = instance; - if (!skipValidation) Validate(); } @@ -172,19 +160,4 @@ protected internal Dictionary ArgumentsArrayToDictionary(Ref return formattedArguments; } - - /// - public override int ComputeHashCode(RuntimeResult result) - { - return HashCode.Combine(HashTag, Executable); - } - - /// - public override bool StrictEquals(IEzrObject other, RuntimeResult result) - { - return other is EzrSharpCompatibilityExecutable executable - && executable.Executable == Executable - && executable.Instance?.GetHashCode() == Instance?.GetHashCode() - && other.HashTag == HashTag; - } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs index bd87ef8..822703f 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs @@ -14,7 +14,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.E /// The starting position of the object. /// The ending position of the object. /// Skip method signature validation? -public class EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : EzrSharpCompatibilityExecutable(sharpFunction, instance, parentContext, startPosition, endPosition, skipValidation) +public class EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : EzrSharpCompatibilityExecutable(sharpFunction, instance, parentContext, startPosition, endPosition, skipValidation) { /// public override string TypeName { get; protected internal set; } = "csharp function"; @@ -35,7 +35,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run try { - object? output = Executable.Invoke(Instance, mappedArguments); + object? output = SharpMember.Invoke(Instance, mappedArguments); if (output is null) result.Success(NewNothingConstant()); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index d1b104e..b838e48 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -8,7 +8,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; /// /// Class to automatically wrap C# fields so that they can be used in ezr². /// -public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper +public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper { /// public override string TypeName { get; protected internal set; } = "csharp field"; @@ -16,16 +16,6 @@ public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpField"; - /// - /// Reflection information about the wrapped field. - /// - public readonly FieldInfo SharpField; - - /// - /// The object which contains the field, if static. - /// - public readonly object? Instance; - /// /// Creates a new . /// @@ -35,10 +25,8 @@ public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper /// The starting position of the object. /// The ending position of the object. /// Skip field type validation? - public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : base(sharpField, parentContext, startPosition, endPosition) + public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : base(sharpField, instance, parentContext, startPosition, endPosition) { - SharpField = sharpField; - Instance = instance; Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; if (!skipValidation) @@ -62,13 +50,13 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run break; case { Length: 1 }: - object? argumentAsPrimitive = EzrObjectToCSharp(arguments[0].Object, SharpField.FieldType, result); + object? argumentAsPrimitive = EzrObjectToCSharp(arguments[0].Object, SharpMember.FieldType, result); if (result.ShouldReturn) break; try { - SharpField.SetValue(Instance, argumentAsPrimitive); + SharpMember.SetValue(Instance, argumentAsPrimitive); result.Success(NewNothingConstant()); } catch (Exception error) @@ -85,27 +73,12 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run break; } - object? value = SharpField.GetValue(Instance); + object? value = SharpMember.GetValue(Instance); CSharpToEzrObject(value, result); break; } } - /// - public override bool StrictEquals(IEzrObject other, RuntimeResult result) - { - return other is EzrSharpCompatibilityField field - && field.SharpField == SharpField - && field.Instance?.GetHashCode() == Instance?.GetHashCode() - && other.HashTag == HashTag; - } - - /// - public override int ComputeHashCode(RuntimeResult result) - { - return HashCode.Combine(HashTag, SharpField); - } - /// public override string ToString(RuntimeResult result) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs index d8d2707..e869f73 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -8,7 +8,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; /// /// Class to automatically wrap C# properties so that they can be used in ezr². /// -public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper +public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper { /// public override string TypeName { get; protected internal set; } = "csharp property"; @@ -16,16 +16,6 @@ public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpProperty"; - /// - /// Reflection information about the wrapped property. - /// - public readonly PropertyInfo SharpProperty; - - /// - /// The object which contains the property, if static. - /// - public readonly object? Instance; - /// /// Creates a new . /// @@ -35,10 +25,8 @@ public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper /// The starting position of the object. /// The ending position of the object. /// Skip property type validation? - public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : base(sharpProperty, parentContext, startPosition, endPosition) + public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : base(sharpProperty, instance, parentContext, startPosition, endPosition) { - SharpProperty = sharpProperty; - Instance = instance; Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; if (!skipValidation) @@ -59,22 +47,22 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run if (arguments.Length == 0) { - if (AutoWrapperAttribute?.IsWriteOnly == true || SharpProperty.GetMethod is null || (AutoWrapperAttribute == null && !SharpProperty.GetMethod.IsPublic)) + if (AutoWrapperAttribute?.IsWriteOnly == true || SharpMember.GetMethod is null || (AutoWrapperAttribute == null && !SharpMember.GetMethod.IsPublic)) { result.Failure(new EzrIllegalOperationError($"Cannot get value from CSharp property wrapper \"{SharpMemberName}\" as it is write-only!", Context, StartPosition, EndPosition)); return; } - object? value = SharpProperty.GetValue(Instance); + object? value = SharpMember.GetValue(Instance); CSharpToEzrObject(value, result); } else { - object? value = EzrObjectToCSharp(arguments[0].Object, SharpProperty.PropertyType, result); + object? value = EzrObjectToCSharp(arguments[0].Object, SharpMember.PropertyType, result); if (result.ShouldReturn) return; - if (AutoWrapperAttribute?.IsReadOnly == true || SharpProperty.SetMethod is null || (AutoWrapperAttribute == null && !SharpProperty.SetMethod.IsPublic)) + if (AutoWrapperAttribute?.IsReadOnly == true || SharpMember.SetMethod is null || (AutoWrapperAttribute == null && !SharpMember.SetMethod.IsPublic)) { result.Failure(new EzrIllegalOperationError($"Cannot set value to CSharp property wrapper \"{SharpMemberName}\" as it is read-only!", Context, StartPosition, EndPosition)); return; @@ -82,7 +70,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run try { - SharpProperty.SetValue(Instance, value); + SharpMember.SetValue(Instance, value); result.Success(NewNothingConstant()); } catch (Exception error) @@ -93,21 +81,6 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run } } - /// - public override int ComputeHashCode(RuntimeResult result) - { - return HashCode.Combine(HashTag, SharpProperty); - } - - /// - public override bool StrictEquals(IEzrObject other, RuntimeResult result) - { - return other is EzrSharpCompatibilityProperty property - && property.SharpProperty == SharpProperty - && property.Instance?.GetHashCode() == Instance?.GetHashCode() - && other.HashTag == HashTag; - } - /// public override string ToString(RuntimeResult result) { diff --git a/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs index 0a25407..5411016 100644 --- a/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs @@ -74,7 +74,7 @@ public SharpAutoWrapperAttribute(string name, bool isReadOnly = false, bool isWr /// if the check was successful, an otherwise. public static ArgumentException? ValidateField(FieldInfo fieldInfo) { - return !EzrSharpCompatibilityWrapper.IsSupportedType(fieldInfo.FieldType) + return !EzrSharpCompatibilityWrapper.IsSupportedType(fieldInfo.FieldType) ? new($"Expected field \"{fieldInfo.Name}\" to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\"", nameof(fieldInfo)) : null; } @@ -86,7 +86,7 @@ public SharpAutoWrapperAttribute(string name, bool isReadOnly = false, bool isWr /// if the check was successful, an otherwise. public static ArgumentException? ValidateProperty(PropertyInfo propertyInfo) { - return !EzrSharpCompatibilityWrapper.IsSupportedType(propertyInfo.PropertyType) + return !EzrSharpCompatibilityWrapper.IsSupportedType(propertyInfo.PropertyType) ? new($"Expected property \"{propertyInfo.Name}\" to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\"", nameof(propertyInfo)) : null; } @@ -101,12 +101,12 @@ public SharpAutoWrapperAttribute(string name, bool isReadOnly = false, bool isWr if (methodBase.IsGenericMethod || methodBase.ContainsGenericParameters) return new($"The \"{nameof(SharpAutoWrapperAttribute)}\" attribute does not support generic method/constructor \"{methodBase.Name}\".", nameof(methodBase)); - if (methodBase is MethodInfo methodInfo && methodInfo.ReturnType != typeof(void) && !EzrSharpCompatibilityWrapper.IsSupportedReturnType(methodInfo.ReturnType)) + if (methodBase is MethodInfo methodInfo && methodInfo.ReturnType != typeof(void) && !EzrSharpCompatibilityWrapper.IsSupportedReturnType(methodInfo.ReturnType)) return new($"Expected method \"{methodBase.Name}\"'s return type to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\"", nameof(methodBase)); foreach (ParameterInfo parameterInfo in methodBase.GetParameters()) { - if (!EzrSharpCompatibilityWrapper.IsSupportedType(parameterInfo.ParameterType)) + if (!EzrSharpCompatibilityWrapper.IsSupportedType(parameterInfo.ParameterType)) return new($"Expected all of method/constructor \"{methodBase.Name}\"'s parameters to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\", but found parameter \"{parameterInfo.Name}\" of type \"{parameterInfo.ParameterType.Name}\"", nameof(methodBase)); } From ce5ecc786e31a397a7276dbb93f63978b5aa82c2 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Mon, 4 Nov 2024 14:01:29 +0530 Subject: [PATCH 071/113] Code analysis. --- src/IEzrError.cs | 4 ++-- src/Runtime/Context.cs | 2 +- .../CompatWrappers/EzrSharpCompatibilityObjectInstance.cs | 3 +-- .../Executables/EzrSharpCompatibilityConstructor.cs | 2 +- .../Executables/EzrSharpCompatibilityExecutable.cs | 2 +- .../ObjectMembers/EzrSharpCompatibilityProperty.cs | 4 ++-- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/IEzrError.cs b/src/IEzrError.cs index e77f10d..77c105d 100644 --- a/src/IEzrError.cs +++ b/src/IEzrError.cs @@ -1,5 +1,5 @@ -using System.Text; -using System; +using System; +using System.Text; namespace EzrSquared; diff --git a/src/Runtime/Context.cs b/src/Runtime/Context.cs index e99cff6..d3239a3 100644 --- a/src/Runtime/Context.cs +++ b/src/Runtime/Context.cs @@ -159,7 +159,7 @@ public Context(string name, bool isStatic, Position startPosition, Context? pare Id = UIDProvider.Get(); LinkedContexts = linkedContexts == 0 ? [] : new Context[linkedContexts]; - if (isStatic && StaticContext != null) + if (isStatic && StaticContext is not null) throw new ArgumentException("A context cannot be static AND have a static context assigned to it.", nameof(staticContext)); IsStatic = isStatic; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index df82932..1e2bb26 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -1,7 +1,6 @@ using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; using EzrSquared.Runtime.WrapperAttributes; -using EzrSquared.Util; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -39,7 +38,7 @@ public EzrSharpCompatibilityObjectInstance( | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] Type instanceType, - + Context parentContext, Position startPosition, Position endPosition) : base(instanceType, instance, parentContext, startPosition, endPosition) { Tag = $"{Tag}.{SharpMemberName}.{SharpMember.GetHashCode()}"; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index 5cb734d..e067a35 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -47,7 +47,7 @@ public EzrSharpCompatibilityConstructor( | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] Type constructingType, - + ConstructorInfo sharpConstructor, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : base(sharpConstructor, null, parentContext, startPosition, endPosition, skipValidation) { ConstructingType = constructingType; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index 4846b49..091e55c 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -43,7 +43,7 @@ public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? inst Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; Parameters = SharpMember.GetParameters(); - + ParameterNames = Array.ConvertAll(Parameters, p => { string? definedName = p.GetCustomAttribute()?.Name; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs index e869f73..ea659a7 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -47,7 +47,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run if (arguments.Length == 0) { - if (AutoWrapperAttribute?.IsWriteOnly == true || SharpMember.GetMethod is null || (AutoWrapperAttribute == null && !SharpMember.GetMethod.IsPublic)) + if (AutoWrapperAttribute?.IsWriteOnly == true || SharpMember.GetMethod is null || (AutoWrapperAttribute is null && !SharpMember.GetMethod.IsPublic)) { result.Failure(new EzrIllegalOperationError($"Cannot get value from CSharp property wrapper \"{SharpMemberName}\" as it is write-only!", Context, StartPosition, EndPosition)); return; @@ -62,7 +62,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run if (result.ShouldReturn) return; - if (AutoWrapperAttribute?.IsReadOnly == true || SharpMember.SetMethod is null || (AutoWrapperAttribute == null && !SharpMember.SetMethod.IsPublic)) + if (AutoWrapperAttribute?.IsReadOnly == true || SharpMember.SetMethod is null || (AutoWrapperAttribute is null && !SharpMember.SetMethod.IsPublic)) { result.Failure(new EzrIllegalOperationError($"Cannot set value to CSharp property wrapper \"{SharpMemberName}\" as it is read-only!", Context, StartPosition, EndPosition)); return; From ac48361095c188c470ca9a21a13529effe6d5ef0 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Mon, 4 Nov 2024 15:33:08 +0530 Subject: [PATCH 072/113] =?UTF-8?q?ezr=C2=B2=20v0.9.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 4 ++++ docs/index.md | 6 +++--- src/Shell/EzrShell.cs | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 09cb9a6..1e7e225 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,10 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.9.0 [04-11-24] + * There are *many* breaking changes in this version. Please check the GitHub changelogs for more details. + * Overhaul of C# compatibility and source wrappers. + * ezr² RE - v0.8.5 [02-11-24] * [BREAKING CHANGE] `CodeExecutor.s_runtimeContext` is now public-access-only as `CodeExecutor.RuntimeContext`. * Added option to exclude built-in I/O functions from `CodeExecutor.PopulateRuntimeContext`. diff --git a/docs/index.md b/docs/index.md index 30fc548..0650721 100644 --- a/docs/index.md +++ b/docs/index.md @@ -85,15 +85,15 @@ out, you can download it from the [***releases page on GitHub***](https://github * Run the installer and go through the installation.
-[![ezr² RE v0.8.5 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.5_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.5/ezrSquared.Shell.Setup.Win64.exe) -[![ezr² RE v0.8.5 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.5_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.5/ezrSquared.Shell.Setup.Win32.exe) +[![ezr² RE v0.9.0 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.9.0_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.9.0/ezrSquared.Shell.Setup.Win64.exe) +[![ezr² RE v0.9.0 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.9.0_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.9.0/ezrSquared.Shell.Setup.Win32.exe) # [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! [![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) -[![ezr² RE v0.8.5 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.8.5_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.8.5/ezrSquared.0.8.5-unstable.nupkg) +[![ezr² RE v0.9.0 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.9.0_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.9.0/ezrSquared.0.9.0-unstable.nupkg) # [Other](#tab/REother) diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index cc76c3b..ed5a773 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -20,7 +20,7 @@ internal class Shell public static void Main() { - Console.OutputEncoding = Encoding.Unicode; + Console.OutputEncoding = Encoding.UTF8; string[] commandLineArguments = Environment.GetCommandLineArgs(); if (!ParseCommandLineArguments(commandLineArguments)) From dd9951f1dcdc7a13da6ca27cc91218621ac7614a Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Mon, 4 Nov 2024 20:26:13 +0530 Subject: [PATCH 073/113] Made dictionaries iterable and more generic. --- .../Collections/RuntimeEzrObjectDictionary.cs | 81 ++++++++++++++++++- src/Runtime/Interpreter.cs | 6 +- src/Runtime/Types/Collections/EzrArray.cs | 20 ++--- .../Types/Collections/EzrDictionary.cs | 79 +++++++++++++++--- src/Runtime/Types/Collections/EzrList.cs | 14 ++-- .../Types/Collections/IEzrDictionary.cs | 25 ++++++ .../Collections/IEzrIndexedCollection.cs | 9 +-- .../Types/Core/Text/EzrCharacterList.cs | 14 ++-- src/Runtime/Types/Core/Text/EzrString.cs | 16 ++-- 9 files changed, 209 insertions(+), 55 deletions(-) create mode 100644 src/Runtime/Types/Collections/IEzrDictionary.cs diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index 64589a4..4a1c8bf 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -1,4 +1,6 @@ using EzrSquared.Runtime.Types; +using EzrSquared.Runtime.Types.Collections; +using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.WrapperAttributes; using System.Collections.Generic; @@ -113,10 +115,47 @@ public bool RemoveHash(int key) /// Merges a to the current . ///
/// The other to be merged. - public void Merge(RuntimeEzrObjectDictionary other) + /// The object for returning errors. + public void Merge(RuntimeEzrObjectDictionary other, RuntimeResult result) { foreach (KeyValuePair> pair in other._items) - _items[pair.Key] = pair.Value; + { + IEzrObject keyObject = pair.Value.Key; + if (keyObject is IEzrMutableObject mutableElement) + { + IEzrObject? keyCopy = (IEzrObject?)mutableElement.DeepCopy(result); + if (result.ShouldReturn) + return; + + keyObject = keyCopy!; + } + + _items[pair.Key] = new KeyValuePair(keyObject, pair.Value.Value); + } + } + + /// + /// Merges an to the current . + /// + /// The other to be merged. + /// The context under which this operation is being executed. + /// The object for returning errors. + public void Merge(IEzrDictionary other, Context executionContext, RuntimeResult result) + { + foreach (IEzrIndexedCollection pair in other) + { + if (pair.Count is > 2 or < 2) + { + result.Failure(new EzrUnexpectedTypeError($"Object of type \"{other.TypeName}\" is in an unexpected format and cannot be merged into this dictionary!", executionContext, other.StartPosition, other.EndPosition)); + return; + } + + (IEzrObject keyObject, IEzrObject valueObject) = (pair.At(0), pair.At(1)); + + Update(keyObject, valueObject, result); + if (result.ShouldReturn) + return; + } } /// @@ -172,6 +211,44 @@ public bool IsEqual(RuntimeEzrObjectDictionary other, RuntimeResult result) return true; } + /// + /// Checks if the current dictionary is equal to the given keyed collection. + /// + /// The other keyed collection. + /// The context under which this operation is being executed. + /// The object for returning errors. + /// The comparison result. + public bool IsEqual(IEzrDictionary other, Context executionContext, RuntimeResult result) + { + if (other.Count != _items.Count) + return false; + + foreach (IEzrIndexedCollection pair in other) + { + if (pair.Count is > 2 or < 2) + { + result.Failure(new EzrUnexpectedTypeError($"Object of type \"{other.TypeName}\" is in an unexpected format and cannot be compared with this dictionary!", executionContext, other.StartPosition, other.EndPosition)); + return false; + } + + (IEzrObject keyObject, IEzrObject valueObject) = (pair.At(0), pair.At(1)); + + int keyHashCode = keyObject.ComputeHashCode(result); + if (result.ShouldReturn || !_items.TryGetValue(keyHashCode, out KeyValuePair thisPair)) + return false; + + bool keyEquals = keyObject.StrictEquals(thisPair.Key, result); + if (result.ShouldReturn || !keyEquals) + return false; + + bool valueEquals = valueObject.StrictEquals(thisPair.Value.Object, result); + if (result.ShouldReturn || !valueEquals) + return false; + } + + return true; + } + /// /// Retrieves all keys from the . /// diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index 4a7ef2c..f3255fa 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -440,7 +440,7 @@ private void AssignValuesToVariables(VariableAssignmentNode node, Reference[] va switch (value) { - case IEzrIndexedCollection otherCollection when otherCollection.Length != variables.Length: + case IEzrIndexedCollection otherCollection when otherCollection.Count != variables.Length: RuntimeResult.Failure(new EzrIllegalOperationError("Mismatched number of variables and values in assignment!", executionContext, node.StartPosition, node.EndPosition)); return; @@ -1037,13 +1037,13 @@ private void VisitForEachNode(ForEachNode node, Context executionContext, Contex return; Reference iterableObjectReference = RuntimeResult.Reference; - if (iterableObjectReference.Object is not IEzrIndexedCollection iterableObject) + if (iterableObjectReference.Object is not IReadOnlyCollection iterableObject) { RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected an iterable object to iterate, but got object of type \"{iterableObjectReference.Object.TypeName}\"!", executionContext, node.Expression.Right.StartPosition, node.Expression.Right.EndPosition)); return; } - List returns = new(iterableObject.Length); + List returns = new(iterableObject.Count); foreach (IEzrObject ezrObject in iterableObject) { ezrObject.Update(executionContext, node.Expression.StartPosition, node.Expression.EndPosition); diff --git a/src/Runtime/Types/Collections/EzrArray.cs b/src/Runtime/Types/Collections/EzrArray.cs index 67b5983..35ce71d 100644 --- a/src/Runtime/Types/Collections/EzrArray.cs +++ b/src/Runtime/Types/Collections/EzrArray.cs @@ -26,7 +26,7 @@ public class EzrArray : EzrObject, IEzrIndexedCollection public readonly IEzrObject[] Value; /// - public int Length { get; } + public int Count { get; } /// /// Creates a new . @@ -38,9 +38,9 @@ public class EzrArray : EzrObject, IEzrIndexedCollection public EzrArray(IEzrObject[] elements, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { Value = elements; - Length = elements.Length; + Count = elements.Length; - Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Length))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); } /// @@ -51,7 +51,7 @@ public EzrArray(IEzrObject[] elements, Context parentContext, Position startPosi /// The result of the comparison. private bool Compare(IEzrIndexedCollection other, RuntimeResult result) { - if (Value.Length != other.Length) + if (Value.Length != other.Count) return false; for (int i = 0; i < Value.Length; i++) @@ -154,10 +154,10 @@ public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) case EzrInteger: result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: < 2 }: + case IEzrIndexedCollection { Count: < 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: > 2 }: + case IEzrIndexedCollection { Count: > 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; case IEzrIndexedCollection otherCollection: @@ -231,10 +231,10 @@ public override void Addition(IEzrObject other, RuntimeResult result) switch (other) { case EzrArray otherArray: - newArray = new IEzrObject[Value.Length + otherArray.Length]; + newArray = new IEzrObject[Value.Length + otherArray.Count]; Array.Copy(Value, newArray, Value.Length); - Array.Copy(otherArray.Value, 0, newArray, Value.Length, otherArray.Length); + Array.Copy(otherArray.Value, 0, newArray, Value.Length, otherArray.Count); break; @@ -279,10 +279,10 @@ public override void Subtraction(IEzrObject other, RuntimeResult result) case EzrInteger: result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: < 2 }: + case IEzrIndexedCollection { Count: < 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: > 2 }: + case IEzrIndexedCollection { Count: > 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; case IEzrIndexedCollection otherCollection: diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index f9a1e0a..a107f7a 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -7,6 +7,7 @@ using EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; using EzrSquared.Runtime.WrapperAttributes; using System; +using System.Collections; using System.Collections.Generic; using System.Reflection; @@ -15,7 +16,7 @@ namespace EzrSquared.Runtime.Types.Collections; /// /// The mutable dictionary type object. /// -public class EzrDictionary : EzrObject, IEzrMutableObject +public class EzrDictionary : EzrObject, IEzrMutableObject, IEzrDictionary { /// public override string TypeName { get; protected internal set; } = "dictionary"; @@ -28,6 +29,9 @@ public class EzrDictionary : EzrObject, IEzrMutableObject /// public readonly RuntimeEzrObjectDictionary Value; + /// + public int Count => Value.Length; + /// /// Creates a new . /// @@ -44,6 +48,36 @@ public EzrDictionary(RuntimeEzrObjectDictionary value, Context parentContext, Po Context.Set(null, "has_key", ReferencePool.Get(new EzrSharpSourceFunctionWrapper(DictionaryExists, Context, StartPosition, EndPosition), AccessMod.Constant)); } + /// + /// Thrown if the key could not be hashed or was not found. + public IEzrObject At(IEzrObject key, RuntimeResult result) + { + Reference value = Value.Get(key, result); + return !value.IsEmpty + ? value.Object + : throw new KeyNotFoundException("The key could not be hashed or was not found in the dictionary!"); + } + + /// + public IEzrObject? TryAt(IEzrObject key, RuntimeResult result) + { + Reference value = Value.Get(key, result); + return !value.IsEmpty ? value.Object : null; + } + + /// + public IEnumerator GetEnumerator() + { + EzrArray[] pairs = Array.ConvertAll(Value.GetPairs(), pair => new EzrArray([pair.Key, pair.Value], _executionContext, StartPosition, EndPosition)); + return ((IEnumerable)pairs).GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + /// /// Basic key checking function. Implements . /// @@ -78,11 +112,18 @@ public override void ComparisonEqual(IEzrObject other, RuntimeResult result) switch (other) { case EzrDictionary otherDictionary: - bool equal = Value.IsEqual(otherDictionary.Value, result); + bool equalDictionaries = Value.IsEqual(otherDictionary.Value, result); if (result.ShouldReturn) return; - result.Success(NewBooleanConstant(equal)); break; + result.Success(NewBooleanConstant(equalDictionaries)); break; + + case IEzrDictionary otherIDictionary: + bool equalIDictionaries = Value.IsEqual(otherIDictionary, _executionContext, result); + if (result.ShouldReturn) + break; + + result.Success(NewBooleanConstant(equalIDictionaries)); break; default: result.Success(NewBooleanConstant(false)); break; @@ -95,11 +136,19 @@ public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) switch (other) { case EzrDictionary otherDictionary: - bool equal = Value.IsEqual(otherDictionary.Value, result); + bool equalDictionaries = Value.IsEqual(otherDictionary.Value, result); if (result.ShouldReturn) return; - result.Success(NewBooleanConstant(!equal)); break; + result.Success(NewBooleanConstant(!equalDictionaries)); break; + + + case IEzrDictionary otherIDictionary: + bool equalIDictionaries = Value.IsEqual(otherIDictionary, _executionContext, result); + if (result.ShouldReturn) + break; + + result.Success(NewBooleanConstant(!equalIDictionaries)); break; default: result.Success(NewBooleanConstant(true)); break; @@ -136,24 +185,32 @@ public override void Addition(IEzrObject other, RuntimeResult result) { switch (other) { - case IEzrIndexedCollection { Length: < 2 }: + case IEzrIndexedCollection { Count: < 2 }: result.Failure(new EzrIllegalOperationError($"The {other.TypeName} must contain two values, the key and value!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: > 2 }: + case IEzrIndexedCollection { Count: > 2 }: result.Failure(new EzrIllegalOperationError($"The {other.TypeName} must only contain two values, the key and value!", _executionContext, other.StartPosition, other.EndPosition)); break; case IEzrIndexedCollection otherCollection: Value.Update(otherCollection.At(0), otherCollection.At(1), result); if (result.ShouldReturn) - return; + break; result.Success(NewNothingConstant()); break; case EzrDictionary otherDictionary: - Value.Merge(otherDictionary.Value); - result.Success(NewNothingConstant()); + Value.Merge(otherDictionary.Value, result); + if (result.ShouldReturn) + break; - break; + result.Success(NewNothingConstant()); break; + + case IEzrDictionary otherIDictionary: + Value.Merge(otherIDictionary, _executionContext, result); + if (result.ShouldReturn) + break; + + result.Success(NewNothingConstant()); break; default: result.Failure(IllegalOperation(other)); break; diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index 2389e3e..7e0fa98 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -29,7 +29,7 @@ public class EzrList : EzrObject, IEzrMutableObject, IEzrIndexedCollection /// [SharpAutoWrapper(isReadOnly: true)] - public int Length => Value.Count; + public int Count => Value.Count; /// The base value. /// The parent context. @@ -39,7 +39,7 @@ public EzrList(RuntimeEzrObjectList elements, Context parentContext, Position st { Value = elements; - Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Length))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); } /// @@ -50,7 +50,7 @@ public EzrList(RuntimeEzrObjectList elements, Context parentContext, Position st /// The result of the comparison. private bool Compare(IEzrIndexedCollection other, RuntimeResult result) { - if (Value.Count != other.Length) + if (Value.Count != other.Count) return false; for (int i = 0; i < Value.Count; i++) @@ -153,10 +153,10 @@ public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) case EzrInteger: result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: < 2 }: + case IEzrIndexedCollection { Count: < 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: > 2 }: + case IEzrIndexedCollection { Count: > 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; case IEzrIndexedCollection otherCollection: @@ -266,10 +266,10 @@ public override void Subtraction(IEzrObject other, RuntimeResult result) case EzrInteger: result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: < 2 }: + case IEzrIndexedCollection { Count: < 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: > 2 }: + case IEzrIndexedCollection { Count: > 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; case IEzrIndexedCollection otherCollection: diff --git a/src/Runtime/Types/Collections/IEzrDictionary.cs b/src/Runtime/Types/Collections/IEzrDictionary.cs new file mode 100644 index 0000000..c79a6f1 --- /dev/null +++ b/src/Runtime/Types/Collections/IEzrDictionary.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Collections; + +/// +/// Interface for a keyed collection of ezr² objects. +/// +public interface IEzrDictionary : IEzrObject, IReadOnlyCollection +{ + /// + /// Gets the object at the specified key. + /// + /// The key. + /// Runtime result for operations on the . + /// The object at the key. + public IEzrObject At(IEzrObject key, RuntimeResult result); + + /// + /// Tries to get the object at the specified key. + /// + /// The key. + /// Runtime result for operations on the . + /// The object at the key or if not found or something went wrong. + public IEzrObject? TryAt(IEzrObject key, RuntimeResult result); +} diff --git a/src/Runtime/Types/Collections/IEzrIndexedCollection.cs b/src/Runtime/Types/Collections/IEzrIndexedCollection.cs index 62e0a11..200619a 100644 --- a/src/Runtime/Types/Collections/IEzrIndexedCollection.cs +++ b/src/Runtime/Types/Collections/IEzrIndexedCollection.cs @@ -5,15 +5,10 @@ namespace EzrSquared.Runtime.Types.Collections; /// /// Interface for an indexed collection of ezr² objects. /// -public interface IEzrIndexedCollection : IEzrObject, IEnumerable +public interface IEzrIndexedCollection : IEzrObject, IReadOnlyCollection { /// - /// The length of the collection. - /// - public int Length { get; } - - /// - /// Gets the object at the specified index/ + /// Gets the object at the specified index. /// /// The index. /// The object at the index. diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index 15d1d38..fb00545 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -35,7 +35,7 @@ public class EzrCharacterList : EzrObject, IEzrMutableObject, IEzrString, IEzrIn /// [SharpAutoWrapper(isReadOnly: true)] - public int Length => Value.Length; + public int Count => Value.Length; /// /// Creates a new . @@ -48,7 +48,7 @@ public EzrCharacterList(string value, Context parentContext, Position startPosit { Value = new(value); - Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Length))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); } /// @@ -58,7 +58,7 @@ public EzrCharacterList(string value, Context parentContext, Position startPosit /// The result of the comparison. private bool Compare(IEzrIndexedCollection other) { - if (Value.Length != other.Length) + if (Value.Length != other.Count) return false; for (int i = 0; i < Value.Length; i++) @@ -140,10 +140,10 @@ public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) case EzrInteger: result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: < 2 }: + case IEzrIndexedCollection { Count: < 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: > 2 }: + case IEzrIndexedCollection { Count: > 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; case IEzrIndexedCollection otherCollection: @@ -289,10 +289,10 @@ public override void Subtraction(IEzrObject other, RuntimeResult result) case EzrInteger: result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: < 2 }: + case IEzrIndexedCollection { Count: < 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: > 2 }: + case IEzrIndexedCollection { Count: > 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; case IEzrIndexedCollection otherCollection: diff --git a/src/Runtime/Types/Core/Text/EzrString.cs b/src/Runtime/Types/Core/Text/EzrString.cs index 62bee3e..ef0c7a5 100644 --- a/src/Runtime/Types/Core/Text/EzrString.cs +++ b/src/Runtime/Types/Core/Text/EzrString.cs @@ -31,7 +31,7 @@ public class EzrString : EzrObject, IEzrString, IEzrIndexedCollection public string StringValue => Value; /// - public int Length { get; } + public int Count { get; } /// /// Creates a new . @@ -43,9 +43,9 @@ public class EzrString : EzrObject, IEzrString, IEzrIndexedCollection public EzrString(string value, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { Value = value; - Length = value.Length; + Count = value.Length; - Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Length))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); } /// @@ -55,7 +55,7 @@ public EzrString(string value, Context parentContext, Position startPosition, Po /// The result of the comparison. private bool Compare(IEzrIndexedCollection other) { - if (Value.Length != other.Length) + if (Value.Length != other.Count) return false; for (int i = 0; i < Value.Length; i++) @@ -137,10 +137,10 @@ public override void ComparisonLessThan(IEzrObject other, RuntimeResult result) case EzrInteger: result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: < 2 }: + case IEzrIndexedCollection { Count: < 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: > 2 }: + case IEzrIndexedCollection { Count: > 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; case IEzrIndexedCollection otherCollection: @@ -284,10 +284,10 @@ public override void Subtraction(IEzrObject other, RuntimeResult result) case EzrInteger: result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: < 2 }: + case IEzrIndexedCollection { Count: < 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; - case IEzrIndexedCollection { Length: > 2 }: + case IEzrIndexedCollection { Count: > 2 }: result.Failure(new EzrIllegalOperationError($"The indices {other.TypeName} must only contain two values, the starting index and the ending index!", _executionContext, other.StartPosition, other.EndPosition)); break; case IEzrIndexedCollection otherCollection: From 59bb7a5493235dba0fb1eebfee06542f8ffad6eb Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 6 Nov 2024 00:15:44 +0530 Subject: [PATCH 074/113] Improved `RuntimeEzrObjectDictionary` error messages. --- src/Runtime/Collections/RuntimeEzrObjectDictionary.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index 4a1c8bf..e1095b6 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -130,6 +130,7 @@ public void Merge(RuntimeEzrObjectDictionary other, RuntimeResult result) keyObject = keyCopy!; } + // This is possibly too naive as it assumes that the hash of a copied IEzrMutableObject does not change. _items[pair.Key] = new KeyValuePair(keyObject, pair.Value.Value); } } @@ -146,12 +147,12 @@ public void Merge(IEzrDictionary other, Context executionContext, RuntimeResult { if (pair.Count is > 2 or < 2) { - result.Failure(new EzrUnexpectedTypeError($"Object of type \"{other.TypeName}\" is in an unexpected format and cannot be merged into this dictionary!", executionContext, other.StartPosition, other.EndPosition)); + result.Failure(new EzrUnexpectedTypeError($"Object of type \"{other.TypeName}\" is in an unexpected format and could not be fully merged into this dictionary!", executionContext, other.StartPosition, other.EndPosition)); return; } (IEzrObject keyObject, IEzrObject valueObject) = (pair.At(0), pair.At(1)); - + Update(keyObject, valueObject, result); if (result.ShouldReturn) return; @@ -232,7 +233,7 @@ public bool IsEqual(IEzrDictionary other, Context executionContext, RuntimeResul } (IEzrObject keyObject, IEzrObject valueObject) = (pair.At(0), pair.At(1)); - + int keyHashCode = keyObject.ComputeHashCode(result); if (result.ShouldReturn || !_items.TryGetValue(keyHashCode, out KeyValuePair thisPair)) return false; From 23d020dcb01103f70f2b4b9b301c5a04e1f3074c Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Wed, 6 Nov 2024 21:57:21 +0530 Subject: [PATCH 075/113] Made for-each loops work better for dictionaries. - Also fixed a context release bug in functions. --- src/EzrSquared.csproj | 2 +- .../Collections/RuntimeEzrObjectDictionary.cs | 185 ++++++++++-------- src/Runtime/Interpreter.cs | 12 +- src/Runtime/Reference.cs | 8 +- src/Runtime/Types/Collections/EzrArray.cs | 6 + .../Types/Collections/EzrDictionary.cs | 62 +++--- src/Runtime/Types/Collections/EzrList.cs | 6 + .../Types/Collections/IEzrDictionary.cs | 2 +- .../Types/Collections/IEzrEnumerable.cs | 21 ++ .../Collections/IEzrIndexedCollection.cs | 2 +- .../Types/Core/Text/EzrCharacterList.cs | 6 + src/Runtime/Types/Core/Text/EzrString.cs | 6 + src/Runtime/Types/Executables/EzrFunction.cs | 17 +- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 17 files changed, 221 insertions(+), 122 deletions(-) create mode 100644 src/Runtime/Types/Collections/IEzrEnumerable.cs diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index b2c58da..6a7797f 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.9.0-unstable + 0.10.0-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index e1095b6..a711e9c 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -2,6 +2,7 @@ using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.WrapperAttributes; +using System.Collections; using System.Collections.Generic; namespace EzrSquared.Runtime.Collections; @@ -9,11 +10,7 @@ namespace EzrSquared.Runtime.Collections; /// /// A Dictionary for s. /// -/// -/// > [!IMPORTANT] -/// > BUG: If the keys can be access and are mutable objects, they can still be changed. -/// -public class RuntimeEzrObjectDictionary : IMutable +public class RuntimeEzrObjectDictionary : IMutable, IEnumerable>> { /// /// The collection of s stored in the , in the format Dictionary<hashOfKey, KeyValuePair<key, valueReference>>. @@ -23,8 +20,8 @@ public class RuntimeEzrObjectDictionary : IMutable /// /// The number of s in the . /// - [SharpAutoWrapper(isReadOnly: true)] - public int Length => _items.Count; + [SharpAutoWrapper("length", isReadOnly: true)] + public int Count => _items.Count; /// /// Creates a new . @@ -42,6 +39,26 @@ public RuntimeEzrObjectDictionary(IDictionary + /// Tries to get a copy of the given object. + /// + /// The object to copy. + /// The object for returning errors. + /// The object, its copy or if something went wrong. + private static IEzrObject? TryCopyObject(IEzrObject ezrObject, RuntimeResult result) + { + if (ezrObject is IEzrMutableObject mutableElement) + { + IEzrObject? keyCopy = (IEzrObject?)mutableElement.DeepCopy(result); + if (result.ShouldReturn) + return null; + + ezrObject = keyCopy!; + } + + return ezrObject; + } + /// /// Updates the with a new value. /// @@ -58,19 +75,13 @@ public void Update(IEzrObject key, IEzrObject value, RuntimeResult result) reference.Value.UpdateObject(value); else { - if (key is IEzrMutableObject mutableElement) - { - IEzrObject? keyCopy = (IEzrObject?)mutableElement.DeepCopy(result); - if (result.ShouldReturn) - return; - - key = keyCopy!; - } + if (TryCopyObject(key, result) is not IEzrObject keyCopy) + return; Reference valueReference = ReferencePool.Get(value); valueReference.UpdateRegister(true); - _items.Add(hash, new KeyValuePair(key, valueReference)); + _items.Add(hash, new KeyValuePair(keyCopy, valueReference)); } } @@ -120,17 +131,9 @@ public void Merge(RuntimeEzrObjectDictionary other, RuntimeResult result) { foreach (KeyValuePair> pair in other._items) { - IEzrObject keyObject = pair.Value.Key; - if (keyObject is IEzrMutableObject mutableElement) - { - IEzrObject? keyCopy = (IEzrObject?)mutableElement.DeepCopy(result); - if (result.ShouldReturn) - return; - - keyObject = keyCopy!; - } + if (TryCopyObject(pair.Value.Key, result) is not IEzrObject keyObject) + return; - // This is possibly too naive as it assumes that the hash of a copied IEzrMutableObject does not change. _items[pair.Key] = new KeyValuePair(keyObject, pair.Value.Value); } } @@ -143,9 +146,9 @@ public void Merge(RuntimeEzrObjectDictionary other, RuntimeResult result) /// The object for returning errors. public void Merge(IEzrDictionary other, Context executionContext, RuntimeResult result) { - foreach (IEzrIndexedCollection pair in other) + foreach (IEzrObject ezrObject in other) { - if (pair.Count is > 2 or < 2) + if (ezrObject is not IEzrIndexedCollection pair || pair.Count is > 2 or < 2) { result.Failure(new EzrUnexpectedTypeError($"Object of type \"{other.TypeName}\" is in an unexpected format and could not be fully merged into this dictionary!", executionContext, other.StartPosition, other.EndPosition)); return; @@ -168,7 +171,6 @@ public void Merge(IEzrDictionary other, Context executionContext, RuntimeResult public Reference Get(IEzrObject key, RuntimeResult result) { int hash = key.ComputeHashCode(result); - return (!result.ShouldReturn && _items.TryGetValue(hash, out KeyValuePair pair)) ? pair.Value : Reference.Empty; } @@ -224,9 +226,9 @@ public bool IsEqual(IEzrDictionary other, Context executionContext, RuntimeResul if (other.Count != _items.Count) return false; - foreach (IEzrIndexedCollection pair in other) + foreach (IEzrObject ezrObject in other) { - if (pair.Count is > 2 or < 2) + if (ezrObject is not IEzrIndexedCollection pair || pair.Count is > 2 or < 2) { result.Failure(new EzrUnexpectedTypeError($"Object of type \"{other.TypeName}\" is in an unexpected format and cannot be compared with this dictionary!", executionContext, other.StartPosition, other.EndPosition)); return false; @@ -251,26 +253,35 @@ public bool IsEqual(IEzrDictionary other, Context executionContext, RuntimeResul } /// - /// Retrieves all keys from the . + /// Returns the actual integer (hash) keys from the . /// - /// The keys. - public IEzrObject[] GetKeys() + /// The integer hashes. + public int[] GetRealKeys() { - KeyValuePair[] pairs = [.. _items.Values]; - IEzrObject[] keys = new IEzrObject[pairs.Length]; - - for (int i = 0; i < pairs.Length; i++) - keys[i] = pairs[i].Key; - return keys; + return [.. _items.Keys]; } /// - /// Returns the actual integer (hash) keys from the . + /// Retrieves all keys from the . /// - /// The integer hashes. - public int[] GetRealKeys() + /// The object for returning errors. + /// The keys or if something went wrong. + public IEzrObject[]? GetKeys(RuntimeResult result) { - return [.. _items.Keys]; + IEzrObject[] keys = new IEzrObject[_items.Count]; + using IEnumerator> pairs = _items.Values.GetEnumerator(); + + for (int i = 0; i < keys.Length; i++) + { + pairs.MoveNext(); + + if (TryCopyObject(pairs.Current.Key, result) is not IEzrObject keyObject) + return null; + + keys[i] = keyObject; + } + + return keys; } /// @@ -279,64 +290,62 @@ public int[] GetRealKeys() /// The values. public IEzrObject[] GetValues() { - KeyValuePair[] pairs = [.. _items.Values]; - IEzrObject[] values = new IEzrObject[pairs.Length]; + IEzrObject[] values = new IEzrObject[_items.Count]; + using IEnumerator> pairs = _items.Values.GetEnumerator(); + + for (int i = 0; i < values.Length; i++) + { + pairs.MoveNext(); + values[i] = pairs.Current.Value.Object; + } - for (int i = 0; i < pairs.Length; i++) - values[i] = pairs[i].Value.Object; return values; } /// /// Retrieves all keys and values from the . /// - /// The keys and values as an array of s. - public KeyValuePair[] GetPairs() + /// The object for returning errors. + /// The keys and values as an array of s or if something went wrong. + public KeyValuePair[]? GetPairs(RuntimeResult result) { - KeyValuePair[] pairs = [.. _items.Values]; - KeyValuePair[] purePairs = new KeyValuePair[pairs.Length]; + KeyValuePair[] pairsArray = new KeyValuePair[_items.Count]; + using IEnumerator> pairs = _items.Values.GetEnumerator(); + + for (int i = 0; i < pairsArray.Length; i++) + { + pairs.MoveNext(); + + if (TryCopyObject(pairs.Current.Key, result) is not IEzrObject keyObject) + return null; - for (int i = 0; i < pairs.Length; i++) - purePairs[i] = new KeyValuePair(pairs[i].Key, pairs[i].Value.Object); - return purePairs; + pairsArray[i] = new KeyValuePair(keyObject, pairs.Current.Value.Object); + } + + return pairsArray; } /// public IMutable? DeepCopy(RuntimeResult result) { - KeyValuePair[] keyValuePairs = [.. _items.Values]; Dictionary> copiedItems = new(_items.Count); - for (int i = 0; i < keyValuePairs.Length; i++) + foreach (KeyValuePair pair in _items.Values) { - (IEzrObject key, Reference value) = (keyValuePairs[i].Key, keyValuePairs[i].Value); - if (key is IEzrMutableObject mutableKey) - { - IEzrObject? keyCopy = (IEzrObject?)mutableKey.DeepCopy(result); - if (result.ShouldReturn) - return null; - - key = keyCopy!; - } - - IEzrObject valueObject = value.Object; - if (valueObject is IEzrMutableObject mutableValue) - { - IEzrObject? valueObjectCopy = (IEzrObject?)mutableValue.DeepCopy(result); - if (result.ShouldReturn) - return null; + if (TryCopyObject(pair.Key, result) is not IEzrObject keyObject) + return null; - valueObject = valueObjectCopy!; - } + if (TryCopyObject(pair.Value.Object, result) is not IEzrObject valueObject) + return null; Reference valueCopy = ReferencePool.Get(valueObject); valueCopy.UpdateRegister(true); - int hash = key.ComputeHashCode(result); + int hash = keyObject.ComputeHashCode(result); if (result.ShouldReturn) return null; - copiedItems.Add(hash, new KeyValuePair(key, valueCopy)); + copiedItems.Add(hash, new KeyValuePair(keyObject, valueCopy)); } return new RuntimeEzrObjectDictionary(copiedItems); @@ -356,6 +365,28 @@ public void Release() _items.Clear(); } + /// + /// + /// Unlike or this + /// method does NOT copy the keys. So it's best not to expose the key values from this to the + /// ezr² runtime as mutable key objects can be changed. + /// + public IEnumerator>> GetEnumerator() + { + return _items.GetEnumerator(); + } + + /// + /// + /// Unlike or this + /// method does NOT copy the keys. So it's best not to expose the key values from this to the + /// ezr² runtime as mutable key objects can be changed. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + /// Destructor. ~RuntimeEzrObjectDictionary() => Release(); } diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index f3255fa..acf1ee6 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -1037,15 +1037,18 @@ private void VisitForEachNode(ForEachNode node, Context executionContext, Contex return; Reference iterableObjectReference = RuntimeResult.Reference; - if (iterableObjectReference.Object is not IReadOnlyCollection iterableObject) + if (iterableObjectReference.Object is not IEzrEnumerable iterableObject) { RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected an iterable object to iterate, but got object of type \"{iterableObjectReference.Object.TypeName}\"!", executionContext, node.Expression.Right.StartPosition, node.Expression.Right.EndPosition)); return; } - List returns = new(iterableObject.Count); - foreach (IEzrObject ezrObject in iterableObject) + List returns = []; + using IEnumerator enumerator = iterableObject.GetEnumerator(RuntimeResult); + + while (enumerator.MoveNext()) { + IEzrObject ezrObject = enumerator.Current; ezrObject.Update(executionContext, node.Expression.StartPosition, node.Expression.EndPosition); (IEzrObject Object, string Name) newIterationVariable = (ezrObject, iterationVariableName); @@ -1076,6 +1079,9 @@ private void VisitForEachNode(ForEachNode node, Context executionContext, Contex returns.Add(RuntimeResult.Reference.Object); } + if (RuntimeResult.ShouldReturn) + return; + RuntimeResult.Success(ReferencePool.Get(new EzrArray([.. returns], executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); } diff --git a/src/Runtime/Reference.cs b/src/Runtime/Reference.cs index 454c4fe..46a0731 100644 --- a/src/Runtime/Reference.cs +++ b/src/Runtime/Reference.cs @@ -102,11 +102,15 @@ public void UpdateObject(IEzrObject @object, AccessMod accessibilityModifiers = /// but it changes the reference to the this is defined in.
/// /// The new context. - public void UpdateRegisteredContext(Context? context) + /// + /// The context that may be deleted after this is called. If the referenced object's creation context + /// matches this, it is updated. + /// + public void UpdateRegisteredContext(Context? context, Context? releasingContext = null) { RegisteredContext = context; - if (context is not null && ReferenceEquals(Object.CreationContext, Context.Empty)) + if (context is not null && (ReferenceEquals(Object.CreationContext, Context.Empty) || Object.CreationContext.Id == releasingContext?.Id)) Object.UpdateCreationContext(context); } diff --git a/src/Runtime/Types/Collections/EzrArray.cs b/src/Runtime/Types/Collections/EzrArray.cs index 35ce71d..dfaa79a 100644 --- a/src/Runtime/Types/Collections/EzrArray.cs +++ b/src/Runtime/Types/Collections/EzrArray.cs @@ -91,6 +91,12 @@ public IEnumerator GetEnumerator() return ((IEnumerable)Value).GetEnumerator(); } + /// + public IEnumerator GetEnumerator(RuntimeResult result) + { + return GetEnumerator(); + } + /// IEnumerator IEnumerable.GetEnumerator() { diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index a107f7a..7f34d09 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -30,7 +30,7 @@ public class EzrDictionary : EzrObject, IEzrMutableObject, IEzrDictionary public readonly RuntimeEzrObjectDictionary Value; /// - public int Count => Value.Length; + public int Count => Value.Count; /// /// Creates a new . @@ -43,7 +43,7 @@ public EzrDictionary(RuntimeEzrObjectDictionary value, Context parentContext, Po { Value = value; - Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Value.Length))!, Value, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Value.Count))!, Value, Context, StartPosition, EndPosition), AccessMod.Constant)); Context.Set(null, "remove_by_hash", ReferencePool.Get(new EzrSharpCompatibilityFunction(GetMemberInfo(nameof(Value.RemoveHash))!, Value, Context, StartPosition, EndPosition), AccessMod.Constant)); Context.Set(null, "has_key", ReferencePool.Get(new EzrSharpSourceFunctionWrapper(DictionaryExists, Context, StartPosition, EndPosition), AccessMod.Constant)); } @@ -66,10 +66,21 @@ public IEzrObject At(IEzrObject key, RuntimeResult result) } /// - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator(RuntimeResult result) { - EzrArray[] pairs = Array.ConvertAll(Value.GetPairs(), pair => new EzrArray([pair.Key, pair.Value], _executionContext, StartPosition, EndPosition)); - return ((IEnumerable)pairs).GetEnumerator(); + KeyValuePair[]? pairs = Value.GetPairs(result); + if (result.ShouldReturn) + yield break; + + foreach (KeyValuePair pair in pairs!) + yield return new EzrArray([pair.Key, pair.Value], _executionContext, StartPosition, EndPosition); + } + + /// + public IEnumerator GetEnumerator() + { + foreach (KeyValuePair> keyValuePair in Value) + yield return new EzrArray([keyValuePair.Value.Key, keyValuePair.Value.Value.Object], _executionContext, StartPosition, EndPosition); } /// @@ -244,22 +255,22 @@ public override void Division(IEzrObject other, RuntimeResult result) case EzrInteger otherInteger when otherInteger.Value <= 0: result.Failure(new EzrMathError("Division error", "Divisor cannot be less than or equal to zero in dictionary division!", _executionContext, other.StartPosition, other.EndPosition)); return; - case EzrFloat when Value.Length == 0: - case EzrInteger when Value.Length == 0: + case EzrFloat when Value.Count == 0: + case EzrInteger when Value.Count == 0: result.Success(NewNothingConstant()); return; case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int divisor): - newLength = Value.Length / divisor; break; + newLength = Value.Count / divisor; break; case EzrInteger: result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", _executionContext, other.StartPosition, other.EndPosition)); return; case EzrFloat otherFloat: - newLength = (int)(Value.Length / otherFloat.Value); + newLength = (int)(Value.Count / otherFloat.Value); - if (newLength > Value.Length) + if (newLength > Value.Count) { - result.Failure(new EzrIllegalOperationError($"Divided length of dictionary is greater than its length ({Value.Length} / {otherFloat.Value} = {newLength})!", _executionContext, other.StartPosition, other.EndPosition)); + result.Failure(new EzrIllegalOperationError($"Divided length of dictionary is greater than its length ({Value.Count} / {otherFloat.Value} = {newLength})!", _executionContext, other.StartPosition, other.EndPosition)); return; } @@ -270,7 +281,7 @@ public override void Division(IEzrObject other, RuntimeResult result) } int[] keys = Value.GetRealKeys(); - for (int i = Value.Length - 1; i >= newLength; i--) + for (int i = Value.Count - 1; i >= newLength; i--) { if (!Value.RemoveHash(keys[i])) { @@ -311,20 +322,16 @@ public override bool StrictEquals(IEzrObject other, RuntimeResult result) /// public override int ComputeHashCode(RuntimeResult result) { - KeyValuePair[] pairs = Value.GetPairs(); int hash = HashTag; - - for (int i = 0; i < pairs.Length; i++) + foreach (KeyValuePair> keyValuePair in Value) { - int hash1 = pairs[i].Key.ComputeHashCode(result); + int keyHash = keyValuePair.Key; + + int valueHash = keyValuePair.Value.Value.Object.ComputeHashCode(result); if (result.ShouldReturn) return int.MinValue; - int hash2 = pairs[i].Value.ComputeHashCode(result); - if (result.ShouldReturn) - return int.MinValue; - - hash = HashCode.Combine(hash, hash1, hash2); + hash = HashCode.Combine(hash, keyHash, valueHash); } return hash; @@ -333,16 +340,19 @@ public override int ComputeHashCode(RuntimeResult result) /// public override string ToString(RuntimeResult result) { - KeyValuePair[] pairs = Value.GetPairs(); - string[] pairsAsString = new string[pairs.Length]; + using IEnumerator>> keyValuePairs = Value.GetEnumerator(); - for (int i = 0; i < pairs.Length; i++) + string[] pairsAsString = new string[Value.Count]; + for (int i = 0; i < pairsAsString.Length; i++) { - string key = pairs[i].Key.ToString(result); + keyValuePairs.MoveNext(); + KeyValuePair pair = keyValuePairs.Current.Value; + + string key = pair.Key.ToString(result); if (result.ShouldReturn) return string.Empty; - string value = pairs[i].Value.ToString(result); + string value = pair.Value.Object.ToString(result); if (result.ShouldReturn) return string.Empty; diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index 7e0fa98..bdcb27c 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -90,6 +90,12 @@ public IEnumerator GetEnumerator() return Value.ConvertAll(reference => reference.Object).GetEnumerator(); } + /// + public IEnumerator GetEnumerator(RuntimeResult result) + { + return GetEnumerator(); + } + /// IEnumerator IEnumerable.GetEnumerator() { diff --git a/src/Runtime/Types/Collections/IEzrDictionary.cs b/src/Runtime/Types/Collections/IEzrDictionary.cs index c79a6f1..06f9e1a 100644 --- a/src/Runtime/Types/Collections/IEzrDictionary.cs +++ b/src/Runtime/Types/Collections/IEzrDictionary.cs @@ -5,7 +5,7 @@ namespace EzrSquared.Runtime.Types.Collections; /// /// Interface for a keyed collection of ezr² objects. /// -public interface IEzrDictionary : IEzrObject, IReadOnlyCollection +public interface IEzrDictionary : IEzrObject, IEzrEnumerable, IReadOnlyCollection { /// /// Gets the object at the specified key. diff --git a/src/Runtime/Types/Collections/IEzrEnumerable.cs b/src/Runtime/Types/Collections/IEzrEnumerable.cs new file mode 100644 index 0000000..14ee8e5 --- /dev/null +++ b/src/Runtime/Types/Collections/IEzrEnumerable.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace EzrSquared.Runtime.Types.Collections; + +/// +/// A read-only collection of s. +/// +public interface IEzrEnumerable : IEzrObject, IEnumerable +{ + /// + /// Similar to . + /// + /// + /// Use this when exposing the enumerator to the ezr² runtime. + /// For example, this is used by to + /// copy read-only keys so that they can't be edited at runtime. + /// + /// Runtime result for carrying errors. + /// The . + public IEnumerator GetEnumerator(RuntimeResult result); +} diff --git a/src/Runtime/Types/Collections/IEzrIndexedCollection.cs b/src/Runtime/Types/Collections/IEzrIndexedCollection.cs index 200619a..502c62b 100644 --- a/src/Runtime/Types/Collections/IEzrIndexedCollection.cs +++ b/src/Runtime/Types/Collections/IEzrIndexedCollection.cs @@ -5,7 +5,7 @@ namespace EzrSquared.Runtime.Types.Collections; /// /// Interface for an indexed collection of ezr² objects. /// -public interface IEzrIndexedCollection : IEzrObject, IReadOnlyCollection +public interface IEzrIndexedCollection : IEzrObject, IEzrEnumerable, IReadOnlyCollection { /// /// Gets the object at the specified index. diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index fb00545..9350595 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -85,6 +85,12 @@ public IEnumerator GetEnumerator() yield return new EzrCharacter(Value[i], _executionContext, StartPosition, EndPosition); } + /// + public IEnumerator GetEnumerator(RuntimeResult result) + { + return GetEnumerator(); + } + /// IEnumerator IEnumerable.GetEnumerator() { diff --git a/src/Runtime/Types/Core/Text/EzrString.cs b/src/Runtime/Types/Core/Text/EzrString.cs index ef0c7a5..3f664f6 100644 --- a/src/Runtime/Types/Core/Text/EzrString.cs +++ b/src/Runtime/Types/Core/Text/EzrString.cs @@ -82,6 +82,12 @@ public IEnumerator GetEnumerator() yield return new EzrCharacter(@char, _executionContext, StartPosition, EndPosition); } + /// + public IEnumerator GetEnumerator(RuntimeResult result) + { + return GetEnumerator(); + } + /// IEnumerator IEnumerable.GetEnumerator() { diff --git a/src/Runtime/Types/Executables/EzrFunction.cs b/src/Runtime/Types/Executables/EzrFunction.cs index 4fc9f88..f3def26 100644 --- a/src/Runtime/Types/Executables/EzrFunction.cs +++ b/src/Runtime/Types/Executables/EzrFunction.cs @@ -43,18 +43,21 @@ public void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResul interpreter.VisitNode(Body, newContext, null, AccessMod.None); if (result.ShouldReturnFunction) - { - Context.Release(); return; - } if (result.Reference.IsEmpty) + { result.Success(NewNothingConstant()); - else if (result.Reference.RegisteredContext?.Id == newContext.Id) - result.Success(ReferencePool.Get(result.Reference.Object, AccessMod.PrivateConstant)); - else - result.Success(result.Reference); + newContext.Release(); + return; + } + if (result.Reference.RegisteredContext?.Id == newContext.Id) + result.Reference.UpdateRegisteredContext(Context, newContext); + else if (result.Reference.Object.CreationContext.Id == newContext.Id) + result.Reference.Object.UpdateCreationContext(newContext); + + result.Success(result.Reference); newContext.Release(); } diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index ed5a773..8f36d74 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.9.0"; + private const string Version = "0.10.0"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 5544b78..cbf61cb 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.9.0" +#define MyAppVersion "0.10.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 22198ce..ccb7e90 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.9.0" +#define MyAppVersion "0.10.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index ab32e27..acd1cb3 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.9.0 + 0.10.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From d142b366ec358ae79d023e9f0e43f6578ca02cca Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 7 Nov 2024 00:18:51 +0530 Subject: [PATCH 076/113] Fixed list reference registration issues. --- .../Collections/RuntimeEzrObjectList.cs | 25 ++++++++++++- src/Runtime/Interpreter.cs | 5 +-- src/Runtime/Types/Collections/EzrList.cs | 37 +++---------------- .../Types/Executables/EzrRuntimeExecutable.cs | 8 +--- 4 files changed, 31 insertions(+), 44 deletions(-) diff --git a/src/Runtime/Collections/RuntimeEzrObjectList.cs b/src/Runtime/Collections/RuntimeEzrObjectList.cs index 3d40c8d..e0d76a5 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectList.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectList.cs @@ -25,6 +25,29 @@ public RuntimeEzrObjectList(int capacity) : base(capacity) { } /// The base collection of s. public RuntimeEzrObjectList(IEnumerable collection) : base(collection) { } + /// + /// Adds a new reference to the list. + /// + /// The reference to add. + public new void Add(Reference reference) + { + reference.UpdateRegister(true); + base.Add(reference); + } + + /// + /// Adds multiple new reference to the list. + /// + /// + /// This actually creates a new object for each added reference. + /// + /// The references to add. + public new void AddRange(IEnumerable references) + { + foreach (Reference reference in references) + Add(ReferencePool.Get(reference.Object)); + } + /// /// Removes an element in the list at the given index. /// @@ -73,8 +96,6 @@ public RuntimeEzrObjectList(IEnumerable collection) : base(collection for (int i = 0; i < Count; i++) { Reference newReference = ReferencePool.Get(this[i].Object, this[i].AccessibilityModifiers); - newReference.UpdateRegister(true); - if (newReference.Object is IEzrMutableObject mutableElement) { IEzrObject? objectCopy = (IEzrObject?)mutableElement.DeepCopy(result); diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index acf1ee6..27423af 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -221,10 +221,7 @@ private void VisitArrayLikeNodeList(ArrayLikeNode node, Context executionContext if (RuntimeResult.ShouldReturn) return; - Reference reference = ReferencePool.Get(RuntimeResult.Reference.Object); - reference.UpdateRegister(true); - - elementsReferences.Add(reference); + elementsReferences.Add(ReferencePool.Get(RuntimeResult.Reference.Object)); } RuntimeResult.Success(ReferencePool.Get(new EzrList(elementsReferences, executionContext, node.StartPosition, node.EndPosition), AccessMod.PrivateConstant)); diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index bdcb27c..adb452d 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -238,10 +238,7 @@ public override void Addition(IEzrObject other, RuntimeResult result) Value.AddRange(otherList.Value); break; default: - Reference reference = ReferencePool.Get(other); - reference.UpdateRegister(true); - - Value.Add(reference); break; + Value.Add(ReferencePool.Get(other)); break; } result.Success(NewNothingConstant()); @@ -379,23 +376,11 @@ public override void Multiplication(IEzrObject other, RuntimeResult result) int i; for (i = 0; i < loops; i++) - Value.AddRange(Array.ConvertAll(original, element => - { - Reference copy = element.ShallowCopy(); - copy.UpdateRegister(true); - - return copy; - })); + Value.AddRange(original); int currentEnd = (loops == 0 ? 1 : i + 1) * original.Length; if (newLength > currentEnd) - Value.AddRange(Array.ConvertAll(original[..(newLength - currentEnd)], element => - { - Reference copy = element.ShallowCopy(); - copy.UpdateRegister(true); - - return copy; - })); + Value.AddRange(original[..(newLength - currentEnd)]); break; } @@ -442,23 +427,11 @@ public override void Division(IEzrObject other, RuntimeResult result) int i; for (i = 0; i < loops; i++) - Value.AddRange(Array.ConvertAll(original, element => - { - Reference copy = element.ShallowCopy(); - copy.UpdateRegister(true); - - return copy; - })); + Value.AddRange(original); int currentEnd = (loops == 0 ? 1 : i + 1) * original.Length; if (newLength > currentEnd) - Value.AddRange(Array.ConvertAll(original[..(newLength - currentEnd)], element => - { - Reference copy = element.ShallowCopy(); - copy.UpdateRegister(true); - - return copy; - })); + Value.AddRange(original[..(newLength - currentEnd)]); } result.Success(NewNothingConstant()); diff --git a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs index 019d65d..2c801db 100644 --- a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs +++ b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs @@ -138,12 +138,8 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context // If the argument is not a kwarg and there are no more parameters to define and EPAs are allowed: if (!isKeywordArgument && currentIndexThroughParameters >= Parameters.Length && extraPositionalArguments is not null) { - // Create a new reference. - Reference newReference = ReferencePool.Get(argumentObject); - newReference.UpdateRegister(true); - - // And add it to the EPA list. - extraPositionalArguments.Add(newReference); + // And a reference to it to the EPA list. + extraPositionalArguments.Add(ReferencePool.Get(argumentObject)); ReferencePool.TryRelease(argument); continue; From fae2e10a4a37acf2405449583d523cdc9444bd1a Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 7 Nov 2024 00:24:35 +0530 Subject: [PATCH 077/113] Fixed dictionary reference registration issues. --- .../Collections/RuntimeEzrObjectDictionary.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index a711e9c..3b2ff47 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -119,7 +119,15 @@ public bool Remove(IEzrObject key, RuntimeResult result) [SharpAutoWrapper("remove_by_hash")] public bool RemoveHash(int key) { - return _items.Remove(key); + if (_items.TryGetValue(key, out KeyValuePair pair)) + { + pair.Value.UpdateRegister(false); + ReferencePool.TryRelease(pair.Value); + + return _items.Remove(key); + } + + return false; } /// @@ -134,7 +142,10 @@ public void Merge(RuntimeEzrObjectDictionary other, RuntimeResult result) if (TryCopyObject(pair.Value.Key, result) is not IEzrObject keyObject) return; - _items[pair.Key] = new KeyValuePair(keyObject, pair.Value.Value); + Reference newReference = ReferencePool.Get(pair.Value.Value.Object); + newReference.UpdateRegister(true); + + _items[pair.Key] = new KeyValuePair(keyObject, newReference); } } From 938c725f40d21ff4e7d4d812e1c324841edbc323 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 7 Nov 2024 01:52:05 +0530 Subject: [PATCH 078/113] =?UTF-8?q?ezr=C2=B2=20v0.10.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 11 +++++++++++ docs/index.md | 6 +++--- src/Runtime/Types/Collections/EzrDictionary.cs | 2 +- src/Runtime/Types/Executables/EzrFunction.cs | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 1e7e225..d788eb8 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,17 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.10.0 [06-11-24] + * [BREAKING CHANGE] `EzrArray.Length` is now `EzrArray.Count`. + * [BREAKING CHANGE] `EzrList.Length` is now `EzrList.Count`. + * [BREAKING CHANGE] `RuntimeEzrObjectDictionary.Length` is now `RuntimeEzrObjectDictionary.Count`. + * Dictionaries can now be iterated through using for-each loops. + * When requesting the keys of a dictionary, `RuntimeEzrObjectDictionary` will now copy them before returning, except for when using `IEnumerable` overrides. + * Fixed reference registration bugs in `EzrList` and `EzrDictionary`. + * Fixed context releasing bug in `EzrFunction`. + * New `IEzrEnumerable` interface for iterables that can be used by the for-each loop. + * New `IDictionary` interface for dictionary-like types. + * ezr² RE - v0.9.0 [04-11-24] * There are *many* breaking changes in this version. Please check the GitHub changelogs for more details. * Overhaul of C# compatibility and source wrappers. diff --git a/docs/index.md b/docs/index.md index 0650721..09696ca 100644 --- a/docs/index.md +++ b/docs/index.md @@ -85,15 +85,15 @@ out, you can download it from the [***releases page on GitHub***](https://github * Run the installer and go through the installation.
-[![ezr² RE v0.9.0 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.9.0_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.9.0/ezrSquared.Shell.Setup.Win64.exe) -[![ezr² RE v0.9.0 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.9.0_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.9.0/ezrSquared.Shell.Setup.Win32.exe) +[![ezr² RE v0.10.0 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.10.0_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.10.0/ezrSquared.Shell.Setup.Win64.exe) +[![ezr² RE v0.10.0 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.10.0_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.10.0/ezrSquared.Shell.Setup.Win32.exe) # [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! [![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) -[![ezr² RE v0.9.0 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.9.0_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.9.0/ezrSquared.0.9.0-unstable.nupkg) +[![ezr² RE v0.10.0 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.10.0_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.10.0/ezrSquared.0.10.0-unstable.nupkg) # [Other](#tab/REother) diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index 7f34d09..9ef2ff1 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -326,7 +326,7 @@ public override int ComputeHashCode(RuntimeResult result) foreach (KeyValuePair> keyValuePair in Value) { int keyHash = keyValuePair.Key; - + int valueHash = keyValuePair.Value.Value.Object.ComputeHashCode(result); if (result.ShouldReturn) return int.MinValue; diff --git a/src/Runtime/Types/Executables/EzrFunction.cs b/src/Runtime/Types/Executables/EzrFunction.cs index f3def26..333bdb9 100644 --- a/src/Runtime/Types/Executables/EzrFunction.cs +++ b/src/Runtime/Types/Executables/EzrFunction.cs @@ -56,7 +56,7 @@ public void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResul result.Reference.UpdateRegisteredContext(Context, newContext); else if (result.Reference.Object.CreationContext.Id == newContext.Id) result.Reference.Object.UpdateCreationContext(newContext); - + result.Success(result.Reference); newContext.Release(); } From f4c5b2f520a362247a96bd662779449c2b51704c Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 7 Nov 2024 18:12:42 +0530 Subject: [PATCH 079/113] =?UTF-8?q?Added=20array=20support=20for=20wrapper?= =?UTF-8?q?s.=20-=20The=20ezr=C2=B2=20library=20is=20no=20longer=20officia?= =?UTF-8?q?lly=20AOT=20compatible.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/EzrSquared.csproj | 2 +- src/GlobalSuppressions.cs | 1 + .../EzrSharpCompatibilityWrapper.cs | 322 ++++++++++-------- 3 files changed, 178 insertions(+), 147 deletions(-) diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 6a7797f..80690ee 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -17,7 +17,7 @@ True True - True + False diff --git a/src/GlobalSuppressions.cs b/src/GlobalSuppressions.cs index 7a40ed1..4314e75 100644 --- a/src/GlobalSuppressions.cs +++ b/src/GlobalSuppressions.cs @@ -11,3 +11,4 @@ [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Collections.EzrList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrString.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "That's too many ternary operations.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.EzrSharpCompatibilityWrapper`1.Validate~System.Boolean")] +[assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.EzrSharpCompatibilityWrapper`1.EzrObjectToCSharp(EzrSquared.Runtime.Types.IEzrObject,System.Type,EzrSquared.Runtime.RuntimeResult)~System.Object")] diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index c4b3be5..bb1105f 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -1,9 +1,11 @@ -using EzrSquared.Runtime.Types.Core; +using EzrSquared.Runtime.Types.Collections; +using EzrSquared.Runtime.Types.Core; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; using EzrSquared.Runtime.WrapperAttributes; using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text; @@ -18,6 +20,11 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; public abstract class EzrSharpCompatibilityWrapper : EzrObject where TMemberInfo : MemberInfo { + /// + /// Reflection info for / + /// + private static readonly MethodInfo s_completedTaskMethodReflectionInfo = typeof(Task).GetMethod(nameof(Task.FromResult))!; + /// public override string TypeName { get; protected internal set; } = "csharp wrapper"; @@ -102,7 +109,9 @@ internal protected static string PascalToSnakeCase(string text) /// if yes, otherwise. public static bool IsSupportedType(Type type) { - return typeof(IEzrObject).IsAssignableFrom(type) || Type.GetTypeCode(type) is TypeCode.Empty + return typeof(IEzrObject).IsAssignableFrom(type) + || (type.IsArray && type.HasElementType && IsSupportedType(type.GetElementType()!)) + || Type.GetTypeCode(type) is TypeCode.Empty or TypeCode.Int16 or TypeCode.Int32 or TypeCode.Int64 @@ -134,7 +143,7 @@ TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArgu } /// - /// Converts an ezr² type to a C# type. + /// Converts an ezr² object to a C# object. /// /// The to convert. /// The type to convert it to. @@ -142,211 +151,203 @@ TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArgu /// The converted object. protected internal object? EzrObjectToCSharp(IEzrObject value, Type targetType, RuntimeResult result) { - if (targetType.IsAssignableFrom(value.GetType())) - return value; - else if (typeof(IEzrObject).IsAssignableFrom(targetType)) - { - result.Failure(new EzrUnexpectedTypeError($"Expected ezr² object of type \"{targetType.Name}\" (this is the name of the object in C#), but got object of type \"{value.TypeName}\".", Context, value.StartPosition, value.EndPosition)); - return null; - } - switch (Type.GetTypeCode(targetType)) { + case TypeCode.Int16 or TypeCode.Int32 or TypeCode.Int64 or TypeCode.UInt16 or TypeCode.UInt32 or TypeCode.UInt64 or TypeCode.Byte or TypeCode.SByte when value is not EzrFloat and not EzrInteger: + result.Failure(new EzrUnexpectedTypeError($"Expected integer or float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.Int16: - if (value is EzrInteger integer16Value) - if (integer16Value.TryGetIntRepresentation(out int output)) - if (output is < short.MinValue or > short.MaxValue) - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - return (short)output; - else - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + double outputShort = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); + if (outputShort is >= short.MinValue and <= short.MaxValue) + return (short)outputShort; + + result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {short.MinValue} - {short.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.Int32: - if (value is EzrInteger integer32Value) - if (integer32Value.TryGetIntRepresentation(out int output)) - return output; - else - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + double outputInt = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); + if (outputInt is >= int.MinValue and <= int.MaxValue) + return (int)outputInt; + + result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {int.MinValue} - {int.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.Int64: - if (value is EzrInteger integer64Value) - if (integer64Value.TryGetLongRepresentation(out long output)) - return output; - else - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + double outputLong = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); + if (outputLong is >= long.MinValue and <= long.MaxValue) + return (long)outputLong; + + result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {long.MinValue} - {long.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.UInt16: - if (value is EzrInteger unsignedInteger16Value) - if (unsignedInteger16Value.TryGetIntRepresentation(out int output)) - if (output < 0) - result.Failure(new EzrValueOutOfRangeError($"Expected integer of value greater than or equal to 0, but got {output}!", Context, value.StartPosition, value.EndPosition)); - else if (output > ushort.MaxValue) - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - return (ushort)output; - else - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + double outputUShort = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); + if (outputUShort is >= ushort.MinValue and <= ushort.MaxValue) + return (ushort)outputUShort; + + result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {ushort.MinValue} - {ushort.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.UInt32: - if (value is EzrInteger unsignedInteger32Value) - if (unsignedInteger32Value.TryGetIntRepresentation(out int output)) - if (output < 0) - result.Failure(new EzrValueOutOfRangeError($"Expected integer of value greater than or equal to 0, but got {output}!", Context, value.StartPosition, value.EndPosition)); - else - return (uint)output; - else - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + double outputUInt = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); + if (outputUInt is >= uint.MinValue and <= uint.MaxValue) + return (uint)outputUInt; + + result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {uint.MinValue} - {uint.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.UInt64: - if (value is EzrInteger unsignedInteger64Value) - if (unsignedInteger64Value.TryGetLongRepresentation(out long output)) - if (output < 0) - result.Failure(new EzrValueOutOfRangeError($"Expected integer of value greater than or equal to 0, but got {output}!", Context, value.StartPosition, value.EndPosition)); - else - return (ulong)output; - else - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + double outputULong = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); + if (outputULong is >= ulong.MinValue and <= ulong.MaxValue) + return (ulong)outputULong; + + result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {ulong.MinValue} - {ulong.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.Byte: - if (value is EzrInteger byteValue) - if (byteValue.TryGetIntRepresentation(out int output)) - if (output < 0) - result.Failure(new EzrValueOutOfRangeError($"Expected integer of value greater than or equal to 0, but got {output}!", Context, value.StartPosition, value.EndPosition)); - else if (output > byte.MaxValue) - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - return (byte)output; - else - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + double outputByte = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); + if (outputByte is >= byte.MinValue and <= byte.MaxValue) + return (byte)outputByte; + + result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {byte.MinValue} - {byte.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.SByte: - if (value is EzrInteger signedByteValue) - if (signedByteValue.TryGetIntRepresentation(out int output)) - if (output is < sbyte.MinValue or > sbyte.MaxValue) - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - return (sbyte)output; - else - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - result.Failure(new EzrUnexpectedTypeError($"Expected integer, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + double outputSByte = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); + if (outputSByte is >= sbyte.MinValue and <= sbyte.MaxValue) + return (sbyte)outputSByte; + + result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {sbyte.MinValue} - {sbyte.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + + case TypeCode.Single or TypeCode.Double or TypeCode.Decimal when value is not EzrFloat and not EzrInteger: + result.Failure(new EzrUnexpectedTypeError($"Expected integer or float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.Single: - if (value is EzrFloat floatValue) - { - double output = floatValue.Value; - if (output is < float.MinValue or > float.MaxValue) - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - return (float)output; - } - else if (value is EzrInteger integerValue) - { - double output = integerValue.GetDoubleRepresentation(); - if (output is < float.MinValue or > float.MaxValue) - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - return (float)output; - } - else - result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + double outputSingle = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); + if (outputSingle is >= float.MinValue and <= float.MaxValue) + return (float)outputSingle; + + result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {float.MinValue} - {float.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.Double: - if (value is EzrFloat doubleValue) - return doubleValue.Value; - else if (value is EzrInteger integerValue) - { - double output = integerValue.GetDoubleRepresentation(); - if (output is < double.MinValue or > double.MaxValue) - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - return output; - } - else - result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + double outputDouble = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); + if (outputDouble is >= double.MinValue or <= double.MaxValue) + return outputDouble; + + result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {double.MinValue} - {double.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.Decimal: - if (value is EzrFloat decimalValue) - { - double output = decimalValue.Value; - if (output is < (double)decimal.MinValue or > (double)decimal.MaxValue) - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - return (decimal)output; - } - else if (value is EzrInteger integerValue) - { - double output = integerValue.GetDoubleRepresentation(); - if (output is < (double)decimal.MinValue or > (double)decimal.MaxValue) - result.Failure(new EzrValueOutOfRangeError("The value is too large for this operation!", Context, value.StartPosition, value.EndPosition)); - else - return (decimal)output; - } - else - result.Failure(new EzrUnexpectedTypeError($"Expected float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + double outputDecimal = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); + if (outputDecimal >= (double)decimal.MinValue && outputDecimal <= (double)decimal.MaxValue) + return (decimal)outputDecimal; + + result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {decimal.MinValue} - {decimal.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.Boolean: if (value is EzrBoolean booleanValue) return booleanValue.Value; result.Failure(new EzrUnexpectedTypeError($"Expected boolean, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.Char: if (value is EzrCharacter characterValue) return characterValue.Value; result.Failure(new EzrUnexpectedTypeError($"Expected character, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.String: if (value is IEzrString ezrString) return ezrString.StringValue; result.Failure(new EzrUnexpectedTypeError($"Expected string, character or character list, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; + + case TypeCode.Object when targetType.IsAssignableFrom(value.GetType()): + return value; + + case TypeCode.Object when typeof(IEzrObject).IsAssignableFrom(targetType): + result.Failure(new EzrUnexpectedTypeError($"Expected ezr² object of type \"{targetType.Name}\" (this is the name of the type in C#), but got object of type \"{value.TypeName}\".", Context, value.StartPosition, value.EndPosition)); + break; + + case TypeCode.Object when targetType == typeof(Task): + return Task.CompletedTask; + + case TypeCode.Object when targetType.IsArray && targetType.HasElementType: + return HandleEzrArrayLikeToCSharp(value, targetType, result); + + case TypeCode.Object when targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Task<>): + Type taskTargetType = targetType.GetGenericArguments()[0]; + MethodInfo completedTaskMethod = s_completedTaskMethodReflectionInfo.MakeGenericMethod(taskTargetType); + + return completedTaskMethod.Invoke(null, [EzrObjectToCSharp(value, taskTargetType, result)]); + case TypeCode.Empty: - if (value is EzrNothing) - return null; + if (value is not EzrNothing) + result.Failure(new EzrUnexpectedTypeError($"Expected type nothing, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); - result.Failure(new EzrUnexpectedTypeError($"Expected type nothing, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; + default: result.Failure(new EzrUnsupportedWrappingError($"Object of type \"{value.TypeName}\" cannot be converted to CSharp type \"{targetType.Name}\"!", Context, value.StartPosition, value.EndPosition)); break; } - return 0; + return null; + } + + /// + /// Converts an ezr² array-like object to a C# array. + /// + /// The value to convert. + /// The type to convert to. + /// Runtime result for carrying any errors. + protected internal object? HandleEzrArrayLikeToCSharp(IEzrObject value, Type targetType, RuntimeResult result) + { + if (value is not IEzrIndexedCollection ezrIndexedCollection) + { + result.Failure(new EzrUnexpectedTypeError($"Expected array or list, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + return null; + } + + Type arrayElementType = targetType.GetElementType()!; + Array array = Array.CreateInstance(arrayElementType, ezrIndexedCollection.Count); + + using IEnumerator enumerator = ezrIndexedCollection.GetEnumerator(); + for (int i = 0; enumerator.MoveNext(); i++) + { + object? element = EzrObjectToCSharp(enumerator.Current, arrayElementType, result); + if (result.ShouldReturn) + return null; + + array.SetValue(element, i); + } + + return array; } /// - /// Converts a C# primitive type object or a task which returns a C# primitive type object to an ezr² object. + /// Converts a C# object to an ezr² object. /// /// The C# object to convert. /// Runtime result for carrying the result and any errors. /// The converted . protected internal void CSharpToEzrObject(object? value, RuntimeResult result) { - Type? valueType = value?.GetType(); - if (value is null || valueType is null) + if (value is null) { result.Success(NewNothingConstant()); return; } + Type valueType = value.GetType(); switch (Type.GetTypeCode(valueType)) { case TypeCode.Int16: @@ -391,11 +392,17 @@ protected internal void CSharpToEzrObject(object? value, RuntimeResult result) case TypeCode.String: result.Success(NewStringConstant((string)value)); break; + case TypeCode.Object when valueType.IsArray && valueType.HasElementType: + HandleCSharpArrayToEzrObject((Array)value, valueType, result); + break; case TypeCode.Object when typeof(IEzrObject).IsAssignableFrom(valueType): result.Success(ReferencePool.Get((IEzrObject)value, AccessMod.PrivateConstant)); break; case TypeCode.Object when typeof(Task).IsAssignableFrom(valueType): - HandleAsynchronousObject(value, valueType, result); + HandleAsynchronousObjectToEzrObject(value, valueType, result); + break; + case TypeCode.Empty: + result.Success(NewNothingConstant()); break; default: result.Failure(new EzrUnsupportedWrappingError($"CSharp type \"{value.GetType().Name}\" cannot be converted to an ezr² type!", Context, StartPosition, EndPosition)); @@ -403,13 +410,36 @@ protected internal void CSharpToEzrObject(object? value, RuntimeResult result) } } + /// + /// Converts a C# array to an ezr² array-like object. + /// + /// The value to convert. + /// The type to convert from. + /// Runtime result for carrying the result and any errors. + protected internal void HandleCSharpArrayToEzrObject(Array value, Type valueType, RuntimeResult result) + { + Type arrayElementType = valueType.GetElementType()!; + IEzrObject[] elements = new IEzrObject[value.Length]; + + for (int i = 0; i < value.Length; i++) + { + CSharpToEzrObject(value.GetValue(i), result); + if (result.ShouldReturn) + return; + + elements[i] = result.Reference.Object; + } + + result.Success(NewArrayConstant(elements)); + } + /// /// Waits for a task to complete and returns the result as an ezr² object. /// /// The task to await. /// The type of the task. /// Runtime result for carrying the result and any errors. - protected internal void HandleAsynchronousObject( + protected internal void HandleAsynchronousObjectToEzrObject( object value, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] From 05846817edd3bd51f4f5d88f06b97535a48856b8 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 7 Nov 2024 23:40:37 +0530 Subject: [PATCH 080/113] Fixed "empty parameter name" bug. - And improved PascalCase to snake_case converter --- .../EzrSharpCompatibilityWrapper.cs | 15 +++++++++------ .../EzrSharpCompatibilityConstructor.cs | 2 +- .../EzrSharpCompatibilityExecutable.cs | 15 +++++++++------ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index bb1105f..04f69c0 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -63,7 +63,7 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, { SharpMember = wrappedMember; AutoWrapperAttribute = wrappedMember.GetCustomAttribute(); - SharpMemberName = !string.IsNullOrEmpty(AutoWrapperAttribute?.Name) ? AutoWrapperAttribute.Name : PascalToSnakeCase(wrappedMember.Name); + SharpMemberName = !string.IsNullOrEmpty(AutoWrapperAttribute?.Name) ? AutoWrapperAttribute.Name : PascalToSnakeCase(wrappedMember.Name)!; Instance = instance; } @@ -85,18 +85,21 @@ public bool Validate() ///
/// The text to convert in PascalCase. /// The converted text in snake_case. - internal protected static string PascalToSnakeCase(string text) + internal protected static string? PascalToSnakeCase(string? text) { + if (string.IsNullOrEmpty(text)) + return null; + StringBuilder result = new(); result.Append(char.ToLowerInvariant(text[0])); for (int i = 1; i < text.Length; ++i) { char c = text[i]; - if (char.IsUpper(c)) - result.Append('_').Append(char.ToLowerInvariant(c)); - else - result.Append(c); + if (c == '_') + continue; + + result.Append(char.IsUpper(c) ? $"_{char.ToLowerInvariant(c)}" : c); } return result.ToString(); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index e067a35..f04c3a4 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -53,7 +53,7 @@ public EzrSharpCompatibilityConstructor( ConstructingType = constructingType; SharpAutoWrapperAttribute? autoWrapperAttribute = constructingType.GetCustomAttribute(); - ConstructingTypeName = !string.IsNullOrEmpty(autoWrapperAttribute?.Name) ? autoWrapperAttribute.Name : PascalToSnakeCase(constructingType.Name); + ConstructingTypeName = !string.IsNullOrEmpty(autoWrapperAttribute?.Name) ? autoWrapperAttribute.Name : PascalToSnakeCase(constructingType.Name)!; } /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index 091e55c..bf7c362 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -43,12 +43,15 @@ public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? inst Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; Parameters = SharpMember.GetParameters(); + ParameterNames = new string[Parameters.Length]; - ParameterNames = Array.ConvertAll(Parameters, p => + for (int i = 0; i < Parameters.Length; i++) { - string? definedName = p.GetCustomAttribute()?.Name; - return string.IsNullOrEmpty(definedName) ? PascalToSnakeCase(p.Name ?? string.Empty) : definedName; - }); + ParameterInfo parameter = Parameters[i]; + string? definedName = parameter.GetCustomAttribute()?.Name; + + ParameterNames[i] = string.IsNullOrEmpty(definedName) ? PascalToSnakeCase(parameter.Name) ?? $"param_{i}" : definedName; + } if (!skipValidation) Validate(); @@ -125,7 +128,7 @@ protected internal Dictionary ArgumentsArrayToDictionary(Ref for (int i = 0; i < Parameters.Length; i++) { ParameterInfo parameter = Parameters[i]; - if (!string.IsNullOrEmpty(parameter.Name) && arguments.TryGetValue(ParameterNames[i], out IEzrObject? argument)) + if (arguments.TryGetValue(ParameterNames[i], out IEzrObject? argument)) { object? primitiveArgument = EzrObjectToCSharp(argument, parameter.ParameterType, result); if (result.ShouldReturn) @@ -151,7 +154,7 @@ protected internal Dictionary ArgumentsArrayToDictionary(Ref if (arguments.Count > 0) { - Dictionary.Enumerator argumentsEnumerator = arguments.GetEnumerator(); + using Dictionary.Enumerator argumentsEnumerator = arguments.GetEnumerator(); argumentsEnumerator.MoveNext(); KeyValuePair first = argumentsEnumerator.Current; From a8d3cf8584d21c7d3656e064f5e91efe1f53d393 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 8 Nov 2024 16:38:01 +0530 Subject: [PATCH 081/113] =?UTF-8?q?ezr=C2=B2=20v0.11.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 12 +++ docs/index.md | 6 +- src/EzrSquared.csproj | 6 +- src/GlobalSuppressions.cs | 2 +- .../EzrSharpCompatibilityObjectInstance.cs | 18 ++--- .../EzrSharpCompatibilityType.cs | 26 +++--- .../EzrSharpCompatibilityWrapper.cs | 79 ++++--------------- .../EzrSharpCompatibilityExecutable.cs | 4 +- .../EzrSharpCompatibilityField.cs | 6 +- .../EzrSharpCompatibilityProperty.cs | 6 +- .../EzrSharpSourceTypeWrapper.cs | 10 +-- .../SharpAutoWrapperAttribute.cs | 73 ++++++----------- .../SharpDoNotWrapAttribute.cs | 11 +++ src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 17 files changed, 101 insertions(+), 166 deletions(-) create mode 100644 src/Runtime/WrapperAttributes/SharpDoNotWrapAttribute.cs diff --git a/Changelog.txt b/Changelog.txt index d788eb8..dc2ff36 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,18 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.11.0 [08-11-24] + * [BREAKING CHANGE] The ezr² library is no longer officially AOT compatible. + * [BREAKING CHANGE] `EzrSharpCompatibilityWrapper.Validate` has been removed. Use `SharpAutoWrapperAttribute.ValidateMethod` instead. + * [BREAKING CHANGE] `EzrSharpCompatibilityWrapper.IsSupportedType` and `EzrSharpCompatibilityWrapper.IsSupportedReturnType` have been removed. + * [BREAKING CHANGE] `SharpAutoWrapperAttribute.Validate`, `SharpAutoWrapperAttribute.ValidateField` and `SharpAutoWrapperAttribute.ValidateProperty` have been removed. + * [BREAKING CHANGE] The `skipValidation` parameter has been removed from the constructors of `EzrSharpCompatibilityField` and `EzrSharpCompatibilityProperty`. + * Added support for all C# members and types through C# compatibility wrappers, except for open generic type and method definitions. + * Added new `SharpDoNotWrapAttribute` to inform `EzrSharpCompatibilityObjectInstance` and `EzrSharpCompatibilityType` that a member should not be wrapped. + * Added new utility methods in `SharpAutoWrapperAttribute` to check if a member is public and to check if a member should be wrapped. + * Improved PascalCase to snake_case converter. + * Fixed bug relating to empty names for C# wrapped parameters. + * ezr² RE - v0.10.0 [06-11-24] * [BREAKING CHANGE] `EzrArray.Length` is now `EzrArray.Count`. * [BREAKING CHANGE] `EzrList.Length` is now `EzrList.Count`. diff --git a/docs/index.md b/docs/index.md index 09696ca..04a9e2b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -85,15 +85,15 @@ out, you can download it from the [***releases page on GitHub***](https://github * Run the installer and go through the installation.
-[![ezr² RE v0.10.0 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.10.0_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.10.0/ezrSquared.Shell.Setup.Win64.exe) -[![ezr² RE v0.10.0 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.10.0_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.10.0/ezrSquared.Shell.Setup.Win32.exe) +[![ezr² RE v0.11.0 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.0_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.0/ezrSquared.Shell.Setup.Win64.exe) +[![ezr² RE v0.11.0 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.0_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.0/ezrSquared.Shell.Setup.Win32.exe) # [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! [![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) -[![ezr² RE v0.10.0 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.10.0_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.10.0/ezrSquared.0.10.0-unstable.nupkg) +[![ezr² RE v0.11.0 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.0_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.0/ezrSquared.0.11.0-unstable.nupkg) # [Other](#tab/REother) diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 80690ee..e0b8f53 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -16,7 +16,7 @@ True True - + False @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.10.0-unstable + 0.11.0-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED @@ -51,7 +51,7 @@ True True - true + True snupkg diff --git a/src/GlobalSuppressions.cs b/src/GlobalSuppressions.cs index 4314e75..68d4a4a 100644 --- a/src/GlobalSuppressions.cs +++ b/src/GlobalSuppressions.cs @@ -10,5 +10,5 @@ [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrCharacterList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Collections.EzrList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrString.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "That's too many ternary operations.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.EzrSharpCompatibilityWrapper`1.Validate~System.Boolean")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.EzrSharpCompatibilityWrapper`1.EzrObjectToCSharp(EzrSquared.Runtime.Types.IEzrObject,System.Type,EzrSquared.Runtime.RuntimeResult)~System.Object")] +[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Too many ternary operators.", Scope = "member", Target = "~M:EzrSquared.Runtime.WrapperAttributes.SharpAutoWrapperAttribute.ValidateMethod(System.Reflection.MethodBase,System.Boolean)~System.Boolean")] diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index 1e2bb26..be056d4 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -48,11 +48,11 @@ public EzrSharpCompatibilityObjectInstance( for (int i = 0; i < allMethods.Length; i++) { MethodInfo method = allMethods[i]; - if (method.IsAbstract || (!method.IsPublic && method.GetCustomAttribute() is null)) + if (!SharpAutoWrapperAttribute.ShouldBeWrapped(method)) continue; EzrSharpCompatibilityFunction methodObject = new(method, Instance, Context, StartPosition, EndPosition, skipValidation: true); - if (!methodObject.Validate()) + if (SharpAutoWrapperAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) continue; string methodObjectName = methodObject.SharpMemberName; @@ -71,13 +71,10 @@ public EzrSharpCompatibilityObjectInstance( for (int i = 0; i < allProperties.Length; i++) { PropertyInfo property = allProperties[i]; - if (property.GetMethod?.IsPublic != true && property.SetMethod?.IsPublic != true && property.GetCustomAttribute() is null) - continue; - - EzrSharpCompatibilityProperty propertyObject = new(property, Instance, Context, StartPosition, EndPosition, skipValidation: true); - if (!propertyObject.Validate()) + if (!SharpAutoWrapperAttribute.ShouldBeWrapped(property)) continue; + EzrSharpCompatibilityProperty propertyObject = new(property, Instance, Context, StartPosition, EndPosition); Context.Set(null, propertyObject.SharpMemberName, ReferencePool.Get(propertyObject, AccessMod.Constant)); } @@ -85,13 +82,10 @@ public EzrSharpCompatibilityObjectInstance( for (int i = 0; i < allFields.Length; i++) { FieldInfo field = allFields[i]; - if (!field.IsPublic && field.GetCustomAttribute() is null) - continue; - - EzrSharpCompatibilityField fieldObject = new(field, Instance, Context, StartPosition, EndPosition, skipValidation: true); - if (!fieldObject.Validate()) + if (!SharpAutoWrapperAttribute.ShouldBeWrapped(field)) continue; + EzrSharpCompatibilityField fieldObject = new(field, Instance, Context, StartPosition, EndPosition); Context.Set(null, fieldObject.SharpMemberName, ReferencePool.Get(fieldObject, AccessMod.Constant)); } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index 9f12b05..337ae4f 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -45,9 +45,9 @@ public EzrSharpCompatibilityType( { Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; - if (sharpType.IsGenericType) + if (sharpType.IsGenericTypeDefinition) { - result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap generic CSharp type \"{SharpMember.Name}\"!", Context, StartPosition, EndPosition)); + result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap generic CSharp type definition \"{SharpMember.Name}\"!", Context, StartPosition, EndPosition)); return; } @@ -56,11 +56,11 @@ public EzrSharpCompatibilityType( for (int i = 0; i < allStaticMethods.Length; i++) { MethodInfo method = allStaticMethods[i]; - if (method.IsAbstract || (!method.IsPublic && method.GetCustomAttribute() is null)) + if (!SharpAutoWrapperAttribute.ShouldBeWrapped(method)) continue; EzrSharpCompatibilityFunction methodObject = new(method, null, Context, StartPosition, EndPosition, skipValidation: true); - if (!methodObject.Validate()) + if (SharpAutoWrapperAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) continue; string methodObjectName = methodObject.SharpMemberName; @@ -79,13 +79,10 @@ public EzrSharpCompatibilityType( for (int i = 0; i < allStaticProperties.Length; i++) { PropertyInfo property = allStaticProperties[i]; - if (property.GetMethod?.IsPublic != true && property.SetMethod?.IsPublic != true && property.GetCustomAttribute() is null) - continue; - - EzrSharpCompatibilityProperty propertyObject = new(property, null, Context, StartPosition, EndPosition, skipValidation: true); - if (!propertyObject.Validate()) + if (!SharpAutoWrapperAttribute.ShouldBeWrapped(property)) continue; + EzrSharpCompatibilityProperty propertyObject = new(property, null, Context, StartPosition, EndPosition); Context.Set(null, propertyObject.SharpMemberName, ReferencePool.Get(propertyObject, AccessMod.Constant)); } @@ -93,13 +90,10 @@ public EzrSharpCompatibilityType( for (int i = 0; i < allStaticFields.Length; i++) { FieldInfo field = allStaticFields[i]; - if (!field.IsPublic && field.GetCustomAttribute() is null) - continue; - - EzrSharpCompatibilityField fieldObject = new(field, null, Context, StartPosition, EndPosition, skipValidation: true); - if (!fieldObject.Validate()) + if (!SharpAutoWrapperAttribute.ShouldBeWrapped(field)) continue; + EzrSharpCompatibilityField fieldObject = new(field, null, Context, StartPosition, EndPosition); Context.Set(null, fieldObject.SharpMemberName, ReferencePool.Get(fieldObject, AccessMod.Constant)); } @@ -107,11 +101,11 @@ public EzrSharpCompatibilityType( for (int i = 0; i < publicConstructors.Length; i++) { ConstructorInfo constructor = publicConstructors[i]; - if (!constructor.IsPublic && constructor.GetCustomAttribute() is null) + if (!SharpAutoWrapperAttribute.ShouldBeWrapped(constructor)) continue; EzrSharpCompatibilityConstructor constructorObject = new(sharpType, constructor, Context, StartPosition, EndPosition, skipValidation: true); - if (!constructorObject.Validate()) + if (SharpAutoWrapperAttribute.ValidateMethod(constructor, constructorObject.AutoWrapperAttribute is null)) continue; Context.Set(null, $"make_{i}", ReferencePool.Get(constructorObject, AccessMod.Constant)); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 04f69c0..389a181 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -23,7 +23,7 @@ public abstract class EzrSharpCompatibilityWrapper : EzrObject /// /// Reflection info for / /// - private static readonly MethodInfo s_completedTaskMethodReflectionInfo = typeof(Task).GetMethod(nameof(Task.FromResult))!; + private static readonly MethodInfo s_taskFromResultMethod = typeof(Task).GetMethod(nameof(Task.FromResult))!; /// public override string TypeName { get; protected internal set; } = "csharp wrapper"; @@ -67,19 +67,6 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, Instance = instance; } - /// - /// Validates the the current object for wrapping. - /// - /// if the member can be wrapped, otherwise. - public bool Validate() - { - Exception? validationException = SharpAutoWrapperAttribute.Validate(SharpMember); - if (validationException is null) - return true; - - return AutoWrapperAttribute is not null ? throw validationException : false; - } - /// /// Converts a string from PascalCase to snake_case. /// @@ -105,46 +92,6 @@ public bool Validate() return result.ToString(); } - /// - /// Checks if the given type is supported by the compatibility wrappers. - /// - /// The type to check. - /// if yes, otherwise. - public static bool IsSupportedType(Type type) - { - return typeof(IEzrObject).IsAssignableFrom(type) - || (type.IsArray && type.HasElementType && IsSupportedType(type.GetElementType()!)) - || Type.GetTypeCode(type) is TypeCode.Empty - or TypeCode.Int16 - or TypeCode.Int32 - or TypeCode.Int64 - or TypeCode.UInt16 - or TypeCode.UInt32 - or TypeCode.UInt64 - or TypeCode.Byte - or TypeCode.SByte - or TypeCode.Single - or TypeCode.Double - or TypeCode.Decimal - or TypeCode.Boolean - or TypeCode.Char - or TypeCode.String; - } - - /// - /// Checks if the given type is supported by the compatibility wrappers, including generic objects. - /// - /// The type to check. - /// if yes, otherwise. - public static bool IsSupportedReturnType(Type type) - { - return Type.GetTypeCode(type) switch - { - TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArguments.Length == 0 || IsSupportedType(type.GenericTypeArguments[0]), - _ => IsSupportedType(type), - }; - } - /// /// Converts an ezr² object to a C# object. /// @@ -280,17 +227,20 @@ TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArgu result.Failure(new EzrUnexpectedTypeError($"Expected ezr² object of type \"{targetType.Name}\" (this is the name of the type in C#), but got object of type \"{value.TypeName}\".", Context, value.StartPosition, value.EndPosition)); break; - case TypeCode.Object when targetType == typeof(Task): - return Task.CompletedTask; - case TypeCode.Object when targetType.IsArray && targetType.HasElementType: return HandleEzrArrayLikeToCSharp(value, targetType, result); - case TypeCode.Object when targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Task<>): + case TypeCode.Object when targetType == typeof(Task): + return Task.CompletedTask; + + case TypeCode.Object when typeof(Task).IsAssignableFrom(targetType) && !targetType.IsGenericTypeDefinition: Type taskTargetType = targetType.GetGenericArguments()[0]; - MethodInfo completedTaskMethod = s_completedTaskMethodReflectionInfo.MakeGenericMethod(taskTargetType); + object? convertedObject = EzrObjectToCSharp(value, taskTargetType, result); + if (result.ShouldReturn) + break; - return completedTaskMethod.Invoke(null, [EzrObjectToCSharp(value, taskTargetType, result)]); + MethodInfo completedTaskMethod = s_taskFromResultMethod.MakeGenericMethod(taskTargetType); + return completedTaskMethod.Invoke(null, [convertedObject]); case TypeCode.Empty: if (value is not EzrNothing) @@ -299,7 +249,10 @@ TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArgu break; default: - result.Failure(new EzrUnsupportedWrappingError($"Object of type \"{value.TypeName}\" cannot be converted to CSharp type \"{targetType.Name}\"!", Context, value.StartPosition, value.EndPosition)); + if (value is EzrSharpCompatibilityObjectInstance wrapper && wrapper.SharpMember == targetType) + return wrapper.Instance; + + result.Failure(new EzrUnexpectedTypeError($"Expected wrapped object of C# type \"{targetType.Name}\", but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; } @@ -329,7 +282,7 @@ TypeCode.Object when typeof(Task).IsAssignableFrom(type) => type.GenericTypeArgu object? element = EzrObjectToCSharp(enumerator.Current, arrayElementType, result); if (result.ShouldReturn) return null; - + array.SetValue(element, i); } @@ -408,7 +361,7 @@ protected internal void CSharpToEzrObject(object? value, RuntimeResult result) result.Success(NewNothingConstant()); break; default: - result.Failure(new EzrUnsupportedWrappingError($"CSharp type \"{value.GetType().Name}\" cannot be converted to an ezr² type!", Context, StartPosition, EndPosition)); + result.Success(ReferencePool.Get(new EzrSharpCompatibilityObjectInstance(value, valueType, _executionContext, StartPosition, EndPosition), AccessMod.PrivateConstant)); break; } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index bf7c362..59643f6 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -49,12 +49,12 @@ public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? inst { ParameterInfo parameter = Parameters[i]; string? definedName = parameter.GetCustomAttribute()?.Name; - + ParameterNames[i] = string.IsNullOrEmpty(definedName) ? PascalToSnakeCase(parameter.Name) ?? $"param_{i}" : definedName; } if (!skipValidation) - Validate(); + SharpAutoWrapperAttribute.ValidateMethod(SharpMember, AutoWrapperAttribute is null); } /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index b838e48..ab53e2a 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -24,13 +24,9 @@ public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapperThe context in which this object was created. /// The starting position of the object. /// The ending position of the object. - /// Skip field type validation? - public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : base(sharpField, instance, parentContext, startPosition, endPosition) + public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(sharpField, instance, parentContext, startPosition, endPosition) { Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; - - if (!skipValidation) - Validate(); } /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs index ea659a7..c5e16d2 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -24,13 +24,9 @@ public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapperThe context in which this object was created. /// The starting position of the object. /// The ending position of the object. - /// Skip property type validation? - public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : base(sharpProperty, instance, parentContext, startPosition, endPosition) + public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(sharpProperty, instance, parentContext, startPosition, endPosition) { Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; - - if (!skipValidation) - Validate(); } /// diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index 78f8850..80353b1 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -65,8 +65,8 @@ public EzrSharpSourceTypeWrapper( SharpType = type; // Check generics. - if (type.IsGenericType) - throw new ArgumentException($"Cannot wrap generic CSharp type {type.Name}!", nameof(type)); + if (type.IsGenericTypeDefinition) + throw new ArgumentException($"Cannot wrap generic CSharp type definition {type.Name}!", nameof(type)); // Check for type attribute. SharpTypeWrapperAttribute typeAttribute = type.GetCustomAttribute(true) @@ -122,7 +122,7 @@ public EzrSharpSourceTypeWrapper( EzrSharpSourceFunctionWrapper sourceMethod = new(method, Context, StartPosition, EndPosition); (wrappedMethod, methodName) = (sourceMethod, sourceMethod.SharpFunctionName); } - else if (method.GetCustomAttribute(false) is not null) + else if (method.GetCustomAttribute() is not null) { EzrSharpCompatibilityFunction compatMethod = new(method, null, Context, StartPosition, EndPosition); (wrappedMethod, methodName) = (compatMethod, compatMethod.SharpMemberName); @@ -147,7 +147,7 @@ public EzrSharpSourceTypeWrapper( string propertyName; // Check if property can be wrapped. - if (property.GetCustomAttribute(false) is not null) + if (property.GetCustomAttribute() is not null) { EzrSharpCompatibilityProperty compatWrapper = new(property, null, Context, StartPosition, EndPosition); (wrappedProperty, propertyName) = (compatWrapper, compatWrapper.SharpMemberName); @@ -171,7 +171,7 @@ public EzrSharpSourceTypeWrapper( string fieldName; // Check if property can be wrapped. - if (field.GetCustomAttribute(false) is not null) + if (field.GetCustomAttribute() is not null) { EzrSharpCompatibilityField compatWrapper = new(field, null, Context, StartPosition, EndPosition); (wrappedField, fieldName) = (compatWrapper, compatWrapper.SharpMemberName); diff --git a/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs index 5411016..4adbde0 100644 --- a/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs @@ -1,5 +1,4 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; -using System; +using System; using System.Reflection; namespace EzrSquared.Runtime.WrapperAttributes; @@ -52,64 +51,44 @@ public SharpAutoWrapperAttribute(string name, bool isReadOnly = false, bool isWr } /// - /// Checks if the given member is supported for wrapping. + /// Checks if the given method has the supported signature for wrapping. /// - /// The member. - /// if the check was successful, an otherwise. - public static Exception? Validate(MemberInfo memberInfo) + /// The method. + /// Disable exception throwing. + /// if valid, an exception or otherwise. + /// Thrown if the method is generic or has generic parameters. + public static bool ValidateMethod(MethodBase methodBase, bool dontThrow = false) { - return memberInfo switch - { - FieldInfo field => ValidateField(field), - PropertyInfo property => ValidateProperty(property), - MethodBase method => ValidateMethod(method), - _ => throw new ArgumentException($"Unsupported {nameof(MemberInfo)} type {memberInfo.GetType().Name} for validation!", nameof(memberInfo)) - }; - } + if (methodBase.IsGenericMethodDefinition || methodBase.ContainsGenericParameters) + return dontThrow ? false : throw new ArgumentException($"The \"{nameof(SharpAutoWrapperAttribute)}\" attribute does not support generic method/constructor \"{methodBase.Name}\".", nameof(methodBase)); - /// - /// Checks if the given field is a supported type for wrapping. - /// - /// The field. - /// if the check was successful, an otherwise. - public static ArgumentException? ValidateField(FieldInfo fieldInfo) - { - return !EzrSharpCompatibilityWrapper.IsSupportedType(fieldInfo.FieldType) - ? new($"Expected field \"{fieldInfo.Name}\" to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\"", nameof(fieldInfo)) - : null; + return true; } /// - /// Checks if the given property is a supported type for wrapping. + /// Is the member eligible to be wrapped? /// - /// The property. - /// if the check was successful, an otherwise. - public static ArgumentException? ValidateProperty(PropertyInfo propertyInfo) + /// The member to be wrapped. + /// if yes, otherwise. + public static bool ShouldBeWrapped(MemberInfo member) { - return !EzrSharpCompatibilityWrapper.IsSupportedType(propertyInfo.PropertyType) - ? new($"Expected property \"{propertyInfo.Name}\" to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\"", nameof(propertyInfo)) - : null; + return member.GetCustomAttribute() is null && (GetIsPublic(member) || member.GetCustomAttribute() is not null); } /// - /// Checks if the given method has the supported signature for wrapping. + /// Is the member publicly accessible in some way? /// - /// The method. - /// if the check was successful, an otherwise. - public static ArgumentException? ValidateMethod(MethodBase methodBase) + /// The member to check. + /// if yes, otherwise. + /// If is of an unknown or unsupported type. + public static bool GetIsPublic(MemberInfo member) { - if (methodBase.IsGenericMethod || methodBase.ContainsGenericParameters) - return new($"The \"{nameof(SharpAutoWrapperAttribute)}\" attribute does not support generic method/constructor \"{methodBase.Name}\".", nameof(methodBase)); - - if (methodBase is MethodInfo methodInfo && methodInfo.ReturnType != typeof(void) && !EzrSharpCompatibilityWrapper.IsSupportedReturnType(methodInfo.ReturnType)) - return new($"Expected method \"{methodBase.Name}\"'s return type to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\"", nameof(methodBase)); - - foreach (ParameterInfo parameterInfo in methodBase.GetParameters()) + return member switch { - if (!EzrSharpCompatibilityWrapper.IsSupportedType(parameterInfo.ParameterType)) - return new($"Expected all of method/constructor \"{methodBase.Name}\"'s parameters to be of a supported primitive type, as it uses the attribute \"{nameof(SharpAutoWrapperAttribute)}\", but found parameter \"{parameterInfo.Name}\" of type \"{parameterInfo.ParameterType.Name}\"", nameof(methodBase)); - } - - return null; + MethodBase method => method.IsPublic, + FieldInfo field => field.IsPublic, + PropertyInfo property => property.GetMethod?.IsPublic == true || property.SetMethod?.IsPublic == true, + _ => throw new ArgumentException($"Unknown or unsupported {nameof(MemberInfo)} type {member.GetType().Name}!", nameof(member)) + }; } } diff --git a/src/Runtime/WrapperAttributes/SharpDoNotWrapAttribute.cs b/src/Runtime/WrapperAttributes/SharpDoNotWrapAttribute.cs new file mode 100644 index 0000000..7d84181 --- /dev/null +++ b/src/Runtime/WrapperAttributes/SharpDoNotWrapAttribute.cs @@ -0,0 +1,11 @@ +using System; + +namespace EzrSquared.Runtime.WrapperAttributes; + +/// +/// Attribute for C# type members which should NOT be automatically wrapped from C# types into ezr² types by and . +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] +public class SharpDoNotWrapAttribute : Attribute +{ +} diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 8f36d74..6a64a42 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.10.0"; + private const string Version = "0.11.0"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index cbf61cb..dfb3f62 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.10.0" +#define MyAppVersion "0.11.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index ccb7e90..4eb37c1 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.10.0" +#define MyAppVersion "0.11.0" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index acd1cb3..0e2a921 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.10.0 + 0.11.0 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From 39e58db1dca78eb269e19fdfba3d6504e88b9d06 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 8 Nov 2024 18:35:02 +0530 Subject: [PATCH 082/113] Bugfixes for wrappers. --- .../EzrSharpCompatibilityObjectInstance.cs | 2 +- .../EzrSharpCompatibilityType.cs | 8 ++--- .../EzrSharpCompatibilityWrapper.cs | 35 ++++++++++++------- .../EzrSharpSourceTypeWrapper.cs | 10 ++---- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index be056d4..0bffed0 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -52,7 +52,7 @@ public EzrSharpCompatibilityObjectInstance( continue; EzrSharpCompatibilityFunction methodObject = new(method, Instance, Context, StartPosition, EndPosition, skipValidation: true); - if (SharpAutoWrapperAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) + if (!SharpAutoWrapperAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) continue; string methodObjectName = methodObject.SharpMemberName; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index 337ae4f..2726eb1 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -45,9 +45,9 @@ public EzrSharpCompatibilityType( { Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; - if (sharpType.IsGenericTypeDefinition) + if (sharpType.IsAbstract || sharpType.IsGenericTypeDefinition) { - result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap generic CSharp type definition \"{SharpMember.Name}\"!", Context, StartPosition, EndPosition)); + result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap generic/abstract C# type \"{SharpMember.Name}\"!", Context, StartPosition, EndPosition)); return; } @@ -60,7 +60,7 @@ public EzrSharpCompatibilityType( continue; EzrSharpCompatibilityFunction methodObject = new(method, null, Context, StartPosition, EndPosition, skipValidation: true); - if (SharpAutoWrapperAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) + if (!SharpAutoWrapperAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) continue; string methodObjectName = methodObject.SharpMemberName; @@ -105,7 +105,7 @@ public EzrSharpCompatibilityType( continue; EzrSharpCompatibilityConstructor constructorObject = new(sharpType, constructor, Context, StartPosition, EndPosition, skipValidation: true); - if (SharpAutoWrapperAttribute.ValidateMethod(constructor, constructorObject.AutoWrapperAttribute is null)) + if (!SharpAutoWrapperAttribute.ValidateMethod(constructor, constructorObject.AutoWrapperAttribute is null)) continue; Context.Set(null, $"make_{i}", ReferencePool.Get(constructorObject, AccessMod.Constant)); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 389a181..45b1770 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -8,7 +8,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection; -using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; @@ -67,6 +67,20 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, Instance = instance; } + +#pragma warning disable SYSLIB1045 // Convert to 'GeneratedRegexAttribute'. + /// + /// Regex for converting PascalCase/camelCase to snake_case. + /// + /// + /// Regex explanation:
+ /// 1. (?<!^)(?=[A-Z][a-z]) - Add underscore before capital letter followed by a lowercase letter, except at the start.
+ /// 2. (?<=[a-z0-9])(?=[A-Z]) - Add underscore when transitioning from lowercase or number to uppercase.
+ /// 3. (?<=[A-Z])(?=[A-Z][a-z]) - Add underscore between uppercase sequences followed by lowercase (e.g., "TCProtocol"). + ///
+ private static readonly Regex s_caseConverterRegex = new(@"(? /// Converts a string from PascalCase to snake_case. ///
@@ -75,21 +89,16 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, internal protected static string? PascalToSnakeCase(string? text) { if (string.IsNullOrEmpty(text)) - return null; - - StringBuilder result = new(); - result.Append(char.ToLowerInvariant(text[0])); + return text; - for (int i = 1; i < text.Length; ++i) - { - char c = text[i]; - if (c == '_') - continue; + // Remove any leading underscore + if (text.StartsWith('_')) + text = text[1..]; - result.Append(char.IsUpper(c) ? $"_{char.ToLowerInvariant(c)}" : c); - } + string snakeCase = s_caseConverterRegex.Replace(text, "_"); - return result.ToString(); + // Convert entire string to lowercase + return snakeCase.ToLower(); } /// diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index 80353b1..5051d23 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -64,9 +64,9 @@ public EzrSharpSourceTypeWrapper( { SharpType = type; - // Check generics. - if (type.IsGenericTypeDefinition) - throw new ArgumentException($"Cannot wrap generic CSharp type definition {type.Name}!", nameof(type)); + // Check if generic or abstract. + if (type.IsAbstract || type.IsGenericTypeDefinition) + throw new ArgumentException($"Cannot wrap generic/abstract C# type \"{type.Name}\"!", nameof(type)); // Check for type attribute. SharpTypeWrapperAttribute typeAttribute = type.GetCustomAttribute(true) @@ -109,10 +109,6 @@ public EzrSharpSourceTypeWrapper( { MethodInfo method = staticMethods[i]; - // Check if abstract. - if (method.IsAbstract) - continue; - IEzrObject wrappedMethod; string methodName; From 697750f27c381655b610ec04eacc4c185ce7e0eb Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 8 Nov 2024 18:44:57 +0530 Subject: [PATCH 083/113] =?UTF-8?q?ezr=C2=B2=20RE=20v0.11.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 5 +++++ docs/index.md | 6 +++--- src/EzrSquared.csproj | 2 +- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index dc2ff36..b559387 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,11 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.11.1 [08-11-24] + * Fixed bug in C# compatibility wrappers where they won't wrap compliant methods and constructors. + * C# type wrappers should now fail when given abstract types. + * Improved PascalCase to snake_case converter even more. + * ezr² RE - v0.11.0 [08-11-24] * [BREAKING CHANGE] The ezr² library is no longer officially AOT compatible. * [BREAKING CHANGE] `EzrSharpCompatibilityWrapper.Validate` has been removed. Use `SharpAutoWrapperAttribute.ValidateMethod` instead. diff --git a/docs/index.md b/docs/index.md index 04a9e2b..a8895c5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -85,15 +85,15 @@ out, you can download it from the [***releases page on GitHub***](https://github * Run the installer and go through the installation.
-[![ezr² RE v0.11.0 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.0_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.0/ezrSquared.Shell.Setup.Win64.exe) -[![ezr² RE v0.11.0 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.0_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.0/ezrSquared.Shell.Setup.Win32.exe) +[![ezr² RE v0.11.1 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.1_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.1/ezrSquared.Shell.Setup.Win64.exe) +[![ezr² RE v0.11.1 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.1_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.1/ezrSquared.Shell.Setup.Win32.exe) # [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! [![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) -[![ezr² RE v0.11.0 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.0_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.0/ezrSquared.0.11.0-unstable.nupkg) +[![ezr² RE v0.11.1 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.1_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.1/ezrSquared.0.11.1-unstable.nupkg) # [Other](#tab/REother) diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index e0b8f53..15386b3 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.11.0-unstable + 0.11.1-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 6a64a42..8a1e2ed 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; ///
internal class Shell { - private const string Version = "0.11.0"; + private const string Version = "0.11.1"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index dfb3f62..7e64a29 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.11.0" +#define MyAppVersion "0.11.1" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 4eb37c1..c7a0cd9 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.11.0" +#define MyAppVersion "0.11.1" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 0e2a921..9bb19b7 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.11.0 + 0.11.1 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From 62af557272057f8c2f5d35725b20ec5c977fef91 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 9 Nov 2024 12:07:19 +0530 Subject: [PATCH 084/113] General improvements: - Wrapped constructors are now named starting with "make" then "make_1" and so on. - Improved case converter to account for non-alphanum+underscore characters. - Tasks are now no longer awaited before being wrapped and are now wrapped like any other C# object. - Added new method in CodeExecutor for adding wrappers to the context. --- src/Executor/CodeExecutor.cs | 21 ++++++++ .../EzrSharpCompatibilityType.cs | 4 +- .../EzrSharpCompatibilityWrapper.cs | 49 +++---------------- 3 files changed, 31 insertions(+), 43 deletions(-) diff --git a/src/Executor/CodeExecutor.cs b/src/Executor/CodeExecutor.cs index b8f62b2..17460c7 100644 --- a/src/Executor/CodeExecutor.cs +++ b/src/Executor/CodeExecutor.cs @@ -1,9 +1,11 @@ using EzrSquared.Runtime; using EzrSquared.Runtime.Types.CSharpWrappers.Builtins; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; using EzrSquared.Syntax; using EzrSquared.Syntax.Errors; using System; using System.Collections.Generic; +using System.Reflection; namespace EzrSquared.Executor; @@ -75,6 +77,25 @@ public static void AddToContext(Reference reference, string name) RuntimeContext.Set(null, name, reference); } + /// + /// Adds the given wrapped C# object to the runtime context. + /// + /// + /// Thrown if the runtime context is . + /// Use to initialize the runtime context. + /// + /// The wrapped object to add. + /// The accessibility modifiers for the reference. Defaults to . + /// See . + public static void AddToContext(EzrSharpCompatibilityWrapper wrapper, AccessMod accessibilityModifiers = AccessMod.Constant) + where TMemberInfo : MemberInfo + { + if (RuntimeContext is null) + throw new NullReferenceException($"{nameof(RuntimeContext)} is null! Call {nameof(CreateRuntimeContext)} to create it!"); + + RuntimeContext.Set(null, wrapper.SharpMemberName, ReferencePool.Get(wrapper, accessibilityModifiers)); + } + /// /// Executes the given script. /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index 2726eb1..db3d25f 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -97,6 +97,7 @@ public EzrSharpCompatibilityType( Context.Set(null, fieldObject.SharpMemberName, ReferencePool.Get(fieldObject, AccessMod.Constant)); } + int definedConstructors = 0; ConstructorInfo[] publicConstructors = sharpType.GetConstructors(); for (int i = 0; i < publicConstructors.Length; i++) { @@ -108,7 +109,8 @@ public EzrSharpCompatibilityType( if (!SharpAutoWrapperAttribute.ValidateMethod(constructor, constructorObject.AutoWrapperAttribute is null)) continue; - Context.Set(null, $"make_{i}", ReferencePool.Get(constructorObject, AccessMod.Constant)); + Context.Set(null, definedConstructors == 0 ? "make" : $"make_{definedConstructors}", ReferencePool.Get(constructorObject, AccessMod.Constant)); + definedConstructors++; } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 45b1770..2e26118 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -79,6 +79,11 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, /// 3. (?<=[A-Z])(?=[A-Z][a-z]) - Add underscore between uppercase sequences followed by lowercase (e.g., "TCProtocol"). /// private static readonly Regex s_caseConverterRegex = new(@"(? + /// Regex for matching non-alphanumeric + underscore characters. + ///
+ private static readonly Regex s_alphaNumericUnderscoreOnlyFilterRegex = new(@"[^a-zA-Z0-9_]", RegexOptions.Compiled | RegexOptions.CultureInvariant); #pragma warning restore SYSLIB1045 // Convert to 'GeneratedRegexAttribute'. /// @@ -95,7 +100,8 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, if (text.StartsWith('_')) text = text[1..]; - string snakeCase = s_caseConverterRegex.Replace(text, "_"); + string alphaNumPlusUnderscoreFiltered = s_alphaNumericUnderscoreOnlyFilterRegex.Replace(text, string.Empty); + string snakeCase = s_caseConverterRegex.Replace(alphaNumPlusUnderscoreFiltered, "_"); // Convert entire string to lowercase return snakeCase.ToLower(); @@ -363,9 +369,6 @@ protected internal void CSharpToEzrObject(object? value, RuntimeResult result) case TypeCode.Object when typeof(IEzrObject).IsAssignableFrom(valueType): result.Success(ReferencePool.Get((IEzrObject)value, AccessMod.PrivateConstant)); break; - case TypeCode.Object when typeof(Task).IsAssignableFrom(valueType): - HandleAsynchronousObjectToEzrObject(value, valueType, result); - break; case TypeCode.Empty: result.Success(NewNothingConstant()); break; @@ -398,44 +401,6 @@ protected internal void HandleCSharpArrayToEzrObject(Array value, Type valueType result.Success(NewArrayConstant(elements)); } - /// - /// Waits for a task to complete and returns the result as an ezr² object. - /// - /// The task to await. - /// The type of the task. - /// Runtime result for carrying the result and any errors. - protected internal void HandleAsynchronousObjectToEzrObject( - object value, - - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] - Type type, - - RuntimeResult result) - { - try - { - ((Task)value).Wait(); - - // Get the Result property of the Task - PropertyInfo? resultProperty = type.GetProperty("Result"); - - // Check if it's a Task - if (resultProperty is not null) - { - // Get the value of the Result property - object taskResult = resultProperty.GetValue(value)!; - - CSharpToEzrObject(taskResult, result); - } - else - result.Success(NewNothingConstant()); - } - catch (Exception error) - { - result.Failure(new EzrWrapperExecutionError(error.InnerException?.Message ?? error.Message, Context, StartPosition, EndPosition)); - } - } - /// public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { From 2015fbdc14a10890c034601236ade128819c30e3 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 9 Nov 2024 22:16:00 +0530 Subject: [PATCH 085/113] =?UTF-8?q?ezr=C2=B2=20v0.11.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 6 ++++++ docs/index.md | 6 +++--- src/EzrSquared.csproj | 2 +- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 2 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 2 +- src/Shell/Shell.csproj | 2 +- 7 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index b559387..ddcc9e6 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,12 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.11.2 [09-11-24] + * Tasks are no longer awaited before being wrapped and are now wrapped like any other C# object. + * Wrapped constructors are now named "make" then "make_1" and so on for variations. + * Improved case converter to account for non-alphanum+underscore characters. + * Added new method in `CodeExecutor` for adding wrappers to the context. + * ezr² RE - v0.11.1 [08-11-24] * Fixed bug in C# compatibility wrappers where they won't wrap compliant methods and constructors. * C# type wrappers should now fail when given abstract types. diff --git a/docs/index.md b/docs/index.md index a8895c5..cc0c195 100644 --- a/docs/index.md +++ b/docs/index.md @@ -85,15 +85,15 @@ out, you can download it from the [***releases page on GitHub***](https://github * Run the installer and go through the installation.
-[![ezr² RE v0.11.1 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.1_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.1/ezrSquared.Shell.Setup.Win64.exe) -[![ezr² RE v0.11.1 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.1_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.1/ezrSquared.Shell.Setup.Win32.exe) +[![ezr² RE v0.11.2 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.2_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.2/ezrSquared.Shell.Setup.Win64.exe) +[![ezr² RE v0.11.2 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.2_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.2/ezrSquared.Shell.Setup.Win32.exe) # [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! [![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) -[![ezr² RE v0.11.1 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.1_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.1/ezrSquared.0.11.1-unstable.nupkg) +[![ezr² RE v0.11.2 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.2_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.2/ezrSquared.0.11.2-unstable.nupkg) # [Other](#tab/REother) diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 15386b3..1ac9579 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.11.1-unstable + 0.11.2-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 8a1e2ed..0629c1d 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; ///
internal class Shell { - private const string Version = "0.11.1"; + private const string Version = "0.11.2"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index 7e64a29..c5265a4 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.11.1" +#define MyAppVersion "0.11.2" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index c7a0cd9..63d8ec9 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.11.1" +#define MyAppVersion "0.11.2" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 9bb19b7..3231c20 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.11.1 + 0.11.2 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED From 8d980e3c300b2b0e2b94aa3d7554f992c4a2bea5 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 9 Nov 2024 22:43:29 +0530 Subject: [PATCH 086/113] Code cleanup. --- .../CompatWrappers/EzrSharpCompatibilityWrapper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 2e26118..35e42bc 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -6,7 +6,6 @@ using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text.RegularExpressions; using System.Threading.Tasks; From ef941d67f078202353475199c20538ccc31c4dfc Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sun, 10 Nov 2024 22:14:35 +0530 Subject: [PATCH 087/113] Added some new built-ins. - Also added wrapper attributes to all wrapped type members for naming consistency. - Also made Context an IEnumerable. --- src/Runtime/Context.cs | 15 +++- .../Builtins/EzrBuiltinFunctions.cs | 68 ++++++++++++++++++- .../Builtins/EzrBuiltinsUtility.cs | 4 ++ .../EzrSharpCompatibilityField.cs | 4 +- src/Runtime/Types/Collections/EzrArray.cs | 2 + .../Types/Collections/EzrDictionary.cs | 1 + src/Runtime/Types/Collections/EzrList.cs | 2 +- .../Types/Core/Text/EzrCharacterList.cs | 2 +- src/Runtime/Types/Core/Text/EzrString.cs | 2 + 9 files changed, 94 insertions(+), 6 deletions(-) diff --git a/src/Runtime/Context.cs b/src/Runtime/Context.cs index d3239a3..ba42ba1 100644 --- a/src/Runtime/Context.cs +++ b/src/Runtime/Context.cs @@ -1,6 +1,7 @@ using EzrSquared.Runtime.Types; using EzrSquared.Util; using System; +using System.Collections; using System.Collections.Generic; namespace EzrSquared.Runtime; @@ -8,7 +9,7 @@ namespace EzrSquared.Runtime; /// /// Stores all user defined variables/constant references, called symbols. /// -public class Context +public class Context : IEnumerable> { /// /// Represents the status of a call. @@ -473,6 +474,18 @@ public void Release() LinkedContexts[i]?.Release(); } + /// + public IEnumerator> GetEnumerator() + { + return _symbols.GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + /// Destructor. ~Context() => Release(); } diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs index f327877..aa6ae94 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs @@ -1,7 +1,10 @@ -using EzrSquared.Runtime.Types.Core; +using EzrSquared.Runtime.Collections; +using EzrSquared.Runtime.Types.Collections; +using EzrSquared.Runtime.Types.Core; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections.Generic; @@ -377,4 +380,67 @@ public static void Copy(SharpMethodParameters arguments) result.Success(ReferencePool.Get(copy, AccessMod.PrivateConstant)); } + + /// + /// Wraps the given ezr² object so that the runtime has access to its raw C# object. + /// + /// + /// ezr² parameters: + /// + /// + /// to_wrap + /// () The object to wrap. + /// + /// + /// + /// ezr² return type: + /// + /// + /// The method arguments. + [SharpMethodWrapper("get_raw", RequiredParameters = ["to_wrap"])] + public static void GetRaw(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + IEzrObject objectToWrap = arguments.ArgumentReferences["to_wrap"].Object; + + IEzrObject wrapped = new EzrSharpCompatibilityObjectInstance(objectToWrap, objectToWrap.GetType(), arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition); + result.Success(ReferencePool.Get(wrapped, AccessMod.PrivateConstant)); + } + + /// + /// Returns an of the references (as <name, object>) contained in the of the given object. + /// + /// + /// ezr² parameters: + /// + /// + /// to_get + /// () The object to get the context of. + /// + /// + /// + /// ezr² return type: + /// + /// + /// The method arguments. + [SharpMethodWrapper("get_context", RequiredParameters = ["to_get"])] + public static void GetContext(SharpMethodParameters arguments) + { + RuntimeResult result = arguments.Result; + IEzrObject objectToWrap = arguments.ArgumentReferences["to_get"].Object; + + RuntimeEzrObjectDictionary context = new(); + foreach (KeyValuePair pair in objectToWrap.Context) + { + if (pair.Value.AccessibilityModifiers.HasFlag(AccessMod.Private)) + continue; + + context.Update(new EzrString(pair.Key, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), pair.Value.Object, result); + if (result.ShouldReturn) + return; + } + + IEzrObject dictionary = new EzrDictionary(context, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition); + result.Success(ReferencePool.Get(dictionary, AccessMod.PrivateConstant)); + } } diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs index 04c84a2..1694850 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs @@ -22,6 +22,8 @@ public static void AddBuiltinFunctions(Context context) EzrSharpSourceFunctionWrapper typeNameOf = new(EzrBuiltinFunctions.TypeNameOf, context, Position.None, Position.None); EzrSharpSourceFunctionWrapper typeHashOf = new(EzrBuiltinFunctions.TypeHashOf, context, Position.None, Position.None); EzrSharpSourceFunctionWrapper copy = new(EzrBuiltinFunctions.Copy, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper getRaw = new(EzrBuiltinFunctions.GetRaw, context, Position.None, Position.None); + EzrSharpSourceFunctionWrapper getContext = new(EzrBuiltinFunctions.GetContext, context, Position.None, Position.None); context.Set(null, throwError.SharpFunctionName, ReferencePool.Get(throwError, AccessMod.Constant)); context.Set(null, assert.SharpFunctionName, ReferencePool.Get(assert, AccessMod.Constant)); @@ -30,6 +32,8 @@ public static void AddBuiltinFunctions(Context context) context.Set(null, typeNameOf.SharpFunctionName, ReferencePool.Get(typeNameOf, AccessMod.Constant)); context.Set(null, typeHashOf.SharpFunctionName, ReferencePool.Get(typeHashOf, AccessMod.Constant)); context.Set(null, copy.SharpFunctionName, ReferencePool.Get(copy, AccessMod.Constant)); + context.Set(null, getRaw.SharpFunctionName, ReferencePool.Get(getRaw, AccessMod.Constant)); + context.Set(null, getContext.SharpFunctionName, ReferencePool.Get(getContext, AccessMod.Constant)); } /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index ab53e2a..fff4ce0 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -46,13 +46,13 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run break; case { Length: 1 }: - object? argumentAsPrimitive = EzrObjectToCSharp(arguments[0].Object, SharpMember.FieldType, result); + object? convertedArgument = EzrObjectToCSharp(arguments[0].Object, SharpMember.FieldType, result); if (result.ShouldReturn) break; try { - SharpMember.SetValue(Instance, argumentAsPrimitive); + SharpMember.SetValue(Instance, convertedArgument); result.Success(NewNothingConstant()); } catch (Exception error) diff --git a/src/Runtime/Types/Collections/EzrArray.cs b/src/Runtime/Types/Collections/EzrArray.cs index dfaa79a..0823b47 100644 --- a/src/Runtime/Types/Collections/EzrArray.cs +++ b/src/Runtime/Types/Collections/EzrArray.cs @@ -1,6 +1,7 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections; using System.Collections.Generic; @@ -26,6 +27,7 @@ public class EzrArray : EzrObject, IEzrIndexedCollection public readonly IEzrObject[] Value; /// + [SharpAutoWrapper("length")] public int Count { get; } /// diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index 9ef2ff1..03206c6 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -30,6 +30,7 @@ public class EzrDictionary : EzrObject, IEzrMutableObject, IEzrDictionary public readonly RuntimeEzrObjectDictionary Value; /// + [SharpAutoWrapper("length")] public int Count => Value.Count; /// diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index adb452d..6905c05 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -28,7 +28,7 @@ public class EzrList : EzrObject, IEzrMutableObject, IEzrIndexedCollection public readonly RuntimeEzrObjectList Value; /// - [SharpAutoWrapper(isReadOnly: true)] + [SharpAutoWrapper("length", isReadOnly: true)] public int Count => Value.Count; /// The base value. diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index 9350595..4ff1b72 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -34,7 +34,7 @@ public class EzrCharacterList : EzrObject, IEzrMutableObject, IEzrString, IEzrIn public string StringValue => Value.ToString(); /// - [SharpAutoWrapper(isReadOnly: true)] + [SharpAutoWrapper("length", isReadOnly: true)] public int Count => Value.Length; /// diff --git a/src/Runtime/Types/Core/Text/EzrString.cs b/src/Runtime/Types/Core/Text/EzrString.cs index 3f664f6..88908ef 100644 --- a/src/Runtime/Types/Core/Text/EzrString.cs +++ b/src/Runtime/Types/Core/Text/EzrString.cs @@ -2,6 +2,7 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections; using System.Collections.Generic; @@ -31,6 +32,7 @@ public class EzrString : EzrObject, IEzrString, IEzrIndexedCollection public string StringValue => Value; /// + [SharpAutoWrapper("length")] public int Count { get; } /// From 30dabe7d5a263e9088b21ac41e47ccd16be4b5e1 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Mon, 11 Nov 2024 23:31:17 +0530 Subject: [PATCH 088/113] =?UTF-8?q?Added=20signing=20for=20ezr=C2=B2=20and?= =?UTF-8?q?=20removed=20`CsealAttribute`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +-- src/EzrSquared.csproj | 3 +++ src/Runtime/WrapperAttributes/CsealAttribute.cs | 14 -------------- .../WrapperAttributes/SharpAutoWrapperAttribute.cs | 2 +- .../WrapperAttributes/SharpDoNotWrapAttribute.cs | 2 +- 5 files changed, 6 insertions(+), 18 deletions(-) delete mode 100644 src/Runtime/WrapperAttributes/CsealAttribute.cs diff --git a/.gitignore b/.gitignore index 674d9c5..a72bd99 100644 --- a/.gitignore +++ b/.gitignore @@ -365,5 +365,4 @@ FodyWeavers.xsd # -------------------------------------------------- [Ll]ibraries/ -[Dd]ocs/offline/_site/ -[Dd]ocs/offline/ezrSquared.Offline.Documentation.zip \ No newline at end of file +/NOCOMMIT diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 1ac9579..a6f5118 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -53,6 +53,9 @@ True snupkg + True + False + D:\Code\csharp\ezrSquared\NOCOMMIT\sgKey.snk diff --git a/src/Runtime/WrapperAttributes/CsealAttribute.cs b/src/Runtime/WrapperAttributes/CsealAttribute.cs deleted file mode 100644 index 7096644..0000000 --- a/src/Runtime/WrapperAttributes/CsealAttribute.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace EzrSquared.Runtime.WrapperAttributes; - -/// -/// Attribute for identifying CSAELs (C# Assisted ezr² Libraries). -/// -/// -/// This has not been implemented. It doesn't do anything right now. -/// -[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = true)] -public class CsealAttribute : Attribute -{ -} diff --git a/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs index 4adbde0..36e9794 100644 --- a/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs @@ -4,7 +4,7 @@ namespace EzrSquared.Runtime.WrapperAttributes; /// -/// Attribute for C# type members which to be automatically wrapped from C# types into ezr² types. +/// Attribute for C# types and members to be automatically wrapped from C# types into ezr² types. /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] public class SharpAutoWrapperAttribute : Attribute diff --git a/src/Runtime/WrapperAttributes/SharpDoNotWrapAttribute.cs b/src/Runtime/WrapperAttributes/SharpDoNotWrapAttribute.cs index 7d84181..e5bbc61 100644 --- a/src/Runtime/WrapperAttributes/SharpDoNotWrapAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpDoNotWrapAttribute.cs @@ -3,7 +3,7 @@ namespace EzrSquared.Runtime.WrapperAttributes; /// -/// Attribute for C# type members which should NOT be automatically wrapped from C# types into ezr² types by and . +/// Attribute for C# types and members which should NOT be automatically wrapped from C# types into ezr² types by the interpreter. /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] public class SharpDoNotWrapAttribute : Attribute From da46a74017b9f6df684a55b64e00aad22995a69c Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 12 Nov 2024 11:39:14 +0530 Subject: [PATCH 089/113] Updated actions. --- .github/workflows/pages-upload-action.yml | 12 ++++++++++-- .gitignore | 2 +- src/EzrSquared.csproj | 4 ++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pages-upload-action.yml b/.github/workflows/pages-upload-action.yml index 418f221..06ca269 100644 --- a/.github/workflows/pages-upload-action.yml +++ b/.github/workflows/pages-upload-action.yml @@ -25,13 +25,20 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 - - name: Dotnet Setup + + - name: Setup Signing + run: | + mkdir Secrets + echo "${{ secrets.LIB_SIGNING_KEY }}" > Secrets/sgKey.txt + openssl base64 -d -in Secrets/sgKey.txt -out Secrets/sgKey.snk + + - name: .NET Setup uses: actions/setup-dotnet@v3 with: dotnet-version: 8.x + # Build ezr², install docfx and generate the docs. - run: dotnet build ezrSquared.sln -c Release - - run: dotnet tool update -g docfx - run: docfx docs/docfx.json @@ -40,6 +47,7 @@ jobs: with: # Upload entire repository path: 'docs/_site' + - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index a72bd99..7c612c4 100644 --- a/.gitignore +++ b/.gitignore @@ -365,4 +365,4 @@ FodyWeavers.xsd # -------------------------------------------------- [Ll]ibraries/ -/NOCOMMIT +[Ss]ecrets/ diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index a6f5118..2ec09dd 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -53,9 +53,9 @@ True snupkg + True - False - D:\Code\csharp\ezrSquared\NOCOMMIT\sgKey.snk + ..\Secrets\sgKey.snk From a72a80ec8633f4d04fee91508512032f86838f05 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 19 Nov 2024 02:28:12 +0530 Subject: [PATCH 090/113] .NET 9 and some minor improvements - Improved/fixed samples. - Operations of mutable types can now be chained as they return a reference to themselves for addition, subtraction, multiplication and division operations. - Wrapped fields and properties now return the value after set operations. - `EzrObject`'s `NewNothingConstant` and `NewBooleanConstant` are now static. - Private static symbols accessing using the static keyword no longer raise errors. --- samples/better_turing_machine.ezr2 | 92 +++++++++++ ...e_demo.ezr2 => simple_turing_machine.ezr2} | 33 ++-- samples/tic_tac_toe_demo.ezr2 | 147 ++++++++++-------- src/EzrSquared.csproj | 6 +- .../Collections/RuntimeEzrObjectDictionary.cs | 2 +- src/Runtime/Context.cs | 6 +- src/Runtime/Types/BaseTypes.cs | 4 +- .../EzrSharpCompatibilityField.cs | 5 +- .../EzrSharpCompatibilityProperty.cs | 5 +- .../Types/Collections/EzrDictionary.cs | 14 +- src/Runtime/Types/Collections/EzrList.cs | 18 +-- .../Types/Core/Text/EzrCharacterList.cs | 18 +-- src/Shell/EzrShell.cs | 2 +- src/Shell/InstallerSrc/ezrSquared 32-bit.iss | 6 +- src/Shell/InstallerSrc/ezrSquared 64-bit.iss | 6 +- src/Shell/Shell.csproj | 8 +- 16 files changed, 242 insertions(+), 130 deletions(-) create mode 100644 samples/better_turing_machine.ezr2 rename samples/{turing_machine_demo.ezr2 => simple_turing_machine.ezr2} (50%) diff --git a/samples/better_turing_machine.ezr2 b/samples/better_turing_machine.ezr2 new file mode 100644 index 0000000..8e591c3 --- /dev/null +++ b/samples/better_turing_machine.ezr2 @@ -0,0 +1,92 @@ +@ A turing machine written in ezr² +@ Based on https://python-course.eu/applications-python/turing-machine.php + +object tape do + private static constant blank_symbol: ` ` + + private tape: [] + constant function initialize with tape_string: "" do + for each char in tape_string do + tape + char + end + end + + constant function to_string do + str: '' + for each char in tape do + str + char + end + + return str + end + + constant function is_less_than with other do + if type_of(other) ! "ezrSquared.Integer" do + throw_error(unexpected_type_error("Expected an integer but got object of type \"" + type_name_of(other) + "\"!")) + end + + return if other >= 0 and other < this.tape.length() do (this.tape < other) else do (static blank_symbol) + end +end + +object turing_machine do + + private tape: nothing + private final_states: () + private transition_functions: {} + + private head_position: 0 + private current_state: nothing + + constant function initialize with tape, initial_state, final_states: nothing, transition_functions: nothing do + this.tape: global tape(tape) + this.current_state: initial_state + + if transition_functions ! nothing do + this.transition_functions: transition_functions + end + + if final_states ! nothing do + this.final_states: final_states + end + end + + function get_tape do tape.to_string() + + function do_step do + char_under_head: tape < head_position + x: (current_state, char_under_head) + + if x in transition_functions do + y: transition_functions < x + this.tape < this.head_position: y < 1 + + if y < 2 = `R` do + this.head_position:+ 1 + else if y < 2 = `L` do + this.head_position:- 1 + end + + this.current_state: y < 0 + end + end + + function final do current_state in final_states +end + +initial_state: "init" +accepting_states: ("final",) +transition_functions: {("init",`0`):("init", `1`, `R`), + ("init",`1`):("init", `0`, `R`), + ("init",` `):("final",` `, `N`)} +final_states: ("final",) + +machine: turing_machine("010011001 ", initial_state, final_states, transition_functions) + +show("Input on tape: ", machine.get_tape()) + +while not machine.final() do + machine.do_step() +end + +show("Tape after processing: ", machine.get_tape()) \ No newline at end of file diff --git a/samples/turing_machine_demo.ezr2 b/samples/simple_turing_machine.ezr2 similarity index 50% rename from samples/turing_machine_demo.ezr2 rename to samples/simple_turing_machine.ezr2 index 708421f..ae7f29f 100644 --- a/samples/turing_machine_demo.ezr2 +++ b/samples/simple_turing_machine.ezr2 @@ -42,43 +42,44 @@ function action with input_char, replace_with, move, new_state do return false end +accept: false while old_tapehead ! tapehead do old_tapehead: tapehead show(tape, " with tapehead at index ", tapehead, " on state ", state) if state = 0 do - if action(a, X, R, 1) do 1 else if action(B, B, R, 10) do 1 else if action(Z, Z, R, 7) do 1 else if action(b, U, R, 4) do 1 + action(a, X, R, 1) or action(B, B, R, 10) or action(Z, Z, R, 7) or action(b, U, R, 4) else if state = 1 do - if action(a, a, R, 1) do 1 else if action(b, b, R, 2) do 1 else if action(B, B, L, 11) do 1 + action(a, a, R, 1) or action(b, b, R, 2) or action(B, B, L, 11) else if state = 2 do - if action(b, b, R, 2) do 1 else if action(Z, Z, R, 2) do 1 else if action(a, Z, L, 3) do 1 + action(b, b, R, 2) or action(Z, Z, R, 2) or action(a, Z, L, 3) else if state = 3 do - if action(b, b, L, 3) do 1 else if action(Z, Z, L, 3) do 1 else if action(a, a, L, 3) do 1 else if action(X, X, R, 0) do 1 + action(b, b, L, 3) or action(Z, Z, L, 3) or action(a, a, L, 3) or action(X, X, R, 0) else if state = 4 do - if action(b, b, R, 4) do 1 else if action(Z, Z, R, 5) do 1 else if action(B, B, L, 15) do 1 + action(b, b, R, 4) or action(Z, Z, R, 5) or action(B, B, L, 15) else if state = 5 do - if action(Z, Z, R, 5) do 1 else if action(V, V, R, 5) do 1 else if action(b, V, L, 6) do 1 + action(Z, Z, R, 5) or action(V, V, R, 5) or action(b, V, L, 6) else if state = 6 do - if action(Z, Z, L, 6) do 1 else if action(V, V, L, 6) do 1 else if action(b, b, L, 6) do 1 else if action(U, U, R, 0) do 1 + action(Z, Z, L, 6) or action(V, V, L, 6) or action(b, b, L, 6) or action(U, U, R, 0) else if state = 7 do - if action(Z, Z, R, 7) do 1 else if action(V, V, R, 8) do 1 + action(Z, Z, R, 7) or action(V, V, R, 8) else if state = 8 do - if action(V, V, R, 8) do 1 else if action(B, B, R, 9) do 1 + action(V, V, R, 8) or action(B, B, R, 9) else if state = 11 do - if action(a, a, L, 11) do 1 else if action(X, X, R, 12) do 1 + action(a, a, L, 11) or action(X, X, R, 12) else if state = 12 do - if action(a, Z, R, 13) do 1 + action(a, Z, R, 13) else if state = 13 do - if action(a, X, R, 12) do 1 else if action(B, B, R, 14) do 1 + action(a, X, R, 12) or action(B, B, R, 14) else if state = 15 do - if action(b, b, L, 15) do 1 else if action(U, U, R, 16) do 1 + action(b, b, L, 15) or action(U, U, R, 16) else if state = 16 do - if action(b, V, R, 17) do 1 + action(b, V, R, 17) else if state = 17 do - if action(b, U, R, 16) do 1 else if action(B, B, R, 18) do 1 + action(b, U, R, 16) or action(B, B, R, 18) else do - item accept: true + accept: true end end diff --git a/samples/tic_tac_toe_demo.ezr2 b/samples/tic_tac_toe_demo.ezr2 index d6cc66c..1043600 100644 --- a/samples/tic_tac_toe_demo.ezr2 +++ b/samples/tic_tac_toe_demo.ezr2 @@ -1,135 +1,150 @@ @ A demo for the ezr² programming language @ https://github.com/Uralstech/ezrSquared +static object POSITION do + EMPTY: `-` + X: `X` + O: `O` + ANY: `/` +end + @ Main game matrix -game: [["-", "-", "-"], - ["-", "-", "-"], - ["-", "-", "-"]] +game: ([POSITION.EMPTY, POSITION.EMPTY, POSITION.EMPTY], + [POSITION.EMPTY, POSITION.EMPTY, POSITION.EMPTY], + [POSITION.EMPTY, POSITION.EMPTY, POSITION.EMPTY]) @ Winning cases -wins: [[["n", "n", "n"], - ["-", "-", "-"], - ["-", "-", "-"]], +wins: (((POSITION.ANY, POSITION.ANY, POSITION.ANY), + (POSITION.EMPTY, POSITION.EMPTY, POSITION.EMPTY), + (POSITION.EMPTY, POSITION.EMPTY, POSITION.EMPTY)), - [["-", "-", "-"], - ["n", "n", "n"], - ["-", "-", "-"]], + ((POSITION.EMPTY, POSITION.EMPTY, POSITION.EMPTY), + (POSITION.ANY, POSITION.ANY, POSITION.ANY), + (POSITION.EMPTY, POSITION.EMPTY, POSITION.EMPTY)), - [["-", "-", "-"], - ["-", "-", "-"], - ["n", "n", "n"]], + ((POSITION.EMPTY, POSITION.EMPTY, POSITION.EMPTY), + (POSITION.EMPTY, POSITION.EMPTY, POSITION.EMPTY), + (POSITION.ANY, POSITION.ANY, POSITION.ANY)), - [["n", "-", "-"], - ["n", "-", "-"], - ["n", "-", "-"]], + ((POSITION.ANY, POSITION.EMPTY, POSITION.EMPTY), + (POSITION.ANY, POSITION.EMPTY, POSITION.EMPTY), + (POSITION.ANY, POSITION.EMPTY, POSITION.EMPTY)), - [["-", "n", "-"], - ["-", "n", "-"], - ["-", "n", "-"]], + ((POSITION.EMPTY, POSITION.ANY, POSITION.EMPTY), + (POSITION.EMPTY, POSITION.ANY, POSITION.EMPTY), + (POSITION.EMPTY, POSITION.ANY, POSITION.EMPTY)), - [["-", "-", "n"], - ["-", "-", "n"], - ["-", "-", "n"]], + ((POSITION.EMPTY, POSITION.EMPTY, POSITION.ANY), + (POSITION.EMPTY, POSITION.EMPTY, POSITION.ANY), + (POSITION.EMPTY, POSITION.EMPTY, POSITION.ANY)), - [["-", "-", "n"], - ["-", "n", "-"], - ["n", "-", "-"]], + ((POSITION.EMPTY, POSITION.EMPTY, POSITION.ANY), + (POSITION.EMPTY, POSITION.ANY, POSITION.EMPTY), + (POSITION.ANY, POSITION.EMPTY, POSITION.EMPTY)), - [["n", "-", "-"], - ["-", "n", "-"], - ["-", "-", "n"]]] + ((POSITION.ANY, POSITION.EMPTY, POSITION.EMPTY), + (POSITION.EMPTY, POSITION.ANY, POSITION.EMPTY), + (POSITION.EMPTY, POSITION.EMPTY, POSITION.ANY))) @ Function to show game matrix in more readable form function show_game do - count to game.length as i do - s: "" - count to (game <= i).length as j do s: s + game <= i <= j + " " + for each i in game do + row: '' - show(s) + for each j in i do + row + j + row + ` ` + end + + show(row) end end @ Function for checking if the game is over, and who has won function check_result do full: true - count to wins.length as i do - x_pts: 0 - o_pts: 0 - count to game.length as j do - count to (game <= j).length as k do - if wins <= i <= j <= k = "n" do - if game <= j <= k = "x" do x_pts: x_pts + 1 - if game <= j <= k = "o" do o_pts: o_pts + 1 + + for each case in wins do + x_points: 0 + o_points: 0 + + count to game.length() as i do + count to (game < i).length() as j do + if game < i < j = POSITION.EMPTY do + full: false + skip + else if case < i < j = POSITION.EMPTY do + skip end - if game <= j <= k = "-" do full: false + if game < i < j = POSITION.X do + x_points:+ 1 + else if game < i < j = POSITION.O do + o_points:+ 1 + end end - if x_pts >= 3 do - return "x" - else if o_pts >= 3 do - return "o" + if x_points >= 3 do + return POSITION.X + else if o_points >= 3 do + return POSITION.O end end end - return full.as_integer().as_string() + return if full do "FULL" else do false end -@ Function to register the players" current move +@ Function to register the player's current move function move_game with position, char do y: if position <= 3 do 0 else if position <= 6 do 1 else if position <= 9 do 2 else do -1 x: if position <= 3 do position - 1 else if position <= 6 do position - 4 else if position <= 9 do position - 7 else do -1 if (y < 0 or x < 0) or position <= 0 do return "INVALID POSITION" - if game <= y <= x ! "-" do return "INVALID POSITION" + if game < y < x ! POSITION.EMPTY do return "INVALID POSITION" - gamey : game <= y - - gamey - x - gamey.insert(x, char) - - game - y - game.insert(y, gamey) - - return game + (global game) < y < x: char end @ Showing the matrix -show("\n") show_game() @ Main gameloop -char: "x" +char: POSITION.X while true do try do - move: get(("Enter position (" + char) + ") ").as_integer() + input: get("Enter position (" + char + ") ") + + if input.length() ! 1 do throw_error(unexpected_type_error("Expected single-digit number!")) + + move_char: "" + input < 0 + if move_char < 48 or move_char > 57 do throw_error(unexpected_type_error("Expected single-digit number!")) + + move: move_char - 48 catch do show("INVALID INPUT") skip end move: move_game(move, char) - if type_of(move) = "string" do + if type_name_of(move) = "string" do show(move) skip - else do - game: move end show("\n") show_game() result: check_result() - if result = "1" do + if result = "FULL" do show("Draw!") stop - else if result = "x" do + else if result = POSITION.X do show("X has won!") stop - else if result = "o" do + else if result = POSITION.O do show("O has won!") stop end - char: if char = "x" do "o" else do "x" + char: if char = POSITION.X do POSITION.O else do POSITION.X end \ No newline at end of file diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 2ec09dd..5d74bd5 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -3,8 +3,8 @@ Library win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64 AnyCPU - net8.0;netstandard2.1 - 12 + net9.0;netstandard2.1 + 13 Disable Enable @@ -28,7 +28,7 @@ ezr² Portable Library The ezr² programming language, as a portable class library! This can be used to integrate ezr² as an embedded scripting language in your apps, websites and more! - 0.11.2-unstable + 0.11.3-unstable Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index 3b2ff47..93a0b4e 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -20,7 +20,7 @@ public class RuntimeEzrObjectDictionary : IMutable, /// /// The number of s in the . /// - [SharpAutoWrapper("length", isReadOnly: true)] + [SharpAutoWrapper("length")] public int Count => _items.Count; /// diff --git a/src/Runtime/Context.cs b/src/Runtime/Context.cs index ba42ba1..dfe1df8 100644 --- a/src/Runtime/Context.cs +++ b/src/Runtime/Context.cs @@ -252,6 +252,7 @@ public GetStatus Get(Context? callingContext, string symbol, out Reference objec if (_symbols.TryGetValue(symbol, out Reference? reference)) { if ((reference.AccessibilityModifiers & AccessMod.Private) == AccessMod.Private + && (accessibilityModifiers & AccessMod.Static) != AccessMod.Static && callingContext.Id != Id && !callingContext.IsContextParent(this)) { objectReference = Reference.Empty; @@ -276,8 +277,7 @@ public GetStatus Get(Context? callingContext, string symbol, out Reference objec { for (int i = 0; i < LinkedContexts.Length; i++) { - Context linkedContext = LinkedContexts[i]; - if (linkedContext is null) + if (LinkedContexts[i] is not Context linkedContext) continue; GetStatus status = linkedContext.Get(callingContext, symbol, out objectReference, AccessMod.LocalScope); @@ -340,6 +340,7 @@ public GetStatus Get(Context? callingContext, string symbol, out Reference objec if (oldReference.RegisteredContext is not null && ((oldReference.AccessibilityModifiers | accessibilityModifiers) & AccessMod.Private) == AccessMod.Private + && (accessibilityModifiers & AccessMod.Static) != AccessMod.Static && !isCallingContextRelatedToReceivingContext) return (SetStatus.PrivateSymbolAssignmentNotAllowed, Reference.Empty); @@ -395,6 +396,7 @@ public SetStatus Set(Context? callingContext, string symbol, Reference objectRef return SetStatus.ConstantAssignmentNotAllowed; if (((reference.AccessibilityModifiers & AccessMod.Private) == AccessMod.Private || objectReferenceIsPrivate) + && (accessibilityModifiers & AccessMod.Static) != AccessMod.Static && !isCallingContextRelatedToReceivingContext) return SetStatus.PrivateSymbolAssignmentNotAllowed; diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs index 73905aa..7bc7f6f 100644 --- a/src/Runtime/Types/BaseTypes.cs +++ b/src/Runtime/Types/BaseTypes.cs @@ -373,7 +373,7 @@ public virtual string ToPureString(RuntimeResult result) /// Creates a new "nothing" constant. /// /// The constant. - protected internal Reference NewNothingConstant() + protected internal static Reference NewNothingConstant() { return ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant); } @@ -383,7 +383,7 @@ protected internal Reference NewNothingConstant() /// /// The raw boolean value. /// The constant. - protected internal Reference NewBooleanConstant(bool value) + protected internal static Reference NewBooleanConstant(bool value) { return ReferencePool.Get(value ? EzrConstants.True diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index fff4ce0..7805046 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -46,14 +46,15 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run break; case { Length: 1 }: - object? convertedArgument = EzrObjectToCSharp(arguments[0].Object, SharpMember.FieldType, result); + IEzrObject ezrObject = arguments[0].Object; + object? convertedArgument = EzrObjectToCSharp(ezrObject, SharpMember.FieldType, result); if (result.ShouldReturn) break; try { SharpMember.SetValue(Instance, convertedArgument); - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(ezrObject, AccessMod.PrivateConstant)); } catch (Exception error) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs index c5e16d2..167729b 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -54,7 +54,8 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run } else { - object? value = EzrObjectToCSharp(arguments[0].Object, SharpMember.PropertyType, result); + IEzrObject ezrObject = arguments[0].Object; + object? value = EzrObjectToCSharp(ezrObject, SharpMember.PropertyType, result); if (result.ShouldReturn) return; @@ -67,7 +68,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run try { SharpMember.SetValue(Instance, value); - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(ezrObject, AccessMod.PrivateConstant)); } catch (Exception error) { diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index 03206c6..3e3d40f 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -115,7 +115,7 @@ private void DictionaryExists(SharpMethodParameters arguments) if (arguments.Result.ShouldReturn) return; - arguments.Result.Success(ReferencePool.Get(hasKey ? EzrConstants.True : EzrConstants.False, AccessMod.PrivateConstant)); + arguments.Result.Success(NewBooleanConstant(hasKey)); } /// @@ -208,21 +208,21 @@ public override void Addition(IEzrObject other, RuntimeResult result) if (result.ShouldReturn) break; - result.Success(NewNothingConstant()); break; + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; case EzrDictionary otherDictionary: Value.Merge(otherDictionary.Value, result); if (result.ShouldReturn) break; - result.Success(NewNothingConstant()); break; + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; case IEzrDictionary otherIDictionary: Value.Merge(otherIDictionary, _executionContext, result); if (result.ShouldReturn) break; - result.Success(NewNothingConstant()); break; + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; default: result.Failure(IllegalOperation(other)); break; @@ -242,7 +242,7 @@ public override void Subtraction(IEzrObject other, RuntimeResult result) if (!success) result.Failure(new EzrKeyNotFoundError("The key not found in the dictionary and connot be removed!", _executionContext, other.StartPosition, other.EndPosition)); else - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); } /// Here, "divide" means "decrease the number of pairs in the dictionary X times". @@ -258,7 +258,7 @@ public override void Division(IEzrObject other, RuntimeResult result) case EzrFloat when Value.Count == 0: case EzrInteger when Value.Count == 0: - result.Success(NewNothingConstant()); return; + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); return; case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int divisor): newLength = Value.Count / divisor; break; @@ -291,7 +291,7 @@ public override void Division(IEzrObject other, RuntimeResult result) } } - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); } /// diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index 6905c05..8366fe2 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -28,7 +28,7 @@ public class EzrList : EzrObject, IEzrMutableObject, IEzrIndexedCollection public readonly RuntimeEzrObjectList Value; /// - [SharpAutoWrapper("length", isReadOnly: true)] + [SharpAutoWrapper("length")] public int Count => Value.Count; /// The base value. @@ -241,7 +241,7 @@ public override void Addition(IEzrObject other, RuntimeResult result) Value.Add(ReferencePool.Get(other)); break; } - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); } /// @@ -262,7 +262,7 @@ public override void Subtraction(IEzrObject other, RuntimeResult result) case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int index): Value.RemoveAt(index >= 0 ? index : Value.Count + index); - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; @@ -310,7 +310,7 @@ public override void Subtraction(IEzrObject other, RuntimeResult result) } Value.RemoveRange(Value.Count + endIndexInt, -(endIndexInt - startIndexInt) + 1); - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; } @@ -321,7 +321,7 @@ public override void Subtraction(IEzrObject other, RuntimeResult result) } Value.RemoveRange(startIndexInt, endIndexInt - startIndexInt + 1); - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; default: @@ -385,7 +385,7 @@ public override void Multiplication(IEzrObject other, RuntimeResult result) break; } - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); } /// Here, "divide" means "duplicate/decrease the current value X times". @@ -401,13 +401,13 @@ public override void Division(IEzrObject other, RuntimeResult result) case EzrFloat when Value.Count == 0: case EzrInteger when Value.Count == 0: - result.Success(NewNothingConstant()); break; + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int divisor): newLength = Value.Count / divisor; Value.RemoveRange(newLength, Value.Count - newLength); - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; case EzrInteger: @@ -434,7 +434,7 @@ public override void Division(IEzrObject other, RuntimeResult result) Value.AddRange(original[..(newLength - currentEnd)]); } - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; default: diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index 4ff1b72..1bf5d7e 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -34,7 +34,7 @@ public class EzrCharacterList : EzrObject, IEzrMutableObject, IEzrString, IEzrIn public string StringValue => Value.ToString(); /// - [SharpAutoWrapper("length", isReadOnly: true)] + [SharpAutoWrapper("length")] public int Count => Value.Length; /// @@ -269,7 +269,7 @@ public override void Addition(IEzrObject other, RuntimeResult result) break; } - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); } /// @@ -289,7 +289,7 @@ public override void Subtraction(IEzrObject other, RuntimeResult result) case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int index): Value.Remove(index >= 0 ? index : Value.Length + index, 1); - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; case EzrInteger: @@ -336,7 +336,7 @@ public override void Subtraction(IEzrObject other, RuntimeResult result) } Value.Remove(Value.Length + endIndexInt, startIndexInt - endIndexInt + 1); - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; } @@ -347,7 +347,7 @@ public override void Subtraction(IEzrObject other, RuntimeResult result) } Value.Remove(startIndexInt, endIndexInt - startIndexInt + 1); - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; default: @@ -414,7 +414,7 @@ public override void Multiplication(IEzrObject other, RuntimeResult result) break; } - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); } /// Here, "divide" means "duplicate/decrease the current value X times". @@ -430,13 +430,13 @@ public override void Division(IEzrObject other, RuntimeResult result) case EzrFloat when Value.Length == 0: case EzrInteger when Value.Length == 0: - result.Success(NewNothingConstant()); break; + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; case EzrInteger otherInteger when otherInteger.TryGetIntRepresentation(out int divisor): newLength = Value.Length / divisor; Value.Remove(newLength, Value.Length - newLength); - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; case EzrInteger: @@ -454,7 +454,7 @@ public override void Division(IEzrObject other, RuntimeResult result) Value.Append(originalValue[..Math.Clamp(newLength - originalValue.Length, 0, originalValue.Length)]); } - result.Success(NewNothingConstant()); + result.Success(ReferencePool.Get(this, AccessMod.PrivateConstant)); break; default: diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 0629c1d..0adae92 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -12,7 +12,7 @@ namespace EzrSquaredCli; /// internal class Shell { - private const string Version = "0.11.2"; + private const string Version = "0.11.3"; private static bool s_showLexerOutput; private static bool s_showParserOutput; diff --git a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss index c5265a4..1342fa7 100644 --- a/src/Shell/InstallerSrc/ezrSquared 32-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 32-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.11.2" +#define MyAppVersion "0.11.3" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" @@ -68,10 +68,10 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{ Name: "{app}\Libraries" [Files] -Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x86\publish\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion +Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net9.0\win-x86\publish\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion Source: "D:\Code\csharp\ezrSquared\docs\_site\api\APIReferenceManual.pdf"; DestDir: "{app}\Documentation"; Flags: ignoreversion; Components: docs Source: "D:\Code\csharp\ezrSquared\docs\_site\docsrc\QuickStartDocumentation.pdf"; DestDir: "{app}\Documentation"; Flags: ignoreversion; Components: docs -Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x86\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net9.0\win-x86\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "D:\Code\csharp\ezrSquared\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion ; NOTE: Don't use "Flags: ignoreversion" on any shared system files diff --git a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss index 63d8ec9..1ae3187 100644 --- a/src/Shell/InstallerSrc/ezrSquared 64-bit.iss +++ b/src/Shell/InstallerSrc/ezrSquared 64-bit.iss @@ -4,7 +4,7 @@ #include "environment.iss" #define MyAppName "ezr² Shell" -#define MyAppVersion "0.11.2" +#define MyAppVersion "0.11.3" #define MyAppPublisher "Urav Advanced Learning Systems Pvt Ltd" #define MyAppURL "https://uralstech.github.io/ezrSquared/" #define MyAppExeName "ezrSquared.exe" @@ -77,8 +77,8 @@ Name: "{app}\Libraries" [Files] Source: "D:\Code\csharp\ezrSquared\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion -Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x64\publish\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion -Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net8.0\win-x64\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net9.0\win-x64\publish\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion +Source: "D:\Code\csharp\ezrSquared\Binaries\Shell\Release\net9.0\win-x64\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "D:\Code\csharp\ezrSquared\docs\_site\docsrc\QuickStartDocumentation.pdf"; DestDir: "{app}\Documentation"; Flags: ignoreversion; Components: docs Source: "D:\Code\csharp\ezrSquared\docs\_site\api\APIReferenceManual.pdf"; DestDir: "{app}\Documentation"; Flags: ignoreversion; Components: docs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 3231c20..6ca014a 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -3,8 +3,8 @@ Exe win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64 AnyCPU - net8.0 - 12 + net9.0 + 13 Disable Enable @@ -24,7 +24,7 @@ The ezrSquared Command Line Interface The Command Line Interface for the ezrSquared programming language. - 0.11.2 + 0.11.3 Udayshankar Ravikumar URAV ADVANCED LEARNING SYSTEMS PRIVATE LIMITED @@ -43,7 +43,7 @@ - ..\..\Binaries\ezrSquared\Release\net8.0\ezrSquared-lib.dll + ..\..\Binaries\ezrSquared\Release\net9.0\ezrSquared-lib.dll From 3027083055e7a8db990707de926d5df480b46ae5 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar <106602744+Uralstech@users.noreply.github.com> Date: Tue, 19 Nov 2024 02:30:41 +0530 Subject: [PATCH 091/113] Update pages-upload-action.yml --- .github/workflows/pages-upload-action.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pages-upload-action.yml b/.github/workflows/pages-upload-action.yml index 06ca269..0b7b5db 100644 --- a/.github/workflows/pages-upload-action.yml +++ b/.github/workflows/pages-upload-action.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Signing run: | @@ -33,9 +33,9 @@ jobs: openssl base64 -d -in Secrets/sgKey.txt -out Secrets/sgKey.snk - name: .NET Setup - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 8.x + dotnet-version: 9.x # Build ezr², install docfx and generate the docs. - run: dotnet build ezrSquared.sln -c Release From 8a472b0e414f81429bdf969b14d55d49e60d0938 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar <106602744+Uralstech@users.noreply.github.com> Date: Tue, 19 Nov 2024 02:37:29 +0530 Subject: [PATCH 092/113] Update pages-upload-action.yml --- .github/workflows/pages-upload-action.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pages-upload-action.yml b/.github/workflows/pages-upload-action.yml index 0b7b5db..3d603b7 100644 --- a/.github/workflows/pages-upload-action.yml +++ b/.github/workflows/pages-upload-action.yml @@ -21,16 +21,16 @@ jobs: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest + runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Signing run: | - mkdir Secrets - echo "${{ secrets.LIB_SIGNING_KEY }}" > Secrets/sgKey.txt - openssl base64 -d -in Secrets/sgKey.txt -out Secrets/sgKey.snk + New-Item -ItemType "directory" -Path Secrets + Set-Content -Path Secrets\sgKey.txt -Value '${{ secrets.LIB_SIGNING_KEY }}' + certutil -decode Secrets\sgKey.txt Secrets\sgKey.snk - name: .NET Setup uses: actions/setup-dotnet@v4 From f2849eb0f21d78ecfa07dc5a47ff55b4f94318b2 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 29 Nov 2024 17:53:11 +0530 Subject: [PATCH 093/113] =?UTF-8?q?ezr=C2=B2=20v0.11.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.txt | 10 ++++++++++ docs/index.md | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index ddcc9e6..3032157 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,6 +3,16 @@ CHANGELOG - What's new? See the GitHub releases for more detailed info: https://github.com/Uralstech/ezrSquared/releases +* ezr² RE - v0.11.3 [29-11-24] + * [BREAKING CHANGE] `CsealAttribute` has been removed. + * [BREAKING CHANGE] `NewNothingConstant()` and `NewBooleanConstant(bool)` have been made static. + * Added new `get_raw` and `get_context` built-in functions. + * Object instances will now be able to access private static members. + * Mutable types now return references to themselves after mutation operations have been performed on them. + * Field and property wrappers now return the set value instead of "nothing". + * All `SharpAutoWrapper` wrapped `Count` properties are now named "length" in the wrapper. + * `Context` now inherits from `IEnumerable>`. + * ezr² RE - v0.11.2 [09-11-24] * Tasks are no longer awaited before being wrapped and are now wrapped like any other C# object. * Wrapped constructors are now named "make" then "make_1" and so on for variations. diff --git a/docs/index.md b/docs/index.md index cc0c195..50b1fba 100644 --- a/docs/index.md +++ b/docs/index.md @@ -85,15 +85,15 @@ out, you can download it from the [***releases page on GitHub***](https://github * Run the installer and go through the installation.
-[![ezr² RE v0.11.2 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.2_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.2/ezrSquared.Shell.Setup.Win64.exe) -[![ezr² RE v0.11.2 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.2_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.2/ezrSquared.Shell.Setup.Win32.exe) +[![ezr² RE v0.11.3 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.3/ezrSquared.Shell.Setup.Win64.exe) +[![ezr² RE v0.11.3 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.3/ezrSquared.Shell.Setup.Win32.exe) # [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! [![ezr² RE on NuGet](https://img.shields.io/badge/ezr%C2%B2_RE_on_NuGet-32CD32?style=for-the-badge&logo=nuget&logoColor=white)](https://www.nuget.org/packages/ezrSquared) -[![ezr² RE v0.11.2 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.2_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.2/ezrSquared.0.11.2-unstable.nupkg) +[![ezr² RE v0.11.3 (.nupkg download)](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28.nupkg_download%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.3/ezrSquared.0.11.3-unstable.nupkg) # [Other](#tab/REother) From 1783a7391b53f115efeed438ff2c9457705bc705 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 29 Nov 2024 18:08:26 +0530 Subject: [PATCH 094/113] Updated index. --- docs/index.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 50b1fba..12ad51d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -79,7 +79,7 @@ ezr² RE still has a lot missing features, like the `include` expression and man It is also very unstable, and the API and syntax may change in updates. So, it is not recommended to use ezr² RE for scripting. If you want to try it out, you can download it from the [***releases page on GitHub***](https://github.com/Uralstech/ezrSquared/releases/), or, from here: -# [Windows](#tab/REwindows) +# [Windows Installers](#tab/REwindowsInstallers) * Download the appropriate installer. * Run the installer and go through the installation. @@ -88,6 +88,29 @@ out, you can download it from the [***releases page on GitHub***](https://github [![ezr² RE v0.11.3 for Windows x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28Windows_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.3/ezrSquared.Shell.Setup.Win64.exe) [![ezr² RE v0.11.3 for Windows x86](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28Windows_x86%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.3/ezrSquared.Shell.Setup.Win32.exe) +# [Windows Archives](#tab/REwindowsArchives) + +* Download and extract the appropriate archive. +
+ +[![ezr² RE v0.11.3 for Windows Arm64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28Windows_arm64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.3/ezrSquared.Shell.Windows-Arm64.tar.xz) + +# [Linux](#tab/RElinux) + +* Download and extract the appropriate archive. +
+ +[![ezr² RE v0.11.3 for Linux x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28Linux_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.3/ezrSquared.Shell.Linux-x64.tar.xz) +[![ezr² RE v0.11.3 for Linux Arm64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28Linux_arm64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.3/ezrSquared.Shell.Linux-Arm64.tar.xz) + +# [MacOS](#tab/REmacOS) + +* Download and extract the appropriate archive. +
+ +[![ezr² RE v0.11.3 for MacOS x64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28MacOS_x64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.3/ezrSquared.Shell.MacOS-x64.tar.xz) +[![ezr² RE v0.11.3 for MacOS Arm64](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28MacOS_arm64%29-32CD32?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Uralstech/ezrSquared/releases/download/v0.11.3/ezrSquared.Shell.MacOS-Arm64.tar.xz) + # [NuGet](#tab/REnuget) You can use ezr² RE as a scripting language for your .NET apps by downloading it from NuGet! From 921660883a52841ebeacc2e46485f8a24831d1ca Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 29 Nov 2024 18:19:20 +0530 Subject: [PATCH 095/113] Added documentation download links. --- docs/index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/index.md b/docs/index.md index 12ad51d..72743ce 100644 --- a/docs/index.md +++ b/docs/index.md @@ -124,6 +124,12 @@ For other OSes you can clone the [***branch***](https://github.com/Uralstech/ezr --- +The offline documentation is included as an optional component in the installers. You can also download them from here: + +[![ezr² RE v0.11.3 documentation](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28documentation%29-32CD32?style=for-the-badge&logo=jekyll&logoColor=white)](https://uralstech.github.io/ezrSquared/docsrc/QuickStartDocumentation.pdf) +[![ezr² RE v0.11.3 API reference manual](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28API_reference_manual%29-32CD32?style=for-the-badge&logo=jekyll&logoColor=white)](https://uralstech.github.io/ezrSquared/api/APIReferenceManual.pdf) + + ## Contributing > [!NOTE] From efc6e59f57d51deb8a5bd2561d18da0ad28f2d3f Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 17 Dec 2024 15:03:28 +0530 Subject: [PATCH 096/113] General improvements and bugfixes. --- src/EzrSquared.csproj | 2 +- src/Runtime/Types/BaseTypes.cs | 12 ++--- .../Builtins/EzrBuiltinFunctions.cs | 2 +- .../EzrSharpCompatibilityWrapper.cs | 52 ++++++++++++++++--- .../EzrSharpCompatibilityExecutable.cs | 6 --- .../EzrSharpCompatibilityField.cs | 2 +- .../EzrSharpSourceFunctionWrapper.cs | 5 +- .../EzrSharpSourceTypeWrapper.cs | 12 ++--- .../Core/RuntimeErrors/EzrAssertionError.cs | 2 +- .../SharpTypeWrapperAttribute.cs | 3 +- src/Shell/Shell.csproj | 9 ++-- src/Syntax/Lexer.cs | 34 +++++++++--- 12 files changed, 97 insertions(+), 44 deletions(-) diff --git a/src/EzrSquared.csproj b/src/EzrSquared.csproj index 5d74bd5..3ec2945 100644 --- a/src/EzrSquared.csproj +++ b/src/EzrSquared.csproj @@ -1,7 +1,6 @@  Library - win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64 AnyCPU net9.0;netstandard2.1 13 @@ -17,6 +16,7 @@ True True + False False diff --git a/src/Runtime/Types/BaseTypes.cs b/src/Runtime/Types/BaseTypes.cs index 7bc7f6f..a64b1f8 100644 --- a/src/Runtime/Types/BaseTypes.cs +++ b/src/Runtime/Types/BaseTypes.cs @@ -6,7 +6,7 @@ using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; using System; -using System.Collections.Generic; +using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Reflection; @@ -26,7 +26,7 @@ internal class EzrRuntimeInvalidObject : EzrObject /// /// Creates a new . /// - EzrRuntimeInvalidObject() : base(Context.Empty, Context.Empty, Position.None, Position.None) { } + private EzrRuntimeInvalidObject() : base(Context.Empty, Context.Empty, Position.None, Position.None) { } } /// @@ -37,7 +37,7 @@ public abstract class EzrObject : IEzrObject /// /// Cache of reflection data for all types. /// - internal static readonly Lazy> s_memberMap = new(); + internal static readonly ConcurrentDictionary<(Type ParentType, string MemberName), MemberInfo> s_reflectionCache = []; /// /// Gets cached reflection data about a member of . @@ -54,14 +54,14 @@ public abstract class EzrObject : IEzrObject Type parentType = typeof(TParentType); (Type, string) key = (parentType, name); - if (s_memberMap.Value.TryGetValue(key, out MemberInfo? cachedMemberInfo)) + if (s_reflectionCache.TryGetValue(key, out MemberInfo? cachedMemberInfo)) return (TMemberInfo)cachedMemberInfo; MemberInfo[] members = parentType.GetMember(name); if (members.Length == 0 || members[0] is not TMemberInfo memberInfo) - return default; + return null; - s_memberMap.Value[key] = memberInfo; + s_reflectionCache[key] = memberInfo; return memberInfo; } diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs index aa6ae94..31e7d9c 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs @@ -402,7 +402,7 @@ public static void GetRaw(SharpMethodParameters arguments) { RuntimeResult result = arguments.Result; IEzrObject objectToWrap = arguments.ArgumentReferences["to_wrap"].Object; - + IEzrObject wrapped = new EzrSharpCompatibilityObjectInstance(objectToWrap, objectToWrap.GetType(), arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition); result.Success(ReferencePool.Get(wrapped, AccessMod.PrivateConstant)); } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 35e42bc..7f703b2 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -6,6 +6,7 @@ using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections.Generic; +using System.Numerics; using System.Reflection; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -16,8 +17,14 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; /// Parent class for all automatic wrappers which wrap existing C# objects and members so that they can be used in ezr². /// /// The type for the C# member being wrapped. + +#if NET7_0_OR_GREATER +public abstract partial class EzrSharpCompatibilityWrapper : EzrObject + where TMemberInfo : MemberInfo +#else public abstract class EzrSharpCompatibilityWrapper : EzrObject where TMemberInfo : MemberInfo +#endif { /// /// Reflection info for / @@ -66,8 +73,6 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, Instance = instance; } - -#pragma warning disable SYSLIB1045 // Convert to 'GeneratedRegexAttribute'. /// /// Regex for converting PascalCase/camelCase to snake_case. /// @@ -77,13 +82,12 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, /// 2. (?<=[a-z0-9])(?=[A-Z]) - Add underscore when transitioning from lowercase or number to uppercase.
/// 3. (?<=[A-Z])(?=[A-Z][a-z]) - Add underscore between uppercase sequences followed by lowercase (e.g., "TCProtocol"). /// - private static readonly Regex s_caseConverterRegex = new(@"(? /// Regex for matching non-alphanumeric + underscore characters. ///
- private static readonly Regex s_alphaNumericUnderscoreOnlyFilterRegex = new(@"[^a-zA-Z0-9_]", RegexOptions.Compiled | RegexOptions.CultureInvariant); -#pragma warning restore SYSLIB1045 // Convert to 'GeneratedRegexAttribute'. + private static readonly Regex s_alphaNumericUnderscoreOnlyFilterRegex = GetAlphaNumericUnderscoreOnlyFilterRegex(); /// /// Converts a string from PascalCase to snake_case. @@ -145,6 +149,17 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, result.Failure(new EzrValueOutOfRangeError($"Expected value to be between {long.MinValue} - {long.MaxValue} (inclusive)!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.Object when typeof(BigInteger).IsAssignableFrom(targetType): + if (value is EzrInteger or EzrFloat) + { + return value is EzrInteger ezrInteger + ? ezrInteger.Value + : new BigInteger(((EzrFloat)value).Value); + } + + result.Failure(new EzrUnexpectedTypeError($"Expected integer or float, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); + break; + case TypeCode.UInt16: double outputUShort = (value as EzrFloat)?.Value ?? ((EzrInteger)value).GetDoubleRepresentation(); if (outputUShort is >= ushort.MinValue and <= ushort.MaxValue) @@ -245,7 +260,10 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, return HandleEzrArrayLikeToCSharp(value, targetType, result); case TypeCode.Object when targetType == typeof(Task): - return Task.CompletedTask; + if (value is EzrSharpCompatibilityObjectInstance taskWrapper && targetType.IsAssignableFrom(taskWrapper.SharpMember)) + return (Task)taskWrapper.Instance!; + + return s_taskFromResultMethod.MakeGenericMethod(value.GetType()).Invoke(null, [value]); case TypeCode.Object when typeof(Task).IsAssignableFrom(targetType) && !targetType.IsGenericTypeDefinition: Type taskTargetType = targetType.GetGenericArguments()[0]; @@ -362,6 +380,9 @@ protected internal void CSharpToEzrObject(object? value, RuntimeResult result) case TypeCode.String: result.Success(NewStringConstant((string)value)); break; + case TypeCode.Object when typeof(BigInteger).IsAssignableFrom(valueType): + result.Success(NewIntegerConstant((BigInteger)value)); + break; case TypeCode.Object when valueType.IsArray && valueType.HasElementType: HandleCSharpArrayToEzrObject((Array)value, valueType, result); break; @@ -442,4 +463,23 @@ public override int ComputeHashCode(RuntimeResult result) ? HashCode.Combine(HashTag, SharpMember, Instance) : HashCode.Combine(HashTag, SharpMember); } + + +#if NET7_0_OR_GREATER + [GeneratedRegex(@"(? ArgumentsArrayToDictionary(Ref if (result.ShouldReturn) return []; - if (primitiveArgument?.GetType() != parameter.ParameterType) - { - result.Failure(new EzrUnexpectedTypeError($"CSharp argument \"{ParameterNames[i]}\" expected value of CSharp type \"{parameter.ParameterType.Name}\", but got object of type \"{argument.TypeName}\"!", Context, argument.StartPosition, argument.EndPosition)); - return []; - } - formattedArguments[i] = primitiveArgument; arguments.Remove(ParameterNames[i]); } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index 7805046..21724b7 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -41,7 +41,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run result.Failure(new EzrUnexpectedArgumentError($"Only expected 0 (for getting the value) or 1 (for setting the value) argument(s) for CSharp field wrapper \"{SharpMemberName}\"!", Context, StartPosition, EndPosition)); break; - case { Length: 1 } when AutoWrapperAttribute?.IsReadOnly == true: + case { Length: 1 } when AutoWrapperAttribute?.IsReadOnly == true || SharpMember.IsInitOnly: result.Failure(new EzrIllegalOperationError($"Cannot set value to CSharp field wrapper \"{SharpMemberName}\" as it is read-only!", Context, StartPosition, EndPosition)); break; diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs index bbb3443..be1a6e5 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs @@ -30,16 +30,17 @@ public partial class EzrSharpSourceFunctionWrapper : EzrSharpSourceExecutableWra /// Creates a new from a function's . /// /// The method to wrap. + /// The object which contains the method, if static. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrSharpSourceFunctionWrapper(MethodInfo function, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + public EzrSharpSourceFunctionWrapper(MethodInfo function, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { Exception? parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(function); if (parameterException is not null) throw parameterException; - SharpFunction = (EzrSharpSourceWrappableMethod)function.CreateDelegate(typeof(EzrSharpSourceWrappableMethod)); + SharpFunction = (EzrSharpSourceWrappableMethod)function.CreateDelegate(typeof(EzrSharpSourceWrappableMethod), instance); (SharpFunctionName, SharpMethodWrapperAttribute attribute) = GetFunctionInfo(function); AddParameters(attribute); diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index 5051d23..042e9fc 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -64,6 +64,10 @@ public EzrSharpSourceTypeWrapper( { SharpType = type; + // Check if type inherits from IEzrObject. + if (!typeof(IEzrObject).IsAssignableFrom(SharpType)) + throw new ArgumentException($"A source wrapper cannot be used to wrap \"{type.Name}\", as it does not inherit {nameof(IEzrObject)}!", nameof(type)); + // Check if generic or abstract. if (type.IsAbstract || type.IsGenericTypeDefinition) throw new ArgumentException($"Cannot wrap generic/abstract C# type \"{type.Name}\"!", nameof(type)); @@ -82,12 +86,8 @@ public EzrSharpSourceTypeWrapper( if (typeAttributeException is not null) throw typeAttributeException; - Exception? parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(constructor!.Value.Info); - if (parameterException is not null) - throw parameterException; - // Get constructor parameters. - int requiredParameters = constructor.Value.Attribute.RequiredParameters.Length; + int requiredParameters = constructor!.Value.Attribute.RequiredParameters.Length; Parameters = new (string Name, bool IsRequired)[constructor.Value.Attribute.RequiredParameters.Length + constructor.Value.Attribute.OptionalParameters.Length]; // Required parameters. @@ -115,7 +115,7 @@ public EzrSharpSourceTypeWrapper( // Check if method can be wrapped. if (method.GetCustomAttribute(false) is not null) { - EzrSharpSourceFunctionWrapper sourceMethod = new(method, Context, StartPosition, EndPosition); + EzrSharpSourceFunctionWrapper sourceMethod = new(method, null, Context, StartPosition, EndPosition); (wrappedMethod, methodName) = (sourceMethod, sourceMethod.SharpFunctionName); } else if (method.GetCustomAttribute() is not null) diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs index 464a5a7..d42f331 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs @@ -21,6 +21,6 @@ public class EzrAssertionError(Context context, Position startPosition, Position /// Wrapper constructor for creating the error object. ///
/// The constructor arguments. - [SharpMethodWrapper()] + [SharpMethodWrapper] public EzrAssertionError(SharpMethodParameters arguments) : this(arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition) { } } diff --git a/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs index 89123e8..96c10ae 100644 --- a/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs @@ -40,7 +40,8 @@ public class SharpTypeWrapperAttribute(string name) : Attribute SharpMethodWrapperAttribute? attribute = constructorInfo.GetCustomAttribute(false); if (constructor is not null && attribute is not null) return new AmbiguousMatchException($"Found multiple constructors for type \"{typeInfo.Name}\" with attribute {nameof(SharpMethodWrapperAttribute)}"); - else if (attribute is not null) + + if (attribute is not null) { constructor = (constructorInfo, attribute); if (SharpMethodWrapperAttribute.ValidateMethodParameters(constructorInfo) is Exception exception) diff --git a/src/Shell/Shell.csproj b/src/Shell/Shell.csproj index 6ca014a..300bfb3 100644 --- a/src/Shell/Shell.csproj +++ b/src/Shell/Shell.csproj @@ -1,7 +1,6 @@  Exe - win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64 AnyCPU net9.0 13 @@ -15,6 +14,10 @@ True True + False + + True + Partial @@ -37,10 +40,6 @@ https://github.com/uralstech/ezrSquared - - True - - ..\..\Binaries\ezrSquared\Release\net9.0\ezrSquared-lib.dll diff --git a/src/Syntax/Lexer.cs b/src/Syntax/Lexer.cs index f724a90..c588030 100644 --- a/src/Syntax/Lexer.cs +++ b/src/Syntax/Lexer.cs @@ -88,7 +88,6 @@ private void ReverseTo(int index) /// Any that occurred in the lexing; if none occurred. public EzrSyntaxError? Tokenize(out List tokens) { - EzrSyntaxError? error; tokens = []; while (!_reachedEnd) { @@ -109,7 +108,7 @@ private void ReverseTo(int index) case '"': case '`': case '\'': - tokens.Add(CompileStringLike(out error)); + tokens.Add(CompileStringLike(out EzrSyntaxError? error)); if (error is not null) return error; break; @@ -238,9 +237,13 @@ private void ReverseTo(int index) tokens.Add(new Token(TokenType.Tilde, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); Advance(); break; + case '#': case '_': case char current when char.IsLetter(current): - tokens.Add(CompileIdentifier()); + tokens.Add(CompileIdentifier(out error)); + if (error is not null) + return error; + break; case char current when char.IsDigit(current): tokens.Add(CompileNumber()); @@ -583,12 +586,25 @@ private Token CompileColon() /// /// Creates , keyword type (, , etc) and qeyword type (, , etc) objects. /// + /// Any that occurred in the process; if none occurred. /// The created . - private Token CompileIdentifier() + private Token CompileIdentifier(out EzrSyntaxError? error) { Position startPosition = _position.Copy(); - StringBuilder idValue = new(); + error = null; + bool isEscapedIdentifier = _currentChar == '#'; + if (isEscapedIdentifier) + { + Advance(); + if (!char.IsLetterOrDigit(_currentChar) && _currentChar != '_') + { + error = new EzrSyntaxError(EzrSyntaxError.UnexpectedCharacter, "The hash symbol should only be used before identifiers to escape keyword detection.", startPosition, _position); + return Token.Empty; + } + } + + StringBuilder idValue = new(); while (!_reachedEnd && (char.IsLetterOrDigit(_currentChar) || _currentChar == '_')) { idValue.Append(_currentChar); @@ -596,8 +612,10 @@ private Token CompileIdentifier() } string original = idValue.ToString(); - return original.ToLower() switch - { + return isEscapedIdentifier + ? new Token(TokenType.Identifier, TokenTypeGroup.Special, original, startPosition, _position.Copy()) + : original.ToLower() switch + { "private" => new Token(TokenType.KeywordPrivate, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), "constant" => new Token(TokenType.KeywordConstant, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), "readonly" => new Token(TokenType.KeywordReadonly, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), @@ -658,6 +676,6 @@ private Token CompileIdentifier() "g" => new Token(TokenType.QeywordG, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), "v" => new Token(TokenType.QeywordV, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), _ => new Token(TokenType.Identifier, TokenTypeGroup.Special, original, startPosition, _position.Copy()), - }; + }; } } \ No newline at end of file From 68d032c2c7201652aeaaf960891cdb24afbe9a5a Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 17 Dec 2024 20:14:09 +0530 Subject: [PATCH 097/113] Improved wrappers. --- .../EzrSharpCompatibilityWrapper.cs | 9 +- .../EzrSharpCompatibilityConstructor.cs | 18 +-- .../EzrSharpCompatibilityExecutable.cs | 124 ++++++++---------- .../EzrSharpCompatibilityFunction.cs | 24 ++-- .../EzrSharpCompatibilityField.cs | 2 +- .../EzrSharpCompatibilityProperty.cs | 12 +- .../Types/Collections/EzrDictionary.cs | 2 +- src/Shell/EzrShell.cs | 7 +- 8 files changed, 88 insertions(+), 110 deletions(-) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 7f703b2..8566d7b 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -325,9 +325,10 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, /// Converts a C# object to an ezr² object. ///
/// The C# object to convert. + /// The type of . /// Runtime result for carrying the result and any errors. /// The converted . - protected internal void CSharpToEzrObject(object? value, RuntimeResult result) + protected internal void CSharpToEzrObject(object? value, Type valueType, RuntimeResult result) { if (value is null) { @@ -335,7 +336,9 @@ protected internal void CSharpToEzrObject(object? value, RuntimeResult result) return; } - Type valueType = value.GetType(); + if (valueType == typeof(object)) + valueType = value.GetType(); + switch (Type.GetTypeCode(valueType)) { case TypeCode.Int16: @@ -411,7 +414,7 @@ protected internal void HandleCSharpArrayToEzrObject(Array value, Type valueType for (int i = 0; i < value.Length; i++) { - CSharpToEzrObject(value.GetValue(i), result); + CSharpToEzrObject(value.GetValue(i), arrayElementType, result); if (result.ShouldReturn) return; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index f04c3a4..ccfd60f 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -59,28 +59,14 @@ public EzrSharpCompatibilityConstructor( /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { - Dictionary formattedArguments = ArgumentsArrayToDictionary(arguments, result); - if (result.ShouldReturn) - return; - - object?[] mappedArguments = CheckAndPopulateArguments(formattedArguments, result); + object?[] mappedArguments = CheckAndPopulateArguments(arguments, result); if (result.ShouldReturn) return; try { object? output = SharpMember.Invoke(mappedArguments); - - if (output is null) - result.Success(NewNothingConstant()); - else - { - IEzrObject wrapper = new EzrSharpCompatibilityObjectInstance(output, ConstructingType, _executionContext, StartPosition, EndPosition); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(wrapper)); - } + CSharpToEzrObject(output, ConstructingType, result); } catch (Exception error) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index 2110d6a..767c3b3 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -2,7 +2,6 @@ using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; -using System.Collections.Generic; using System.Reflection; namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; @@ -58,101 +57,82 @@ public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? inst } /// - /// Converts an array of arguments from ezr² code to an ordered dictionary. + /// Converts an array of arguments from ezr² code to an array of primitive C# objects in the order the executable expects them in. /// /// The arguments. /// Runtime result for carrying errors. - /// The dictionary. - protected internal Dictionary ArgumentsArrayToDictionary(Reference[] arguments, RuntimeResult result) + /// The array of objects. + protected internal object?[] CheckAndPopulateArguments(Reference[] arguments, RuntimeResult result) { - Dictionary formattedArguments = new(arguments.Length); + int parametersLength = Parameters.Length; + + object?[] formattedArguments = parametersLength == 0 ? [] : new object?[parametersLength]; + Array.Fill(formattedArguments, Type.Missing); - int index = 0; - int requiredKeywordArguments = 0; - for (int i = 0; i < arguments.Length; i++) + int nextUnnamedParamIndex = 0; // Track the index for unnamed params. + for (int argIndex = 0; argIndex < arguments.Length; argIndex++) { - Reference reference = arguments[i]; - if (!string.IsNullOrEmpty(reference.Name) && !reference.IsRegistered) - { - if (formattedArguments.ContainsKey(reference.Name)) - { - result.Failure(new EzrIllegalOperationError($"Cannot override already defined argument \"{reference.Name}\"!", _executionContext, reference.Object.StartPosition, reference.Object.EndPosition)); - break; - } + Reference argumentReference = arguments[argIndex]; + string? argumentName = argumentReference.Name; + IEzrObject argumentObject = argumentReference.Object; - formattedArguments[reference.Name] = reference.Object; - if (Array.IndexOf(ParameterNames, reference.Name) >= 0) - requiredKeywordArguments++; - } - else + if (!string.IsNullOrEmpty(argumentName) && !argumentReference.IsRegistered) { - IndexCheck: - if (ParameterNames.Length <= index) - { - result.Failure(new EzrUnexpectedArgumentError( - requiredKeywordArguments > 0 - ? $"Only expected {ParameterNames.Length - requiredKeywordArguments} unnamed argument(s) as {requiredKeywordArguments} required argument(s) has/have been declared as (a) keyword argument(s)!" - : $"Only expected {ParameterNames.Length} unnamed argument(s)!", - _executionContext, StartPosition, EndPosition)); - break; - } - - string argumentName = ParameterNames[index]; - if (!formattedArguments.ContainsKey(argumentName)) + // Handle named parameter. + int parameterIndex = Array.IndexOf(ParameterNames, argumentName); + if (parameterIndex == -1) { - formattedArguments[argumentName] = reference.Object; - index++; + result.Failure(new EzrUnexpectedArgumentError($"Did not expect argument \"{argumentName}\"!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); + return []; } - else + + if (!ReferenceEquals(formattedArguments[parameterIndex], Type.Missing)) { - index++; - goto IndexCheck; + result.Failure(new EzrIllegalOperationError($"Cannot override already defined argument \"{argumentName}\"!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); + return []; } - } - } - - return formattedArguments; - } - - /// - /// Converts an ordered dictionary of named arguments into an array of primitive C# objects in the order the executable expects them in. - /// - /// The arguments. - /// Runtime result for carrying errors. - /// The array of objects. - protected internal object?[] CheckAndPopulateArguments(Dictionary arguments, RuntimeResult result) - { - object?[] formattedArguments = new object?[Parameters.Length]; - Array.Fill(formattedArguments, Type.Missing); - for (int i = 0; i < Parameters.Length; i++) - { - ParameterInfo parameter = Parameters[i]; - if (arguments.TryGetValue(ParameterNames[i], out IEzrObject? argument)) - { - object? primitiveArgument = EzrObjectToCSharp(argument, parameter.ParameterType, result); + formattedArguments[parameterIndex] = EzrObjectToCSharp(argumentObject, Parameters[parameterIndex].ParameterType, result); if (result.ShouldReturn) return []; - formattedArguments[i] = primitiveArgument; - arguments.Remove(ParameterNames[i]); + ReferencePool.TryRelease(argumentReference); + continue; } - else if (parameter.HasDefaultValue) - formattedArguments[i] = parameter.DefaultValue; - else + + // Handle unnamed parameter. + + // Find the next unfilled parameter, skip already assigned ones. + for (; nextUnnamedParamIndex < parametersLength && !ReferenceEquals(formattedArguments[nextUnnamedParamIndex], Type.Missing); nextUnnamedParamIndex++) + continue; + + if (nextUnnamedParamIndex >= parametersLength) { - result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{ParameterNames[i]}\"!", _executionContext, StartPosition, EndPosition)); + result.Failure(new EzrUnexpectedArgumentError("Did not expect any more unnamed arguments!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); return []; } + + formattedArguments[nextUnnamedParamIndex] = EzrObjectToCSharp(argumentObject, Parameters[nextUnnamedParamIndex].ParameterType, result); + if (result.ShouldReturn) + return []; + + nextUnnamedParamIndex++; + ReferencePool.TryRelease(argumentReference); } - if (arguments.Count > 0) + // Check for missing parameters, but skip parameters with default values. + for (int i = 0; i < parametersLength; i++) { - using Dictionary.Enumerator argumentsEnumerator = arguments.GetEnumerator(); - argumentsEnumerator.MoveNext(); + if (!ReferenceEquals(formattedArguments[i], Type.Missing)) + continue; + + if (!Parameters[i].HasDefaultValue) + { + result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{ParameterNames[i]}\"!", _executionContext, StartPosition, EndPosition)); + return []; + } - KeyValuePair first = argumentsEnumerator.Current; - result.Failure(new EzrUnexpectedArgumentError($"Did not expect argument \"{first.Key}\"!", _executionContext, first.Value.StartPosition, first.Value.EndPosition)); + formattedArguments[i] = Parameters[i].DefaultValue; } return formattedArguments; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs index 822703f..8479151 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs @@ -22,25 +22,29 @@ public class EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? ins /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpFunction"; + /// + /// Creates a new from a delegate. + /// + /// The method to wrap. + /// The context in which this object was created. + /// The starting position of the object. + /// The ending position of the object. + /// Skip method signature validation? + public EzrSharpCompatibilityFunction(Delegate sharpFunction, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) + : this(sharpFunction.Method, sharpFunction.Target, parentContext, startPosition, endPosition, skipValidation) + { } + /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { - Dictionary formattedArguments = ArgumentsArrayToDictionary(arguments, result); - if (result.ShouldReturn) - return; - - object?[] mappedArguments = CheckAndPopulateArguments(formattedArguments, result); + object?[] mappedArguments = CheckAndPopulateArguments(arguments, result); if (result.ShouldReturn) return; try { object? output = SharpMember.Invoke(Instance, mappedArguments); - - if (output is null) - result.Success(NewNothingConstant()); - else - CSharpToEzrObject(output, result); + CSharpToEzrObject(output, SharpMember.ReturnType, result); } catch (Exception error) { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs index 21724b7..14c8154 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs @@ -71,7 +71,7 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run } object? value = SharpMember.GetValue(Instance); - CSharpToEzrObject(value, result); + CSharpToEzrObject(value, SharpMember.FieldType, result); break; } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs index 167729b..7b73173 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs @@ -49,8 +49,16 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run return; } - object? value = SharpMember.GetValue(Instance); - CSharpToEzrObject(value, result); + try + { + object? value = SharpMember.GetValue(Instance); + CSharpToEzrObject(value, SharpMember.PropertyType, result); + } + catch (Exception error) + { + result.Failure(new EzrWrapperExecutionError(error.Message, Context, StartPosition, EndPosition)); + return; + } } else { diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index 3e3d40f..3aa5372 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -45,7 +45,7 @@ public EzrDictionary(RuntimeEzrObjectDictionary value, Context parentContext, Po Value = value; Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Value.Count))!, Value, Context, StartPosition, EndPosition), AccessMod.Constant)); - Context.Set(null, "remove_by_hash", ReferencePool.Get(new EzrSharpCompatibilityFunction(GetMemberInfo(nameof(Value.RemoveHash))!, Value, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "remove_by_hash", ReferencePool.Get(new EzrSharpCompatibilityFunction(Value.RemoveHash, Context, StartPosition, EndPosition), AccessMod.Constant)); Context.Set(null, "has_key", ReferencePool.Get(new EzrSharpSourceFunctionWrapper(DictionaryExists, Context, StartPosition, EndPosition), AccessMod.Constant)); } diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index 0adae92..d477b3e 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -1,6 +1,5 @@ using EzrSquared; using EzrSquared.Executor; -using EzrSquared.Runtime.Types.Collections; using System; using System.IO; using System.Text; @@ -141,14 +140,12 @@ private static bool ExecuteCode(string script) return false; } - string outputText = result.Result is EzrArray array && array.Value.Length == 1 - ? array.Value[0].ToString(CodeExecutor.Interpreter.RuntimeResult) - : result.Result!.ToString(CodeExecutor.Interpreter.RuntimeResult); - + string outputText = result.Result!.ToString(CodeExecutor.Interpreter.RuntimeResult); if (CodeExecutor.Interpreter.RuntimeResult.Error is not null) EzrShellConsoleHelper.ShowError(CodeExecutor.Interpreter.RuntimeResult.Error.ToPureString(CodeExecutor.Interpreter.RuntimeResult)); else EzrShellConsoleHelper.ShowOutput(outputText); + return true; } } \ No newline at end of file From 0980766d9a5939c9c7b008a9dd1c6e20338773bb Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 17 Dec 2024 20:43:56 +0530 Subject: [PATCH 098/113] Added special handling for statements instead of just being arrays. --- docs/index.md | 5 ++-- src/Runtime/Interpreter.cs | 22 ++++++++++++++++ .../Nodes/CollectionNodes/StatementsNode.cs | 26 +++++++++++++++++++ src/Syntax/Parser/Parser.cs | 2 +- 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 src/Runtime/Nodes/CollectionNodes/StatementsNode.cs diff --git a/docs/index.md b/docs/index.md index 72743ce..7884733 100644 --- a/docs/index.md +++ b/docs/index.md @@ -126,9 +126,10 @@ For other OSes you can clone the [***branch***](https://github.com/Uralstech/ezr The offline documentation is included as an optional component in the installers. You can also download them from here: -[![ezr² RE v0.11.3 documentation](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28documentation%29-32CD32?style=for-the-badge&logo=jekyll&logoColor=white)](https://uralstech.github.io/ezrSquared/docsrc/QuickStartDocumentation.pdf) -[![ezr² RE v0.11.3 API reference manual](https://img.shields.io/badge/ezr%C2%B2_RE_v0.11.3_%28API_reference_manual%29-32CD32?style=for-the-badge&logo=jekyll&logoColor=white)](https://uralstech.github.io/ezrSquared/api/APIReferenceManual.pdf) +This is documentation for the latest, bleeding-edge version of ezr² RE, so some things may not match up with the latest release: +[![ezr² RE documentation](https://img.shields.io/badge/ezr%C2%B2_RE_documentation-32CD32?style=for-the-badge&logo=jekyll&logoColor=white)](https://uralstech.github.io/ezrSquared/docsrc/QuickStartDocumentation.pdf) +[![ezr² RE API reference manual](https://img.shields.io/badge/ezr%C2%B2_RE_API_reference_manual-32CD32?style=for-the-badge&logo=jekyll&logoColor=white)](https://uralstech.github.io/ezrSquared/api/APIReferenceManual.pdf) ## Contributing diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index 27423af..9efac64 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -57,6 +57,9 @@ internal void VisitNode(Node astNode, Context executionContext, Context? calling case ValueNode node: VisitValueNode(node, executionContext); break; + case StatementsNode node: + VisitStatementsNode(node, executionContext, callingContext, accessibilityModifiers); + break; case ArrayLikeNode node when node.CreateList: VisitArrayLikeNodeList(node, executionContext, callingContext, accessibilityModifiers); break; @@ -202,6 +205,25 @@ private void VisitValueNode(ValueNode node, Context executionContext) } } + /// + /// Interprets multiple statements. + /// + /// The to execute. + /// The under which the statements will be executed. + /// The calling on the execution of the statements. + /// The accessibility modifiers for objects that will be assigned from executing the statements. + private void VisitStatementsNode(StatementsNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) + { + foreach (Node statement in node.Statements) + { + VisitNode(statement, executionContext, callingContext, accessibilityModifiers); + if (RuntimeResult.ShouldReturn) + return; + } + + RuntimeResult.Success(node.Statements.Count > 0 ? RuntimeResult.Reference : ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant)); + } + #region VisitArrayLikeNode /// diff --git a/src/Runtime/Nodes/CollectionNodes/StatementsNode.cs b/src/Runtime/Nodes/CollectionNodes/StatementsNode.cs new file mode 100644 index 0000000..b96616f --- /dev/null +++ b/src/Runtime/Nodes/CollectionNodes/StatementsNode.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +namespace EzrSquared.Runtime.Nodes; + +/// +/// The structure for holding multiple statements. +/// +/// The statements. +/// The starting of the . +/// The ending of the . +public class StatementsNode(List statements, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +{ + /// + /// The statements being held by the node. + /// + public List Statements = statements; + + /// + public override string ToString() + { + string[] elements = new string[Statements.Count]; + for (int i = 0; i < Statements.Count; i++) + elements[i] = Statements[i].ToString(); + + return $"{nameof(StatementsNode)}([{string.Join(", ", elements)}])"; + } +} diff --git a/src/Syntax/Parser/Parser.cs b/src/Syntax/Parser/Parser.cs index ac96a35..9f01088 100644 --- a/src/Syntax/Parser/Parser.cs +++ b/src/Syntax/Parser/Parser.cs @@ -227,7 +227,7 @@ or TokenType.KeywordElse statements.Add(_result.Node); } - _result.Success(new ArrayLikeNode(statements, false, startPosition, statements[^1].EndPosition)); + _result.Success(new StatementsNode(statements, startPosition, statements[^1].EndPosition)); } /// From 2ed8ffa8f3d376767e98de51c16227092cf4b150 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 17 Dec 2024 22:20:08 +0530 Subject: [PATCH 099/113] Code cleanup. --- .../CompatWrappers/EzrSharpCompatibilityWrapper.cs | 2 +- .../Executables/EzrSharpCompatibilityConstructor.cs | 1 - .../Executables/EzrSharpCompatibilityExecutable.cs | 4 ++-- .../Executables/EzrSharpCompatibilityFunction.cs | 1 - src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs | 2 +- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index 8566d7b..c5a62e8 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -262,7 +262,7 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, case TypeCode.Object when targetType == typeof(Task): if (value is EzrSharpCompatibilityObjectInstance taskWrapper && targetType.IsAssignableFrom(taskWrapper.SharpMember)) return (Task)taskWrapper.Instance!; - + return s_taskFromResultMethod.MakeGenericMethod(value.GetType()).Invoke(null, [value]); case TypeCode.Object when typeof(Task).IsAssignableFrom(targetType) && !targetType.IsGenericTypeDefinition: diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index ccfd60f..fbed9fb 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -1,7 +1,6 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.WrapperAttributes; using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index 767c3b3..82e4223 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -85,7 +85,7 @@ public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? inst result.Failure(new EzrUnexpectedArgumentError($"Did not expect argument \"{argumentName}\"!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); return []; } - + if (!ReferenceEquals(formattedArguments[parameterIndex], Type.Missing)) { result.Failure(new EzrIllegalOperationError($"Cannot override already defined argument \"{argumentName}\"!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); @@ -115,7 +115,7 @@ public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? inst formattedArguments[nextUnnamedParamIndex] = EzrObjectToCSharp(argumentObject, Parameters[nextUnnamedParamIndex].ParameterType, result); if (result.ShouldReturn) return []; - + nextUnnamedParamIndex++; ReferencePool.TryRelease(argumentReference); } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs index 8479151..6b42000 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs @@ -1,6 +1,5 @@ using EzrSquared.Runtime.Types.Core.Errors; using System; -using System.Collections.Generic; using System.Reflection; namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; diff --git a/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs index 96c10ae..098ca71 100644 --- a/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs +++ b/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs @@ -40,7 +40,7 @@ public class SharpTypeWrapperAttribute(string name) : Attribute SharpMethodWrapperAttribute? attribute = constructorInfo.GetCustomAttribute(false); if (constructor is not null && attribute is not null) return new AmbiguousMatchException($"Found multiple constructors for type \"{typeInfo.Name}\" with attribute {nameof(SharpMethodWrapperAttribute)}"); - + if (attribute is not null) { constructor = (constructorInfo, attribute); From e3d629e151e76005042f72fb85d30eb00baa3b12 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 20 Dec 2024 01:21:42 +0530 Subject: [PATCH 100/113] Wrapper unification part 1. --- src/Executor/CodeExecutor.cs | 4 +- .../Collections/RuntimeEzrObjectDictionary.cs | 5 +- .../Builtins/EzrBuiltinFunctions.cs | 206 ++++++------------ .../Builtins/EzrBuiltinsUtility.cs | 49 +++-- .../Attributes/DontWrapMemberAttribute.cs} | 4 +- .../Attributes/WrappedMemberAttribute.cs} | 18 +- .../EzrSharpCompatibilityObjectInstance.cs | 12 +- .../EzrSharpCompatibilityType.cs | 14 +- .../EzrSharpCompatibilityWrapper.cs | 8 +- .../Executables/Attributes/ExposeAttribute.cs | 28 +++ .../Executables/Attributes/Feature.cs | 43 ++++ .../Attributes/RuntimeAttribute.cs | 52 +++++ .../EzrSharpCompatibilityConstructor.cs | 32 ++- .../EzrSharpCompatibilityExecutable.cs | 139 +++++++++--- .../EzrSharpCompatibilityFunction.cs | 28 ++- .../EzrSharpSourceTypeWrapper.cs | 9 +- src/Runtime/Types/Collections/EzrArray.cs | 3 +- .../Types/Collections/EzrDictionary.cs | 3 +- src/Runtime/Types/Collections/EzrList.cs | 3 +- .../Types/Core/Text/EzrCharacterList.cs | 3 +- src/Runtime/Types/Core/Text/EzrString.cs | 3 +- .../Types/Executables/EzrRuntimeExecutable.cs | 40 ++-- src/Shell/EzrShell.cs | 2 +- 23 files changed, 451 insertions(+), 257 deletions(-) rename src/Runtime/{WrapperAttributes/SharpDoNotWrapAttribute.cs => Types/CSharpWrappers/CompatWrappers/Attributes/DontWrapMemberAttribute.cs} (74%) rename src/Runtime/{WrapperAttributes/SharpAutoWrapperAttribute.cs => Types/CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs} (80%) create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/ExposeAttribute.cs create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/Feature.cs create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/RuntimeAttribute.cs diff --git a/src/Executor/CodeExecutor.cs b/src/Executor/CodeExecutor.cs index 17460c7..a148035 100644 --- a/src/Executor/CodeExecutor.cs +++ b/src/Executor/CodeExecutor.cs @@ -36,7 +36,7 @@ public static class CodeExecutor public static void CreateRuntimeContext(string filePath) { RuntimeContext?.Release(); - RuntimeContext = new Context($"<\"{filePath}\" context>", true, new Position(0, 0, filePath, string.Empty)); + RuntimeContext = new Context(filePath, true, new Position(0, 0, filePath, string.Empty)); } /// @@ -46,7 +46,7 @@ public static void CreateRuntimeContext(string filePath) /// Thrown if the runtime context is . /// Use to initialize the runtime context. /// - /// Exclude built-in I/O functions like ? + /// Exclude built-in I/O functions like ? public static void PopulateRuntimeContext(bool excludeIO = false) { if (RuntimeContext is null) diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index 93a0b4e..67dbcd3 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -1,6 +1,7 @@ using EzrSquared.Runtime.Types; using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.WrapperAttributes; using System.Collections; using System.Collections.Generic; @@ -20,7 +21,7 @@ public class RuntimeEzrObjectDictionary : IMutable, /// /// The number of s in the . /// - [SharpAutoWrapper("length")] + [WrappedMember("length")] public int Count => _items.Count; /// @@ -116,7 +117,7 @@ public bool Remove(IEzrObject key, RuntimeResult result) /// /// The key (hash) to be removed. /// if the operation was successful, if not. - [SharpAutoWrapper("remove_by_hash")] + [WrappedMember("remove_by_hash")] public bool RemoveHash(int key) { if (_items.TryGetValue(key, out KeyValuePair pair)) diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs index 31e7d9c..6908142 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs @@ -5,6 +5,8 @@ using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections.Generic; @@ -53,37 +55,29 @@ public static class EzrBuiltinFunctions /// /// /// The method arguments. - [SharpMethodWrapper("show", HasExtraPositionalArguments = true, OptionalParameters = ["line_end", "separator"])] - public static void Show(SharpMethodParameters arguments) + [WrappedMember] + public static void Show( + [Expose(true)] string lineEnd, + [Expose(true)] string separator, + [Runtime(Feature.PositionalArguments)] ExtraPositionalArguments messages, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ResultRef)] RuntimeResult result, + [Runtime(Feature.ExecutionRef)] Context executionContext) { - RuntimeResult result = arguments.Result; - List messageReferences = arguments.ExtraPositionalArgumentReferences!; - - if (messageReferences.Count == 0) + if (messages.Count == 0) { - result.Failure(new EzrMissingRequiredArgumentError("At least one message must be provided!", arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition)); - return; - } - string separator = string.Empty; - if (arguments.ArgumentReferences.TryGetValue("separator", out Reference? separatorReference)) - { - IEzrObject separatorObject = separatorReference.Object; - if (separatorObject is IEzrString separatorString) - separator = separatorString.StringValue; - else - { - result.Failure(new EzrUnexpectedTypeError($"Expected separator of type string, character or character list, but got object of type \"{separatorObject.TypeName}\"", arguments.ExecutionContext, separatorObject.StartPosition, separatorObject.EndPosition)); - return; - } + result.Failure(new EzrMissingRequiredArgumentError("At least one message must be provided!", executionContext, wrapper.StartPosition, wrapper.EndPosition)); + return; } + separator ??= ", "; StringBuilder messageBuilder = new(); - int messagesCount = messageReferences.Count; + int messagesCount = messages.Count; for (int i = 0; i < messagesCount; i++) { - string messagePart = messageReferences[i].Object.ToPureString(result); + string messagePart = messages[i].ToPureString(result); if (result.ShouldReturn) return; @@ -92,21 +86,7 @@ public static void Show(SharpMethodParameters arguments) messageBuilder.Append(separator); } - string lineEnd = Environment.NewLine; - if (arguments.ArgumentReferences.TryGetValue("line_end", out Reference? lineEndReference)) - { - IEzrObject lineEndObject = lineEndReference.Object; - if (lineEndObject is IEzrString lineEndString) - lineEnd = lineEndString.StringValue; - else - { - result.Failure(new EzrUnexpectedTypeError($"Expected line ending of type string, character or character list, but got object of type \"{lineEndObject.TypeName}\"", arguments.ExecutionContext, lineEndObject.StartPosition, lineEndObject.EndPosition)); - return; - } - } - - Console.Write(messageBuilder.Append(lineEnd).ToString()); - result.Success(ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant)); + Console.Write(messageBuilder.Append(lineEnd ?? Environment.NewLine).ToString()); } /// @@ -134,16 +114,10 @@ public static void Show(SharpMethodParameters arguments) /// /// /// The method arguments. - [SharpMethodWrapper("throw_error", RequiredParameters = ["error"])] - public static void ThrowError(SharpMethodParameters arguments) + [WrappedMember] + public static void ThrowError(IEzrRuntimeError error, [Runtime(Feature.ResultRef)] RuntimeResult result) { - Reference reference = arguments.ArgumentReferences["error"]; - - IEzrObject referenceObject = reference.Object; - if (referenceObject is not IEzrRuntimeError error) - arguments.Result.Failure(new EzrUnexpectedTypeError($"Expected runtime error, but got object of type \"{referenceObject.TypeName}\"!", arguments.ExecutionContext, referenceObject.StartPosition, referenceObject.EndPosition)); - else - arguments.Result.Failure(error); + result.Failure(error); } /// @@ -162,20 +136,19 @@ public static void ThrowError(SharpMethodParameters arguments) /// /// /// The method arguments. - [SharpMethodWrapper("get", OptionalParameters = ["message"])] - public static void Get(SharpMethodParameters arguments) + [WrappedMember] + public static string Get([Expose(true)] IEzrObject? message, [Runtime(Feature.ResultRef)] RuntimeResult result) { - RuntimeResult result = arguments.Result; - if (arguments.ArgumentReferences.TryGetValue("message", out Reference? messageReference)) + if (message is not null) { - string message = messageReference.Object.ToPureString(result); + string messageStr = message.ToPureString(result); if (result.ShouldReturn) - return; + return string.Empty; - Console.Write(message); + Console.Write(messageStr); } - result.Success(ReferencePool.Get(new EzrString(Console.ReadLine() ?? string.Empty, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + return Console.ReadLine() ?? string.Empty; } /// @@ -186,11 +159,10 @@ public static void Get(SharpMethodParameters arguments) /// /// /// The method arguments. - [SharpMethodWrapper("clear")] - public static void Clear(SharpMethodParameters arguments) + [WrappedMember] + public static void Clear() { Console.Clear(); - arguments.Result.Success(ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant)); } /// @@ -212,23 +184,15 @@ public static void Clear(SharpMethodParameters arguments) /// if the condition is not met. /// /// The method arguments. - [SharpMethodWrapper("assert", RequiredParameters = ["condition"])] - public static void Assert(SharpMethodParameters arguments) + [WrappedMember] + public static void Assert(IEzrObject condition, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ResultRef)] RuntimeResult result, + [Runtime(Feature.ExecutionRef)] Context executionContext) { - RuntimeResult result = arguments.Result; - IEzrObject condition = arguments.ArgumentReferences["condition"].Object; - bool conditionResult = condition.EvaluateBoolean(result); - if (result.ShouldReturn) - return; - - if (!conditionResult) - { - result.Failure(new EzrAssertionError(arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition)); - return; - } - - result.Success(ReferencePool.Get(EzrConstants.Nothing, AccessMod.PrivateConstant)); + if (!result.ShouldReturn && !conditionResult) + result.Failure(new EzrAssertionError(executionContext, wrapper.StartPosition, wrapper.EndPosition)); } /// @@ -247,17 +211,10 @@ public static void Assert(SharpMethodParameters arguments) /// /// /// The method arguments. - [SharpMethodWrapper("hash", RequiredParameters = ["to_hash"])] - public static void Hash(SharpMethodParameters arguments) + [WrappedMember] + public static int Hash(IEzrObject toHash, [Runtime(Feature.ResultRef)] RuntimeResult result) { - RuntimeResult result = arguments.Result; - Reference reference = arguments.ArgumentReferences["to_hash"]; - - int hash = reference.Object.ComputeHashCode(result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(new EzrInteger(hash, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), AccessMod.PrivateConstant)); + return toHash.ComputeHashCode(result); } /// @@ -276,16 +233,10 @@ public static void Hash(SharpMethodParameters arguments) /// /// /// The method arguments. - [SharpMethodWrapper("type_of", RequiredParameters = ["to_check"])] - public static void TypeOf(SharpMethodParameters arguments) + [WrappedMember] + public static string TypeOf(IEzrObject toCheck) { - arguments.Result.Success(ReferencePool.Get( - new EzrString( - arguments.ArgumentReferences["to_check"].Object.Tag, - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition), - AccessMod.PrivateConstant)); + return toCheck.Tag; } /// @@ -304,16 +255,10 @@ public static void TypeOf(SharpMethodParameters arguments) /// /// /// The method arguments. - [SharpMethodWrapper("type_name_of", RequiredParameters = ["to_check"])] - public static void TypeNameOf(SharpMethodParameters arguments) + [WrappedMember] + public static string TypeNameOf(IEzrObject toCheck) { - arguments.Result.Success(ReferencePool.Get( - new EzrString( - arguments.ArgumentReferences["to_check"].Object.TypeName, - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition), - AccessMod.PrivateConstant)); + return toCheck.TypeName; } /// @@ -332,16 +277,10 @@ public static void TypeNameOf(SharpMethodParameters arguments) /// /// /// The method arguments. - [SharpMethodWrapper("type_hash_of", RequiredParameters = ["to_check"])] - public static void TypeHashOf(SharpMethodParameters arguments) + [WrappedMember] + public static int TypeHashOf(IEzrObject toCheck) { - arguments.Result.Success(ReferencePool.Get( - new EzrInteger( - arguments.ArgumentReferences["to_check"].Object.HashTag, - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition), - AccessMod.PrivateConstant)); + return toCheck.HashTag; } /// @@ -363,22 +302,10 @@ public static void TypeHashOf(SharpMethodParameters arguments) /// if "to_copy" is not of the expected type. /// /// The method arguments. - [SharpMethodWrapper("copy", RequiredParameters = ["to_copy"])] - public static void Copy(SharpMethodParameters arguments) + [WrappedMember] + public static IEzrObject Copy(IEzrMutableObject toCopy, [Runtime(Feature.ResultRef)] RuntimeResult result) { - RuntimeResult result = arguments.Result; - IEzrObject objectToCopy = arguments.ArgumentReferences["to_copy"].Object; - if (objectToCopy is not IEzrMutableObject mutableObject) - { - result.Failure(new EzrUnexpectedTypeError($"Cannot create copy of immutable object of type \"{objectToCopy.TypeName}\"!", arguments.ExecutionContext, objectToCopy.StartPosition, objectToCopy.EndPosition)); - return; - } - - IEzrObject? copy = (IEzrObject?)mutableObject.DeepCopy(result); - if (result.ShouldReturn) - return; - - result.Success(ReferencePool.Get(copy, AccessMod.PrivateConstant)); + return (IEzrObject?)toCopy.DeepCopy(result) ?? EzrConstants.Nothing; } /// @@ -397,14 +324,12 @@ public static void Copy(SharpMethodParameters arguments) /// /// /// The method arguments. - [SharpMethodWrapper("get_raw", RequiredParameters = ["to_wrap"])] - public static void GetRaw(SharpMethodParameters arguments) + [WrappedMember] + public static EzrSharpCompatibilityObjectInstance GetRaw(IEzrObject toGet, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) { - RuntimeResult result = arguments.Result; - IEzrObject objectToWrap = arguments.ArgumentReferences["to_wrap"].Object; - - IEzrObject wrapped = new EzrSharpCompatibilityObjectInstance(objectToWrap, objectToWrap.GetType(), arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition); - result.Success(ReferencePool.Get(wrapped, AccessMod.PrivateConstant)); + return new EzrSharpCompatibilityObjectInstance(toGet, toGet.GetType(), executionContext, wrapper.StartPosition, wrapper.EndPosition); } /// @@ -423,24 +348,23 @@ public static void GetRaw(SharpMethodParameters arguments) /// /// /// The method arguments. - [SharpMethodWrapper("get_context", RequiredParameters = ["to_get"])] - public static void GetContext(SharpMethodParameters arguments) + [WrappedMember] + public static IEzrObject GetContext(IEzrObject toGet, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ResultRef)] RuntimeResult result, + [Runtime(Feature.ExecutionRef)] Context executionContext) { - RuntimeResult result = arguments.Result; - IEzrObject objectToWrap = arguments.ArgumentReferences["to_get"].Object; - RuntimeEzrObjectDictionary context = new(); - foreach (KeyValuePair pair in objectToWrap.Context) + foreach (KeyValuePair pair in toGet.Context) { if (pair.Value.AccessibilityModifiers.HasFlag(AccessMod.Private)) continue; - context.Update(new EzrString(pair.Key, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition), pair.Value.Object, result); + context.Update(new EzrString(pair.Key, executionContext, wrapper.StartPosition, wrapper.EndPosition), pair.Value.Object, result); if (result.ShouldReturn) - return; + return EzrConstants.Nothing; } - IEzrObject dictionary = new EzrDictionary(context, arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition); - result.Success(ReferencePool.Get(dictionary, AccessMod.PrivateConstant)); + return new EzrDictionary(context, executionContext, wrapper.StartPosition, wrapper.EndPosition); } } diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs index 1694850..52e5cb1 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs @@ -1,5 +1,6 @@ using EzrSquared.Runtime.Types.Core; using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; using EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; namespace EzrSquared.Runtime.Types.CSharpWrappers.Builtins; @@ -15,25 +16,25 @@ public static class EzrBuiltinsUtility /// The context to add to. public static void AddBuiltinFunctions(Context context) { - EzrSharpSourceFunctionWrapper throwError = new(EzrBuiltinFunctions.ThrowError, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper assert = new(EzrBuiltinFunctions.Assert, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper hash = new(EzrBuiltinFunctions.Hash, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper typeOf = new(EzrBuiltinFunctions.TypeOf, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper typeNameOf = new(EzrBuiltinFunctions.TypeNameOf, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper typeHashOf = new(EzrBuiltinFunctions.TypeHashOf, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper copy = new(EzrBuiltinFunctions.Copy, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper getRaw = new(EzrBuiltinFunctions.GetRaw, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper getContext = new(EzrBuiltinFunctions.GetContext, context, Position.None, Position.None); + EzrSharpCompatibilityFunction throwError = new(EzrBuiltinFunctions.ThrowError, context, Position.None, Position.None); + EzrSharpCompatibilityFunction assert = new(EzrBuiltinFunctions.Assert, context, Position.None, Position.None); + EzrSharpCompatibilityFunction hash = new(EzrBuiltinFunctions.Hash, context, Position.None, Position.None); + EzrSharpCompatibilityFunction typeOf = new(EzrBuiltinFunctions.TypeOf, context, Position.None, Position.None); + EzrSharpCompatibilityFunction typeNameOf = new(EzrBuiltinFunctions.TypeNameOf, context, Position.None, Position.None); + EzrSharpCompatibilityFunction typeHashOf = new(EzrBuiltinFunctions.TypeHashOf, context, Position.None, Position.None); + EzrSharpCompatibilityFunction copy = new(EzrBuiltinFunctions.Copy, context, Position.None, Position.None); + EzrSharpCompatibilityFunction getRaw = new(EzrBuiltinFunctions.GetRaw, context, Position.None, Position.None); + EzrSharpCompatibilityFunction getContext = new(EzrBuiltinFunctions.GetContext, context, Position.None, Position.None); - context.Set(null, throwError.SharpFunctionName, ReferencePool.Get(throwError, AccessMod.Constant)); - context.Set(null, assert.SharpFunctionName, ReferencePool.Get(assert, AccessMod.Constant)); - context.Set(null, hash.SharpFunctionName, ReferencePool.Get(hash, AccessMod.Constant)); - context.Set(null, typeOf.SharpFunctionName, ReferencePool.Get(typeOf, AccessMod.Constant)); - context.Set(null, typeNameOf.SharpFunctionName, ReferencePool.Get(typeNameOf, AccessMod.Constant)); - context.Set(null, typeHashOf.SharpFunctionName, ReferencePool.Get(typeHashOf, AccessMod.Constant)); - context.Set(null, copy.SharpFunctionName, ReferencePool.Get(copy, AccessMod.Constant)); - context.Set(null, getRaw.SharpFunctionName, ReferencePool.Get(getRaw, AccessMod.Constant)); - context.Set(null, getContext.SharpFunctionName, ReferencePool.Get(getContext, AccessMod.Constant)); + context.Set(null, throwError.SharpMemberName, ReferencePool.Get(throwError, AccessMod.Constant)); + context.Set(null, assert.SharpMemberName, ReferencePool.Get(assert, AccessMod.Constant)); + context.Set(null, hash.SharpMemberName, ReferencePool.Get(hash, AccessMod.Constant)); + context.Set(null, typeOf.SharpMemberName, ReferencePool.Get(typeOf, AccessMod.Constant)); + context.Set(null, typeNameOf.SharpMemberName, ReferencePool.Get(typeNameOf, AccessMod.Constant)); + context.Set(null, typeHashOf.SharpMemberName, ReferencePool.Get(typeHashOf, AccessMod.Constant)); + context.Set(null, copy.SharpMemberName, ReferencePool.Get(copy, AccessMod.Constant)); + context.Set(null, getRaw.SharpMemberName, ReferencePool.Get(getRaw, AccessMod.Constant)); + context.Set(null, getContext.SharpMemberName, ReferencePool.Get(getContext, AccessMod.Constant)); } /// @@ -42,13 +43,13 @@ public static void AddBuiltinFunctions(Context context) /// The context to add to. public static void AddBuiltinIOFunctions(Context context) { - EzrSharpSourceFunctionWrapper show = new(EzrBuiltinFunctions.Show, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper get = new(EzrBuiltinFunctions.Get, context, Position.None, Position.None); - EzrSharpSourceFunctionWrapper clear = new(EzrBuiltinFunctions.Clear, context, Position.None, Position.None); + EzrSharpCompatibilityFunction show = new(EzrBuiltinFunctions.Show, context, Position.None, Position.None); + EzrSharpCompatibilityFunction get = new(EzrBuiltinFunctions.Get, context, Position.None, Position.None); + EzrSharpCompatibilityFunction clear = new(EzrBuiltinFunctions.Clear, context, Position.None, Position.None); - context.Set(null, show.SharpFunctionName, ReferencePool.Get(show, AccessMod.Constant)); - context.Set(null, get.SharpFunctionName, ReferencePool.Get(get, AccessMod.Constant)); - context.Set(null, clear.SharpFunctionName, ReferencePool.Get(clear, AccessMod.Constant)); + context.Set(null, show.SharpMemberName, ReferencePool.Get(show, AccessMod.Constant)); + context.Set(null, get.SharpMemberName, ReferencePool.Get(get, AccessMod.Constant)); + context.Set(null, clear.SharpMemberName, ReferencePool.Get(clear, AccessMod.Constant)); } /// diff --git a/src/Runtime/WrapperAttributes/SharpDoNotWrapAttribute.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/DontWrapMemberAttribute.cs similarity index 74% rename from src/Runtime/WrapperAttributes/SharpDoNotWrapAttribute.cs rename to src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/DontWrapMemberAttribute.cs index e5bbc61..84181b5 100644 --- a/src/Runtime/WrapperAttributes/SharpDoNotWrapAttribute.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/DontWrapMemberAttribute.cs @@ -1,11 +1,11 @@ using System; -namespace EzrSquared.Runtime.WrapperAttributes; +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; /// /// Attribute for C# types and members which should NOT be automatically wrapped from C# types into ezr² types by the interpreter. /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] -public class SharpDoNotWrapAttribute : Attribute +public class DontWrapMemberAttribute : Attribute { } diff --git a/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs similarity index 80% rename from src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs rename to src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs index 36e9794..90d58fc 100644 --- a/src/Runtime/WrapperAttributes/SharpAutoWrapperAttribute.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs @@ -1,13 +1,13 @@ using System; using System.Reflection; -namespace EzrSquared.Runtime.WrapperAttributes; +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; /// /// Attribute for C# types and members to be automatically wrapped from C# types into ezr² types. /// -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] -public class SharpAutoWrapperAttribute : Attribute +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] +public class WrappedMemberAttribute : Attribute { /// /// The ezr² name for the member. @@ -25,12 +25,12 @@ public class SharpAutoWrapperAttribute : Attribute public readonly bool IsWriteOnly; /// - /// Creates a new . + /// Creates a new . /// /// Is the member read-only? Only for properties and fields. /// Is the member write-only? Only for properties and fields. /// Thrown if both and are set to . - public SharpAutoWrapperAttribute(bool isReadOnly = false, bool isWriteOnly = false) + public WrappedMemberAttribute(bool isReadOnly = false, bool isWriteOnly = false) { IsReadOnly = isReadOnly; IsWriteOnly = isWriteOnly; @@ -40,12 +40,12 @@ public SharpAutoWrapperAttribute(bool isReadOnly = false, bool isWriteOnly = fal } /// - /// Creates a new . + /// Creates a new . /// /// The ezr² name for the member. /// Is the member read-only? Only for properties and fields. /// Is the member write-only? Only for properties and fields. - public SharpAutoWrapperAttribute(string name, bool isReadOnly = false, bool isWriteOnly = false) : this(isReadOnly, isWriteOnly) + public WrappedMemberAttribute(string name, bool isReadOnly = false, bool isWriteOnly = false) : this(isReadOnly, isWriteOnly) { Name = name; } @@ -60,7 +60,7 @@ public SharpAutoWrapperAttribute(string name, bool isReadOnly = false, bool isWr public static bool ValidateMethod(MethodBase methodBase, bool dontThrow = false) { if (methodBase.IsGenericMethodDefinition || methodBase.ContainsGenericParameters) - return dontThrow ? false : throw new ArgumentException($"The \"{nameof(SharpAutoWrapperAttribute)}\" attribute does not support generic method/constructor \"{methodBase.Name}\".", nameof(methodBase)); + return dontThrow ? false : throw new ArgumentException($"The \"{nameof(WrappedMemberAttribute)}\" attribute does not support generic method/constructor \"{methodBase.Name}\".", nameof(methodBase)); return true; } @@ -72,7 +72,7 @@ public static bool ValidateMethod(MethodBase methodBase, bool dontThrow = false) /// if yes, otherwise. public static bool ShouldBeWrapped(MemberInfo member) { - return member.GetCustomAttribute() is null && (GetIsPublic(member) || member.GetCustomAttribute() is not null); + return member.GetCustomAttribute() is null && (GetIsPublic(member) || member.GetCustomAttribute() is not null); } /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs index 0bffed0..060d83b 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs @@ -1,6 +1,6 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; -using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -48,11 +48,11 @@ public EzrSharpCompatibilityObjectInstance( for (int i = 0; i < allMethods.Length; i++) { MethodInfo method = allMethods[i]; - if (!SharpAutoWrapperAttribute.ShouldBeWrapped(method)) + if (!WrappedMemberAttribute.ShouldBeWrapped(method)) continue; EzrSharpCompatibilityFunction methodObject = new(method, Instance, Context, StartPosition, EndPosition, skipValidation: true); - if (!SharpAutoWrapperAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) + if (!WrappedMemberAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) continue; string methodObjectName = methodObject.SharpMemberName; @@ -71,7 +71,7 @@ public EzrSharpCompatibilityObjectInstance( for (int i = 0; i < allProperties.Length; i++) { PropertyInfo property = allProperties[i]; - if (!SharpAutoWrapperAttribute.ShouldBeWrapped(property)) + if (!WrappedMemberAttribute.ShouldBeWrapped(property)) continue; EzrSharpCompatibilityProperty propertyObject = new(property, Instance, Context, StartPosition, EndPosition); @@ -82,7 +82,7 @@ public EzrSharpCompatibilityObjectInstance( for (int i = 0; i < allFields.Length; i++) { FieldInfo field = allFields[i]; - if (!SharpAutoWrapperAttribute.ShouldBeWrapped(field)) + if (!WrappedMemberAttribute.ShouldBeWrapped(field)) continue; EzrSharpCompatibilityField fieldObject = new(field, Instance, Context, StartPosition, EndPosition); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index db3d25f..df5064a 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -1,7 +1,7 @@ using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; -using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; using System; using System.Collections.Generic; @@ -56,11 +56,11 @@ public EzrSharpCompatibilityType( for (int i = 0; i < allStaticMethods.Length; i++) { MethodInfo method = allStaticMethods[i]; - if (!SharpAutoWrapperAttribute.ShouldBeWrapped(method)) + if (!WrappedMemberAttribute.ShouldBeWrapped(method)) continue; EzrSharpCompatibilityFunction methodObject = new(method, null, Context, StartPosition, EndPosition, skipValidation: true); - if (!SharpAutoWrapperAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) + if (!WrappedMemberAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) continue; string methodObjectName = methodObject.SharpMemberName; @@ -79,7 +79,7 @@ public EzrSharpCompatibilityType( for (int i = 0; i < allStaticProperties.Length; i++) { PropertyInfo property = allStaticProperties[i]; - if (!SharpAutoWrapperAttribute.ShouldBeWrapped(property)) + if (!WrappedMemberAttribute.ShouldBeWrapped(property)) continue; EzrSharpCompatibilityProperty propertyObject = new(property, null, Context, StartPosition, EndPosition); @@ -90,7 +90,7 @@ public EzrSharpCompatibilityType( for (int i = 0; i < allStaticFields.Length; i++) { FieldInfo field = allStaticFields[i]; - if (!SharpAutoWrapperAttribute.ShouldBeWrapped(field)) + if (!WrappedMemberAttribute.ShouldBeWrapped(field)) continue; EzrSharpCompatibilityField fieldObject = new(field, null, Context, StartPosition, EndPosition); @@ -102,11 +102,11 @@ public EzrSharpCompatibilityType( for (int i = 0; i < publicConstructors.Length; i++) { ConstructorInfo constructor = publicConstructors[i]; - if (!SharpAutoWrapperAttribute.ShouldBeWrapped(constructor)) + if (!WrappedMemberAttribute.ShouldBeWrapped(constructor)) continue; EzrSharpCompatibilityConstructor constructorObject = new(sharpType, constructor, Context, StartPosition, EndPosition, skipValidation: true); - if (!SharpAutoWrapperAttribute.ValidateMethod(constructor, constructorObject.AutoWrapperAttribute is null)) + if (!WrappedMemberAttribute.ValidateMethod(constructor, constructorObject.AutoWrapperAttribute is null)) continue; Context.Set(null, definedConstructors == 0 ? "make" : $"make_{definedConstructors}", ReferencePool.Get(constructorObject, AccessMod.Constant)); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs index c5a62e8..68c7882 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs @@ -3,7 +3,7 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using System; using System.Collections.Generic; using System.Numerics; @@ -38,9 +38,9 @@ public abstract class EzrSharpCompatibilityWrapper : EzrObject public override string Tag { get; protected internal set; } = "ezrSquared.CSharpWrapper"; /// - /// The of the wrapped object, if defined. + /// The of the wrapped object, if defined. /// - public readonly SharpAutoWrapperAttribute? AutoWrapperAttribute; + public readonly WrappedMemberAttribute? AutoWrapperAttribute; /// /// The name of the wrapped member in snake_case. @@ -68,7 +68,7 @@ public abstract class EzrSharpCompatibilityWrapper : EzrObject public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpMember = wrappedMember; - AutoWrapperAttribute = wrappedMember.GetCustomAttribute(); + AutoWrapperAttribute = wrappedMember.GetCustomAttribute(); SharpMemberName = !string.IsNullOrEmpty(AutoWrapperAttribute?.Name) ? AutoWrapperAttribute.Name : PascalToSnakeCase(wrappedMember.Name)!; Instance = instance; } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/ExposeAttribute.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/ExposeAttribute.cs new file mode 100644 index 0000000..cca7826 --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/ExposeAttribute.cs @@ -0,0 +1,28 @@ +using System; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; + +/// +/// Attribute to expose additonal data about the wrapped C# method parameter. +/// +/// The ezr² name for the parameter. +/// Is the parameter optional? +[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] +public class ExposeAttribute(string name, bool optional) : Attribute +{ + /// + /// The ezr² name for the parameter. + /// + public readonly string Name = name; + + /// + /// Is the parameter optional? + /// + public readonly bool Optional = optional; + + /// The ezr² name for the parameter. + public ExposeAttribute(string name) : this(name, false) { } + + /// Is the parameter optional? + public ExposeAttribute(bool optional) : this("", optional) { } +} diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/Feature.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/Feature.cs new file mode 100644 index 0000000..450ae6b --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/Feature.cs @@ -0,0 +1,43 @@ +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; + +/// +/// The metadata for . +/// +public enum Feature +{ + /// + /// Requests extra keyword arguments. + /// The parameter must be assignable from . + /// + KeywordArguments, + + /// + /// Requests extra positional arguments. + /// The parameter must be assignable from . + /// + PositionalArguments, + + /// + /// Requests a reference to the calling . + /// The parameter must be assignable from . + /// + CallerRef, + + /// + /// Requests a reference to the execution context. + /// The parameter must be assignable from . + /// + ExecutionRef, + + /// + /// Requests a reference to the execution context. + /// The parameter must be assignable from . + /// + InterpreterRef, + + /// + /// Requests a reference to the current . + /// The parameter must be assignable from . + /// + ResultRef, +} \ No newline at end of file diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/RuntimeAttribute.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/RuntimeAttribute.cs new file mode 100644 index 0000000..b0fd894 --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/RuntimeAttribute.cs @@ -0,0 +1,52 @@ +global using ExtraKeywordArguments = System.Collections.Generic.Dictionary; +global using ExtraPositionalArguments = System.Collections.Generic.List; +using System; +using System.Reflection; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; + +/// +/// Attribute for wrapped C# methods that need to enable features or request data from the ezr² runtime. +/// +/// +/// This can include enabling extra keyword arguments, extra positional arguments, requesting references
+/// to the interpreter, wrapper, context, etc. The parameter must conform to the attributed .
+/// For example, a parameter attributed with must be assignable from the
+/// type. +///
+[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] +public class RuntimeAttribute(Feature type) : Attribute +{ + /// + /// The type of the parameter. + /// + public readonly Feature Type = type; + + /// + /// Checks if the given parameter has the correct signature. + /// + /// The parameter. + public void ValidateParameter(ParameterInfo parameter) + { + switch (Type) + { + case Feature.KeywordArguments when !parameter.ParameterType.IsAssignableFrom(typeof(ExtraKeywordArguments)): + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(ExtraKeywordArguments)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + + case Feature.PositionalArguments when !parameter.ParameterType.IsAssignableFrom(typeof(ExtraPositionalArguments)): + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(ExtraPositionalArguments)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + + case Feature.CallerRef when !parameter.ParameterType.IsAssignableFrom(typeof(IEzrObject)): + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(IEzrObject)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + + case Feature.ExecutionRef when !parameter.ParameterType.IsAssignableFrom(typeof(Context)): + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(Context)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + + case Feature.InterpreterRef when !parameter.ParameterType.IsAssignableFrom(typeof(Interpreter)): + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(Interpreter)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + + case Feature.ResultRef when !parameter.ParameterType.IsAssignableFrom(typeof(RuntimeResult)): + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(RuntimeResult)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + } + } +} diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs index fbed9fb..ebbb40d 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs @@ -1,8 +1,9 @@ using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Text; namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; @@ -51,20 +52,23 @@ public EzrSharpCompatibilityConstructor( { ConstructingType = constructingType; - SharpAutoWrapperAttribute? autoWrapperAttribute = constructingType.GetCustomAttribute(); + WrappedMemberAttribute? autoWrapperAttribute = constructingType.GetCustomAttribute(); ConstructingTypeName = !string.IsNullOrEmpty(autoWrapperAttribute?.Name) ? autoWrapperAttribute.Name : PascalToSnakeCase(constructingType.Name)!; } /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { - object?[] mappedArguments = CheckAndPopulateArguments(arguments, result); + object?[] mappedArguments = CheckAndPopulateArguments(arguments, interpreter, result); if (result.ShouldReturn) return; try { object? output = SharpMember.Invoke(mappedArguments); + if (result.ShouldReturn) + return; + CSharpToEzrObject(output, ConstructingType, result); } catch (Exception error) @@ -76,8 +80,24 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run /// public override string ToString(RuntimeResult result) { - return ParameterNames.Length > 0 - ? $"<{TypeName} for type \"{ConstructingTypeName}\", with \"{string.Join("\", \"", ParameterNames)}\">" - : $"<{TypeName} for \"{ConstructingTypeName}\">"; + bool hasParameters = ParameterNames.Length > 0; + StringBuilder builder = new($"<{TypeName} for \"{ConstructingTypeName}\""); + + if (hasParameters) + builder.Append($", with \"{string.Join("\", \"", ParameterNames)}\""); + + if (AcceptsExtraKeywordArguments) + { + builder.Append(hasParameters && AcceptsExtraPositionalArguments ? ", " : AcceptsExtraPositionalArguments || !hasParameters ? ", with " : " and "); + builder.Append("extra keyword arguments"); + } + + if (AcceptsExtraPositionalArguments) + { + builder.Append(hasParameters || AcceptsExtraKeywordArguments ? " and " : ", with "); + builder.Append("extra positional arguments"); + } + + return builder.Append('>').ToString(); } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs index 82e4223..1bc6041 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs @@ -1,7 +1,9 @@ using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; using EzrSquared.Util; using System; +using System.Collections.Generic; using System.Reflection; namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; @@ -19,15 +21,30 @@ public abstract class EzrSharpCompatibilityExecutable : EzrSharpCom public override string Tag { get; protected internal set; } = "ezrSquared.CSharpRuntimeExecutable"; /// - /// Reflection information about the parameters of the executable to wrap. + /// Reflection information about the exposed parameters of the executable to wrap. /// - public readonly ParameterInfo[] Parameters; + public readonly (ParameterInfo Info, bool Optional)[] Parameters; /// - /// The names of the parameters of the executable to wrap, in ezr² (snake_case) format. + /// The names of the exposed parameters of the executable to wrap, in ezr² (snake_case) format. /// public readonly string[] ParameterNames; + /// + /// The attributes of the executable's runtime-provided parameters. + /// + public readonly RuntimeAttribute[] RuntimeProvidedParameters; + + /// + /// Does this executable accept extra keyword arguments? + /// + public readonly bool AcceptsExtraKeywordArguments; + + /// + /// Does this executable accept extra positional arguments? + /// + public readonly bool AcceptsExtraPositionalArguments; + /// /// Creates a new . /// @@ -40,34 +57,69 @@ public abstract class EzrSharpCompatibilityExecutable : EzrSharpCom public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation) : base(sharpMethodBase, instance, parentContext, startPosition, endPosition) { Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; + if (!skipValidation) + WrappedMemberAttribute.ValidateMethod(SharpMember, AutoWrapperAttribute is null); - Parameters = SharpMember.GetParameters(); - ParameterNames = new string[Parameters.Length]; + ParameterInfo[] allParameters = SharpMember.GetParameters(); + List<(ParameterInfo, bool)> exposedParameters = new(allParameters.Length); + List exposedParameterNames = new(allParameters.Length); - for (int i = 0; i < Parameters.Length; i++) + Lazy> runtimeProvidedParameters = new(); + + for (int i = 0; i < allParameters.Length; i++) { - ParameterInfo parameter = Parameters[i]; - string? definedName = parameter.GetCustomAttribute()?.Name; + ParameterInfo parameterInfo = allParameters[i]; + + ExposeAttribute? autoWrapperAttribute = parameterInfo.GetCustomAttribute(); + RuntimeAttribute? runtimeParamAttribute = parameterInfo.GetCustomAttribute(); + + if (autoWrapperAttribute is not null && runtimeParamAttribute is not null) + throw new ArgumentException($"Method \"{SharpMember.Name}\" cannot have a parameter with both {nameof(ExposeAttribute)} and {nameof(RuntimeAttribute)} attributes ({parameterInfo.Name})!", nameof(sharpMethodBase)); + else if (runtimeParamAttribute is null && runtimeProvidedParameters.IsValueCreated) + throw new ArgumentException($"Method \"{SharpMember.Name}\" cannot have a normal parameter after {nameof(RuntimeAttribute)}-attributed parameters ({parameterInfo.Name})!", nameof(sharpMethodBase)); - ParameterNames[i] = string.IsNullOrEmpty(definedName) ? PascalToSnakeCase(parameter.Name) ?? $"param_{i}" : definedName; + if (runtimeParamAttribute is null) + { + exposedParameters.Add((parameterInfo, autoWrapperAttribute?.Optional ?? false)); + exposedParameterNames.Add(string.IsNullOrEmpty(autoWrapperAttribute?.Name) ? PascalToSnakeCase(parameterInfo.Name) ?? $"param_{i}" : autoWrapperAttribute.Name); + continue; + } + + runtimeParamAttribute.ValidateParameter(parameterInfo); + runtimeProvidedParameters.Value.Add(runtimeParamAttribute); + + switch (runtimeParamAttribute.Type) + { + case Feature.KeywordArguments: + AcceptsExtraKeywordArguments = true; break; + + case Feature.PositionalArguments: + AcceptsExtraPositionalArguments = true; break; + } } - if (!skipValidation) - SharpAutoWrapperAttribute.ValidateMethod(SharpMember, AutoWrapperAttribute is null); + Parameters = [.. exposedParameters]; + ParameterNames = [.. exposedParameterNames]; + RuntimeProvidedParameters = runtimeProvidedParameters.IsValueCreated ? [.. runtimeProvidedParameters.Value] : []; } /// /// Converts an array of arguments from ezr² code to an array of primitive C# objects in the order the executable expects them in. /// /// The arguments. + /// The interpreter to be used in execution. /// Runtime result for carrying errors. /// The array of objects. - protected internal object?[] CheckAndPopulateArguments(Reference[] arguments, RuntimeResult result) + protected internal object?[] CheckAndPopulateArguments(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { - int parametersLength = Parameters.Length; + int exposedParametersLength = Parameters.Length; + int totalParametersLength = exposedParametersLength + RuntimeProvidedParameters.Length; - object?[] formattedArguments = parametersLength == 0 ? [] : new object?[parametersLength]; - Array.Fill(formattedArguments, Type.Missing); + object?[] formattedArguments = totalParametersLength == 0 ? [] : new object?[totalParametersLength]; + Array.Fill(formattedArguments, Type.Missing, 0, Parameters.Length); + + Lazy extraKeywordArguments = new(); + Lazy extraPositionalArguments = new(); int nextUnnamedParamIndex = 0; // Track the index for unnamed params. for (int argIndex = 0; argIndex < arguments.Length; argIndex++) @@ -80,19 +132,29 @@ public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? inst { // Handle named parameter. int parameterIndex = Array.IndexOf(ParameterNames, argumentName); - if (parameterIndex == -1) + bool isExtraArgument = parameterIndex == -1; + + if (isExtraArgument && !AcceptsExtraKeywordArguments) { result.Failure(new EzrUnexpectedArgumentError($"Did not expect argument \"{argumentName}\"!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); return []; } - if (!ReferenceEquals(formattedArguments[parameterIndex], Type.Missing)) + if ((isExtraArgument && extraKeywordArguments.Value.ContainsKey(argumentName)) + || (!isExtraArgument && !ReferenceEquals(formattedArguments[parameterIndex], Type.Missing))) { result.Failure(new EzrIllegalOperationError($"Cannot override already defined argument \"{argumentName}\"!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); return []; } - formattedArguments[parameterIndex] = EzrObjectToCSharp(argumentObject, Parameters[parameterIndex].ParameterType, result); + if (isExtraArgument) + { + extraKeywordArguments.Value.Add(argumentName, argumentObject); + ReferencePool.TryRelease(argumentReference); + continue; + } + + formattedArguments[parameterIndex] = EzrObjectToCSharp(argumentObject, Parameters[parameterIndex].Info.ParameterType, result); if (result.ShouldReturn) return []; @@ -103,16 +165,24 @@ public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? inst // Handle unnamed parameter. // Find the next unfilled parameter, skip already assigned ones. - for (; nextUnnamedParamIndex < parametersLength && !ReferenceEquals(formattedArguments[nextUnnamedParamIndex], Type.Missing); nextUnnamedParamIndex++) + for (; nextUnnamedParamIndex < exposedParametersLength && !ReferenceEquals(formattedArguments[nextUnnamedParamIndex], Type.Missing); nextUnnamedParamIndex++) continue; - if (nextUnnamedParamIndex >= parametersLength) + bool allPositionalArgumentsFilled = nextUnnamedParamIndex >= exposedParametersLength; + if ((allPositionalArgumentsFilled || Parameters[nextUnnamedParamIndex].Optional) && AcceptsExtraPositionalArguments) + { + extraPositionalArguments.Value.Add(argumentObject); + ReferencePool.TryRelease(argumentReference); + continue; + } + + if (allPositionalArgumentsFilled) { result.Failure(new EzrUnexpectedArgumentError("Did not expect any more unnamed arguments!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); return []; } - formattedArguments[nextUnnamedParamIndex] = EzrObjectToCSharp(argumentObject, Parameters[nextUnnamedParamIndex].ParameterType, result); + formattedArguments[nextUnnamedParamIndex] = EzrObjectToCSharp(argumentObject, Parameters[nextUnnamedParamIndex].Info.ParameterType, result); if (result.ShouldReturn) return []; @@ -121,18 +191,37 @@ public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? inst } // Check for missing parameters, but skip parameters with default values. - for (int i = 0; i < parametersLength; i++) + for (int i = 0; i < exposedParametersLength; i++) { if (!ReferenceEquals(formattedArguments[i], Type.Missing)) continue; - if (!Parameters[i].HasDefaultValue) + (ParameterInfo parameterInfo, bool isOptional) = Parameters[i]; + if (!parameterInfo.HasDefaultValue && !isOptional) { result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{ParameterNames[i]}\"!", _executionContext, StartPosition, EndPosition)); return []; } - formattedArguments[i] = Parameters[i].DefaultValue; + formattedArguments[i] = parameterInfo.HasDefaultValue ? parameterInfo.DefaultValue : null; + } + + // Supply runtime-provided parameters. + for (int i = 0; i < RuntimeProvidedParameters.Length; i++) + { + Feature paramtype = RuntimeProvidedParameters[i].Type; + formattedArguments[exposedParametersLength + i] = paramtype switch + { + Feature.KeywordArguments => extraKeywordArguments.Value, + Feature.PositionalArguments => extraPositionalArguments.Value, + + Feature.CallerRef => this, + Feature.ExecutionRef => _executionContext, + Feature.InterpreterRef => interpreter, + Feature.ResultRef => result, + + _ => throw new NotImplementedException($"Case for handling runtime-provided parameter type \"{paramtype}\" has not been implemented!") + }; } return formattedArguments; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs index 6b42000..7b8b20f 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs @@ -1,6 +1,7 @@ using EzrSquared.Runtime.Types.Core.Errors; using System; using System.Reflection; +using System.Text; namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; @@ -36,13 +37,16 @@ public EzrSharpCompatibilityFunction(Delegate sharpFunction, Context parentConte /// public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) { - object?[] mappedArguments = CheckAndPopulateArguments(arguments, result); + object?[] mappedArguments = CheckAndPopulateArguments(arguments, interpreter, result); if (result.ShouldReturn) return; try { object? output = SharpMember.Invoke(Instance, mappedArguments); + if (result.ShouldReturn) + return; + CSharpToEzrObject(output, SharpMember.ReturnType, result); } catch (Exception error) @@ -54,8 +58,24 @@ public override void Execute(Reference[] arguments, Interpreter interpreter, Run /// public override string ToString(RuntimeResult result) { - return ParameterNames.Length > 0 - ? $"<{TypeName} \"{SharpMemberName}\", with \"{string.Join("\", \"", ParameterNames)}\">" - : $"<{TypeName} \"{SharpMemberName}\">"; + bool hasParameters = ParameterNames.Length > 0; + StringBuilder builder = new($"<{TypeName} \"{SharpMemberName}\""); + + if (hasParameters) + builder.Append($", with \"{string.Join("\", \"", ParameterNames)}\""); + + if (AcceptsExtraKeywordArguments) + { + builder.Append(hasParameters && AcceptsExtraPositionalArguments ? ", " : AcceptsExtraPositionalArguments || !hasParameters ? ", with " : " and "); + builder.Append("extra keyword arguments"); + } + + if (AcceptsExtraPositionalArguments) + { + builder.Append(hasParameters || AcceptsExtraKeywordArguments ? " and " : ", with "); + builder.Append("extra positional arguments"); + } + + return builder.Append('>').ToString(); } } diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs index 042e9fc..de494d3 100644 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; using EzrSquared.Runtime.WrapperAttributes; using EzrSquared.Util; @@ -118,7 +119,7 @@ public EzrSharpSourceTypeWrapper( EzrSharpSourceFunctionWrapper sourceMethod = new(method, null, Context, StartPosition, EndPosition); (wrappedMethod, methodName) = (sourceMethod, sourceMethod.SharpFunctionName); } - else if (method.GetCustomAttribute() is not null) + else if (method.GetCustomAttribute() is not null) { EzrSharpCompatibilityFunction compatMethod = new(method, null, Context, StartPosition, EndPosition); (wrappedMethod, methodName) = (compatMethod, compatMethod.SharpMemberName); @@ -143,7 +144,7 @@ public EzrSharpSourceTypeWrapper( string propertyName; // Check if property can be wrapped. - if (property.GetCustomAttribute() is not null) + if (property.GetCustomAttribute() is not null) { EzrSharpCompatibilityProperty compatWrapper = new(property, null, Context, StartPosition, EndPosition); (wrappedProperty, propertyName) = (compatWrapper, compatWrapper.SharpMemberName); @@ -167,7 +168,7 @@ public EzrSharpSourceTypeWrapper( string fieldName; // Check if property can be wrapped. - if (field.GetCustomAttribute() is not null) + if (field.GetCustomAttribute() is not null) { EzrSharpCompatibilityField compatWrapper = new(field, null, Context, StartPosition, EndPosition); (wrappedField, fieldName) = (compatWrapper, compatWrapper.SharpMemberName); diff --git a/src/Runtime/Types/Collections/EzrArray.cs b/src/Runtime/Types/Collections/EzrArray.cs index 0823b47..e16a9c9 100644 --- a/src/Runtime/Types/Collections/EzrArray.cs +++ b/src/Runtime/Types/Collections/EzrArray.cs @@ -1,5 +1,6 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.WrapperAttributes; using System; @@ -27,7 +28,7 @@ public class EzrArray : EzrObject, IEzrIndexedCollection public readonly IEzrObject[] Value; /// - [SharpAutoWrapper("length")] + [WrappedMember("length")] public int Count { get; } /// diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index 3aa5372..6bb8f02 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -2,6 +2,7 @@ using EzrSquared.Runtime.Types.Core; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; using EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; @@ -30,7 +31,7 @@ public class EzrDictionary : EzrObject, IEzrMutableObject, IEzrDictionary public readonly RuntimeEzrObjectDictionary Value; /// - [SharpAutoWrapper("length")] + [WrappedMember("length")] public int Count => Value.Count; /// diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index 8366fe2..a643e94 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -1,6 +1,7 @@ using EzrSquared.Runtime.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.WrapperAttributes; using System; @@ -28,7 +29,7 @@ public class EzrList : EzrObject, IEzrMutableObject, IEzrIndexedCollection public readonly RuntimeEzrObjectList Value; /// - [SharpAutoWrapper("length")] + [WrappedMember("length")] public int Count => Value.Count; /// The base value. diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index 1bf5d7e..41c193a 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -1,6 +1,7 @@ using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.WrapperAttributes; using System; @@ -34,7 +35,7 @@ public class EzrCharacterList : EzrObject, IEzrMutableObject, IEzrString, IEzrIn public string StringValue => Value.ToString(); /// - [SharpAutoWrapper("length")] + [WrappedMember("length")] public int Count => Value.Length; /// diff --git a/src/Runtime/Types/Core/Text/EzrString.cs b/src/Runtime/Types/Core/Text/EzrString.cs index 88908ef..ea2648d 100644 --- a/src/Runtime/Types/Core/Text/EzrString.cs +++ b/src/Runtime/Types/Core/Text/EzrString.cs @@ -1,6 +1,7 @@ using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.WrapperAttributes; using System; @@ -32,7 +33,7 @@ public class EzrString : EzrObject, IEzrString, IEzrIndexedCollection public string StringValue => Value; /// - [SharpAutoWrapper("length")] + [WrappedMember("length")] public int Count { get; } /// diff --git a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs index 2c801db..7a57e58 100644 --- a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs +++ b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs @@ -7,6 +7,7 @@ using EzrSquared.Runtime.Types.Core.Text; using EzrSquared.Util; using System; +using System.Text; namespace EzrSquared.Runtime.Types.Executables; @@ -83,8 +84,8 @@ public EzrRuntimeExecutable(string? name, Node body, (string Name, Node Node)[] protected internal void CheckAndPopulateArguments(Reference[] arguments, Context context, Interpreter interpreter, RuntimeResult result, bool ignoreExtraArguments) { // Create dictionary or list to store extra arguments, if allowed. - RuntimeEzrObjectDictionary? extraKeywordArguments = ExtraKeywordArguments.HasValue ? new() : null; - RuntimeEzrObjectList? extraPositionalArguments = ExtraPositionalArguments.HasValue ? new() : null; + Lazy extraKeywordArguments = new(); + Lazy extraPositionalArguments = new(); int currentIndexThroughParameters = 0; for (int i = 0; i < arguments.Length; i++) @@ -113,7 +114,7 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context else if (extraKeywordArguments is not null) // Otherwise, if extra keyword arguments (EKAs) are allowed: { // Add it to the EKA dictionary. - extraKeywordArguments.Update(new EzrString(keywordArgumentName, context, argumentObject.StartPosition, argumentObject.EndPosition), argumentObject, result); + extraKeywordArguments.Value.Update(new EzrString(keywordArgumentName, context, argumentObject.StartPosition, argumentObject.EndPosition), argumentObject, result); // Continue onto the next argument. ReferencePool.TryRelease(argument); @@ -139,7 +140,7 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context if (!isKeywordArgument && currentIndexThroughParameters >= Parameters.Length && extraPositionalArguments is not null) { // And a reference to it to the EPA list. - extraPositionalArguments.Add(ReferencePool.Get(argumentObject)); + extraPositionalArguments.Value.Add(ReferencePool.Get(argumentObject)); ReferencePool.TryRelease(argument); continue; @@ -203,11 +204,11 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context // If the extra keyword arguments dictionary should be set: if (ExtraKeywordArguments.HasValue) - context.Set(null, ExtraKeywordArguments.Value.Name, ReferencePool.Get(new EzrDictionary(extraKeywordArguments!, context, ExtraKeywordArguments.Value.StartPosition, ExtraKeywordArguments.Value.EndPosition), AccessMod.Private)); // Set it. + context.Set(null, ExtraKeywordArguments.Value.Name, ReferencePool.Get(new EzrDictionary(extraKeywordArguments!.Value, context, ExtraKeywordArguments.Value.StartPosition, ExtraKeywordArguments.Value.EndPosition), AccessMod.Private)); // Set it. // If the extra positional arguments list should be set: if (ExtraPositionalArguments.HasValue) - context.Set(null, ExtraPositionalArguments.Value.Name, ReferencePool.Get(new EzrList(extraPositionalArguments!, context, ExtraPositionalArguments.Value.StartPosition, ExtraPositionalArguments.Value.EndPosition), AccessMod.Private)); // Set it. + context.Set(null, ExtraPositionalArguments.Value.Name, ReferencePool.Get(new EzrList(extraPositionalArguments!.Value, context, ExtraPositionalArguments.Value.StartPosition, ExtraPositionalArguments.Value.EndPosition), AccessMod.Private)); // Set it. } /// @@ -251,19 +252,28 @@ public override int ComputeHashCode(RuntimeResult result) /// public override string ToString(RuntimeResult result) { - static string ToEnabledOrDisabled(bool enabled) + bool hasParameters = Parameters.Length > 0; + + StringBuilder builder = new($"<{TypeName} "); + builder.Append(IsAnonymous ? ExecutableName : $"\"{ExecutableName}\""); + + if (hasParameters) + builder.Append($", with \"{string.Join("\", \"", Array.ConvertAll(Parameters, param => param.Name))}\""); + + bool hasExtraKeywordArguments = ExtraKeywordArguments.HasValue; + bool hasExtraPositionalArguments = ExtraPositionalArguments.HasValue; + if (hasExtraKeywordArguments) { - return enabled ? "enabled" : "disabled"; + builder.Append(hasParameters && hasExtraPositionalArguments ? ", " : hasExtraPositionalArguments || !hasParameters ? ", with " : " and "); + builder.Append("extra keyword arguments"); } - string[] parameterNames = Array.ConvertAll(Parameters, parameter => parameter.Name); - return (Parameters.Length > 0, IsAnonymous) switch + if (hasExtraPositionalArguments) { - (true, true) => $"<{TypeName} {ExecutableName}, with \"{string.Join("\", \"", parameterNames)}\", extra keyword arguments {ToEnabledOrDisabled(ExtraKeywordArguments.HasValue)} and extra positional arguments {ToEnabledOrDisabled(ExtraPositionalArguments.HasValue)}>", - (true, false) => $"<{TypeName} \"{ExecutableName}\", with \"{string.Join("\", \"", parameterNames)}\", extra keyword arguments {ToEnabledOrDisabled(ExtraKeywordArguments.HasValue)} and extra positional arguments {ToEnabledOrDisabled(ExtraPositionalArguments.HasValue)}>", + builder.Append(hasParameters || hasExtraKeywordArguments ? " and " : ", with "); + builder.Append("extra positional arguments"); + } - (false, true) => $"<{TypeName} {ExecutableName} with extra keyword arguments {ToEnabledOrDisabled(ExtraKeywordArguments.HasValue)} and extra positional arguments {ToEnabledOrDisabled(ExtraPositionalArguments.HasValue)}>", - (false, false) => $"<{TypeName} \"{ExecutableName}\" with extra keyword arguments {ToEnabledOrDisabled(ExtraKeywordArguments.HasValue)} and extra positional arguments {ToEnabledOrDisabled(ExtraPositionalArguments.HasValue)}>", - }; + return builder.Append('>').ToString(); } } diff --git a/src/Shell/EzrShell.cs b/src/Shell/EzrShell.cs index d477b3e..0b4143c 100644 --- a/src/Shell/EzrShell.cs +++ b/src/Shell/EzrShell.cs @@ -97,7 +97,7 @@ ezrSquared [file] [-h or --help] [-l or --lexer-output] [-p or --parser-output] private static void ExecuteFile() { - CodeExecutor.CreateRuntimeContext(s_filePath); + CodeExecutor.CreateRuntimeContext(Path.GetFileName(s_filePath)); CodeExecutor.PopulateRuntimeContext(); ExecuteCode(File.ReadAllText(s_filePath, Encoding.UTF8)); From c2b908aaf7f40de1417f90f2df5148c65c7e5ce8 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 20 Dec 2024 17:41:54 +0530 Subject: [PATCH 101/113] Wrapper unification part 2. --- src/GlobalSuppressions.cs | 3 +- .../Collections/RuntimeEzrObjectDictionary.cs | 5 +- src/Runtime/Interpreter.cs | 6 +- .../Builtins/EzrBuiltinFunctions.cs | 1 - .../Builtins/EzrBuiltinsUtility.cs | 56 ++--- .../Attributes/WrappedMemberAttribute.cs | 17 +- .../EzrSharpCompatibilityType.cs | 60 ++++- .../Attributes/PrimaryConstructorAttribute.cs | 11 + .../EzrSharpSourceExecutableWrapper.cs | 209 ---------------- .../EzrSharpSourceFunctionWrapper.cs | 142 ----------- .../EzrSharpSourceTypeWrapper.cs | 232 ------------------ src/Runtime/Types/Collections/EzrArray.cs | 1 - .../Types/Collections/EzrDictionary.cs | 33 +-- src/Runtime/Types/Collections/EzrList.cs | 1 - .../Core/RuntimeErrors/EzrAssertionError.cs | 15 +- .../RuntimeErrors/EzrIllegalOperationError.cs | 26 +- .../Core/RuntimeErrors/EzrKeyNotFoundError.cs | 26 +- .../Types/Core/RuntimeErrors/EzrMathError.cs | 29 ++- .../EzrMissingRequiredArgumentError.cs | 26 +- .../EzrPrivateMemberOperationError.cs | 25 +- .../Core/RuntimeErrors/EzrRuntimeError.cs | 30 ++- .../RuntimeErrors/EzrUndefinedValueError.cs | 25 +- .../EzrUnexpectedArgumentError.cs | 25 +- .../RuntimeErrors/EzrUnexpectedTypeError.cs | 25 +- .../EzrUnsupportedWrappingError.cs | 25 +- .../RuntimeErrors/EzrValueOutOfRangeError.cs | 25 +- .../RuntimeErrors/EzrWrapperExecutionError.cs | 25 +- .../Types/Core/Text/EzrCharacterList.cs | 1 - src/Runtime/Types/Core/Text/EzrString.cs | 1 - .../SharpMethodParameters.cs | 72 ------ .../SharpMethodWrapperAttribute.cs | 72 ------ .../SharpTypeWrapperAttribute.cs | 56 ----- 32 files changed, 307 insertions(+), 999 deletions(-) create mode 100644 src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/PrimaryConstructorAttribute.cs delete mode 100644 src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs delete mode 100644 src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs delete mode 100644 src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs delete mode 100644 src/Runtime/WrapperAttributes/SharpMethodParameters.cs delete mode 100644 src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs delete mode 100644 src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs diff --git a/src/GlobalSuppressions.cs b/src/GlobalSuppressions.cs index 68d4a4a..9f9fee6 100644 --- a/src/GlobalSuppressions.cs +++ b/src/GlobalSuppressions.cs @@ -11,4 +11,5 @@ [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Collections.EzrList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrString.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.EzrSharpCompatibilityWrapper`1.EzrObjectToCSharp(EzrSquared.Runtime.Types.IEzrObject,System.Type,EzrSquared.Runtime.RuntimeResult)~System.Object")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Too many ternary operators.", Scope = "member", Target = "~M:EzrSquared.Runtime.WrapperAttributes.SharpAutoWrapperAttribute.ValidateMethod(System.Reflection.MethodBase,System.Boolean)~System.Boolean")] +[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Too many ternary operators.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes.WrappedMemberAttribute.ValidateMethod(System.Reflection.MethodBase,System.Boolean)~System.Boolean")] +[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Too many ternary operators.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes.WrappedMemberAttribute.ValidateType(System.Type,System.Boolean)~System.Boolean")] diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index 67dbcd3..7058a77 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -2,7 +2,7 @@ using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; using System.Collections; using System.Collections.Generic; @@ -192,7 +192,8 @@ public Reference Get(IEzrObject key, RuntimeResult result) /// The key to be checked. /// The object for returning errors. /// if the key was found, if any error occured or the key was not found. - public bool HasKey(IEzrObject key, RuntimeResult result) + [WrappedMember] + public bool HasKey(IEzrObject key, [Runtime(Feature.ResultRef)] RuntimeResult result) { int hash = key.ComputeHashCode(result); return !result.ShouldReturn && _items.ContainsKey(hash); diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index 9efac64..02ebcd0 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -6,7 +6,7 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; -using EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; using EzrSquared.Runtime.Types.Executables; using System; using System.Collections.Generic; @@ -1174,13 +1174,13 @@ private void VisitTryNode(TryNode node, Context executionContext, Context callin return; IEzrObject targetObject = RuntimeResult.Reference.Object; - if (targetObject is not EzrSharpSourceTypeWrapper target || !typeof(IEzrRuntimeError).IsAssignableFrom(target.SharpType)) + if (targetObject is not EzrSharpCompatibilityType target || !typeof(IEzrRuntimeError).IsAssignableFrom(target.SharpMember)) { RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected error type, but got object of type \"{targetObject.TypeName}\"!", executionContext, errorType.StartPosition, errorType.EndPosition)); return; } - if (target.SharpType.IsAssignableFrom(error.GetType())) + if (target.SharpMember.IsAssignableFrom(error.GetType())) { if (errorVariableNode is not null) { diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs index 6908142..c08786c 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs @@ -7,7 +7,6 @@ using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; -using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections.Generic; using System.Text; diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs index 52e5cb1..b438a59 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs +++ b/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs @@ -1,7 +1,7 @@ using EzrSquared.Runtime.Types.Core; using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; -using EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; namespace EzrSquared.Runtime.Types.CSharpWrappers.Builtins; @@ -56,36 +56,36 @@ public static void AddBuiltinIOFunctions(Context context) /// Adds all built-in types to the given context. /// /// The context to add to. - public static void AddBuiltinTypes(Context context) + public static void AddBuiltinTypes(Context context ) { - EzrSharpSourceTypeWrapper runtimeError = new(typeof(EzrRuntimeError), context, Position.None, Position.None); - context.Set(null, runtimeError.SharpTypeName, ReferencePool.Get(runtimeError, AccessMod.Constant)); + EzrSharpCompatibilityType runtimeError = new(typeof(EzrRuntimeError), context, Position.None, Position.None); + context.Set(null, runtimeError.SharpMemberName, ReferencePool.Get(runtimeError, AccessMod.Constant)); - EzrSharpSourceTypeWrapper assertionError = new(typeof(EzrAssertionError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper illegalOperationError = new(typeof(EzrIllegalOperationError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper keyNotFoundError = new(typeof(EzrKeyNotFoundError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper mathError = new(typeof(EzrMathError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper missingRequiredArgumentError = new(typeof(EzrMissingRequiredArgumentError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper privateMemberOperationError = new(typeof(EzrPrivateMemberOperationError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper undefinedValueError = new(typeof(EzrUndefinedValueError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper unexpectedArgumentError = new(typeof(EzrUnexpectedArgumentError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper unexpectedTypeError = new(typeof(EzrUnexpectedTypeError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper unsupportedWrappingError = new(typeof(EzrUnsupportedWrappingError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper valueOutOfRangeError = new(typeof(EzrValueOutOfRangeError), context, Position.None, Position.None); - EzrSharpSourceTypeWrapper wrapperExecutionError = new(typeof(EzrWrapperExecutionError), context, Position.None, Position.None); + EzrSharpCompatibilityType assertionError = new(typeof(EzrAssertionError), context, Position.None, Position.None); + EzrSharpCompatibilityType illegalOperationError = new(typeof(EzrIllegalOperationError), context, Position.None, Position.None); + EzrSharpCompatibilityType keyNotFoundError = new(typeof(EzrKeyNotFoundError), context, Position.None, Position.None); + EzrSharpCompatibilityType mathError = new(typeof(EzrMathError), context, Position.None, Position.None); + EzrSharpCompatibilityType missingRequiredArgumentError = new(typeof(EzrMissingRequiredArgumentError), context, Position.None, Position.None); + EzrSharpCompatibilityType privateMemberOperationError = new(typeof(EzrPrivateMemberOperationError), context, Position.None, Position.None); + EzrSharpCompatibilityType undefinedValueError = new(typeof(EzrUndefinedValueError), context, Position.None, Position.None); + EzrSharpCompatibilityType unexpectedArgumentError = new(typeof(EzrUnexpectedArgumentError), context, Position.None, Position.None); + EzrSharpCompatibilityType unexpectedTypeError = new(typeof(EzrUnexpectedTypeError), context, Position.None, Position.None); + EzrSharpCompatibilityType unsupportedWrappingError = new(typeof(EzrUnsupportedWrappingError), context, Position.None, Position.None); + EzrSharpCompatibilityType valueOutOfRangeError = new(typeof(EzrValueOutOfRangeError), context, Position.None, Position.None); + EzrSharpCompatibilityType wrapperExecutionError = new(typeof(EzrWrapperExecutionError), context, Position.None, Position.None); - context.Set(null, assertionError.SharpTypeName, ReferencePool.Get(assertionError, AccessMod.Constant)); - context.Set(null, illegalOperationError.SharpTypeName, ReferencePool.Get(illegalOperationError, AccessMod.Constant)); - context.Set(null, keyNotFoundError.SharpTypeName, ReferencePool.Get(keyNotFoundError, AccessMod.Constant)); - context.Set(null, mathError.SharpTypeName, ReferencePool.Get(mathError, AccessMod.Constant)); - context.Set(null, missingRequiredArgumentError.SharpTypeName, ReferencePool.Get(missingRequiredArgumentError, AccessMod.Constant)); - context.Set(null, privateMemberOperationError.SharpTypeName, ReferencePool.Get(privateMemberOperationError, AccessMod.Constant)); - context.Set(null, undefinedValueError.SharpTypeName, ReferencePool.Get(undefinedValueError, AccessMod.Constant)); - context.Set(null, unexpectedArgumentError.SharpTypeName, ReferencePool.Get(unexpectedArgumentError, AccessMod.Constant)); - context.Set(null, unexpectedTypeError.SharpTypeName, ReferencePool.Get(unexpectedTypeError, AccessMod.Constant)); - context.Set(null, unsupportedWrappingError.SharpTypeName, ReferencePool.Get(unsupportedWrappingError, AccessMod.Constant)); - context.Set(null, valueOutOfRangeError.SharpTypeName, ReferencePool.Get(valueOutOfRangeError, AccessMod.Constant)); - context.Set(null, wrapperExecutionError.SharpTypeName, ReferencePool.Get(wrapperExecutionError, AccessMod.Constant)); + context.Set(null, assertionError.SharpMemberName, ReferencePool.Get(assertionError, AccessMod.Constant)); + context.Set(null, illegalOperationError.SharpMemberName, ReferencePool.Get(illegalOperationError, AccessMod.Constant)); + context.Set(null, keyNotFoundError.SharpMemberName, ReferencePool.Get(keyNotFoundError, AccessMod.Constant)); + context.Set(null, mathError.SharpMemberName, ReferencePool.Get(mathError, AccessMod.Constant)); + context.Set(null, missingRequiredArgumentError.SharpMemberName, ReferencePool.Get(missingRequiredArgumentError, AccessMod.Constant)); + context.Set(null, privateMemberOperationError.SharpMemberName, ReferencePool.Get(privateMemberOperationError, AccessMod.Constant)); + context.Set(null, undefinedValueError.SharpMemberName, ReferencePool.Get(undefinedValueError, AccessMod.Constant)); + context.Set(null, unexpectedArgumentError.SharpMemberName, ReferencePool.Get(unexpectedArgumentError, AccessMod.Constant)); + context.Set(null, unexpectedTypeError.SharpMemberName, ReferencePool.Get(unexpectedTypeError, AccessMod.Constant)); + context.Set(null, unsupportedWrappingError.SharpMemberName, ReferencePool.Get(unsupportedWrappingError, AccessMod.Constant)); + context.Set(null, valueOutOfRangeError.SharpMemberName, ReferencePool.Get(valueOutOfRangeError, AccessMod.Constant)); + context.Set(null, wrapperExecutionError.SharpMemberName, ReferencePool.Get(wrapperExecutionError, AccessMod.Constant)); } /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs index 90d58fc..815d62d 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs @@ -6,7 +6,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; /// /// Attribute for C# types and members to be automatically wrapped from C# types into ezr² types. /// -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] public class WrappedMemberAttribute : Attribute { /// @@ -50,6 +50,21 @@ public WrappedMemberAttribute(string name, bool isReadOnly = false, bool isWrite Name = name; } + /// + /// Checks if the given type has the supported signature for wrapping. + /// + /// The type. + /// Disable exception throwing. + /// if valid, an exception or otherwise. + /// Thrown if the type is generic or has generic parameters. + public static bool ValidateType(Type type, bool dontThrow = false) + { + if (type.IsAbstract || type.IsGenericTypeDefinition) + return dontThrow ? false : throw new ArgumentException($"The \"{nameof(WrappedMemberAttribute)}\" attribute does not support abstract/generic type \"{type.Name}\".", nameof(type)); + + return true; + } + /// /// Checks if the given method has the supported signature for wrapping. /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs index df5064a..523670e 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs @@ -2,6 +2,7 @@ using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; using EzrSquared.Util; using System; using System.Collections.Generic; @@ -13,7 +14,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; /// /// Class to automatically wrap C# types so that they can be used in ezr². /// -public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper +public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper, IEzrObject { /// public override string TypeName { get; protected internal set; } = "csharp type"; @@ -21,11 +22,15 @@ public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper /// public override string Tag { get; protected internal set; } = "ezrSquared.CSharpType"; + /// + /// The primary wrapped constructor for the type. May be . + /// + public readonly EzrSharpCompatibilityConstructor? PrimaryConstructor; + /// /// Creates a new . /// /// The type to wrap. - /// Runtime result for carrying any errors. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. @@ -41,15 +46,10 @@ public EzrSharpCompatibilityType( | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type sharpType, - RuntimeResult result, Context parentContext, Position startPosition, Position endPosition) : base(sharpType, null, parentContext, startPosition, endPosition) + Context parentContext, Position startPosition, Position endPosition) : base(sharpType, null, parentContext, startPosition, endPosition) { Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; - - if (sharpType.IsAbstract || sharpType.IsGenericTypeDefinition) - { - result.Failure(new EzrUnsupportedWrappingError($"Cannot wrap generic/abstract C# type \"{SharpMember.Name}\"!", Context, StartPosition, EndPosition)); - return; - } + WrappedMemberAttribute.ValidateType(SharpMember, AutoWrapperAttribute is null); MethodInfo[] allStaticMethods = sharpType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); Dictionary duplicateNames = new(allStaticMethods.Length); @@ -109,9 +109,47 @@ public EzrSharpCompatibilityType( if (!WrappedMemberAttribute.ValidateMethod(constructor, constructorObject.AutoWrapperAttribute is null)) continue; - Context.Set(null, definedConstructors == 0 ? "make" : $"make_{definedConstructors}", ReferencePool.Get(constructorObject, AccessMod.Constant)); - definedConstructors++; + if (constructor.GetCustomAttribute() is not null) + { + if (PrimaryConstructor is not null) + throw new ArgumentException($"Type \"{SharpMember.Name}\" cannot have multiple primary constructors!", nameof(sharpType)); + + PrimaryConstructor = constructorObject; + continue; + } + + string name = definedConstructors == 0 ? "make" : $"make_{definedConstructors}"; + if (constructorObject.AutoWrapperAttribute is not WrappedMemberAttribute attr || string.IsNullOrEmpty(attr.Name)) + definedConstructors++; + else + { + if (Context.IsDefined(attr.Name)) + throw new ArgumentException($"Wrapped member with name \"{attr.Name}\" is already defined for type \"{SharpMember.Name}\".", nameof(sharpType)); + + name = attr.Name; + } + + Context.Set(null, name, ReferencePool.Get(constructorObject, AccessMod.Constant)); + } + } + + /// + public new void Update(Context context, Position startPosition, Position endPosition) + { + base.Update(context, startPosition, endPosition); + PrimaryConstructor?.Update(Context, startPosition, endPosition); + } + + /// + public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) + { + if (PrimaryConstructor is null) + { + base.Execute(arguments, interpreter, result); + return; } + + PrimaryConstructor.Execute(arguments, interpreter, result); } /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/PrimaryConstructorAttribute.cs b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/PrimaryConstructorAttribute.cs new file mode 100644 index 0000000..4ad4b0e --- /dev/null +++ b/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/PrimaryConstructorAttribute.cs @@ -0,0 +1,11 @@ +using System; + +namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; + +/// +/// Attribute that declares a primary constructor. +/// +[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] +public class PrimaryConstructorAttribute : Attribute +{ +} diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs deleted file mode 100644 index daf9078..0000000 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceExecutableWrapper.cs +++ /dev/null @@ -1,209 +0,0 @@ -global using WrapperArgumentPopulationResult = (System.Collections.Generic.Dictionary Arguments, System.Collections.Generic.List? ExtraPositionalArguments); - -using EzrSquared.Runtime.Types.Core.Errors; -using System; -using System.Collections.Generic; -using System.Text; - -namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; - -/// -/// Parent of all wrapper classes which wrap executable members written in C# so that they can be used in ezr². -/// -/// The context in which this object was created. -/// The starting position of the object. -/// The ending position of the object. -public abstract class EzrSharpSourceExecutableWrapper(Context parentContext, Position startPosition, Position endPosition) : EzrObject(parentContext, startPosition, endPosition) -{ - /// - public override string TypeName { get; protected internal set; } = "csharp source executable wrapper"; - - /// - public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceExecutableWrapper"; - - /// - /// The name of the executable's parameters and if they are required. - /// - public (string Name, bool IsRequired)[] Parameters = []; - - /// - /// Does the executable accept extra keyword arguments? - /// - public bool HasExtraKeywordArguments; - - /// - /// Does the executable accept extra positional arguments? - /// - public bool HasExtraPositionalArguments; - - /// - /// Converts a string from PascalCase to lowecase plain text, seperated by spaces. - /// - /// The text to convert in PascalCase. - /// The converted text in lowecase plain text. - internal protected static string PascalCaseToLowerCasePlainText(string text) - { - StringBuilder result = new(); - result.Append(char.ToLowerInvariant(text[0])); - - for (int i = 1; i < text.Length; ++i) - { - char c = text[i]; - if (char.IsUpper(c)) - result.Append(' ').Append(char.ToLowerInvariant(c)); - else - result.Append(c); - } - - return result.ToString(); - } - - /// - /// Converts an index to a power of two, so that the index can be used like an enum flag. - /// - /// - /// This function is used to check if all arguments have been provided to and types.
- /// The indices of the given arguments are converted to powers of two and bitwise-ored together, then bitwise-anded with the index of a defined parameter which is also converted to a power of two.
- /// Finally, if the result is the same as the power of two of the parameter's index, this tells the interpreter that the particular required parameter has been provided. - ///
- /// The index to be converted. - /// The power of two. - protected internal static int IndexToFlag(int index) - { - return (index++ < 3) ? index : (4 * index) - 8; - } - - /// - /// Checks and populates the arguments given by the user's ezr² code into a dictionary. - /// - /// The array of arguments. - /// Runtime result for carrying any errors. - /// The dictionary of all the arguments. - protected internal WrapperArgumentPopulationResult CheckAndPopulateArguments(Reference[] arguments, RuntimeResult result) - { - int totalRequiredArguments = 0; - foreach ((string Name, bool IsRequired) in Parameters) - { - if (IsRequired) - totalRequiredArguments++; - } - - int calculatedParameterIndex = 0; - int requiredKeywordArguments = 0; - int flaggedRequiredArguments = -1; - - Dictionary argumentReferences = new(arguments.Length); - List? extraPositionalArgumentReferences = HasExtraPositionalArguments ? new() : null; - - for (int i = 0; i < arguments.Length; i++) - { - string name; - int parameterIndex = 0; - Reference reference = arguments[i]; - - if (!string.IsNullOrEmpty(reference.Name) && !reference.IsRegistered && !reference.IsEmpty) - { - name = reference.Name; - if (argumentReferences.ContainsKey(name)) - { - result.Failure(new EzrIllegalOperationError($"Cannot override already defined argument \"{name}\"!", _executionContext, reference.Object.StartPosition, reference.Object.EndPosition)); - return (argumentReferences, extraPositionalArgumentReferences); - } - - parameterIndex = Array.FindIndex(Parameters, (param) => param.Name == name); - if (parameterIndex > -1) - { - argumentReferences.Add(name, reference); - requiredKeywordArguments++; - } - else if (HasExtraKeywordArguments) - { - argumentReferences.Add(name, reference); - parameterIndex = -1; - } - else - { - result.Failure(new EzrUnexpectedArgumentError($"Did not expect argument \"{name}\"!", _executionContext, reference.Object.StartPosition, reference.Object.EndPosition)); - return (argumentReferences, extraPositionalArgumentReferences); - } - } - else - { - IndexCheck: - if (Parameters.Length <= calculatedParameterIndex && !HasExtraPositionalArguments) - { - result.Failure(new EzrUnexpectedArgumentError( - requiredKeywordArguments > 0 - ? $"Only expected {Parameters.Length - requiredKeywordArguments} unnamed argument(s) as {requiredKeywordArguments} required argument(s) has/have been declared as (a) keyword argument(s)!" - : $"Only expected {Parameters.Length} unnamed argument(s)!", - _executionContext, StartPosition, EndPosition)); - break; - } - else if (totalRequiredArguments <= calculatedParameterIndex && HasExtraPositionalArguments) - { - extraPositionalArgumentReferences!.Add(reference); - continue; - } - - string argumentName = Parameters[calculatedParameterIndex].Name; - if (!argumentReferences.ContainsKey(argumentName)) - { - name = argumentName; - parameterIndex = calculatedParameterIndex; - - argumentReferences.Add(name, reference); - calculatedParameterIndex++; - } - else - { - calculatedParameterIndex++; - goto IndexCheck; - } - } - - if (parameterIndex > -1) - if (flaggedRequiredArguments < 0) - flaggedRequiredArguments = IndexToFlag(parameterIndex); - else - flaggedRequiredArguments |= IndexToFlag(parameterIndex); - } - - for (int i = 0; i < Parameters.Length; i++) - { - int parameterFlag = IndexToFlag(i); - if (Parameters[i].IsRequired && (flaggedRequiredArguments < 0 || (flaggedRequiredArguments & parameterFlag) != parameterFlag)) - { - result.Failure(new EzrMissingRequiredArgumentError($"Expected required argument \"{Parameters[i].Name}\"!", _executionContext, StartPosition, EndPosition)); - return (argumentReferences, extraPositionalArgumentReferences); - } - } - - return (argumentReferences, extraPositionalArgumentReferences); - } - - /// - public override void ComparisonEqual(IEzrObject other, RuntimeResult result) - { - bool equal = StrictEquals(other, result); - if (result.ShouldReturn) - return; - - result.Success(NewBooleanConstant(equal)); - } - - /// - public override void ComparisonNotEqual(IEzrObject other, RuntimeResult result) - { - bool equal = StrictEquals(other, result); - if (result.ShouldReturn) - return; - - result.Success(NewBooleanConstant(!equal)); - } - - /// - public override bool EvaluateBoolean(RuntimeResult result) - { - return true; - } -} diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs deleted file mode 100644 index be1a6e5..0000000 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceFunctionWrapper.cs +++ /dev/null @@ -1,142 +0,0 @@ -using EzrSquared.Runtime.WrapperAttributes; -using EzrSquared.Util; -using System; -using System.Reflection; - -namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; - -/// -/// A class to wrap methods written in C# so that they can be used in ezr². -/// -public partial class EzrSharpSourceFunctionWrapper : EzrSharpSourceExecutableWrapper -{ - /// - public override string TypeName { get; protected internal set; } = "csharp source function wrapper"; - - /// - public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceFunctionWrapper"; - - /// - /// The wrapped function. - /// - public readonly EzrSharpSourceWrappableMethod SharpFunction; - - /// - /// The name of the function, in snake_case. - /// - public readonly string SharpFunctionName; - - /// - /// Creates a new from a function's . - /// - /// The method to wrap. - /// The object which contains the method, if static. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - public EzrSharpSourceFunctionWrapper(MethodInfo function, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) - { - Exception? parameterException = SharpMethodWrapperAttribute.ValidateMethodParameters(function); - if (parameterException is not null) - throw parameterException; - - SharpFunction = (EzrSharpSourceWrappableMethod)function.CreateDelegate(typeof(EzrSharpSourceWrappableMethod), instance); - (SharpFunctionName, SharpMethodWrapperAttribute attribute) = GetFunctionInfo(function); - - AddParameters(attribute); - } - - /// - /// Creates a new from a function. - /// - /// The method to wrap. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - public EzrSharpSourceFunctionWrapper(EzrSharpSourceWrappableMethod function, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) - { - SharpFunction = function; - (SharpFunctionName, SharpMethodWrapperAttribute attribute) = GetFunctionInfo(function.Method); - - AddParameters(attribute); - } - - /// - /// Gets the function's ezr² (snake_case) name and wrapper attribute. - /// - /// The function's . - /// The function's ezr² name and wrapper attribute - /// - /// Thrown if the attribute was not found in the function - /// or if the name given in the function's is empty. - /// - private (string, SharpMethodWrapperAttribute) GetFunctionInfo(MethodInfo function) - { - SharpMethodWrapperAttribute attribute = function.GetCustomAttribute(true) - ?? throw new ArgumentException($"No \"{nameof(SharpMethodWrapperAttribute)}\" attribute found in function \"{function.Name}\"!", nameof(function)); - - if (string.IsNullOrEmpty(attribute.Name)) - throw new ArgumentException($"Name not provided in {nameof(SharpMethodWrapperAttribute)} of function \"{function.Name}\"!", nameof(function)); - - Tag = $"{Tag}.{attribute.Name}.{UIDProvider.Get()}"; - return (attribute.Name, attribute); - } - - /// - /// Adds the parameters of the function to be wrapped to the object. - /// - /// The attribute of the function containing the details for optional, required and extra keyword parameters. - private void AddParameters(SharpMethodWrapperAttribute attribute) - { - int requiredParameters = attribute.RequiredParameters.Length; - Parameters = new (string Name, bool IsRequired)[attribute.RequiredParameters.Length + attribute.OptionalParameters.Length]; - - for (int j = 0; j < requiredParameters; j++) - Parameters[j] = new(attribute.RequiredParameters[j], true); - - for (int j = 0; j < attribute.OptionalParameters.Length; j++) - Parameters[j + requiredParameters] = new(attribute.OptionalParameters[j], false); - - HasExtraKeywordArguments = attribute.HasExtraKeywordArguments; - HasExtraPositionalArguments = attribute.HasExtraPositionalArguments; - } - - /// - public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) - { - WrapperArgumentPopulationResult argumentReferences = CheckAndPopulateArguments(arguments, result); - if (result.ShouldReturn) - return; - - SharpFunction.Invoke(new SharpMethodParameters - ( - argumentReferences.Arguments, - argumentReferences.ExtraPositionalArguments, - _executionContext, - CreationContext, - Context, - StartPosition, - EndPosition, - interpreter, - result - )); - } - - /// - public override int ComputeHashCode(RuntimeResult result) - { - return HashCode.Combine(HashTag, SharpFunction); - } - - /// - public override bool StrictEquals(IEzrObject other, RuntimeResult result) - { - return (other as EzrSharpSourceFunctionWrapper)?.SharpFunction == SharpFunction && other.HashTag == HashTag; - } - - /// - public override string ToString(RuntimeResult result) - { - return $"<{TypeName} \"{SharpFunctionName}\">"; - } -} diff --git a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs b/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs deleted file mode 100644 index de494d3..0000000 --- a/src/Runtime/Types/CSharpWrappers/SourceWrappers/EzrSharpSourceTypeWrapper.cs +++ /dev/null @@ -1,232 +0,0 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; -using EzrSquared.Runtime.WrapperAttributes; -using EzrSquared.Util; -using System; -using System.Diagnostics.CodeAnalysis; -using System.Reflection; - -namespace EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; - -/// -/// A class to wrap types written in C# so that they can be used in ezr². -/// -public class EzrSharpSourceTypeWrapper : EzrSharpSourceExecutableWrapper -{ - /// - public override string TypeName { get; protected internal set; } = "csharp source type wrapper"; - - /// - public override string Tag { get; protected internal set; } = "ezrSquared.CSharpSourceTypeWrapper"; - - /// - /// The wrapped type. - /// - public readonly Type SharpType; - - /// - /// The name of the type, in snake_case. - /// - public readonly string SharpTypeName; - - /// - /// Reflection information about the type's constructor. - /// - public readonly ConstructorInfo Constructor; - - /// - /// Creates a new . - /// - /// The type to wrap. - /// The context in which this object was created. - /// The starting position of the object. - /// The ending position of the object. - /// - /// Thrown if the type to be wrapped is generic or if the was not found in the type. - /// - /// - /// Thrown if there are multiple methods/properties/fields with the same name. - /// - public EzrSharpSourceTypeWrapper( - - [DynamicallyAccessedMembers( - DynamicallyAccessedMemberTypes.PublicMethods - | DynamicallyAccessedMemberTypes.NonPublicMethods - | DynamicallyAccessedMemberTypes.PublicFields - | DynamicallyAccessedMemberTypes.NonPublicFields - | DynamicallyAccessedMemberTypes.PublicProperties - | DynamicallyAccessedMemberTypes.NonPublicProperties - | DynamicallyAccessedMemberTypes.PublicConstructors - | DynamicallyAccessedMemberTypes.NonPublicConstructors - )] Type type, - - Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) - { - SharpType = type; - - // Check if type inherits from IEzrObject. - if (!typeof(IEzrObject).IsAssignableFrom(SharpType)) - throw new ArgumentException($"A source wrapper cannot be used to wrap \"{type.Name}\", as it does not inherit {nameof(IEzrObject)}!", nameof(type)); - - // Check if generic or abstract. - if (type.IsAbstract || type.IsGenericTypeDefinition) - throw new ArgumentException($"Cannot wrap generic/abstract C# type \"{type.Name}\"!", nameof(type)); - - // Check for type attribute. - SharpTypeWrapperAttribute typeAttribute = type.GetCustomAttribute(true) - ?? throw new ArgumentException($"No \"{nameof(SharpTypeWrapperAttribute)}\" attribute found for type \"{type.Name}\"!", nameof(type)); - - // Set name and tag. - SharpTypeName = typeAttribute.Name; - Tag = $"{Tag}.{SharpTypeName}.{UIDProvider.Get()}"; - - Exception? typeAttributeException = SharpTypeWrapperAttribute.ValidateMethodParameters(type, - out (ConstructorInfo Info, SharpMethodWrapperAttribute Attribute)? constructor); - - if (typeAttributeException is not null) - throw typeAttributeException; - - // Get constructor parameters. - int requiredParameters = constructor!.Value.Attribute.RequiredParameters.Length; - Parameters = new (string Name, bool IsRequired)[constructor.Value.Attribute.RequiredParameters.Length + constructor.Value.Attribute.OptionalParameters.Length]; - - // Required parameters. - for (int j = 0; j < requiredParameters; j++) - Parameters[j] = new(constructor.Value.Attribute.RequiredParameters[j], true); - - // Optional parameters. - for (int j = 0; j < constructor.Value.Attribute.OptionalParameters.Length; j++) - Parameters[j + requiredParameters] = new(constructor.Value.Attribute.OptionalParameters[j], false); - - // Set variables. - HasExtraKeywordArguments = constructor.Value.Attribute.HasExtraKeywordArguments; - HasExtraPositionalArguments = constructor.Value.Attribute.HasExtraPositionalArguments; - Constructor = constructor.Value.Info; - - // Get static methods to wrap. - MethodInfo[] staticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); - for (int i = 0; i < staticMethods.Length; i++) - { - MethodInfo method = staticMethods[i]; - - IEzrObject wrappedMethod; - string methodName; - - // Check if method can be wrapped. - if (method.GetCustomAttribute(false) is not null) - { - EzrSharpSourceFunctionWrapper sourceMethod = new(method, null, Context, StartPosition, EndPosition); - (wrappedMethod, methodName) = (sourceMethod, sourceMethod.SharpFunctionName); - } - else if (method.GetCustomAttribute() is not null) - { - EzrSharpCompatibilityFunction compatMethod = new(method, null, Context, StartPosition, EndPosition); - (wrappedMethod, methodName) = (compatMethod, compatMethod.SharpMemberName); - } - else - continue; - - // Check if name already defined. - if (Context.IsDefined(methodName)) - throw new AmbiguousMatchException($"Cannot wrap CSharp static method \"{methodName}\" of type {type.Name} as another member with the same name already exists!"); - - // Set in context. - Context.Set(null, methodName, ReferencePool.Get(wrappedMethod, AccessMod.Constant)); - } - - // Get public static properties. - PropertyInfo[] publicStaticProperties = type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); - for (int i = 0; i < publicStaticProperties.Length; i++) - { - PropertyInfo property = publicStaticProperties[i]; - IEzrObject wrappedProperty; - string propertyName; - - // Check if property can be wrapped. - if (property.GetCustomAttribute() is not null) - { - EzrSharpCompatibilityProperty compatWrapper = new(property, null, Context, StartPosition, EndPosition); - (wrappedProperty, propertyName) = (compatWrapper, compatWrapper.SharpMemberName); - } - else - continue; - - // Check if name already defined. - if (Context.IsDefined(propertyName)) - throw new AmbiguousMatchException($"Cannot wrap CSharp static property \"{propertyName}\" of type {type.Name} as another member with the same name already exists!"); - - Context.Set(null, propertyName, ReferencePool.Get(wrappedProperty, AccessMod.Constant)); - } - - // Get public static fields. - FieldInfo[] publicStaticFields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); - for (int i = 0; i < publicStaticFields.Length; i++) - { - FieldInfo field = publicStaticFields[i]; - IEzrObject wrappedField; - string fieldName; - - // Check if property can be wrapped. - if (field.GetCustomAttribute() is not null) - { - EzrSharpCompatibilityField compatWrapper = new(field, null, Context, StartPosition, EndPosition); - (wrappedField, fieldName) = (compatWrapper, compatWrapper.SharpMemberName); - } - else - continue; - - // Check if name already defined. - if (Context.IsDefined(fieldName)) - throw new AmbiguousMatchException($"Cannot wrap CSharp static fieldName \"{fieldName}\" of type {type.Name} as another member with the same name already exists!"); - - Context.Set(null, fieldName, ReferencePool.Get(wrappedField, AccessMod.Constant)); - } - } - - /// - public override void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result) - { - WrapperArgumentPopulationResult argumentReferences = CheckAndPopulateArguments(arguments, result); - if (result.ShouldReturn) - return; - - IEzrObject newObject = (IEzrObject)Constructor.Invoke( - [ - new SharpMethodParameters - ( - argumentReferences.Arguments, - argumentReferences.ExtraPositionalArguments, - _executionContext, - CreationContext, - Context, - StartPosition, - EndPosition, - interpreter, - result - ) - ] - ); - - if (!result.ShouldReturn) - result.Success(ReferencePool.Get(newObject, AccessMod.PrivateConstant)); - } - - /// - public override int ComputeHashCode(RuntimeResult result) - { - return HashCode.Combine(HashTag, SharpType); - } - - /// - public override bool StrictEquals(IEzrObject other, RuntimeResult result) - { - return (other as EzrSharpSourceTypeWrapper)?.SharpType == SharpType && other.HashTag == HashTag; - } - - /// - public override string ToString(RuntimeResult result) - { - return $"<{TypeName} \"{SharpTypeName}\">"; - } -} diff --git a/src/Runtime/Types/Collections/EzrArray.cs b/src/Runtime/Types/Collections/EzrArray.cs index e16a9c9..e282b70 100644 --- a/src/Runtime/Types/Collections/EzrArray.cs +++ b/src/Runtime/Types/Collections/EzrArray.cs @@ -2,7 +2,6 @@ using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; -using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections; using System.Collections.Generic; diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index 6bb8f02..099ba6b 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -1,12 +1,9 @@ using EzrSquared.Runtime.Collections; -using EzrSquared.Runtime.Types.Core; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; -using EzrSquared.Runtime.Types.CSharpWrappers.SourceWrappers; -using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections; using System.Collections.Generic; @@ -47,7 +44,7 @@ public EzrDictionary(RuntimeEzrObjectDictionary value, Context parentContext, Po Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Value.Count))!, Value, Context, StartPosition, EndPosition), AccessMod.Constant)); Context.Set(null, "remove_by_hash", ReferencePool.Get(new EzrSharpCompatibilityFunction(Value.RemoveHash, Context, StartPosition, EndPosition), AccessMod.Constant)); - Context.Set(null, "has_key", ReferencePool.Get(new EzrSharpSourceFunctionWrapper(DictionaryExists, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "has_key", ReferencePool.Get(new EzrSharpCompatibilityFunction(Value.HasKey, Context, StartPosition, EndPosition), AccessMod.Constant)); } /// @@ -91,34 +88,6 @@ IEnumerator IEnumerable.GetEnumerator() return GetEnumerator(); } - /// - /// Basic key checking function. Implements . - /// - /// - /// ezr² parameters: - /// - /// - /// key - /// () The key to check for. - /// - /// - /// - /// ezr² return type: - /// - /// - /// The constructor arguments. - [SharpMethodWrapper("has_key", RequiredParameters = ["key"])] - private void DictionaryExists(SharpMethodParameters arguments) - { - Reference reference = arguments.ArgumentReferences["key"]; - - bool hasKey = Value.HasKey(reference.Object, arguments.Result); - if (arguments.Result.ShouldReturn) - return; - - arguments.Result.Success(NewBooleanConstant(hasKey)); - } - /// public override void ComparisonEqual(IEzrObject other, RuntimeResult result) { diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index a643e94..990e4aa 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -3,7 +3,6 @@ using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; -using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections; using System.Collections.Generic; diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs index d42f331..c346211 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -8,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("assertion_error")] +[WrappedMember("assertion_error")] public class EzrAssertionError(Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Assertion failed", "The assertion conditions were not met!", context, startPosition, endPosition) { /// @@ -20,7 +21,11 @@ public class EzrAssertionError(Context context, Position startPosition, Position /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper] - public EzrAssertionError(SharpMethodParameters arguments) : this(arguments.ExecutionContext, arguments.StartPosition, arguments.EndPosition) { } + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrAssertionError( + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this(executionContext, wrapper.StartPosition, wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs index e43db1d..d4a18a6 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -9,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("illegal_operation_error")] +[WrappedMember("illegal_operation_error")] public class EzrIllegalOperationError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Illegal operation", details, context, startPosition, endPosition) { /// @@ -21,13 +22,16 @@ public class EzrIllegalOperationError(string details, Context context, Position /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["details"])] - public EzrIllegalOperationError(SharpMethodParameters arguments) : this( - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) - { } + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrIllegalOperationError(string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs index 303691d..9564326 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -9,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("key_not_found_error")] +[WrappedMember("key_not_found_error")] public class EzrKeyNotFoundError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Key not found", details, context, startPosition, endPosition) { /// @@ -21,13 +22,16 @@ public class EzrKeyNotFoundError(string details, Context context, Position start /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["details"])] - public EzrKeyNotFoundError(SharpMethodParameters arguments) : this( - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) - { } + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrKeyNotFoundError(string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs index 1772dc2..664ecae 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -10,7 +11,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("math_error")] +[WrappedMember("math_error")] public class EzrMathError(string title, string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError(title, details, context, startPosition, endPosition) { /// @@ -22,14 +23,18 @@ public class EzrMathError(string title, string details, Context context, Positio /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["title", "details"])] - public EzrMathError(SharpMethodParameters arguments) : this( - GetStringArgument("title", arguments.ArgumentReferences["title"].Object, arguments.ExecutionContext, arguments.Result), - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) - { } + /// The title of the error. + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrMathError(string title, string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + title, + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs index c2be2b9..5c4820f 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -9,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("missing_required_argument_error")] +[WrappedMember("missing_required_argument_error")] public class EzrMissingRequiredArgumentError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Missing required argument", details, context, startPosition, endPosition) { /// @@ -21,13 +22,16 @@ public class EzrMissingRequiredArgumentError(string details, Context context, Po /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["details"])] - public EzrMissingRequiredArgumentError(SharpMethodParameters arguments) : this( - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) - { } + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrMissingRequiredArgumentError(string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs index a49ec2e..98ea7c6 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -9,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("private_member_operation_error")] +[WrappedMember("private_member_operation_error")] public class EzrPrivateMemberOperationError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Private member operation", details, context, startPosition, endPosition) { /// @@ -21,13 +22,17 @@ public class EzrPrivateMemberOperationError(string details, Context context, Pos /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["details"])] - public EzrPrivateMemberOperationError(SharpMethodParameters arguments) : this( - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrPrivateMemberOperationError(string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs index f1eb24e..55f8c9f 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs @@ -1,5 +1,6 @@ using EzrSquared.Runtime.Types.Core.Text; -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; using System; using System.Text; @@ -8,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// /// Implementation of with some utility methods. /// -[SharpTypeWrapper("runtime_error")] +[WrappedMember("runtime_error")] public class EzrRuntimeError : EzrObject, IEzrRuntimeError { /// @@ -52,20 +53,23 @@ public EzrRuntimeError(string title, string details, Context context, Position s Context.Set(null, "details", ReferencePool.Get(new EzrString(Details, Context, StartPosition, EndPosition), AccessMod.Constant)); } - /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["title", "details"])] - public EzrRuntimeError(SharpMethodParameters arguments) : this( - GetStringArgument("title", arguments.ArgumentReferences["title"].Object, arguments.ExecutionContext, arguments.Result), - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) - { } + /// The title of the error. + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrRuntimeError(string title, string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + title, + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } /// /// Converts the given argument to a string. diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs index 60f6dc6..cee154a 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -9,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("undefined_value_error")] +[WrappedMember("undefined_value_error")] public class EzrUndefinedValueError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Undefined value", details, context, startPosition, endPosition) { /// @@ -21,13 +22,17 @@ public class EzrUndefinedValueError(string details, Context context, Position st /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["details"])] - public EzrUndefinedValueError(SharpMethodParameters arguments) : this( - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrUndefinedValueError(string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs index ed00270..667989f 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -9,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("unexpected_argument_error")] +[WrappedMember("unexpected_argument_error")] public class EzrUnexpectedArgumentError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unexpected argument(s)", details, context, startPosition, endPosition) { /// @@ -21,13 +22,17 @@ public class EzrUnexpectedArgumentError(string details, Context context, Positio /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["details"])] - public EzrUnexpectedArgumentError(SharpMethodParameters arguments) : this( - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrUnexpectedArgumentError(string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs index 71fc49f..6ab622a 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -9,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("unexpected_type_error")] +[WrappedMember("unexpected_type_error")] public class EzrUnexpectedTypeError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unexpected type", details, context, startPosition, endPosition) { /// @@ -21,13 +22,17 @@ public class EzrUnexpectedTypeError(string details, Context context, Position st /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["details"])] - public EzrUnexpectedTypeError(SharpMethodParameters arguments) : this( - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrUnexpectedTypeError(string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs index 458e573..96dc5fd 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -9,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("unsupported_wrapping_error")] +[WrappedMember("unsupported_wrapping_error")] public class EzrUnsupportedWrappingError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unsupported wrapping", details, context, startPosition, endPosition) { /// @@ -21,13 +22,17 @@ public class EzrUnsupportedWrappingError(string details, Context context, Positi /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["details"])] - public EzrUnsupportedWrappingError(SharpMethodParameters arguments) : this( - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrUnsupportedWrappingError(string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs index 829e5e8..80c1c30 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -9,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("value_out_of_range_error")] +[WrappedMember("value_out_of_range_error")] public class EzrValueOutOfRangeError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Value out of range", details, context, startPosition, endPosition) { /// @@ -21,13 +22,17 @@ public class EzrValueOutOfRangeError(string details, Context context, Position s /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["details"])] - public EzrValueOutOfRangeError(SharpMethodParameters arguments) : this( - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrValueOutOfRangeError(string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs index 811fbc3..87ff7b1 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.WrapperAttributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -9,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[SharpTypeWrapper("wrapper_execution_error")] +[WrappedMember("wrapper_execution_error")] public class EzrWrapperExecutionError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Wrapper execution error", details, context, startPosition, endPosition) { /// @@ -21,13 +22,17 @@ public class EzrWrapperExecutionError(string details, Context context, Position /// /// Wrapper constructor for creating the error object. /// - /// The constructor arguments. - [SharpMethodWrapper(RequiredParameters = ["details"])] - public EzrWrapperExecutionError(SharpMethodParameters arguments) : this( - GetStringArgument("details", arguments.ArgumentReferences["details"].Object, arguments.ExecutionContext, arguments.Result), - arguments.ExecutionContext, - arguments.StartPosition, - arguments.EndPosition - ) + /// Details on why the error happened. + /// The caller. + /// The execution context. + [WrappedMember, PrimaryConstructor] + public EzrWrapperExecutionError(string details, + [Runtime(Feature.CallerRef)] IEzrObject wrapper, + [Runtime(Feature.ExecutionRef)] Context executionContext) + : this( + details, + executionContext, + wrapper.StartPosition, + wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index 41c193a..16fb67f 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -3,7 +3,6 @@ using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; -using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections; using System.Collections.Generic; diff --git a/src/Runtime/Types/Core/Text/EzrString.cs b/src/Runtime/Types/Core/Text/EzrString.cs index ea2648d..931a3e8 100644 --- a/src/Runtime/Types/Core/Text/EzrString.cs +++ b/src/Runtime/Types/Core/Text/EzrString.cs @@ -3,7 +3,6 @@ using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; -using EzrSquared.Runtime.WrapperAttributes; using System; using System.Collections; using System.Collections.Generic; diff --git a/src/Runtime/WrapperAttributes/SharpMethodParameters.cs b/src/Runtime/WrapperAttributes/SharpMethodParameters.cs deleted file mode 100644 index 07e48be..0000000 --- a/src/Runtime/WrapperAttributes/SharpMethodParameters.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Collections.Generic; - -namespace EzrSquared.Runtime.WrapperAttributes; - -/// -/// Class for the paramters of a wrapped C# method. -/// -/// See . -/// See . -/// See . -/// See . -/// See . -/// See . -/// See . -/// See . -/// See . -public class SharpMethodParameters( - Dictionary argumentReferences, - List? extraPositionalArgumentReferences, - Context executionContext, - Context creationContext, - Context methodContext, - Position startPosition, - Position endPosition, - Interpreter interpreter, - RuntimeResult result) -{ - /// - /// The references to the actual ezr² arguments. - /// - public Dictionary ArgumentReferences = argumentReferences; - - /// - /// The references to optional extra positional ezr² arguments. - /// - public List? ExtraPositionalArgumentReferences = extraPositionalArgumentReferences; - - /// - /// The context under which the method is being executed. - /// - public Context ExecutionContext = executionContext; - - /// - /// The context under which the method wrapper was created. - /// - public Context CreationContext = creationContext; - - /// - /// The context of the method wrapper itself. - /// - public Context MethodContext = methodContext; - - /// - /// The starting position of the method wrapper object. - /// - public Position StartPosition = startPosition; - - /// - /// The ending position of the method wrapper object. - /// - public Position EndPosition = endPosition; - - /// - /// The interpreter executing the method. - /// - public Interpreter Interpreter = interpreter; - - /// - /// The runtime result to return values or to throw errors. - /// - public RuntimeResult Result = result; -} diff --git a/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs deleted file mode 100644 index 79898ff..0000000 --- a/src/Runtime/WrapperAttributes/SharpMethodWrapperAttribute.cs +++ /dev/null @@ -1,72 +0,0 @@ -global using EzrSharpSourceWrappableMethod = System.Action; - -using System; -using System.Reflection; - -namespace EzrSquared.Runtime.WrapperAttributes; - -/// -/// Attribute for C# methods and constructors which will be wrapped into ezr². -/// -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, AllowMultiple = false, Inherited = true)] -public class SharpMethodWrapperAttribute : Attribute -{ - /// - /// The ezr² name for the method, optional. - /// - public readonly string Name = string.Empty; - - /// - /// The ezr² names of the required parameters of the method. - /// - public string[] RequiredParameters = []; - - /// - /// The ezr² names of the optional parameters of the method. - /// - public string[] OptionalParameters = []; - - /// - /// Does this method support additional keyword arguments (kwargs)? - /// - public bool HasExtraKeywordArguments; - - /// - /// Does this method support additional positional arguments (args)? - /// - public bool HasExtraPositionalArguments; - - /// - /// Creates a new instance of with a name. - /// - /// The ezr² name for the method. - public SharpMethodWrapperAttribute(string name) - { - Name = name; - } - - /// - /// Creates a new instance of . - /// - public SharpMethodWrapperAttribute() { } - - /// - /// Checks if the given method or constructor has the required parameters. - /// - /// The method or constructor to check. - /// if the check was successful, an otherwise. - public static Exception? ValidateMethodParameters(MethodBase methodInfo) - { - // Get the parameter types of the method - Type[] parameterTypes = Array.ConvertAll(methodInfo.GetParameters(), p => p.ParameterType); - - // Check if the number of parameters matches - if (parameterTypes.Length != 1) - return new TargetParameterCountException($"\"{methodInfo.Name}\": Method or constructor must have exactly one parameter, as it uses the {nameof(SharpMethodWrapperAttribute)} attribute."); - - // Check if the required parameter types match - return parameterTypes[0] != typeof(SharpMethodParameters) - ? new FormatException($"\"{methodInfo.Name}\": Parameter 1 must be of type {nameof(SharpMethodParameters)}, as it uses the {nameof(SharpMethodWrapperAttribute)} attribute.") - : null; - } -} diff --git a/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs b/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs deleted file mode 100644 index 098ca71..0000000 --- a/src/Runtime/WrapperAttributes/SharpTypeWrapperAttribute.cs +++ /dev/null @@ -1,56 +0,0 @@ -using EzrSquared.Runtime.Types; -using System; -using System.Diagnostics.CodeAnalysis; -using System.Reflection; - -namespace EzrSquared.Runtime.WrapperAttributes; - -/// -/// Attribute for C# classes which will be wrapped into ezr². -/// -/// The ezr² name for the type. -[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] -public class SharpTypeWrapperAttribute(string name) : Attribute -{ - /// - /// The ezr² name for the type. - /// - public readonly string Name = name; - - /// - /// Checks if the given type has a constructor with the attribute. - /// - /// The type to check. - /// The constructor and its attribute. - /// if the check was successful, an otherwise. - public static Exception? ValidateMethodParameters( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] - Type typeInfo, - - out (ConstructorInfo Info, SharpMethodWrapperAttribute Attribute)? constructor) - { - constructor = null; - if (!typeof(IEzrObject).IsAssignableFrom(typeInfo)) - return new ArgumentException($"Expected type \"{typeInfo.Name}\" to inherit from {nameof(IEzrObject)}, as it uses the attribute \"{nameof(SharpTypeWrapperAttribute)}\"", nameof(typeInfo)); - - ConstructorInfo[] constructors = typeInfo.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance); - - foreach (ConstructorInfo constructorInfo in constructors) - { - SharpMethodWrapperAttribute? attribute = constructorInfo.GetCustomAttribute(false); - if (constructor is not null && attribute is not null) - return new AmbiguousMatchException($"Found multiple constructors for type \"{typeInfo.Name}\" with attribute {nameof(SharpMethodWrapperAttribute)}"); - - if (attribute is not null) - { - constructor = (constructorInfo, attribute); - if (SharpMethodWrapperAttribute.ValidateMethodParameters(constructorInfo) is Exception exception) - return exception; - } - } - - return constructor is null - ? new ArgumentException($"No constructor with attribute {nameof(SharpMethodWrapperAttribute)} found for type \"{typeInfo.Name}\"!", nameof(typeInfo)) - : null; - } -} \ No newline at end of file From f932e449b3332a7251842cc3b695f5f96e59ebdf Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 20 Dec 2024 20:26:59 +0530 Subject: [PATCH 102/113] Wrapper unification part 3. --- src/Executor/CodeExecutor.cs | 8 +- src/GlobalSuppressions.cs | 6 +- .../Collections/RuntimeEzrObjectDictionary.cs | 12 +-- src/Runtime/Interpreter.cs | 4 +- .../Builtins/EzrBuiltinFunctions.cs | 83 ++++++++----------- .../Builtins/EzrBuiltinsUtility.cs | 58 ++++++------- src/Runtime/Types/Collections/EzrArray.cs | 8 +- .../Types/Collections/EzrDictionary.cs | 14 ++-- src/Runtime/Types/Collections/EzrList.cs | 8 +- .../Core/RuntimeErrors/EzrAssertionError.cs | 12 +-- .../RuntimeErrors/EzrIllegalOperationError.cs | 15 ++-- .../Core/RuntimeErrors/EzrKeyNotFoundError.cs | 15 ++-- .../Types/Core/RuntimeErrors/EzrMathError.cs | 15 ++-- .../EzrMissingRequiredArgumentError.cs | 15 ++-- .../EzrPrivateMemberOperationError.cs | 12 +-- .../Core/RuntimeErrors/EzrRuntimeError.cs | 15 ++-- .../RuntimeErrors/EzrUndefinedValueError.cs | 12 +-- .../EzrUnexpectedArgumentError.cs | 12 +-- .../RuntimeErrors/EzrUnexpectedTypeError.cs | 12 +-- .../EzrUnsupportedWrappingError.cs | 12 +-- .../RuntimeErrors/EzrValueOutOfRangeError.cs | 12 +-- .../RuntimeErrors/EzrWrapperExecutionError.cs | 12 +-- .../Types/Core/Text/EzrCharacterList.cs | 8 +- src/Runtime/Types/Core/Text/EzrString.cs | 8 +- .../DontWrapMemberAttribute.cs | 2 +- .../EzrObjectWrapper.cs} | 27 +++--- .../EzrTypeWrapper.cs} | 41 +++++---- .../EzrWrapper.cs} | 25 +++--- .../Members/EzrFieldWrapper.cs} | 8 +- .../Members/EzrPropertyWrapper.cs} | 8 +- .../Members/Methods/EzrConstructorWrapper.cs} | 11 ++- .../Members/Methods/EzrMethodBaseWrapper.cs} | 26 +++--- .../Members/Methods/EzrMethodWrapper.cs} | 8 +- .../Members/Methods}/Feature.cs | 4 +- .../Methods/FeatureParameterAttribute.cs} | 16 ++-- .../Members/Methods/ParameterAttribute.cs} | 8 +- .../Methods}/PrimaryConstructorAttribute.cs | 2 +- .../WrapMemberAttribute.cs} | 18 ++-- 38 files changed, 288 insertions(+), 304 deletions(-) rename src/Runtime/Types/{CSharpWrappers => }/Builtins/EzrBuiltinFunctions.cs (78%) rename src/Runtime/Types/{CSharpWrappers => }/Builtins/EzrBuiltinsUtility.cs (55%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/Attributes => Wrappers}/DontWrapMemberAttribute.cs (84%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs => Wrappers/EzrObjectWrapper.cs} (73%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs => Wrappers/EzrTypeWrapper.cs} (74%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs => Wrappers/EzrWrapper.cs} (94%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs => Wrappers/Members/EzrFieldWrapper.cs} (88%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs => Wrappers/Members/EzrPropertyWrapper.cs} (88%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs => Wrappers/Members/Methods/EzrConstructorWrapper.cs} (88%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs => Wrappers/Members/Methods/EzrMethodBaseWrapper.cs} (86%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs => Wrappers/Members/Methods/EzrMethodWrapper.cs} (82%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes => Wrappers/Members/Methods}/Feature.cs (88%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/RuntimeAttribute.cs => Wrappers/Members/Methods/FeatureParameterAttribute.cs} (78%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/ExposeAttribute.cs => Wrappers/Members/Methods/ParameterAttribute.cs} (70%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes => Wrappers/Members/Methods}/PrimaryConstructorAttribute.cs (70%) rename src/Runtime/Types/{CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs => Wrappers/WrapMemberAttribute.cs} (85%) diff --git a/src/Executor/CodeExecutor.cs b/src/Executor/CodeExecutor.cs index a148035..d9fe8ec 100644 --- a/src/Executor/CodeExecutor.cs +++ b/src/Executor/CodeExecutor.cs @@ -1,6 +1,6 @@ using EzrSquared.Runtime; -using EzrSquared.Runtime.Types.CSharpWrappers.Builtins; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; +using EzrSquared.Runtime.Types.Builtins; +using EzrSquared.Runtime.Types.Wrappers; using EzrSquared.Syntax; using EzrSquared.Syntax.Errors; using System; @@ -86,8 +86,8 @@ public static void AddToContext(Reference reference, string name) /// /// The wrapped object to add. /// The accessibility modifiers for the reference. Defaults to . - /// See . - public static void AddToContext(EzrSharpCompatibilityWrapper wrapper, AccessMod accessibilityModifiers = AccessMod.Constant) + /// See . + public static void AddToContext(EzrWrapper wrapper, AccessMod accessibilityModifiers = AccessMod.Constant) where TMemberInfo : MemberInfo { if (RuntimeContext is null) diff --git a/src/GlobalSuppressions.cs b/src/GlobalSuppressions.cs index 9f9fee6..63184be 100644 --- a/src/GlobalSuppressions.cs +++ b/src/GlobalSuppressions.cs @@ -10,6 +10,6 @@ [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrCharacterList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Collections.EzrList.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] [assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Core.Text.EzrString.Multiplication(EzrSquared.Runtime.Types.IEzrObject,EzrSquared.Runtime.RuntimeResult)")] -[assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.EzrSharpCompatibilityWrapper`1.EzrObjectToCSharp(EzrSquared.Runtime.Types.IEzrObject,System.Type,EzrSquared.Runtime.RuntimeResult)~System.Object")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Too many ternary operators.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes.WrappedMemberAttribute.ValidateMethod(System.Reflection.MethodBase,System.Boolean)~System.Boolean")] -[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Too many ternary operators.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes.WrappedMemberAttribute.ValidateType(System.Type,System.Boolean)~System.Boolean")] +[assembly: SuppressMessage("Style", "IDE0078:Use pattern matching", Justification = "Recommended fix breaks code.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Wrappers.EzrWrapper`1.EzrObjectToCSharp(EzrSquared.Runtime.Types.IEzrObject,System.Type,EzrSquared.Runtime.RuntimeResult)~System.Object")] +[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Too many ternary operators.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Wrappers.WrapMemberAttribute.ValidateMethod(System.Reflection.MethodBase,System.Boolean)~System.Boolean")] +[assembly: SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Too many ternary operators.", Scope = "member", Target = "~M:EzrSquared.Runtime.Types.Wrappers.WrapMemberAttribute.ValidateType(System.Type,System.Boolean)~System.Boolean")] diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index 7058a77..a636264 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -1,8 +1,8 @@ using EzrSquared.Runtime.Types; using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; using System.Collections; using System.Collections.Generic; @@ -21,7 +21,7 @@ public class RuntimeEzrObjectDictionary : IMutable, /// /// The number of s in the . /// - [WrappedMember("length")] + [WrapMember("length")] public int Count => _items.Count; /// @@ -117,7 +117,7 @@ public bool Remove(IEzrObject key, RuntimeResult result) /// /// The key (hash) to be removed. /// if the operation was successful, if not. - [WrappedMember("remove_by_hash")] + [WrapMember("remove_by_hash")] public bool RemoveHash(int key) { if (_items.TryGetValue(key, out KeyValuePair pair)) @@ -192,8 +192,8 @@ public Reference Get(IEzrObject key, RuntimeResult result) /// The key to be checked. /// The object for returning errors. /// if the key was found, if any error occured or the key was not found. - [WrappedMember] - public bool HasKey(IEzrObject key, [Runtime(Feature.ResultRef)] RuntimeResult result) + [WrapMember] + public bool HasKey(IEzrObject key, [FeatureParameter(Feature.ResultRef)] RuntimeResult result) { int hash = key.ComputeHashCode(result); return !result.ShouldReturn && _items.ContainsKey(hash); diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index 02ebcd0..c964506 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -6,8 +6,8 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; using EzrSquared.Runtime.Types.Executables; +using EzrSquared.Runtime.Types.Wrappers; using System; using System.Collections.Generic; using System.Numerics; @@ -1174,7 +1174,7 @@ private void VisitTryNode(TryNode node, Context executionContext, Context callin return; IEzrObject targetObject = RuntimeResult.Reference.Object; - if (targetObject is not EzrSharpCompatibilityType target || !typeof(IEzrRuntimeError).IsAssignableFrom(target.SharpMember)) + if (targetObject is not EzrTypeWrapper target || !typeof(IEzrRuntimeError).IsAssignableFrom(target.SharpMember)) { RuntimeResult.Failure(new EzrUnexpectedTypeError($"Expected error type, but got object of type \"{targetObject.TypeName}\"!", executionContext, errorType.StartPosition, errorType.EndPosition)); return; diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs similarity index 78% rename from src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs rename to src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs index c08786c..12ddd6a 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs @@ -4,14 +4,13 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; using System; using System.Collections.Generic; using System.Text; -namespace EzrSquared.Runtime.Types.CSharpWrappers.Builtins; +namespace EzrSquared.Runtime.Types.Builtins; /// /// All built-in functions in ezr². @@ -53,15 +52,14 @@ public static class EzrBuiltinFunctions /// /// /// - /// The method arguments. - [WrappedMember] + [WrapMember] public static void Show( - [Expose(true)] string lineEnd, - [Expose(true)] string separator, - [Runtime(Feature.PositionalArguments)] ExtraPositionalArguments messages, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ResultRef)] RuntimeResult result, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [Parameter(true)] string lineEnd, + [Parameter(true)] string separator, + [FeatureParameter(Feature.PositionalArguments)] ExtraPositionalArguments messages, + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ResultRef)] RuntimeResult result, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) { if (messages.Count == 0) { @@ -112,9 +110,8 @@ public static void Show( /// /// /// - /// The method arguments. - [WrappedMember] - public static void ThrowError(IEzrRuntimeError error, [Runtime(Feature.ResultRef)] RuntimeResult result) + [WrapMember] + public static void ThrowError(IEzrRuntimeError error, [FeatureParameter(Feature.ResultRef)] RuntimeResult result) { result.Failure(error); } @@ -134,9 +131,8 @@ public static void ThrowError(IEzrRuntimeError error, [Runtime(Feature.ResultRef /// ezr² return type: /// /// - /// The method arguments. - [WrappedMember] - public static string Get([Expose(true)] IEzrObject? message, [Runtime(Feature.ResultRef)] RuntimeResult result) + [WrapMember] + public static string Get([Parameter(true)] IEzrObject? message, [FeatureParameter(Feature.ResultRef)] RuntimeResult result) { if (message is not null) { @@ -157,8 +153,7 @@ public static string Get([Expose(true)] IEzrObject? message, [Runtime(Feature.Re /// ezr² return type: /// /// - /// The method arguments. - [WrappedMember] + [WrapMember] public static void Clear() { Console.Clear(); @@ -182,12 +177,11 @@ public static void Clear() /// ezr² errors: /// if the condition is not met. /// - /// The method arguments. - [WrappedMember] + [WrapMember] public static void Assert(IEzrObject condition, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ResultRef)] RuntimeResult result, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ResultRef)] RuntimeResult result, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) { bool conditionResult = condition.EvaluateBoolean(result); if (!result.ShouldReturn && !conditionResult) @@ -209,9 +203,8 @@ public static void Assert(IEzrObject condition, /// ezr² return type: /// /// - /// The method arguments. - [WrappedMember] - public static int Hash(IEzrObject toHash, [Runtime(Feature.ResultRef)] RuntimeResult result) + [WrapMember] + public static int Hash(IEzrObject toHash, [FeatureParameter(Feature.ResultRef)] RuntimeResult result) { return toHash.ComputeHashCode(result); } @@ -231,8 +224,7 @@ public static int Hash(IEzrObject toHash, [Runtime(Feature.ResultRef)] RuntimeRe /// ezr² return type: /// /// - /// The method arguments. - [WrappedMember] + [WrapMember] public static string TypeOf(IEzrObject toCheck) { return toCheck.Tag; @@ -253,8 +245,7 @@ public static string TypeOf(IEzrObject toCheck) /// ezr² return type: /// /// - /// The method arguments. - [WrappedMember] + [WrapMember] public static string TypeNameOf(IEzrObject toCheck) { return toCheck.TypeName; @@ -275,8 +266,7 @@ public static string TypeNameOf(IEzrObject toCheck) /// ezr² return type: /// /// - /// The method arguments. - [WrappedMember] + [WrapMember] public static int TypeHashOf(IEzrObject toCheck) { return toCheck.HashTag; @@ -300,9 +290,8 @@ public static int TypeHashOf(IEzrObject toCheck) /// ezr² errors: /// if "to_copy" is not of the expected type. /// - /// The method arguments. - [WrappedMember] - public static IEzrObject Copy(IEzrMutableObject toCopy, [Runtime(Feature.ResultRef)] RuntimeResult result) + [WrapMember] + public static IEzrObject Copy(IEzrMutableObject toCopy, [FeatureParameter(Feature.ResultRef)] RuntimeResult result) { return (IEzrObject?)toCopy.DeepCopy(result) ?? EzrConstants.Nothing; } @@ -322,13 +311,12 @@ public static IEzrObject Copy(IEzrMutableObject toCopy, [Runtime(Feature.ResultR /// ezr² return type: /// /// - /// The method arguments. - [WrappedMember] - public static EzrSharpCompatibilityObjectInstance GetRaw(IEzrObject toGet, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [WrapMember] + public static EzrObjectWrapper GetRaw(IEzrObject toGet, + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) { - return new EzrSharpCompatibilityObjectInstance(toGet, toGet.GetType(), executionContext, wrapper.StartPosition, wrapper.EndPosition); + return new EzrObjectWrapper(toGet, toGet.GetType(), executionContext, wrapper.StartPosition, wrapper.EndPosition); } /// @@ -346,12 +334,11 @@ public static EzrSharpCompatibilityObjectInstance GetRaw(IEzrObject toGet, /// ezr² return type: /// /// - /// The method arguments. - [WrappedMember] + [WrapMember] public static IEzrObject GetContext(IEzrObject toGet, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ResultRef)] RuntimeResult result, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ResultRef)] RuntimeResult result, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) { RuntimeEzrObjectDictionary context = new(); foreach (KeyValuePair pair in toGet.Context) diff --git a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs b/src/Runtime/Types/Builtins/EzrBuiltinsUtility.cs similarity index 55% rename from src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs rename to src/Runtime/Types/Builtins/EzrBuiltinsUtility.cs index b438a59..d5b95f1 100644 --- a/src/Runtime/Types/CSharpWrappers/Builtins/EzrBuiltinsUtility.cs +++ b/src/Runtime/Types/Builtins/EzrBuiltinsUtility.cs @@ -1,9 +1,9 @@ using EzrSquared.Runtime.Types.Core; using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; -namespace EzrSquared.Runtime.Types.CSharpWrappers.Builtins; +namespace EzrSquared.Runtime.Types.Builtins; /// /// Utility to add built-ins to contexts. @@ -16,15 +16,15 @@ public static class EzrBuiltinsUtility /// The context to add to. public static void AddBuiltinFunctions(Context context) { - EzrSharpCompatibilityFunction throwError = new(EzrBuiltinFunctions.ThrowError, context, Position.None, Position.None); - EzrSharpCompatibilityFunction assert = new(EzrBuiltinFunctions.Assert, context, Position.None, Position.None); - EzrSharpCompatibilityFunction hash = new(EzrBuiltinFunctions.Hash, context, Position.None, Position.None); - EzrSharpCompatibilityFunction typeOf = new(EzrBuiltinFunctions.TypeOf, context, Position.None, Position.None); - EzrSharpCompatibilityFunction typeNameOf = new(EzrBuiltinFunctions.TypeNameOf, context, Position.None, Position.None); - EzrSharpCompatibilityFunction typeHashOf = new(EzrBuiltinFunctions.TypeHashOf, context, Position.None, Position.None); - EzrSharpCompatibilityFunction copy = new(EzrBuiltinFunctions.Copy, context, Position.None, Position.None); - EzrSharpCompatibilityFunction getRaw = new(EzrBuiltinFunctions.GetRaw, context, Position.None, Position.None); - EzrSharpCompatibilityFunction getContext = new(EzrBuiltinFunctions.GetContext, context, Position.None, Position.None); + EzrMethodWrapper throwError = new(EzrBuiltinFunctions.ThrowError, context, Position.None, Position.None); + EzrMethodWrapper assert = new(EzrBuiltinFunctions.Assert, context, Position.None, Position.None); + EzrMethodWrapper hash = new(EzrBuiltinFunctions.Hash, context, Position.None, Position.None); + EzrMethodWrapper typeOf = new(EzrBuiltinFunctions.TypeOf, context, Position.None, Position.None); + EzrMethodWrapper typeNameOf = new(EzrBuiltinFunctions.TypeNameOf, context, Position.None, Position.None); + EzrMethodWrapper typeHashOf = new(EzrBuiltinFunctions.TypeHashOf, context, Position.None, Position.None); + EzrMethodWrapper copy = new(EzrBuiltinFunctions.Copy, context, Position.None, Position.None); + EzrMethodWrapper getRaw = new(EzrBuiltinFunctions.GetRaw, context, Position.None, Position.None); + EzrMethodWrapper getContext = new(EzrBuiltinFunctions.GetContext, context, Position.None, Position.None); context.Set(null, throwError.SharpMemberName, ReferencePool.Get(throwError, AccessMod.Constant)); context.Set(null, assert.SharpMemberName, ReferencePool.Get(assert, AccessMod.Constant)); @@ -43,9 +43,9 @@ public static void AddBuiltinFunctions(Context context) /// The context to add to. public static void AddBuiltinIOFunctions(Context context) { - EzrSharpCompatibilityFunction show = new(EzrBuiltinFunctions.Show, context, Position.None, Position.None); - EzrSharpCompatibilityFunction get = new(EzrBuiltinFunctions.Get, context, Position.None, Position.None); - EzrSharpCompatibilityFunction clear = new(EzrBuiltinFunctions.Clear, context, Position.None, Position.None); + EzrMethodWrapper show = new(EzrBuiltinFunctions.Show, context, Position.None, Position.None); + EzrMethodWrapper get = new(EzrBuiltinFunctions.Get, context, Position.None, Position.None); + EzrMethodWrapper clear = new(EzrBuiltinFunctions.Clear, context, Position.None, Position.None); context.Set(null, show.SharpMemberName, ReferencePool.Get(show, AccessMod.Constant)); context.Set(null, get.SharpMemberName, ReferencePool.Get(get, AccessMod.Constant)); @@ -56,23 +56,23 @@ public static void AddBuiltinIOFunctions(Context context) /// Adds all built-in types to the given context. /// /// The context to add to. - public static void AddBuiltinTypes(Context context ) + public static void AddBuiltinTypes(Context context) { - EzrSharpCompatibilityType runtimeError = new(typeof(EzrRuntimeError), context, Position.None, Position.None); + EzrTypeWrapper runtimeError = new(typeof(EzrRuntimeError), context, Position.None, Position.None); context.Set(null, runtimeError.SharpMemberName, ReferencePool.Get(runtimeError, AccessMod.Constant)); - EzrSharpCompatibilityType assertionError = new(typeof(EzrAssertionError), context, Position.None, Position.None); - EzrSharpCompatibilityType illegalOperationError = new(typeof(EzrIllegalOperationError), context, Position.None, Position.None); - EzrSharpCompatibilityType keyNotFoundError = new(typeof(EzrKeyNotFoundError), context, Position.None, Position.None); - EzrSharpCompatibilityType mathError = new(typeof(EzrMathError), context, Position.None, Position.None); - EzrSharpCompatibilityType missingRequiredArgumentError = new(typeof(EzrMissingRequiredArgumentError), context, Position.None, Position.None); - EzrSharpCompatibilityType privateMemberOperationError = new(typeof(EzrPrivateMemberOperationError), context, Position.None, Position.None); - EzrSharpCompatibilityType undefinedValueError = new(typeof(EzrUndefinedValueError), context, Position.None, Position.None); - EzrSharpCompatibilityType unexpectedArgumentError = new(typeof(EzrUnexpectedArgumentError), context, Position.None, Position.None); - EzrSharpCompatibilityType unexpectedTypeError = new(typeof(EzrUnexpectedTypeError), context, Position.None, Position.None); - EzrSharpCompatibilityType unsupportedWrappingError = new(typeof(EzrUnsupportedWrappingError), context, Position.None, Position.None); - EzrSharpCompatibilityType valueOutOfRangeError = new(typeof(EzrValueOutOfRangeError), context, Position.None, Position.None); - EzrSharpCompatibilityType wrapperExecutionError = new(typeof(EzrWrapperExecutionError), context, Position.None, Position.None); + EzrTypeWrapper assertionError = new(typeof(EzrAssertionError), context, Position.None, Position.None); + EzrTypeWrapper illegalOperationError = new(typeof(EzrIllegalOperationError), context, Position.None, Position.None); + EzrTypeWrapper keyNotFoundError = new(typeof(EzrKeyNotFoundError), context, Position.None, Position.None); + EzrTypeWrapper mathError = new(typeof(EzrMathError), context, Position.None, Position.None); + EzrTypeWrapper missingRequiredArgumentError = new(typeof(EzrMissingRequiredArgumentError), context, Position.None, Position.None); + EzrTypeWrapper privateMemberOperationError = new(typeof(EzrPrivateMemberOperationError), context, Position.None, Position.None); + EzrTypeWrapper undefinedValueError = new(typeof(EzrUndefinedValueError), context, Position.None, Position.None); + EzrTypeWrapper unexpectedArgumentError = new(typeof(EzrUnexpectedArgumentError), context, Position.None, Position.None); + EzrTypeWrapper unexpectedTypeError = new(typeof(EzrUnexpectedTypeError), context, Position.None, Position.None); + EzrTypeWrapper unsupportedWrappingError = new(typeof(EzrUnsupportedWrappingError), context, Position.None, Position.None); + EzrTypeWrapper valueOutOfRangeError = new(typeof(EzrValueOutOfRangeError), context, Position.None, Position.None); + EzrTypeWrapper wrapperExecutionError = new(typeof(EzrWrapperExecutionError), context, Position.None, Position.None); context.Set(null, assertionError.SharpMemberName, ReferencePool.Get(assertionError, AccessMod.Constant)); context.Set(null, illegalOperationError.SharpMemberName, ReferencePool.Get(illegalOperationError, AccessMod.Constant)); diff --git a/src/Runtime/Types/Collections/EzrArray.cs b/src/Runtime/Types/Collections/EzrArray.cs index e282b70..9726339 100644 --- a/src/Runtime/Types/Collections/EzrArray.cs +++ b/src/Runtime/Types/Collections/EzrArray.cs @@ -1,7 +1,7 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members; using System; using System.Collections; using System.Collections.Generic; @@ -27,7 +27,7 @@ public class EzrArray : EzrObject, IEzrIndexedCollection public readonly IEzrObject[] Value; /// - [WrappedMember("length")] + [WrapMember("length")] public int Count { get; } /// @@ -42,7 +42,7 @@ public EzrArray(IEzrObject[] elements, Context parentContext, Position startPosi Value = elements; Count = elements.Length; - Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "length", ReferencePool.Get(new EzrPropertyWrapper(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); } /// diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index 099ba6b..c87ffa9 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -1,9 +1,9 @@ using EzrSquared.Runtime.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; using System; using System.Collections; using System.Collections.Generic; @@ -28,7 +28,7 @@ public class EzrDictionary : EzrObject, IEzrMutableObject, IEzrDictionary public readonly RuntimeEzrObjectDictionary Value; /// - [WrappedMember("length")] + [WrapMember("length")] public int Count => Value.Count; /// @@ -42,9 +42,9 @@ public EzrDictionary(RuntimeEzrObjectDictionary value, Context parentContext, Po { Value = value; - Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Value.Count))!, Value, Context, StartPosition, EndPosition), AccessMod.Constant)); - Context.Set(null, "remove_by_hash", ReferencePool.Get(new EzrSharpCompatibilityFunction(Value.RemoveHash, Context, StartPosition, EndPosition), AccessMod.Constant)); - Context.Set(null, "has_key", ReferencePool.Get(new EzrSharpCompatibilityFunction(Value.HasKey, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "length", ReferencePool.Get(new EzrPropertyWrapper(GetMemberInfo(nameof(Value.Count))!, Value, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "remove_by_hash", ReferencePool.Get(new EzrMethodWrapper(Value.RemoveHash, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "has_key", ReferencePool.Get(new EzrMethodWrapper(Value.HasKey, Context, StartPosition, EndPosition), AccessMod.Constant)); } /// diff --git a/src/Runtime/Types/Collections/EzrList.cs b/src/Runtime/Types/Collections/EzrList.cs index 990e4aa..e46a5cf 100644 --- a/src/Runtime/Types/Collections/EzrList.cs +++ b/src/Runtime/Types/Collections/EzrList.cs @@ -1,8 +1,8 @@ using EzrSquared.Runtime.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members; using System; using System.Collections; using System.Collections.Generic; @@ -28,7 +28,7 @@ public class EzrList : EzrObject, IEzrMutableObject, IEzrIndexedCollection public readonly RuntimeEzrObjectList Value; /// - [WrappedMember("length")] + [WrapMember("length")] public int Count => Value.Count; /// The base value. @@ -39,7 +39,7 @@ public EzrList(RuntimeEzrObjectList elements, Context parentContext, Position st { Value = elements; - Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "length", ReferencePool.Get(new EzrPropertyWrapper(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); } /// diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs index c346211..f46bb9f 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrAssertionError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("assertion_error")] +[WrapMember("assertion_error")] public class EzrAssertionError(Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Assertion failed", "The assertion conditions were not met!", context, startPosition, endPosition) { /// @@ -23,9 +23,9 @@ public class EzrAssertionError(Context context, Position startPosition, Position /// /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrAssertionError( - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this(executionContext, wrapper.StartPosition, wrapper.EndPosition) { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs index d4a18a6..b05031c 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrIllegalOperationError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -10,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("illegal_operation_error")] +[WrapMember("illegal_operation_error")] public class EzrIllegalOperationError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Illegal operation", details, context, startPosition, endPosition) { /// @@ -25,13 +25,14 @@ public class EzrIllegalOperationError(string details, Context context, Position /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrIllegalOperationError(string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( details, executionContext, wrapper.StartPosition, - wrapper.EndPosition) { } + wrapper.EndPosition) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs index 9564326..c3645bd 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrKeyNotFoundError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -10,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("key_not_found_error")] +[WrapMember("key_not_found_error")] public class EzrKeyNotFoundError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Key not found", details, context, startPosition, endPosition) { /// @@ -25,13 +25,14 @@ public class EzrKeyNotFoundError(string details, Context context, Position start /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrKeyNotFoundError(string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( details, executionContext, wrapper.StartPosition, - wrapper.EndPosition) { } + wrapper.EndPosition) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs index 664ecae..d11b91b 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMathError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -11,7 +11,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("math_error")] +[WrapMember("math_error")] public class EzrMathError(string title, string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError(title, details, context, startPosition, endPosition) { /// @@ -27,14 +27,15 @@ public class EzrMathError(string title, string details, Context context, Positio /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrMathError(string title, string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( title, details, executionContext, wrapper.StartPosition, - wrapper.EndPosition) { } + wrapper.EndPosition) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs index 5c4820f..5b75e56 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrMissingRequiredArgumentError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -10,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("missing_required_argument_error")] +[WrapMember("missing_required_argument_error")] public class EzrMissingRequiredArgumentError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Missing required argument", details, context, startPosition, endPosition) { /// @@ -25,13 +25,14 @@ public class EzrMissingRequiredArgumentError(string details, Context context, Po /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrMissingRequiredArgumentError(string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( details, executionContext, wrapper.StartPosition, - wrapper.EndPosition) { } + wrapper.EndPosition) + { } } diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs index 98ea7c6..d0ec66e 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrPrivateMemberOperationError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -10,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("private_member_operation_error")] +[WrapMember("private_member_operation_error")] public class EzrPrivateMemberOperationError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Private member operation", details, context, startPosition, endPosition) { /// @@ -25,10 +25,10 @@ public class EzrPrivateMemberOperationError(string details, Context context, Pos /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrPrivateMemberOperationError(string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( details, executionContext, diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs index 55f8c9f..e7085f1 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrRuntimeError.cs @@ -1,6 +1,6 @@ using EzrSquared.Runtime.Types.Core.Text; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; using System; using System.Text; @@ -9,7 +9,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// /// Implementation of with some utility methods. /// -[WrappedMember("runtime_error")] +[WrapMember("runtime_error")] public class EzrRuntimeError : EzrObject, IEzrRuntimeError { /// @@ -60,16 +60,17 @@ public EzrRuntimeError(string title, string details, Context context, Position s /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrRuntimeError(string title, string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( title, details, executionContext, wrapper.StartPosition, - wrapper.EndPosition) { } + wrapper.EndPosition) + { } /// /// Converts the given argument to a string. diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs index cee154a..09e1e15 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUndefinedValueError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -10,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("undefined_value_error")] +[WrapMember("undefined_value_error")] public class EzrUndefinedValueError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Undefined value", details, context, startPosition, endPosition) { /// @@ -25,10 +25,10 @@ public class EzrUndefinedValueError(string details, Context context, Position st /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrUndefinedValueError(string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( details, executionContext, diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs index 667989f..b9c1de1 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedArgumentError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -10,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("unexpected_argument_error")] +[WrapMember("unexpected_argument_error")] public class EzrUnexpectedArgumentError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unexpected argument(s)", details, context, startPosition, endPosition) { /// @@ -25,10 +25,10 @@ public class EzrUnexpectedArgumentError(string details, Context context, Positio /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrUnexpectedArgumentError(string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( details, executionContext, diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs index 6ab622a..fb587b9 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnexpectedTypeError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -10,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("unexpected_type_error")] +[WrapMember("unexpected_type_error")] public class EzrUnexpectedTypeError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unexpected type", details, context, startPosition, endPosition) { /// @@ -25,10 +25,10 @@ public class EzrUnexpectedTypeError(string details, Context context, Position st /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrUnexpectedTypeError(string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( details, executionContext, diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs index 96dc5fd..2e74349 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrUnsupportedWrappingError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -10,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("unsupported_wrapping_error")] +[WrapMember("unsupported_wrapping_error")] public class EzrUnsupportedWrappingError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Unsupported wrapping", details, context, startPosition, endPosition) { /// @@ -25,10 +25,10 @@ public class EzrUnsupportedWrappingError(string details, Context context, Positi /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrUnsupportedWrappingError(string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( details, executionContext, diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs index 80c1c30..82c2f8d 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrValueOutOfRangeError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -10,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("value_out_of_range_error")] +[WrapMember("value_out_of_range_error")] public class EzrValueOutOfRangeError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Value out of range", details, context, startPosition, endPosition) { /// @@ -25,10 +25,10 @@ public class EzrValueOutOfRangeError(string details, Context context, Position s /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrValueOutOfRangeError(string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( details, executionContext, diff --git a/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs index 87ff7b1..76bf818 100644 --- a/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs +++ b/src/Runtime/Types/Core/RuntimeErrors/EzrWrapperExecutionError.cs @@ -1,5 +1,5 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; namespace EzrSquared.Runtime.Types.Core.Errors; @@ -10,7 +10,7 @@ namespace EzrSquared.Runtime.Types.Core.Errors; /// The context in which the error occurred. /// The starting position of the error. /// The ending position of the error. -[WrappedMember("wrapper_execution_error")] +[WrapMember("wrapper_execution_error")] public class EzrWrapperExecutionError(string details, Context context, Position startPosition, Position endPosition) : EzrRuntimeError("Wrapper execution error", details, context, startPosition, endPosition) { /// @@ -25,10 +25,10 @@ public class EzrWrapperExecutionError(string details, Context context, Position /// Details on why the error happened. /// The caller. /// The execution context. - [WrappedMember, PrimaryConstructor] + [WrapMember, PrimaryConstructor] public EzrWrapperExecutionError(string details, - [Runtime(Feature.CallerRef)] IEzrObject wrapper, - [Runtime(Feature.ExecutionRef)] Context executionContext) + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) : this( details, executionContext, diff --git a/src/Runtime/Types/Core/Text/EzrCharacterList.cs b/src/Runtime/Types/Core/Text/EzrCharacterList.cs index 16fb67f..9b64ba0 100644 --- a/src/Runtime/Types/Core/Text/EzrCharacterList.cs +++ b/src/Runtime/Types/Core/Text/EzrCharacterList.cs @@ -1,8 +1,8 @@ using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members; using System; using System.Collections; using System.Collections.Generic; @@ -34,7 +34,7 @@ public class EzrCharacterList : EzrObject, IEzrMutableObject, IEzrString, IEzrIn public string StringValue => Value.ToString(); /// - [WrappedMember("length")] + [WrapMember("length")] public int Count => Value.Length; /// @@ -48,7 +48,7 @@ public EzrCharacterList(string value, Context parentContext, Position startPosit { Value = new(value); - Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "length", ReferencePool.Get(new EzrPropertyWrapper(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); } /// diff --git a/src/Runtime/Types/Core/Text/EzrString.cs b/src/Runtime/Types/Core/Text/EzrString.cs index 931a3e8..72ada18 100644 --- a/src/Runtime/Types/Core/Text/EzrString.cs +++ b/src/Runtime/Types/Core/Text/EzrString.cs @@ -1,8 +1,8 @@ using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members; using System; using System.Collections; using System.Collections.Generic; @@ -32,7 +32,7 @@ public class EzrString : EzrObject, IEzrString, IEzrIndexedCollection public string StringValue => Value; /// - [WrappedMember("length")] + [WrapMember("length")] public int Count { get; } /// @@ -47,7 +47,7 @@ public EzrString(string value, Context parentContext, Position startPosition, Po Value = value; Count = value.Length; - Context.Set(null, "length", ReferencePool.Get(new EzrSharpCompatibilityProperty(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); + Context.Set(null, "length", ReferencePool.Get(new EzrPropertyWrapper(GetMemberInfo(nameof(Count))!, this, Context, StartPosition, EndPosition), AccessMod.Constant)); } /// diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/DontWrapMemberAttribute.cs b/src/Runtime/Types/Wrappers/DontWrapMemberAttribute.cs similarity index 84% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/DontWrapMemberAttribute.cs rename to src/Runtime/Types/Wrappers/DontWrapMemberAttribute.cs index 84181b5..712afec 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/DontWrapMemberAttribute.cs +++ b/src/Runtime/Types/Wrappers/DontWrapMemberAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +namespace EzrSquared.Runtime.Types.Wrappers; /// /// Attribute for C# types and members which should NOT be automatically wrapped from C# types into ezr² types by the interpreter. diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs b/src/Runtime/Types/Wrappers/EzrObjectWrapper.cs similarity index 73% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs rename to src/Runtime/Types/Wrappers/EzrObjectWrapper.cs index 060d83b..06fa6ca 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityObjectInstance.cs +++ b/src/Runtime/Types/Wrappers/EzrObjectWrapper.cs @@ -1,17 +1,16 @@ -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +using EzrSquared.Runtime.Types.Wrappers.Members; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; +namespace EzrSquared.Runtime.Types.Wrappers; /// /// Class to automatically wrap instances of C# types so that they can be used in ezr². /// -public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper +public class EzrObjectWrapper : EzrWrapper { /// public override string TypeName { get; protected internal set; } = "csharp object instance"; @@ -20,14 +19,14 @@ public class EzrSharpCompatibilityObjectInstance : EzrSharpCompatibilityWrapper< public override string Tag { get; protected internal set; } = "ezrSquared.CSharpObjectInstance"; /// - /// Creates a new . + /// Creates a new . /// /// The object to wrap. /// The C# object's type. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrSharpCompatibilityObjectInstance( + public EzrObjectWrapper( object instance, [DynamicallyAccessedMembers( @@ -48,11 +47,11 @@ public EzrSharpCompatibilityObjectInstance( for (int i = 0; i < allMethods.Length; i++) { MethodInfo method = allMethods[i]; - if (!WrappedMemberAttribute.ShouldBeWrapped(method)) + if (!WrapMemberAttribute.ShouldBeWrapped(method)) continue; - EzrSharpCompatibilityFunction methodObject = new(method, Instance, Context, StartPosition, EndPosition, skipValidation: true); - if (!WrappedMemberAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) + EzrMethodWrapper methodObject = new(method, Instance, Context, StartPosition, EndPosition, skipValidation: true); + if (!WrapMemberAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) continue; string methodObjectName = methodObject.SharpMemberName; @@ -71,10 +70,10 @@ public EzrSharpCompatibilityObjectInstance( for (int i = 0; i < allProperties.Length; i++) { PropertyInfo property = allProperties[i]; - if (!WrappedMemberAttribute.ShouldBeWrapped(property)) + if (!WrapMemberAttribute.ShouldBeWrapped(property)) continue; - EzrSharpCompatibilityProperty propertyObject = new(property, Instance, Context, StartPosition, EndPosition); + EzrPropertyWrapper propertyObject = new(property, Instance, Context, StartPosition, EndPosition); Context.Set(null, propertyObject.SharpMemberName, ReferencePool.Get(propertyObject, AccessMod.Constant)); } @@ -82,10 +81,10 @@ public EzrSharpCompatibilityObjectInstance( for (int i = 0; i < allFields.Length; i++) { FieldInfo field = allFields[i]; - if (!WrappedMemberAttribute.ShouldBeWrapped(field)) + if (!WrapMemberAttribute.ShouldBeWrapped(field)) continue; - EzrSharpCompatibilityField fieldObject = new(field, Instance, Context, StartPosition, EndPosition); + EzrFieldWrapper fieldObject = new(field, Instance, Context, StartPosition, EndPosition); Context.Set(null, fieldObject.SharpMemberName, ReferencePool.Get(fieldObject, AccessMod.Constant)); } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs b/src/Runtime/Types/Wrappers/EzrTypeWrapper.cs similarity index 74% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs rename to src/Runtime/Types/Wrappers/EzrTypeWrapper.cs index 523670e..181f011 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityType.cs +++ b/src/Runtime/Types/Wrappers/EzrTypeWrapper.cs @@ -1,20 +1,17 @@ -using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +using EzrSquared.Runtime.Types.Wrappers.Members; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; using EzrSquared.Util; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; +namespace EzrSquared.Runtime.Types.Wrappers; /// /// Class to automatically wrap C# types so that they can be used in ezr². /// -public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper, IEzrObject +public class EzrTypeWrapper : EzrWrapper, IEzrObject { /// public override string TypeName { get; protected internal set; } = "csharp type"; @@ -25,16 +22,16 @@ public class EzrSharpCompatibilityType : EzrSharpCompatibilityWrapper, IEz /// /// The primary wrapped constructor for the type. May be . /// - public readonly EzrSharpCompatibilityConstructor? PrimaryConstructor; + public readonly EzrConstructorWrapper? PrimaryConstructor; /// - /// Creates a new . + /// Creates a new . /// /// The type to wrap. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrSharpCompatibilityType( + public EzrTypeWrapper( [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields @@ -49,18 +46,18 @@ public EzrSharpCompatibilityType( Context parentContext, Position startPosition, Position endPosition) : base(sharpType, null, parentContext, startPosition, endPosition) { Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; - WrappedMemberAttribute.ValidateType(SharpMember, AutoWrapperAttribute is null); + WrapMemberAttribute.ValidateType(SharpMember, AutoWrapperAttribute is null); MethodInfo[] allStaticMethods = sharpType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); Dictionary duplicateNames = new(allStaticMethods.Length); for (int i = 0; i < allStaticMethods.Length; i++) { MethodInfo method = allStaticMethods[i]; - if (!WrappedMemberAttribute.ShouldBeWrapped(method)) + if (!WrapMemberAttribute.ShouldBeWrapped(method)) continue; - EzrSharpCompatibilityFunction methodObject = new(method, null, Context, StartPosition, EndPosition, skipValidation: true); - if (!WrappedMemberAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) + EzrMethodWrapper methodObject = new(method, null, Context, StartPosition, EndPosition, skipValidation: true); + if (!WrapMemberAttribute.ValidateMethod(method, methodObject.AutoWrapperAttribute is null)) continue; string methodObjectName = methodObject.SharpMemberName; @@ -79,10 +76,10 @@ public EzrSharpCompatibilityType( for (int i = 0; i < allStaticProperties.Length; i++) { PropertyInfo property = allStaticProperties[i]; - if (!WrappedMemberAttribute.ShouldBeWrapped(property)) + if (!WrapMemberAttribute.ShouldBeWrapped(property)) continue; - EzrSharpCompatibilityProperty propertyObject = new(property, null, Context, StartPosition, EndPosition); + EzrPropertyWrapper propertyObject = new(property, null, Context, StartPosition, EndPosition); Context.Set(null, propertyObject.SharpMemberName, ReferencePool.Get(propertyObject, AccessMod.Constant)); } @@ -90,10 +87,10 @@ public EzrSharpCompatibilityType( for (int i = 0; i < allStaticFields.Length; i++) { FieldInfo field = allStaticFields[i]; - if (!WrappedMemberAttribute.ShouldBeWrapped(field)) + if (!WrapMemberAttribute.ShouldBeWrapped(field)) continue; - EzrSharpCompatibilityField fieldObject = new(field, null, Context, StartPosition, EndPosition); + EzrFieldWrapper fieldObject = new(field, null, Context, StartPosition, EndPosition); Context.Set(null, fieldObject.SharpMemberName, ReferencePool.Get(fieldObject, AccessMod.Constant)); } @@ -102,11 +99,11 @@ public EzrSharpCompatibilityType( for (int i = 0; i < publicConstructors.Length; i++) { ConstructorInfo constructor = publicConstructors[i]; - if (!WrappedMemberAttribute.ShouldBeWrapped(constructor)) + if (!WrapMemberAttribute.ShouldBeWrapped(constructor)) continue; - EzrSharpCompatibilityConstructor constructorObject = new(sharpType, constructor, Context, StartPosition, EndPosition, skipValidation: true); - if (!WrappedMemberAttribute.ValidateMethod(constructor, constructorObject.AutoWrapperAttribute is null)) + EzrConstructorWrapper constructorObject = new(sharpType, constructor, Context, StartPosition, EndPosition, skipValidation: true); + if (!WrapMemberAttribute.ValidateMethod(constructor, constructorObject.AutoWrapperAttribute is null)) continue; if (constructor.GetCustomAttribute() is not null) @@ -119,7 +116,7 @@ public EzrSharpCompatibilityType( } string name = definedConstructors == 0 ? "make" : $"make_{definedConstructors}"; - if (constructorObject.AutoWrapperAttribute is not WrappedMemberAttribute attr || string.IsNullOrEmpty(attr.Name)) + if (constructorObject.AutoWrapperAttribute is not WrapMemberAttribute attr || string.IsNullOrEmpty(attr.Name)) definedConstructors++; else { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs b/src/Runtime/Types/Wrappers/EzrWrapper.cs similarity index 94% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs rename to src/Runtime/Types/Wrappers/EzrWrapper.cs index 68c7882..431f709 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/EzrSharpCompatibilityWrapper.cs +++ b/src/Runtime/Types/Wrappers/EzrWrapper.cs @@ -3,7 +3,6 @@ using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using System; using System.Collections.Generic; using System.Numerics; @@ -11,7 +10,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; +namespace EzrSquared.Runtime.Types.Wrappers; /// /// Parent class for all automatic wrappers which wrap existing C# objects and members so that they can be used in ezr². @@ -19,10 +18,10 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers; /// The type for the C# member being wrapped. #if NET7_0_OR_GREATER -public abstract partial class EzrSharpCompatibilityWrapper : EzrObject +public abstract partial class EzrWrapper : EzrObject where TMemberInfo : MemberInfo #else -public abstract class EzrSharpCompatibilityWrapper : EzrObject +public abstract class EzrWrapper : EzrObject where TMemberInfo : MemberInfo #endif { @@ -38,9 +37,9 @@ public abstract class EzrSharpCompatibilityWrapper : EzrObject public override string Tag { get; protected internal set; } = "ezrSquared.CSharpWrapper"; /// - /// The of the wrapped object, if defined. + /// The of the wrapped object, if defined. /// - public readonly WrappedMemberAttribute? AutoWrapperAttribute; + public readonly WrapMemberAttribute? AutoWrapperAttribute; /// /// The name of the wrapped member in snake_case. @@ -58,17 +57,17 @@ public abstract class EzrSharpCompatibilityWrapper : EzrObject public readonly object? Instance; /// - /// Creates a new . + /// Creates a new . /// /// Reflection info on the wrapped C# member. /// The object which contains the wrapped member, if static. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) + public EzrWrapper(TMemberInfo wrappedMember, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(parentContext, startPosition, endPosition) { SharpMember = wrappedMember; - AutoWrapperAttribute = wrappedMember.GetCustomAttribute(); + AutoWrapperAttribute = wrappedMember.GetCustomAttribute(); SharpMemberName = !string.IsNullOrEmpty(AutoWrapperAttribute?.Name) ? AutoWrapperAttribute.Name : PascalToSnakeCase(wrappedMember.Name)!; Instance = instance; } @@ -260,7 +259,7 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, return HandleEzrArrayLikeToCSharp(value, targetType, result); case TypeCode.Object when targetType == typeof(Task): - if (value is EzrSharpCompatibilityObjectInstance taskWrapper && targetType.IsAssignableFrom(taskWrapper.SharpMember)) + if (value is EzrObjectWrapper taskWrapper && targetType.IsAssignableFrom(taskWrapper.SharpMember)) return (Task)taskWrapper.Instance!; return s_taskFromResultMethod.MakeGenericMethod(value.GetType()).Invoke(null, [value]); @@ -281,7 +280,7 @@ public EzrSharpCompatibilityWrapper(TMemberInfo wrappedMember, object? instance, break; default: - if (value is EzrSharpCompatibilityObjectInstance wrapper && wrapper.SharpMember == targetType) + if (value is EzrObjectWrapper wrapper && wrapper.SharpMember == targetType) return wrapper.Instance; result.Failure(new EzrUnexpectedTypeError($"Expected wrapped object of C# type \"{targetType.Name}\", but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); @@ -396,7 +395,7 @@ protected internal void CSharpToEzrObject(object? value, Type valueType, Runtime result.Success(NewNothingConstant()); break; default: - result.Success(ReferencePool.Get(new EzrSharpCompatibilityObjectInstance(value, valueType, _executionContext, StartPosition, EndPosition), AccessMod.PrivateConstant)); + result.Success(ReferencePool.Get(new EzrObjectWrapper(value, valueType, _executionContext, StartPosition, EndPosition), AccessMod.PrivateConstant)); break; } } @@ -453,7 +452,7 @@ public override bool EvaluateBoolean(RuntimeResult result) /// public override bool StrictEquals(IEzrObject other, RuntimeResult result) { - return other is EzrSharpCompatibilityWrapper otherWrapper + return other is EzrWrapper otherWrapper && otherWrapper.SharpMember == SharpMember && otherWrapper.Instance?.GetHashCode() == Instance?.GetHashCode() && other.HashTag == HashTag; diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs b/src/Runtime/Types/Wrappers/Members/EzrFieldWrapper.cs similarity index 88% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs rename to src/Runtime/Types/Wrappers/Members/EzrFieldWrapper.cs index 14c8154..2d32b6e 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityField.cs +++ b/src/Runtime/Types/Wrappers/Members/EzrFieldWrapper.cs @@ -3,12 +3,12 @@ using System; using System.Reflection; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +namespace EzrSquared.Runtime.Types.Wrappers.Members; /// /// Class to automatically wrap C# fields so that they can be used in ezr². /// -public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper +public class EzrFieldWrapper : EzrWrapper { /// public override string TypeName { get; protected internal set; } = "csharp field"; @@ -17,14 +17,14 @@ public class EzrSharpCompatibilityField : EzrSharpCompatibilityWrapper - /// Creates a new . + /// Creates a new . /// /// The field to wrap. /// The object which contains the field, if static. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrSharpCompatibilityField(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(sharpField, instance, parentContext, startPosition, endPosition) + public EzrFieldWrapper(FieldInfo sharpField, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(sharpField, instance, parentContext, startPosition, endPosition) { Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs b/src/Runtime/Types/Wrappers/Members/EzrPropertyWrapper.cs similarity index 88% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs rename to src/Runtime/Types/Wrappers/Members/EzrPropertyWrapper.cs index 7b73173..bdce4a5 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/EzrSharpCompatibilityProperty.cs +++ b/src/Runtime/Types/Wrappers/Members/EzrPropertyWrapper.cs @@ -3,12 +3,12 @@ using System; using System.Reflection; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers; +namespace EzrSquared.Runtime.Types.Wrappers.Members; /// /// Class to automatically wrap C# properties so that they can be used in ezr². /// -public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper +public class EzrPropertyWrapper : EzrWrapper { /// public override string TypeName { get; protected internal set; } = "csharp property"; @@ -17,14 +17,14 @@ public class EzrSharpCompatibilityProperty : EzrSharpCompatibilityWrapper - /// Creates a new . + /// Creates a new . /// /// The property to wrap. /// The object which contains the property, if static. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. - public EzrSharpCompatibilityProperty(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(sharpProperty, instance, parentContext, startPosition, endPosition) + public EzrPropertyWrapper(PropertyInfo sharpProperty, object? instance, Context parentContext, Position startPosition, Position endPosition) : base(sharpProperty, instance, parentContext, startPosition, endPosition) { Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs b/src/Runtime/Types/Wrappers/Members/Methods/EzrConstructorWrapper.cs similarity index 88% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs rename to src/Runtime/Types/Wrappers/Members/Methods/EzrConstructorWrapper.cs index ebbb40d..e583005 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityConstructor.cs +++ b/src/Runtime/Types/Wrappers/Members/Methods/EzrConstructorWrapper.cs @@ -1,16 +1,15 @@ using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +namespace EzrSquared.Runtime.Types.Wrappers.Members.Methods; /// /// Class to automatically wrap C# constructors so that they can be used in ezr². /// -public class EzrSharpCompatibilityConstructor : EzrSharpCompatibilityExecutable +public class EzrConstructorWrapper : EzrMethodBaseWrapper { /// /// This C# constructor's class. @@ -30,7 +29,7 @@ public class EzrSharpCompatibilityConstructor : EzrSharpCompatibilityExecutable< public readonly string ConstructingTypeName; /// - /// Creates a new . + /// Creates a new . /// /// This C# constructor's class. /// The constructor to wrap. @@ -38,7 +37,7 @@ public class EzrSharpCompatibilityConstructor : EzrSharpCompatibilityExecutable< /// The starting position of the object. /// The ending position of the object. /// Skip method signature validation? - public EzrSharpCompatibilityConstructor( + public EzrConstructorWrapper( [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods @@ -52,7 +51,7 @@ public EzrSharpCompatibilityConstructor( { ConstructingType = constructingType; - WrappedMemberAttribute? autoWrapperAttribute = constructingType.GetCustomAttribute(); + WrapMemberAttribute? autoWrapperAttribute = constructingType.GetCustomAttribute(); ConstructingTypeName = !string.IsNullOrEmpty(autoWrapperAttribute?.Name) ? autoWrapperAttribute.Name : PascalToSnakeCase(constructingType.Name)!; } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs b/src/Runtime/Types/Wrappers/Members/Methods/EzrMethodBaseWrapper.cs similarity index 86% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs rename to src/Runtime/Types/Wrappers/Members/Methods/EzrMethodBaseWrapper.cs index 1bc6041..437ae53 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityExecutable.cs +++ b/src/Runtime/Types/Wrappers/Members/Methods/EzrMethodBaseWrapper.cs @@ -1,17 +1,15 @@ using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; -using EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; using EzrSquared.Util; using System; using System.Collections.Generic; using System.Reflection; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +namespace EzrSquared.Runtime.Types.Wrappers.Members.Methods; /// /// Base class for all automatic wrappers which wrap C# executables so that they can be used in ezr². /// -public abstract class EzrSharpCompatibilityExecutable : EzrSharpCompatibilityWrapper +public abstract class EzrMethodBaseWrapper : EzrWrapper where TMethodBase : MethodBase { /// @@ -33,7 +31,7 @@ public abstract class EzrSharpCompatibilityExecutable : EzrSharpCom /// /// The attributes of the executable's runtime-provided parameters. /// - public readonly RuntimeAttribute[] RuntimeProvidedParameters; + public readonly FeatureParameterAttribute[] RuntimeProvidedParameters; /// /// Does this executable accept extra keyword arguments? @@ -46,7 +44,7 @@ public abstract class EzrSharpCompatibilityExecutable : EzrSharpCom public readonly bool AcceptsExtraPositionalArguments; /// - /// Creates a new . + /// Creates a new . /// /// The executable to wrap. /// The object which contains the executable, if static. @@ -54,29 +52,29 @@ public abstract class EzrSharpCompatibilityExecutable : EzrSharpCom /// The starting position of the object. /// The ending position of the object. /// Skip method signature validation? - public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation) : base(sharpMethodBase, instance, parentContext, startPosition, endPosition) + public EzrMethodBaseWrapper(TMethodBase sharpMethodBase, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation) : base(sharpMethodBase, instance, parentContext, startPosition, endPosition) { Tag = $"{Tag}.{SharpMemberName}.{UIDProvider.Get()}"; if (!skipValidation) - WrappedMemberAttribute.ValidateMethod(SharpMember, AutoWrapperAttribute is null); + WrapMemberAttribute.ValidateMethod(SharpMember, AutoWrapperAttribute is null); ParameterInfo[] allParameters = SharpMember.GetParameters(); List<(ParameterInfo, bool)> exposedParameters = new(allParameters.Length); List exposedParameterNames = new(allParameters.Length); - Lazy> runtimeProvidedParameters = new(); + Lazy> runtimeProvidedParameters = new(); for (int i = 0; i < allParameters.Length; i++) { ParameterInfo parameterInfo = allParameters[i]; - ExposeAttribute? autoWrapperAttribute = parameterInfo.GetCustomAttribute(); - RuntimeAttribute? runtimeParamAttribute = parameterInfo.GetCustomAttribute(); + ParameterAttribute? autoWrapperAttribute = parameterInfo.GetCustomAttribute(); + FeatureParameterAttribute? runtimeParamAttribute = parameterInfo.GetCustomAttribute(); if (autoWrapperAttribute is not null && runtimeParamAttribute is not null) - throw new ArgumentException($"Method \"{SharpMember.Name}\" cannot have a parameter with both {nameof(ExposeAttribute)} and {nameof(RuntimeAttribute)} attributes ({parameterInfo.Name})!", nameof(sharpMethodBase)); + throw new ArgumentException($"Method \"{SharpMember.Name}\" cannot have a parameter with both {nameof(ParameterAttribute)} and {nameof(FeatureParameterAttribute)} attributes ({parameterInfo.Name})!", nameof(sharpMethodBase)); else if (runtimeParamAttribute is null && runtimeProvidedParameters.IsValueCreated) - throw new ArgumentException($"Method \"{SharpMember.Name}\" cannot have a normal parameter after {nameof(RuntimeAttribute)}-attributed parameters ({parameterInfo.Name})!", nameof(sharpMethodBase)); + throw new ArgumentException($"Method \"{SharpMember.Name}\" cannot have a normal parameter after {nameof(FeatureParameterAttribute)}-attributed parameters ({parameterInfo.Name})!", nameof(sharpMethodBase)); if (runtimeParamAttribute is null) { @@ -175,7 +173,7 @@ public EzrSharpCompatibilityExecutable(TMethodBase sharpMethodBase, object? inst ReferencePool.TryRelease(argumentReference); continue; } - + if (allPositionalArgumentsFilled) { result.Failure(new EzrUnexpectedArgumentError("Did not expect any more unnamed arguments!", _executionContext, argumentObject.StartPosition, argumentObject.EndPosition)); diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs b/src/Runtime/Types/Wrappers/Members/Methods/EzrMethodWrapper.cs similarity index 82% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs rename to src/Runtime/Types/Wrappers/Members/Methods/EzrMethodWrapper.cs index 7b8b20f..ec803e5 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/EzrSharpCompatibilityFunction.cs +++ b/src/Runtime/Types/Wrappers/Members/Methods/EzrMethodWrapper.cs @@ -3,7 +3,7 @@ using System.Reflection; using System.Text; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables; +namespace EzrSquared.Runtime.Types.Wrappers.Members.Methods; /// /// Class to automatically wrap C# methods so that they can be used in ezr². @@ -14,7 +14,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.E /// The starting position of the object. /// The ending position of the object. /// Skip method signature validation? -public class EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : EzrSharpCompatibilityExecutable(sharpFunction, instance, parentContext, startPosition, endPosition, skipValidation) +public class EzrMethodWrapper(MethodInfo sharpFunction, object? instance, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : EzrMethodBaseWrapper(sharpFunction, instance, parentContext, startPosition, endPosition, skipValidation) { /// public override string TypeName { get; protected internal set; } = "csharp function"; @@ -23,14 +23,14 @@ public class EzrSharpCompatibilityFunction(MethodInfo sharpFunction, object? ins public override string Tag { get; protected internal set; } = "ezrSquared.CSharpFunction"; /// - /// Creates a new from a delegate. + /// Creates a new from a delegate. /// /// The method to wrap. /// The context in which this object was created. /// The starting position of the object. /// The ending position of the object. /// Skip method signature validation? - public EzrSharpCompatibilityFunction(Delegate sharpFunction, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) + public EzrMethodWrapper(Delegate sharpFunction, Context parentContext, Position startPosition, Position endPosition, bool skipValidation = false) : this(sharpFunction.Method, sharpFunction.Target, parentContext, startPosition, endPosition, skipValidation) { } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/Feature.cs b/src/Runtime/Types/Wrappers/Members/Methods/Feature.cs similarity index 88% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/Feature.cs rename to src/Runtime/Types/Wrappers/Members/Methods/Feature.cs index 450ae6b..557448b 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/Feature.cs +++ b/src/Runtime/Types/Wrappers/Members/Methods/Feature.cs @@ -1,7 +1,7 @@ -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +namespace EzrSquared.Runtime.Types.Wrappers.Members.Methods; /// -/// The metadata for . +/// The metadata for . /// public enum Feature { diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/RuntimeAttribute.cs b/src/Runtime/Types/Wrappers/Members/Methods/FeatureParameterAttribute.cs similarity index 78% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/RuntimeAttribute.cs rename to src/Runtime/Types/Wrappers/Members/Methods/FeatureParameterAttribute.cs index b0fd894..7ecd25d 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/RuntimeAttribute.cs +++ b/src/Runtime/Types/Wrappers/Members/Methods/FeatureParameterAttribute.cs @@ -3,7 +3,7 @@ using System; using System.Reflection; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +namespace EzrSquared.Runtime.Types.Wrappers.Members.Methods; /// /// Attribute for wrapped C# methods that need to enable features or request data from the ezr² runtime. @@ -15,7 +15,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.E /// type. /// [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] -public class RuntimeAttribute(Feature type) : Attribute +public class FeatureParameterAttribute(Feature type) : Attribute { /// /// The type of the parameter. @@ -31,22 +31,22 @@ public void ValidateParameter(ParameterInfo parameter) switch (Type) { case Feature.KeywordArguments when !parameter.ParameterType.IsAssignableFrom(typeof(ExtraKeywordArguments)): - throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(ExtraKeywordArguments)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(ExtraKeywordArguments)} as it has the {nameof(FeatureParameterAttribute)} attribute, with type {Type}.", nameof(parameter)); case Feature.PositionalArguments when !parameter.ParameterType.IsAssignableFrom(typeof(ExtraPositionalArguments)): - throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(ExtraPositionalArguments)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(ExtraPositionalArguments)} as it has the {nameof(FeatureParameterAttribute)} attribute, with type {Type}.", nameof(parameter)); case Feature.CallerRef when !parameter.ParameterType.IsAssignableFrom(typeof(IEzrObject)): - throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(IEzrObject)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(IEzrObject)} as it has the {nameof(FeatureParameterAttribute)} attribute, with type {Type}.", nameof(parameter)); case Feature.ExecutionRef when !parameter.ParameterType.IsAssignableFrom(typeof(Context)): - throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(Context)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(Context)} as it has the {nameof(FeatureParameterAttribute)} attribute, with type {Type}.", nameof(parameter)); case Feature.InterpreterRef when !parameter.ParameterType.IsAssignableFrom(typeof(Interpreter)): - throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(Interpreter)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(Interpreter)} as it has the {nameof(FeatureParameterAttribute)} attribute, with type {Type}.", nameof(parameter)); case Feature.ResultRef when !parameter.ParameterType.IsAssignableFrom(typeof(RuntimeResult)): - throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(RuntimeResult)} as it has the {nameof(RuntimeAttribute)} attribute, with type {Type}.", nameof(parameter)); + throw new ArgumentException($"Parameter \"{parameter.Name}\" must be assignable from type {nameof(RuntimeResult)} as it has the {nameof(FeatureParameterAttribute)} attribute, with type {Type}.", nameof(parameter)); } } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/ExposeAttribute.cs b/src/Runtime/Types/Wrappers/Members/Methods/ParameterAttribute.cs similarity index 70% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/ExposeAttribute.cs rename to src/Runtime/Types/Wrappers/Members/Methods/ParameterAttribute.cs index cca7826..d0b290d 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/ExposeAttribute.cs +++ b/src/Runtime/Types/Wrappers/Members/Methods/ParameterAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +namespace EzrSquared.Runtime.Types.Wrappers.Members.Methods; /// /// Attribute to expose additonal data about the wrapped C# method parameter. @@ -8,7 +8,7 @@ namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.E /// The ezr² name for the parameter. /// Is the parameter optional? [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] -public class ExposeAttribute(string name, bool optional) : Attribute +public class ParameterAttribute(string name, bool optional) : Attribute { /// /// The ezr² name for the parameter. @@ -21,8 +21,8 @@ public class ExposeAttribute(string name, bool optional) : Attribute public readonly bool Optional = optional; /// The ezr² name for the parameter. - public ExposeAttribute(string name) : this(name, false) { } + public ParameterAttribute(string name) : this(name, false) { } /// Is the parameter optional? - public ExposeAttribute(bool optional) : this("", optional) { } + public ParameterAttribute(bool optional) : this("", optional) { } } diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/PrimaryConstructorAttribute.cs b/src/Runtime/Types/Wrappers/Members/Methods/PrimaryConstructorAttribute.cs similarity index 70% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/PrimaryConstructorAttribute.cs rename to src/Runtime/Types/Wrappers/Members/Methods/PrimaryConstructorAttribute.cs index 4ad4b0e..dc78629 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/ObjectMembers/Executables/Attributes/PrimaryConstructorAttribute.cs +++ b/src/Runtime/Types/Wrappers/Members/Methods/PrimaryConstructorAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.ObjectMembers.Executables.Attributes; +namespace EzrSquared.Runtime.Types.Wrappers.Members.Methods; /// /// Attribute that declares a primary constructor. diff --git a/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs b/src/Runtime/Types/Wrappers/WrapMemberAttribute.cs similarity index 85% rename from src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs rename to src/Runtime/Types/Wrappers/WrapMemberAttribute.cs index 815d62d..6f0d89a 100644 --- a/src/Runtime/Types/CSharpWrappers/CompatWrappers/Attributes/WrappedMemberAttribute.cs +++ b/src/Runtime/Types/Wrappers/WrapMemberAttribute.cs @@ -1,13 +1,13 @@ using System; using System.Reflection; -namespace EzrSquared.Runtime.Types.CSharpWrappers.CompatWrappers.Attributes; +namespace EzrSquared.Runtime.Types.Wrappers; /// /// Attribute for C# types and members to be automatically wrapped from C# types into ezr² types. /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] -public class WrappedMemberAttribute : Attribute +public class WrapMemberAttribute : Attribute { /// /// The ezr² name for the member. @@ -25,12 +25,12 @@ public class WrappedMemberAttribute : Attribute public readonly bool IsWriteOnly; /// - /// Creates a new . + /// Creates a new . /// /// Is the member read-only? Only for properties and fields. /// Is the member write-only? Only for properties and fields. /// Thrown if both and are set to . - public WrappedMemberAttribute(bool isReadOnly = false, bool isWriteOnly = false) + public WrapMemberAttribute(bool isReadOnly = false, bool isWriteOnly = false) { IsReadOnly = isReadOnly; IsWriteOnly = isWriteOnly; @@ -40,12 +40,12 @@ public WrappedMemberAttribute(bool isReadOnly = false, bool isWriteOnly = false) } /// - /// Creates a new . + /// Creates a new . /// /// The ezr² name for the member. /// Is the member read-only? Only for properties and fields. /// Is the member write-only? Only for properties and fields. - public WrappedMemberAttribute(string name, bool isReadOnly = false, bool isWriteOnly = false) : this(isReadOnly, isWriteOnly) + public WrapMemberAttribute(string name, bool isReadOnly = false, bool isWriteOnly = false) : this(isReadOnly, isWriteOnly) { Name = name; } @@ -60,7 +60,7 @@ public WrappedMemberAttribute(string name, bool isReadOnly = false, bool isWrite public static bool ValidateType(Type type, bool dontThrow = false) { if (type.IsAbstract || type.IsGenericTypeDefinition) - return dontThrow ? false : throw new ArgumentException($"The \"{nameof(WrappedMemberAttribute)}\" attribute does not support abstract/generic type \"{type.Name}\".", nameof(type)); + return dontThrow ? false : throw new ArgumentException($"The \"{nameof(WrapMemberAttribute)}\" attribute does not support abstract/generic type \"{type.Name}\".", nameof(type)); return true; } @@ -75,7 +75,7 @@ public static bool ValidateType(Type type, bool dontThrow = false) public static bool ValidateMethod(MethodBase methodBase, bool dontThrow = false) { if (methodBase.IsGenericMethodDefinition || methodBase.ContainsGenericParameters) - return dontThrow ? false : throw new ArgumentException($"The \"{nameof(WrappedMemberAttribute)}\" attribute does not support generic method/constructor \"{methodBase.Name}\".", nameof(methodBase)); + return dontThrow ? false : throw new ArgumentException($"The \"{nameof(WrapMemberAttribute)}\" attribute does not support generic method/constructor \"{methodBase.Name}\".", nameof(methodBase)); return true; } @@ -87,7 +87,7 @@ public static bool ValidateMethod(MethodBase methodBase, bool dontThrow = false) /// if yes, otherwise. public static bool ShouldBeWrapped(MemberInfo member) { - return member.GetCustomAttribute() is null && (GetIsPublic(member) || member.GetCustomAttribute() is not null); + return member.GetCustomAttribute() is null && (GetIsPublic(member) || member.GetCustomAttribute() is not null); } /// From 7ee60fe6045e0501ee510763db202265a354fe66 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 20 Dec 2024 23:33:16 +0530 Subject: [PATCH 103/113] Updated docs and CodeExecutor. --- docs/docfx.json | 1 + docs/docsrc/CSharp-and-ezrSquared.md | 3 +- docs/docsrc/Embedding-ezrSquared.md | 153 ++++++++++++++++++++++++++- docs/filterConfig.yml | 8 ++ src/Executor/CodeExecutor.cs | 6 +- 5 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 docs/filterConfig.yml diff --git a/docs/docfx.json b/docs/docfx.json index 6081ec7..8637c72 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -10,6 +10,7 @@ } ], "dest": "api", + "filter": "filterConfig.yml", "includePrivateMembers": true } ], diff --git a/docs/docsrc/CSharp-and-ezrSquared.md b/docs/docsrc/CSharp-and-ezrSquared.md index d470868..e2cff79 100644 --- a/docs/docsrc/CSharp-and-ezrSquared.md +++ b/docs/docsrc/CSharp-and-ezrSquared.md @@ -12,6 +12,7 @@ To learn more about embedding ezr² into your application, check the documentati Now, this is where **CSAELs** step in. CSAELs, or, **CSharp Assisted ezr² Libraries** are libraries written in C# for ezr² scripting. With CSAELs, anyone who knows C# can add any feature they want to ezr². These features can also be built-in to ezr² - it's a win-win situation! -All you have to do is wrap C# variables, functions and whatnot with attributes the ezr² interpreter can identify. All these "wrapper" attributes are part of the ezr² API. +All you have to do is wrap C# variables, functions and whatnot with attributes the ezr² interpreter can identify. All these "wrapper" attributes +are part of the ezr² API. To learn more about CSAELs, check the documentation [***here***](Get-started-with-CSAELs.md) diff --git a/docs/docsrc/Embedding-ezrSquared.md b/docs/docsrc/Embedding-ezrSquared.md index f87f5c1..c88ae93 100644 --- a/docs/docsrc/Embedding-ezrSquared.md +++ b/docs/docsrc/Embedding-ezrSquared.md @@ -1 +1,152 @@ -# TODO \ No newline at end of file +# Embedding ezr² + +Currently, the only version recommended for embedding in your C# apps is +the latest version of ezr² RE, available on [*NuGet*](https://www.nuget.org/packages/ezrSquared). + +The NuGet package is targeted for .NET 9 and .NET Standard 2.1 and is compatible with Unity. +You may need to use third-party packages like [*NuGetForUnity*](https://github.com/GlitchEnzo/NuGetForUnity) +to import it into Unity. + +Also, this documentation only applies to the *bleeding-edge latest version* of ezr² RE, which you may +have to compile from the `ezrSquared-re` branch of the repository. + +## CodeExecutor.cs + +The high-level class to interact with the ezr² runtime is the [`CodeExecutor`](~/api/EzrSquared.Executor.CodeExecutor.yml) class. + +### Setup + +All you have to do is call `CodeExecutor.CreateRuntimeContext("main");`. "main" is just the name for the runtime context. + +If you want to include built-in constants (like `true`, `false`, `nothing`), +functions (like `throw_error`, `assert`) or types (like `runtime_error`, `math_error`) +in the context, just call `CodeExecutor.PopulateRuntimeContext()`. + +If you are not making a console app, or want control of the IO, you can choose to not include the built-in IO +functions (`show`, `get` and `clear`), you can set `excludeIO` to `true`: `CodeExecutor.PopulateRuntimeContext(true)`. + +`CodeExecutor` also provides methods to add objects to the context. For example, you can add +a reference to a custom `show` function, which uses Unity's UI instead of `Console.WriteLine`. +You can check out the [*"Get Started with CSAELS" page*](Get-started-with-CSAELs.md) to know +more about wrappers. + +```csharp +public TMP_Text OutputText; + +private void Start() +{ + CodeExecutor.CreateRuntimeContext("main"); + CodeExecutor.PopulateRuntimeContext(true); + + CodeExecutor.AddToContext(new EzrMethodWrapper((Action)ShowOnCanvas, Context.Empty, Position.None, Position.None)); +} + +[WrapMember("show")] +private async void ShowOnCanvas(string text) +{ + await Awaitable.MainThreadAsync(); // Switch into Unity's main thread to modify the UI. + OutputText.text += $"\n{text}"; + + await Awaitable.BackgroundThreadAsync(); // Switch back to the background thread, so that ezr² does not block Unity. +} +``` + +### Interpreting Code + +Just call `CodeExecutor.Execute` with the code you want to interpret! It returns a +[*ExecutionResult*](~/api/EzrSquared.Executor.ExecutionResult.yml) object, which contains info +about the execution, like the AST, parse errors, runtime errors, and the actual result. + +So, for example, you can run a script asynchronously in Unity like so: + +```csharp +private async Awaitable RunScript(string code) +{ + ShowOnCanvas($">>> {code}"); + + await Awaitable.BackgroundThreadAsync(); + ExecutionResult executionResult = CodeExecutor.Execute(code); + + if (executionResult.Success) + ShowOnCanvas(executionResult.Result.ToString(CodeExecutor.RuntimeResult)); + else if (executionResult.Result is EzrRuntimeError) + ShowOnCanvas($"{executionResult.Result.ToPureString(CodeExecutor.RuntimeResult)}"); + else + ShowOnCanvas($"{executionResult.LexerError ?? executionResult.ParseError}"); +} +``` + +### Unity Shell Example + +This is an example script for making a simple interpreter shell in Unity. + +```csharp +using EzrSquared; +using EzrSquared.Executor; +using EzrSquared.Runtime; +using EzrSquared.Runtime.Types.Core.Errors; +using EzrSquared.Runtime.Types.Wrappers; +using EzrSquared.Runtime.Types.Wrappers.Members.Methods; +using System; +using TMPro; +using UnityEngine; + +public class Runner : MonoBehaviour +{ + [Tooltip("Text to show interpreter output.")] + public TMP_Text OutputText; + + [Tooltip("Input field for getting the user's code.")] + public TMP_InputField InputField; + + private void Start() + { + // Initialize the runtime context. + CodeExecutor.CreateRuntimeContext("main"); + + // Add built-ins, excluding IO functions. + CodeExecutor.PopulateRuntimeContext(true); + + // Add wrapper for "show" function which uses Unity UI. + CodeExecutor.AddToContext(new EzrMethodWrapper((Action)ShowOnCanvas, Context.Empty, Position.None, Position.None)); + } + + // This function will be called by a "Submit" or "Run" button. + public async void Run() + { + await RunScript(InputField.text); + } + + // Function to show text on the screen. + [WrapMember("show")] + private async void ShowOnCanvas(string text) + { + await Awaitable.MainThreadAsync(); // Switch into Unity's main thread to modify the UI. + OutputText.text += $"\n{text}"; + + await Awaitable.BackgroundThreadAsync(); // Switch back to the background thread, so that ezr² does not block Unity. + } + + // Function to run ezr² code in a background thread. + private async Awaitable RunScript(string code) + { + ShowOnCanvas($">>> {code}"); + + await Awaitable.BackgroundThreadAsync(); + ExecutionResult executionResult = CodeExecutor.Execute(code); + + if (executionResult.Success) + ShowOnCanvas(executionResult.Result.ToString(CodeExecutor.RuntimeResult)); + else if (executionResult.Result is EzrRuntimeError) + ShowOnCanvas($"{executionResult.Result.ToPureString(CodeExecutor.RuntimeResult)}"); + else + ShowOnCanvas($"{executionResult.LexerError ?? executionResult.ParseError}"); + } +} +``` + +## Lower-Level Access + +You can directly use the `Lexer`, `Parser` and `Interpreter` classes directly to execute code. You can even inherit from them to +customize the tokenization, parsing and interpretation of the ezr² language. This requires knowledge of the ezr² language +infrastructure, but provides much more customizability. You can start by cloning the ezr² repository and exploring the API! diff --git a/docs/filterConfig.yml b/docs/filterConfig.yml new file mode 100644 index 0000000..77f8513 --- /dev/null +++ b/docs/filterConfig.yml @@ -0,0 +1,8 @@ +### YamlMime:ManagedReference +apiRules: +- include: # The namespaces to generate + uidRegex: ^EzrSquared + type: Namespace +- exclude: + uidRegex: .* # Every other namespaces are ignored + type: Namespace \ No newline at end of file diff --git a/src/Executor/CodeExecutor.cs b/src/Executor/CodeExecutor.cs index d9fe8ec..4cec7aa 100644 --- a/src/Executor/CodeExecutor.cs +++ b/src/Executor/CodeExecutor.cs @@ -32,11 +32,11 @@ public static class CodeExecutor /// /// Creates the runtime context. /// - /// The file path to the code file this context will be used to execute. - public static void CreateRuntimeContext(string filePath) + /// The name of the context. + public static void CreateRuntimeContext(string name) { RuntimeContext?.Release(); - RuntimeContext = new Context(filePath, true, new Position(0, 0, filePath, string.Empty)); + RuntimeContext = new Context(name, true, new Position(0, 0, name, string.Empty)); } /// From 31cbb72e861d583279c5bb67fb61b20de173f0f6 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Fri, 20 Dec 2024 23:49:38 +0530 Subject: [PATCH 104/113] Fixed docs in EzrBuiltinFunctions. --- docs/docsrc/Embedding-ezrSquared.md | 2 +- .../Types/Builtins/EzrBuiltinFunctions.cs | 198 ++++-------------- 2 files changed, 38 insertions(+), 162 deletions(-) diff --git a/docs/docsrc/Embedding-ezrSquared.md b/docs/docsrc/Embedding-ezrSquared.md index c88ae93..1864fa7 100644 --- a/docs/docsrc/Embedding-ezrSquared.md +++ b/docs/docsrc/Embedding-ezrSquared.md @@ -54,7 +54,7 @@ private async void ShowOnCanvas(string text) ### Interpreting Code Just call `CodeExecutor.Execute` with the code you want to interpret! It returns a -[*ExecutionResult*](~/api/EzrSquared.Executor.ExecutionResult.yml) object, which contains info +[`ExecutionResult`](~/api/EzrSquared.Executor.ExecutionResult.yml) object, which contains info about the execution, like the AST, parse errors, runtime errors, and the actual result. So, for example, you can run a script asynchronously in Unity like so: diff --git a/src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs index 12ddd6a..fb8ef22 100644 --- a/src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs @@ -2,7 +2,6 @@ using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core; using EzrSquared.Runtime.Types.Core.Errors; -using EzrSquared.Runtime.Types.Core.Numerics; using EzrSquared.Runtime.Types.Core.Text; using EzrSquared.Runtime.Types.Wrappers; using EzrSquared.Runtime.Types.Wrappers.Members.Methods; @@ -21,37 +20,15 @@ public static class EzrBuiltinFunctions /// Basic console print function. Implements . /// /// - /// ezr² parameters: - /// - /// - /// Extra Positional Arguments - /// ( of s) The message(s) to display on the console. - /// - /// - /// line_end - /// (Optional, ) Line end character(s) to use instead of \n. - /// - /// - /// separator - /// (Optional, ) separator to separate each message to be printed. - /// - /// - /// - /// ezr² return type: - /// - ///
/// ezr² errors: - /// - /// - /// - /// Thrown if no messages are provided. - /// - /// - /// - /// Thrown if "line_end" or "separator" are not of the specified types. - /// - /// + /// if no messages are provided. ///
+ /// Optional line end character(s) to use instead of . + /// Optional separator to separate each message to be printed. + /// The message(s) to display on the console. + /// Reference to the caller. + /// Reference to the current . + /// Reference to the current execution context. [WrapMember] public static void Show( [Parameter(true)] string lineEnd, @@ -89,27 +66,8 @@ public static void Show( /// /// Basic error throwing function. Implements . /// - /// - /// ezr² parameters: - /// - /// - /// error - /// () The error to throw. - /// - /// - /// - /// ezr² errors: - /// - /// - /// - /// if "error" is not of the specified type. - /// - /// - /// error - /// the given error. - /// - /// - /// + /// The error to throw. + /// Reference to the current . [WrapMember] public static void ThrowError(IEzrRuntimeError error, [FeatureParameter(Feature.ResultRef)] RuntimeResult result) { @@ -119,18 +77,9 @@ public static void ThrowError(IEzrRuntimeError error, [FeatureParameter(Feature. /// /// Basic console input function. Implements . /// - /// - /// ezr² parameters: - /// - /// - /// message - /// () The message to display on the console before waiting for user input. - /// - /// - /// - /// ezr² return type: - /// - /// + /// The message to display on the console before waiting for user input. + /// Reference to the current . + /// The user's input. [WrapMember] public static string Get([Parameter(true)] IEzrObject? message, [FeatureParameter(Feature.ResultRef)] RuntimeResult result) { @@ -149,10 +98,6 @@ public static string Get([Parameter(true)] IEzrObject? message, [FeatureParamete /// /// Basic console clear function. Implements . /// - /// - /// ezr² return type: - /// - /// [WrapMember] public static void Clear() { @@ -163,20 +108,13 @@ public static void Clear() /// Assertion function to assert conditions. ///
/// - /// ezr² parameters: - /// - /// - /// condition - /// () The condition to assert. - /// - /// - /// - /// ezr² return type: - /// - ///
/// ezr² errors: /// if the condition is not met. ///
+ /// The condition to assert. + /// Reference to the caller. + /// Reference to the current . + /// Reference to the current execution context. [WrapMember] public static void Assert(IEzrObject condition, [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, @@ -191,18 +129,9 @@ public static void Assert(IEzrObject condition, /// /// Basic hash function. Implements . /// - /// - /// ezr² parameters: - /// - /// - /// to_hash - /// () The object to hash. - /// - /// - /// - /// ezr² return type: - /// - /// + /// The object to hash. + /// Reference to the current . + /// The hash of the object. [WrapMember] public static int Hash(IEzrObject toHash, [FeatureParameter(Feature.ResultRef)] RuntimeResult result) { @@ -212,18 +141,8 @@ public static int Hash(IEzrObject toHash, [FeatureParameter(Feature.ResultRef)] /// /// Basic -like function. Uses . /// - /// - /// ezr² parameters: - /// - /// - /// to_check - /// () The object to check the type of. - /// - /// - /// - /// ezr² return type: - /// - /// + /// The object to check the type of. + /// The tag of the object. [WrapMember] public static string TypeOf(IEzrObject toCheck) { @@ -233,18 +152,8 @@ public static string TypeOf(IEzrObject toCheck) /// /// Gets the plain text name of the type of an object. Uses . /// - /// - /// ezr² parameters: - /// - /// - /// to_check - /// () The object to check the type-name of. - /// - /// - /// - /// ezr² return type: - /// - /// + /// The object to check the type-name of. + /// The type name of the object. [WrapMember] public static string TypeNameOf(IEzrObject toCheck) { @@ -254,18 +163,8 @@ public static string TypeNameOf(IEzrObject toCheck) /// /// Gets the hash ID of the type of an object. Uses . /// - /// - /// ezr² parameters: - /// - /// - /// to_check - /// () The object to check the type hash of. - /// - /// - /// - /// ezr² return type: - /// - /// + /// The object to check the type hash of. + /// The hashed tag of the object. [WrapMember] public static int TypeHashOf(IEzrObject toCheck) { @@ -276,20 +175,12 @@ public static int TypeHashOf(IEzrObject toCheck) /// Creates a copy of an . Uses . ///
/// - /// ezr² parameters: - /// - /// - /// to_copy - /// () The object to copy. - /// - /// - /// - /// ezr² return type: - /// - /// /// ezr² errors: /// if "to_copy" is not of the expected type. /// + /// The object to copy. + /// Reference to the current . + /// The copy of the object. [WrapMember] public static IEzrObject Copy(IEzrMutableObject toCopy, [FeatureParameter(Feature.ResultRef)] RuntimeResult result) { @@ -299,18 +190,10 @@ public static IEzrObject Copy(IEzrMutableObject toCopy, [FeatureParameter(Featur /// /// Wraps the given ezr² object so that the runtime has access to its raw C# object. /// - /// - /// ezr² parameters: - /// - /// - /// to_wrap - /// () The object to wrap. - /// - /// - /// - /// ezr² return type: - /// - /// + /// The object to wrap. + /// Reference to the caller. + /// Reference to the current execution context. + /// The wrapped object. [WrapMember] public static EzrObjectWrapper GetRaw(IEzrObject toGet, [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, @@ -322,18 +205,11 @@ public static EzrObjectWrapper GetRaw(IEzrObject toGet, /// /// Returns an of the references (as <name, object>) contained in the of the given object. /// - /// - /// ezr² parameters: - /// - /// - /// to_get - /// () The object to get the context of. - /// - /// - /// - /// ezr² return type: - /// - /// + /// The object to get the context of. + /// Reference to the caller. + /// Reference to the current . + /// Reference to the current execution context. + /// The content of the object's context. [WrapMember] public static IEzrObject GetContext(IEzrObject toGet, [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, From 67528e25c2a467ddadb36c93a5b01c7a810e99cf Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 21 Dec 2024 01:41:10 +0530 Subject: [PATCH 105/113] Updated docs. --- docs/docsrc/Embedding-ezrSquared.md | 6 +- docs/docsrc/Get-started-with-CSAELs.md | 100 +++++++++++++++++- .../Types/Builtins/EzrBuiltinFunctions.cs | 4 - 3 files changed, 102 insertions(+), 8 deletions(-) diff --git a/docs/docsrc/Embedding-ezrSquared.md b/docs/docsrc/Embedding-ezrSquared.md index 1864fa7..dd48ca3 100644 --- a/docs/docsrc/Embedding-ezrSquared.md +++ b/docs/docsrc/Embedding-ezrSquared.md @@ -1,5 +1,8 @@ # Embedding ezr² +This documentation only applies to the *bleeding-edge latest version* of ezr² RE, which you may +have to compile from the `ezrSquared-re` branch of the repository. + Currently, the only version recommended for embedding in your C# apps is the latest version of ezr² RE, available on [*NuGet*](https://www.nuget.org/packages/ezrSquared). @@ -7,9 +10,6 @@ The NuGet package is targeted for .NET 9 and .NET Standard 2.1 and is compatible You may need to use third-party packages like [*NuGetForUnity*](https://github.com/GlitchEnzo/NuGetForUnity) to import it into Unity. -Also, this documentation only applies to the *bleeding-edge latest version* of ezr² RE, which you may -have to compile from the `ezrSquared-re` branch of the repository. - ## CodeExecutor.cs The high-level class to interact with the ezr² runtime is the [`CodeExecutor`](~/api/EzrSquared.Executor.CodeExecutor.yml) class. diff --git a/docs/docsrc/Get-started-with-CSAELs.md b/docs/docsrc/Get-started-with-CSAELs.md index f87f5c1..e94cd40 100644 --- a/docs/docsrc/Get-started-with-CSAELs.md +++ b/docs/docsrc/Get-started-with-CSAELs.md @@ -1 +1,99 @@ -# TODO \ No newline at end of file +# Get Started with CSAELs + +This documentation only applies to the *bleeding-edge latest version* of ezr² RE, which you may +have to compile from the `ezrSquared-re` branch of the repository. + +CSAELs, or **CS**harp **A**ssisted **E**zr² **L**ibraries, are class libraries written in C# meant to +be used by the ezr² runtime. With the latest versions of ezr² RE supporting automatic C# wrappers which +can wrap existing C# code not specifically meant for use with ezr², CSAELs are very easy to make if you +know C#. + +Although ezr² RE does not yet support importing CSAELs at runtime, it can be added through custom +runtime implementations. See the ["Embedding ezr² page"](Embedding-ezrSquared.md) for more details. + +Currently, the only version recommended for making CSAELs with is the latest version of ezr² RE, +available on [*NuGet*](https://www.nuget.org/packages/ezrSquared). The package is targeted for +.NET 9 and .NET Standard 2.1 and is compatible with Unity. + +## High Level Usage + +The [wrapper infrastructure](~/api/EzrSquared.Runtime.Types.Wrappers.yml) for ezr² already supports +a lot of C# features, so the attributes provided by the NuGet package are only for providing additional +metadata to the runtime or for using specific features like extra keyword arguments or extra positional +arguments (as [*params-modified*](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/method-parameters#params-modifier) +arguments are not support). + +### WrapMember Attribute + +When a type or object is being wrapped, by default, all public members are wrapped. Their names as +defined in C# are also converted to snake_case. If you want to wrap private members, or provide +additional metadata like a unique name, you can decorate the member with [`WrapMemberAttribute`](~/api/EzrSquared.Runtime.Types.Wrappers.WrapMemberAttribute.yml). + +`WrapMemberAttribute` can be used on the following member types: +- Classes +- Structs +- Constructors +- Methods +- Properties +- Fields + +For properties and fields, you can also decorate them as read-only or write-only, without +changing their signature in C#. + +### DontWrapMember Attribute + +To exclude a public member from being wrapped, you can decorate it with [`DontWrapMemberAttribute`](~/api/EzrSquared.Runtime.Types.Wrappers.DontWrapMemberAttribute.yml). + +## Wrapping Methods and Constructors + +### FeatureParameter Attribute + +When wrapping methods and constructors, you may want additional information from the ezr² runtime. +For example, if you want to create a new object, you will need a context and start and end positions. + +To do so, you can use [`FeatureParameterAttribute`](~/api/EzrSquared.Runtime.Types.Wrappers.Members.Methods.FeatureParameterAttribute.yml). +You can define a two parameters, one for the context reference, and one for a reference to the caller +of your method. You can then take the caller's start and end positions for the new object. + +```csharp +/// +/// Wraps the given ezr² object so that the runtime has access to its raw C# object. +/// +/// The object to wrap. +/// Reference to the caller. +/// Reference to the current execution context. +/// The wrapped object. +[WrapMember] +public static EzrObjectWrapper GetRaw(IEzrObject toGet, + [FeatureParameter(Feature.CallerRef)] IEzrObject wrapper, + [FeatureParameter(Feature.ExecutionRef)] Context executionContext) +{ + return new EzrObjectWrapper(toGet, toGet.GetType(), executionContext, wrapper.StartPosition, wrapper.EndPosition); +} +``` + +The attribute can also be used to get references to the interpreter, the current `RuntimeResult` and +access to extra positional/keyword arguments. See [`Feature`](~/api/EzrSquared.Runtime.Types.Wrappers.Members.Methods.Feature.yml) +for more details. + +### Parameter Attribute + +If you want to provide a custom name for your wrapped method's parameters, you can use [ParameterAttribute](~/api/EzrSquared.Runtime.Types.Wrappers.Members.Methods.ParameterAttribute.yml). +You can also declare optional parameters this way. Optional parameters are required to be nullable. + +### PrimaryConstructor Attribute + +All constructors in a type to be wrapped are, by default, named either by the name provided in their +`WrapMemberAttribute`, or given the predefined name `make` or `make_[n]` where `[n]` starts from 1 and +increases every time another constructor without a given name is found. They are then stored in the context +of the `EzrTypeWrapper`. A single constructor, for each type, can be declared a "primary constructor", which +will be used when the `Execute` method is called on the type wrapper. The constructor must be declared with +a [PrimaryConstructorAttribute](~/api/EzrSquared.Runtime.Types.Wrappers.Members.Methods.PrimaryConstructorAttribute.yml). + +## Example References + +All runtime error types in ezr² are wrapped! Although the objects themselves are `IEzrObject`s, the type is +wrapped to provide the constructor at runtime. You can check out the source code for all runtime error types +[*here*](https://github.com/Uralstech/ezrSquared/tree/ezrSquared-re/src/Runtime/Types/Core/RuntimeErrors). + +All built-in methods are also wrapped! You can check out their source code [*here*](https://github.com/Uralstech/ezrSquared/blob/ezrSquared-re/src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs). \ No newline at end of file diff --git a/src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs b/src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs index fb8ef22..d55c308 100644 --- a/src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs +++ b/src/Runtime/Types/Builtins/EzrBuiltinFunctions.cs @@ -174,10 +174,6 @@ public static int TypeHashOf(IEzrObject toCheck) /// /// Creates a copy of an . Uses . /// - /// - /// ezr² errors: - /// if "to_copy" is not of the expected type. - /// /// The object to copy. /// Reference to the current . /// The copy of the object. From 8373cc5a76bf2a606d5379c999a4137f5c394a60 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 21 Dec 2024 13:21:14 +0530 Subject: [PATCH 106/113] Improved converters for wrappers, and updated constraints. --- docs/docsrc/Embedding-ezrSquared.md | 2 +- docs/docsrc/Get-started-with-CSAELs.md | 74 +++++++++++++++++++ src/Runtime/Types/Wrappers/EzrWrapper.cs | 5 +- .../Members/Methods/EzrMethodBaseWrapper.cs | 5 ++ 4 files changed, 84 insertions(+), 2 deletions(-) diff --git a/docs/docsrc/Embedding-ezrSquared.md b/docs/docsrc/Embedding-ezrSquared.md index dd48ca3..76986b5 100644 --- a/docs/docsrc/Embedding-ezrSquared.md +++ b/docs/docsrc/Embedding-ezrSquared.md @@ -10,7 +10,7 @@ The NuGet package is targeted for .NET 9 and .NET Standard 2.1 and is compatible You may need to use third-party packages like [*NuGetForUnity*](https://github.com/GlitchEnzo/NuGetForUnity) to import it into Unity. -## CodeExecutor.cs +## CodeExecutor The high-level class to interact with the ezr² runtime is the [`CodeExecutor`](~/api/EzrSquared.Executor.CodeExecutor.yml) class. diff --git a/docs/docsrc/Get-started-with-CSAELs.md b/docs/docsrc/Get-started-with-CSAELs.md index e94cd40..cb14096 100644 --- a/docs/docsrc/Get-started-with-CSAELs.md +++ b/docs/docsrc/Get-started-with-CSAELs.md @@ -90,6 +90,80 @@ of the `EzrTypeWrapper`. A single constructor, for each type, can be declared a will be used when the `Execute` method is called on the type wrapper. The constructor must be declared with a [PrimaryConstructorAttribute](~/api/EzrSquared.Runtime.Types.Wrappers.Members.Methods.PrimaryConstructorAttribute.yml). +## Type Support + +### ezr² Object -> C# Object + +The method responsible for converting `IEzrObject`s to C# objects is [`EzrWrapper.EzrObjectToCSharp`](~/api/EzrSquared.Runtime.Types.Wrappers.EzrWrapper-1.yml). + +The following table shows which C# types can be converted from which ezr² objects. + +| C# Type | Converted From | +|-------------------|-----------------------| +| byte | EzrFloat, EzrInteger | +| sbyte | EzrFloat, EzrInteger | +| short | EzrFloat, EzrInteger | +| ushort | EzrFloat, EzrInteger | +| int | EzrFloat, EzrInteger | +| uint | EzrFloat, EzrInteger | +| long | EzrFloat, EzrInteger | +| ulong | EzrFloat, EzrInteger | +| BigInteger | EzrFloat, EzrInteger | +| float | EzrFloat, EzrInteger | +| double | EzrFloat, EzrInteger | +| decimal | EzrFloat, EzrInteger | +| bool | EzrBoolean | +| char | EzrCharacter | +| string | IEzrString | +| Null Reference | EzrNothing | + +If the C# type is assignable from the ezr² object's type, for example, if the C# type +is `IEzrObject` and the ezr² object is `EzrInteger`, the method passes the ezr² object +without any conversion. + +If the C# type is `Task`, then it returns `Task.FromResult([the ezr² object])` where `T` is the type of +the ezr² object. If the type is a variant of task, like `Task`, then it uses the enclosed type +to run the method again with it as the target. + +Arrays are also supported, the method checks if the ezr² object is an `IEzrIndexedCollection` and tries to +convert each element to the array's element type. + +For all other types, it checks if the ezr² object is an `EzrObjectWrapper` and checks if the target type +is assignable from the wrapped type. + +The method also supports the `Nullable` variants of all the above, where it checks if the ezr² object +is an `EzrNothing` or tries to convert the object to the underlying type of the `Nullable`. + +### C# Object -> ezr² Object + +The method responsible for converting C# objects to `IEzrObject`s is [`EzrWrapper.CSharpToEzrObject`](~/api/EzrSquared.Runtime.Types.Wrappers.EzrWrapper-1.yml). + +The following table shows which C# types are natively supported: + +| C# Type | Converted To | +|-------------------|-----------------------| +| byte | EzrInteger | +| sbyte | EzrInteger | +| short | EzrInteger | +| ushort | EzrInteger | +| int | EzrInteger | +| uint | EzrInteger | +| long | EzrInteger | +| ulong | EzrInteger | +| BigInteger | EzrInteger | +| float | EzrFloat | +| double | EzrFloat | +| decimal | EzrFloat | +| bool | EzrBoolean | +| char | EzrCharacter | +| string | EzrString | +| Null Reference | EzrNothing | +| Array | EzrArray | + +Array elements are converted based on the array element type. If the C# object is itself +an `IEzrObject`, it is returned as-is. All other types not listed here are wrapped into +`EzrObjectWrapper`s. + ## Example References All runtime error types in ezr² are wrapped! Although the objects themselves are `IEzrObject`s, the type is diff --git a/src/Runtime/Types/Wrappers/EzrWrapper.cs b/src/Runtime/Types/Wrappers/EzrWrapper.cs index 431f709..a48c4e2 100644 --- a/src/Runtime/Types/Wrappers/EzrWrapper.cs +++ b/src/Runtime/Types/Wrappers/EzrWrapper.cs @@ -248,6 +248,9 @@ public EzrWrapper(TMemberInfo wrappedMember, object? instance, Context parentCon result.Failure(new EzrUnexpectedTypeError($"Expected string, character or character list, but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); break; + case TypeCode.Object when Nullable.GetUnderlyingType(targetType) is Type underlyingType: + return value is EzrNothing ? null : EzrObjectToCSharp(value, underlyingType, result); + case TypeCode.Object when targetType.IsAssignableFrom(value.GetType()): return value; @@ -280,7 +283,7 @@ public EzrWrapper(TMemberInfo wrappedMember, object? instance, Context parentCon break; default: - if (value is EzrObjectWrapper wrapper && wrapper.SharpMember == targetType) + if (value is EzrObjectWrapper wrapper && targetType.IsAssignableFrom(wrapper.SharpMember)) return wrapper.Instance; result.Failure(new EzrUnexpectedTypeError($"Expected wrapped object of C# type \"{targetType.Name}\", but got object of type \"{value.TypeName}\"!", Context, value.StartPosition, value.EndPosition)); diff --git a/src/Runtime/Types/Wrappers/Members/Methods/EzrMethodBaseWrapper.cs b/src/Runtime/Types/Wrappers/Members/Methods/EzrMethodBaseWrapper.cs index 437ae53..c16326b 100644 --- a/src/Runtime/Types/Wrappers/Members/Methods/EzrMethodBaseWrapper.cs +++ b/src/Runtime/Types/Wrappers/Members/Methods/EzrMethodBaseWrapper.cs @@ -78,6 +78,11 @@ public EzrMethodBaseWrapper(TMethodBase sharpMethodBase, object? instance, Conte if (runtimeParamAttribute is null) { + if (autoWrapperAttribute?.Optional == true + && parameterInfo.ParameterType.IsValueType + && Nullable.GetUnderlyingType(parameterInfo.ParameterType) is null) + throw new ArgumentException($"Method \"{SharpMember.Name}\" contains a parameter declared optional through its {nameof(ParameterAttribute)} which is not nullable ({parameterInfo.Name})!", nameof(sharpMethodBase)); + exposedParameters.Add((parameterInfo, autoWrapperAttribute?.Optional ?? false)); exposedParameterNames.Add(string.IsNullOrEmpty(autoWrapperAttribute?.Name) ? PascalToSnakeCase(parameterInfo.Name) ?? $"param_{i}" : autoWrapperAttribute.Name); continue; From 0d8cf04ee9b64032c742b14fb6279f8a6590c8ab Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sat, 21 Dec 2024 13:38:59 +0530 Subject: [PATCH 107/113] Updated docs. --- docs/docsrc/Get-started-with-CSAELs.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docsrc/Get-started-with-CSAELs.md b/docs/docsrc/Get-started-with-CSAELs.md index cb14096..1e4a7a0 100644 --- a/docs/docsrc/Get-started-with-CSAELs.md +++ b/docs/docsrc/Get-started-with-CSAELs.md @@ -94,7 +94,7 @@ a [PrimaryConstructorAttribute](~/api/EzrSquared.Runtime.Types.Wrappers.Members. ### ezr² Object -> C# Object -The method responsible for converting `IEzrObject`s to C# objects is [`EzrWrapper.EzrObjectToCSharp`](~/api/EzrSquared.Runtime.Types.Wrappers.EzrWrapper-1.yml). +The method responsible for converting `IEzrObject`s to C# objects is [`EzrWrapper.EzrObjectToCSharp`](~/api/EzrSquared.Runtime.Types.Wrappers.EzrWrapper-1.yml#EzrSquared_Runtime_Types_Wrappers_EzrWrapper_1_EzrObjectToCSharp_EzrSquared_Runtime_Types_IEzrObject_System_Type_EzrSquared_Runtime_RuntimeResult_). The following table shows which C# types can be converted from which ezr² objects. @@ -136,7 +136,7 @@ is an `EzrNothing` or tries to convert the object to the underlying type of the ### C# Object -> ezr² Object -The method responsible for converting C# objects to `IEzrObject`s is [`EzrWrapper.CSharpToEzrObject`](~/api/EzrSquared.Runtime.Types.Wrappers.EzrWrapper-1.yml). +The method responsible for converting C# objects to `IEzrObject`s is [`EzrWrapper.CSharpToEzrObject`](~/api/EzrSquared.Runtime.Types.Wrappers.EzrWrapper-1.yml#EzrSquared_Runtime_Types_Wrappers_EzrWrapper_1_CSharpToEzrObject_System_Object_System_Type_EzrSquared_Runtime_RuntimeResult_). The following table shows which C# types are natively supported: From a1faf5b6add439eb4d147fd9260755dd02738a25 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Sun, 22 Dec 2024 13:01:08 +0530 Subject: [PATCH 108/113] Performance update. --- .../Collections/RuntimeEzrObjectDictionary.cs | 125 ++++++++---------- .../Collections/RuntimeEzrObjectList.cs | 1 - src/Runtime/Context.cs | 2 - .../Types/Collections/EzrDictionary.cs | 16 +-- src/Runtime/Types/Executables/EzrFunction.cs | 53 +++++--- 5 files changed, 94 insertions(+), 103 deletions(-) diff --git a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs index a636264..d84004e 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectDictionary.cs @@ -1,4 +1,5 @@ -using EzrSquared.Runtime.Types; +global using KeyValueRef = (EzrSquared.Runtime.Types.IEzrObject Key, EzrSquared.Runtime.Reference ValueRef); +using EzrSquared.Runtime.Types; using EzrSquared.Runtime.Types.Collections; using EzrSquared.Runtime.Types.Core.Errors; using EzrSquared.Runtime.Types.Wrappers; @@ -11,34 +12,24 @@ namespace EzrSquared.Runtime.Collections; /// /// A Dictionary for s. /// -public class RuntimeEzrObjectDictionary : IMutable, IEnumerable>> +public class RuntimeEzrObjectDictionary : Dictionary, IMutable, IEnumerable { - /// - /// The collection of s stored in the , in the format Dictionary<hashOfKey, KeyValuePair<key, valueReference>>. - /// - private readonly IDictionary> _items; - /// /// The number of s in the . /// [WrapMember("length")] - public int Count => _items.Count; + public new int Count => base.Count; /// /// Creates a new . /// - public RuntimeEzrObjectDictionary() - { - _items = new Dictionary>(); - } + public RuntimeEzrObjectDictionary() : base() { } - /// - /// Creates a new from an existing . - /// - public RuntimeEzrObjectDictionary(IDictionary> items) - { - _items = items; - } + /// The capacity of the dictionary. + public RuntimeEzrObjectDictionary(int capacity) : base(capacity) { } + + /// An existing to create it from. + public RuntimeEzrObjectDictionary(IDictionary items) : base(items) { } /// /// Tries to get a copy of the given object. @@ -72,8 +63,8 @@ public void Update(IEzrObject key, IEzrObject value, RuntimeResult result) if (result.ShouldReturn) return; - if (_items.TryGetValue(hash, out KeyValuePair reference)) - reference.Value.UpdateObject(value); + if (TryGetValue(hash, out KeyValueRef reference)) + reference.ValueRef.UpdateObject(value); else { if (TryCopyObject(key, result) is not IEzrObject keyCopy) @@ -82,7 +73,7 @@ public void Update(IEzrObject key, IEzrObject value, RuntimeResult result) Reference valueReference = ReferencePool.Get(value); valueReference.UpdateRegister(true); - _items.Add(hash, new KeyValuePair(keyCopy, valueReference)); + Add(hash, new KeyValueRef(keyCopy, valueReference)); } } @@ -98,12 +89,12 @@ public bool Remove(IEzrObject key, RuntimeResult result) if (result.ShouldReturn) return false; - if (_items.TryGetValue(hash, out KeyValuePair pair)) + if (TryGetValue(hash, out KeyValueRef pair)) { - pair.Value.UpdateRegister(false); - ReferencePool.TryRelease(pair.Value); + pair.ValueRef.UpdateRegister(false); + ReferencePool.TryRelease(pair.ValueRef); - return _items.Remove(hash); + return Remove(hash); } return false; @@ -120,12 +111,12 @@ public bool Remove(IEzrObject key, RuntimeResult result) [WrapMember("remove_by_hash")] public bool RemoveHash(int key) { - if (_items.TryGetValue(key, out KeyValuePair pair)) + if (TryGetValue(key, out KeyValueRef pair)) { - pair.Value.UpdateRegister(false); - ReferencePool.TryRelease(pair.Value); + pair.ValueRef.UpdateRegister(false); + ReferencePool.TryRelease(pair.ValueRef); - return _items.Remove(key); + return Remove(key); } return false; @@ -138,15 +129,15 @@ public bool RemoveHash(int key) /// The object for returning errors. public void Merge(RuntimeEzrObjectDictionary other, RuntimeResult result) { - foreach (KeyValuePair> pair in other._items) + foreach (KeyValuePair pair in other) { if (TryCopyObject(pair.Value.Key, result) is not IEzrObject keyObject) return; - Reference newReference = ReferencePool.Get(pair.Value.Value.Object); + Reference newReference = ReferencePool.Get(pair.Value.ValueRef.Object); newReference.UpdateRegister(true); - _items[pair.Key] = new KeyValuePair(keyObject, newReference); + this[pair.Key] = new KeyValueRef(keyObject, newReference); } } @@ -183,7 +174,7 @@ public void Merge(IEzrDictionary other, Context executionContext, RuntimeResult public Reference Get(IEzrObject key, RuntimeResult result) { int hash = key.ComputeHashCode(result); - return (!result.ShouldReturn && _items.TryGetValue(hash, out KeyValuePair pair)) ? pair.Value : Reference.Empty; + return (!result.ShouldReturn && TryGetValue(hash, out KeyValueRef pair)) ? pair.ValueRef : Reference.Empty; } /// @@ -196,7 +187,7 @@ public Reference Get(IEzrObject key, RuntimeResult result) public bool HasKey(IEzrObject key, [FeatureParameter(Feature.ResultRef)] RuntimeResult result) { int hash = key.ComputeHashCode(result); - return !result.ShouldReturn && _items.ContainsKey(hash); + return !result.ShouldReturn && ContainsKey(hash); } /// @@ -207,19 +198,19 @@ public bool HasKey(IEzrObject key, [FeatureParameter(Feature.ResultRef)] Runtime /// The comparison result. public bool IsEqual(RuntimeEzrObjectDictionary other, RuntimeResult result) { - if (other._items.Count != _items.Count) + if (other.Count != Count) return false; - foreach (KeyValuePair> pair in _items) + foreach (KeyValuePair pair in this) { - if (!other._items.TryGetValue(pair.Key, out KeyValuePair otherPair)) + if (!other.TryGetValue(pair.Key, out KeyValueRef otherPair)) return false; bool keyEquals = pair.Value.Key.StrictEquals(otherPair.Key, result); if (result.ShouldReturn || !keyEquals) return false; - bool valueEquals = pair.Value.Value.Object.StrictEquals(otherPair.Value.Object, result); + bool valueEquals = pair.Value.ValueRef.Object.StrictEquals(otherPair.ValueRef.Object, result); if (result.ShouldReturn || !valueEquals) return false; } @@ -236,7 +227,7 @@ public bool IsEqual(RuntimeEzrObjectDictionary other, RuntimeResult result) /// The comparison result. public bool IsEqual(IEzrDictionary other, Context executionContext, RuntimeResult result) { - if (other.Count != _items.Count) + if (other.Count != Count) return false; foreach (IEzrObject ezrObject in other) @@ -250,14 +241,14 @@ public bool IsEqual(IEzrDictionary other, Context executionContext, RuntimeResul (IEzrObject keyObject, IEzrObject valueObject) = (pair.At(0), pair.At(1)); int keyHashCode = keyObject.ComputeHashCode(result); - if (result.ShouldReturn || !_items.TryGetValue(keyHashCode, out KeyValuePair thisPair)) + if (result.ShouldReturn || !TryGetValue(keyHashCode, out KeyValueRef thisPair)) return false; bool keyEquals = keyObject.StrictEquals(thisPair.Key, result); if (result.ShouldReturn || !keyEquals) return false; - bool valueEquals = valueObject.StrictEquals(thisPair.Value.Object, result); + bool valueEquals = valueObject.StrictEquals(thisPair.ValueRef.Object, result); if (result.ShouldReturn || !valueEquals) return false; } @@ -265,15 +256,6 @@ public bool IsEqual(IEzrDictionary other, Context executionContext, RuntimeResul return true; } - /// - /// Returns the actual integer (hash) keys from the . - /// - /// The integer hashes. - public int[] GetRealKeys() - { - return [.. _items.Keys]; - } - /// /// Retrieves all keys from the . /// @@ -281,8 +263,8 @@ public int[] GetRealKeys() /// The keys or if something went wrong. public IEzrObject[]? GetKeys(RuntimeResult result) { - IEzrObject[] keys = new IEzrObject[_items.Count]; - using IEnumerator> pairs = _items.Values.GetEnumerator(); + IEzrObject[] keys = new IEzrObject[Count]; + using ValueCollection.Enumerator pairs = Values.GetEnumerator(); for (int i = 0; i < keys.Length; i++) { @@ -303,13 +285,13 @@ public int[] GetRealKeys() /// The values. public IEzrObject[] GetValues() { - IEzrObject[] values = new IEzrObject[_items.Count]; - using IEnumerator> pairs = _items.Values.GetEnumerator(); + IEzrObject[] values = new IEzrObject[Count]; + using ValueCollection.Enumerator pairs = Values.GetEnumerator(); for (int i = 0; i < values.Length; i++) { pairs.MoveNext(); - values[i] = pairs.Current.Value.Object; + values[i] = pairs.Current.ValueRef.Object; } return values; @@ -322,8 +304,8 @@ public IEzrObject[] GetValues() /// The keys and values as an array of s or if something went wrong. public KeyValuePair[]? GetPairs(RuntimeResult result) { - KeyValuePair[] pairsArray = new KeyValuePair[_items.Count]; - using IEnumerator> pairs = _items.Values.GetEnumerator(); + KeyValuePair[] pairsArray = new KeyValuePair[Count]; + using ValueCollection.Enumerator pairs = Values.GetEnumerator(); for (int i = 0; i < pairsArray.Length; i++) { @@ -332,7 +314,7 @@ public IEzrObject[] GetValues() if (TryCopyObject(pairs.Current.Key, result) is not IEzrObject keyObject) return null; - pairsArray[i] = new KeyValuePair(keyObject, pairs.Current.Value.Object); + pairsArray[i] = new KeyValuePair(keyObject, pairs.Current.ValueRef.Object); } return pairsArray; @@ -341,14 +323,13 @@ public IEzrObject[] GetValues() /// public IMutable? DeepCopy(RuntimeResult result) { - Dictionary> copiedItems = new(_items.Count); - - foreach (KeyValuePair pair in _items.Values) + RuntimeEzrObjectDictionary copiedItems = new(Count); + foreach (KeyValueRef pair in Values) { if (TryCopyObject(pair.Key, result) is not IEzrObject keyObject) return null; - if (TryCopyObject(pair.Value.Object, result) is not IEzrObject valueObject) + if (TryCopyObject(pair.ValueRef.Object, result) is not IEzrObject valueObject) return null; Reference valueCopy = ReferencePool.Get(valueObject); @@ -358,10 +339,10 @@ public IEzrObject[] GetValues() if (result.ShouldReturn) return null; - copiedItems.Add(hash, new KeyValuePair(keyObject, valueCopy)); + copiedItems.Add(hash, new KeyValueRef(keyObject, valueCopy)); } - return new RuntimeEzrObjectDictionary(copiedItems); + return copiedItems; } /// @@ -369,13 +350,13 @@ public IEzrObject[] GetValues() /// public void Release() { - foreach (KeyValuePair> item in _items) + foreach (KeyValuePair item in this) { - item.Value.Value.UpdateRegister(false); - ReferencePool.TryRelease(item.Value.Value); + item.Value.ValueRef.UpdateRegister(false); + ReferencePool.TryRelease(item.Value.ValueRef); } - _items.Clear(); + Clear(); } /// @@ -384,9 +365,9 @@ public void Release() /// method does NOT copy the keys. So it's best not to expose the key values from this to the /// ezr² runtime as mutable key objects can be changed. /// - public IEnumerator>> GetEnumerator() + public new Enumerator GetEnumerator() { - return _items.GetEnumerator(); + return base.GetEnumerator(); } /// @@ -397,7 +378,7 @@ public IEnumerator>> GetEn /// IEnumerator IEnumerable.GetEnumerator() { - return GetEnumerator(); + return base.GetEnumerator(); } /// Destructor. diff --git a/src/Runtime/Collections/RuntimeEzrObjectList.cs b/src/Runtime/Collections/RuntimeEzrObjectList.cs index e0d76a5..cf5cabe 100644 --- a/src/Runtime/Collections/RuntimeEzrObjectList.cs +++ b/src/Runtime/Collections/RuntimeEzrObjectList.cs @@ -123,7 +123,6 @@ public void Release() } Clear(); - TrimExcess(); } /// Destructor. diff --git a/src/Runtime/Context.cs b/src/Runtime/Context.cs index dfe1df8..0300b73 100644 --- a/src/Runtime/Context.cs +++ b/src/Runtime/Context.cs @@ -470,8 +470,6 @@ public void Release() } _symbols.Clear(); - _symbols.TrimExcess(); - for (int i = 0; i < LinkedContexts.Length; i++) LinkedContexts[i]?.Release(); } diff --git a/src/Runtime/Types/Collections/EzrDictionary.cs b/src/Runtime/Types/Collections/EzrDictionary.cs index c87ffa9..85de8d3 100644 --- a/src/Runtime/Types/Collections/EzrDictionary.cs +++ b/src/Runtime/Types/Collections/EzrDictionary.cs @@ -78,8 +78,8 @@ public IEnumerator GetEnumerator(RuntimeResult result) /// public IEnumerator GetEnumerator() { - foreach (KeyValuePair> keyValuePair in Value) - yield return new EzrArray([keyValuePair.Value.Key, keyValuePair.Value.Value.Object], _executionContext, StartPosition, EndPosition); + foreach (KeyValuePair keyValuePair in Value) + yield return new EzrArray([keyValuePair.Value.Key, keyValuePair.Value.ValueRef.Object], _executionContext, StartPosition, EndPosition); } /// @@ -251,7 +251,7 @@ public override void Division(IEzrObject other, RuntimeResult result) result.Failure(IllegalOperation(other)); return; } - int[] keys = Value.GetRealKeys(); + int[] keys = [.. Value.Keys]; for (int i = Value.Count - 1; i >= newLength; i--) { if (!Value.RemoveHash(keys[i])) @@ -294,11 +294,11 @@ public override bool StrictEquals(IEzrObject other, RuntimeResult result) public override int ComputeHashCode(RuntimeResult result) { int hash = HashTag; - foreach (KeyValuePair> keyValuePair in Value) + foreach (KeyValuePair keyValuePair in Value) { int keyHash = keyValuePair.Key; - int valueHash = keyValuePair.Value.Value.Object.ComputeHashCode(result); + int valueHash = keyValuePair.Value.ValueRef.Object.ComputeHashCode(result); if (result.ShouldReturn) return int.MinValue; @@ -311,19 +311,19 @@ public override int ComputeHashCode(RuntimeResult result) /// public override string ToString(RuntimeResult result) { - using IEnumerator>> keyValuePairs = Value.GetEnumerator(); + using RuntimeEzrObjectDictionary.Enumerator keyValuePairs = Value.GetEnumerator(); string[] pairsAsString = new string[Value.Count]; for (int i = 0; i < pairsAsString.Length; i++) { keyValuePairs.MoveNext(); - KeyValuePair pair = keyValuePairs.Current.Value; + KeyValueRef pair = keyValuePairs.Current.Value; string key = pair.Key.ToString(result); if (result.ShouldReturn) return string.Empty; - string value = pair.Value.Object.ToString(result); + string value = pair.ValueRef.Object.ToString(result); if (result.ShouldReturn) return string.Empty; diff --git a/src/Runtime/Types/Executables/EzrFunction.cs b/src/Runtime/Types/Executables/EzrFunction.cs index 333bdb9..4e8f8a6 100644 --- a/src/Runtime/Types/Executables/EzrFunction.cs +++ b/src/Runtime/Types/Executables/EzrFunction.cs @@ -5,16 +5,7 @@ namespace EzrSquared.Runtime.Types.Executables; /// /// The function type object. /// -/// The name of the executable. -/// The source code body of the executable. -/// The source code of the executable's parameters and their default values. -/// The position in source code and name of the variable for the executable's extra keyword arguments. -/// The position in source code and name of the variable for the executable's extra positional arguments. -/// Should the function return its last expression as the result? -/// The parent context. -/// The starting position of the object. -/// The ending position of the object. -public class EzrFunction(string? name, Node body, (string Name, Node Node)[] parameters, OptionalExtraArguments extraKeywordArguments, OptionalExtraArguments extraPositionalArguments, bool returnLast, Context parentContext, Position startPosition, Position endPosition) : EzrRuntimeExecutable(name, body, parameters, extraKeywordArguments, extraPositionalArguments, parentContext, startPosition, endPosition), IEzrMutableObject +public class EzrFunction : EzrRuntimeExecutable, IEzrMutableObject { /// public override string TypeName { get; protected internal set; } = "function"; @@ -25,7 +16,30 @@ public class EzrFunction(string? name, Node body, (string Name, Node Node)[] par /// /// Should the function return its last expression as the result? /// - public readonly bool ReturnLast = returnLast; + public readonly bool ReturnLast; + + /// + /// The context used to run the method's code in. + /// + /// + /// Do not use this, it's cleared after the method is run. + /// + private readonly Context _runtimeMethodContext; + + /// The name of the executable. + /// The source code body of the executable. + /// The source code of the executable's parameters and their default values. + /// The position in source code and name of the variable for the executable's extra keyword arguments. + /// The position in source code and name of the variable for the executable's extra positional arguments. + /// Should the function return its last expression as the result? + /// The parent context. + /// The starting position of the object. + /// The ending position of the object. + public EzrFunction(string? name, Node body, (string Name, Node Node)[] parameters, OptionalExtraArguments extraKeywordArguments, OptionalExtraArguments extraPositionalArguments, bool returnLast, Context parentContext, Position startPosition, Position endPosition) : base(name, body, parameters, extraKeywordArguments, extraPositionalArguments, parentContext, startPosition, endPosition) + { + ReturnLast = returnLast; + _runtimeMethodContext = new($"<{TypeName} \"{ExecutableName}\">", false, StartPosition, CreationContext, CreationContext.StaticContext); + } /// /// Executes the current function. @@ -36,29 +50,28 @@ public class EzrFunction(string? name, Node body, (string Name, Node Node)[] par /// Should the function ignore extra arguments? public void Execute(Reference[] arguments, Interpreter interpreter, RuntimeResult result, bool ignoreExtraArguments) { - Context newContext = new($"<{TypeName} \"{ExecutableName}\">", false, StartPosition, CreationContext, CreationContext.StaticContext); - CheckAndPopulateArguments(arguments, newContext, interpreter, result, ignoreExtraArguments); + CheckAndPopulateArguments(arguments, _runtimeMethodContext, interpreter, result, ignoreExtraArguments); if (result.ShouldReturn) return; - interpreter.VisitNode(Body, newContext, null, AccessMod.None); + interpreter.VisitNode(Body, _runtimeMethodContext, null, AccessMod.None); if (result.ShouldReturnFunction) return; if (result.Reference.IsEmpty) { result.Success(NewNothingConstant()); - newContext.Release(); + _runtimeMethodContext.Release(); return; } - if (result.Reference.RegisteredContext?.Id == newContext.Id) - result.Reference.UpdateRegisteredContext(Context, newContext); - else if (result.Reference.Object.CreationContext.Id == newContext.Id) - result.Reference.Object.UpdateCreationContext(newContext); + if (result.Reference.RegisteredContext?.Id == _runtimeMethodContext.Id) + result.Reference.UpdateRegisteredContext(Context, _runtimeMethodContext); + else if (result.Reference.Object.CreationContext.Id == _runtimeMethodContext.Id) + result.Reference.Object.UpdateCreationContext(_runtimeMethodContext); result.Success(result.Reference); - newContext.Release(); + _runtimeMethodContext.Release(); } /// From 50e7704aafc9d437b8aa172ba08f48e59bfa7d24 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 24 Dec 2024 18:34:51 +0530 Subject: [PATCH 109/113] Position is a struct and RuntimeEzrObjectDictionary is a Dictionary. --- src/Position.cs | 39 +-- src/Runtime/Interpreter.cs | 2 +- .../Types/Executables/EzrRuntimeExecutable.cs | 2 +- src/Syntax/Lexer.cs | 256 +++++++++--------- src/Syntax/Parser/Parser.cs | 5 +- src/Token.cs | 10 +- src/TokenType.cs | 2 +- src/TokenTypeGroup.cs | 2 +- 8 files changed, 141 insertions(+), 177 deletions(-) diff --git a/src/Position.cs b/src/Position.cs index 2edb486..3581792 100644 --- a/src/Position.cs +++ b/src/Position.cs @@ -7,22 +7,22 @@ /// The line number of the in the script. /// The file name/path of the script. /// The script as text. -public class Position(int index, int line, string file, string script) +public readonly struct Position(int index, int line, string file, string script) { /// /// A position that does not exist. /// - public readonly static Position None = new(int.MinValue, int.MinValue, string.Empty, string.Empty); + public readonly static Position None = new(0, 0, string.Empty, string.Empty); /// /// The index of the in the script. /// - public int Index = index; + public readonly int Index = index; /// /// The line number of the in the script. /// - public int Line = line; + public readonly int Line = line; /// /// The file name/path of the script. @@ -38,39 +38,26 @@ public class Position(int index, int line, string file, string script) /// Advances the and increments by 1. If is a new-line character, is also incremented by 1. /// /// The character associated with the before advancing. - public void Advance(char currentChar) + public Position Advance(char currentChar) { - Index++; - - if (currentChar == '\n') - Line++; - } - - /// - /// Reverses to the given index. - /// - /// The index to reverse to. - /// The decrement for . - public void ReverseTo(int index, int lineDecrement) - { - Index = index; - Line -= lineDecrement; + return new Position(Index + 1, currentChar == '\n' ? Line + 1 : Line, File, Script); } /// /// Advances the and increments by 1. /// - public void Advance() + public Position Advance() { - Index++; + return new Position(Index + 1, Line, File, Script); } /// - /// Creates a copy of the object. + /// Reverses to the given index. /// - /// The copy. - public Position Copy() + /// The index to reverse to. + /// The decrement for . + public Position ReverseTo(int index, int lineDecrement) { - return new Position(Index, Line, File, Script); + return new Position(index, Line - lineDecrement, File, Script); } } diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index c964506..3db859a 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -282,7 +282,7 @@ private void VisitArrayLikeNodeArray(ArrayLikeNode node, Context executionContex /// The accessibility modifiers for objects that will be assigned from the executing . private void VisitDictionaryNode(DictionaryNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) { - RuntimeEzrObjectDictionary dictionary = new(); + RuntimeEzrObjectDictionary dictionary = []; List<(Node Key, Node Value)> pairs = node.KeyValuePairs; for (int i = 0; i < pairs.Count; i++) diff --git a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs index 7a57e58..e98fe18 100644 --- a/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs +++ b/src/Runtime/Types/Executables/EzrRuntimeExecutable.cs @@ -180,7 +180,7 @@ protected internal void CheckAndPopulateArguments(Reference[] arguments, Context if (parameterCode is VariableAccessNode vaNode) { operationAccessibilityModifiers = (vaNode.AccessibilityModifiers & AccessMod.Global) != AccessMod.Global - ? vaNode.AccessibilityModifiers |= AccessMod.LocalScope + ? vaNode.AccessibilityModifiers | AccessMod.LocalScope : vaNode.AccessibilityModifiers; } diff --git a/src/Syntax/Lexer.cs b/src/Syntax/Lexer.cs index c588030..01f4f00 100644 --- a/src/Syntax/Lexer.cs +++ b/src/Syntax/Lexer.cs @@ -23,7 +23,7 @@ public class Lexer /// /// The of the current lexing iteration in the script. /// - private readonly Position _position; + private Position _position; /// /// The character in the of the current lexing iteration in the script. @@ -57,8 +57,7 @@ private void Advance() if (_reachedEnd) return; - _position.Advance(_currentChar); - + _position = _position.Advance(_currentChar); if (_script.Length > _position.Index) _currentChar = _script[_position.Index]; else @@ -77,8 +76,8 @@ private void Advance() /// The index to reverse to. private void ReverseTo(int index) { - _position.ReverseTo(index, _script[index] == '\n' ? 1 : 0); - _currentChar = _script[_position.Index]; + _currentChar = _script[index]; + _position.ReverseTo(index, _currentChar == '\n' ? 1 : 0); } /// @@ -116,125 +115,125 @@ private void ReverseTo(int index) tokens.Add(CompileColon()); break; case '<': - Position lessThanTokenStartPosition = _position.Copy(); + Position lessThanTokenStartPosition = _position; Advance(); switch (_currentChar) { case '=': Advance(); - tokens.Add(new Token(TokenType.LessThanOrEqual, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.LessThanOrEqual, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position)); break; case '<': Advance(); - tokens.Add(new Token(TokenType.BitwiseLeftShift, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.BitwiseLeftShift, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position)); break; default: - tokens.Add(new Token(TokenType.LessThanSign, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.LessThanSign, TokenTypeGroup.Symbol, string.Empty, lessThanTokenStartPosition, _position)); break; } break; case '>': - Position greaterThanTokenStartPosition = _position.Copy(); + Position greaterThanTokenStartPosition = _position; Advance(); switch (_currentChar) { case '=': Advance(); - tokens.Add(new Token(TokenType.GreaterThanOrEqual, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.GreaterThanOrEqual, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position)); break; case '>': Advance(); - tokens.Add(new Token(TokenType.BitwiseRightShift, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.BitwiseRightShift, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position)); break; default: - tokens.Add(new Token(TokenType.GreaterThanSign, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position.Copy())); + tokens.Add(new Token(TokenType.GreaterThanSign, TokenTypeGroup.Symbol, string.Empty, greaterThanTokenStartPosition, _position)); break; } break; case '-': - tokens.Add(new Token(TokenType.HyphenMinus, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.HyphenMinus, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '+': - tokens.Add(new Token(TokenType.Plus, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.Plus, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '*': - tokens.Add(new Token(TokenType.Asterisk, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.Asterisk, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '/': - tokens.Add(new Token(TokenType.Slash, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.Slash, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '%': - tokens.Add(new Token(TokenType.PercentSign, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.PercentSign, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '^': - tokens.Add(new Token(TokenType.Caret, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.Caret, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '=': - tokens.Add(new Token(TokenType.EqualSign, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.EqualSign, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '!': - tokens.Add(new Token(TokenType.ExclamationMark, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.ExclamationMark, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case ',': - tokens.Add(new Token(TokenType.Comma, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.Comma, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '.': - tokens.Add(new Token(TokenType.Period, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.Period, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '(': - tokens.Add(new Token(TokenType.LeftParenthesis, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.LeftParenthesis, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case ')': - tokens.Add(new Token(TokenType.RightParenthesis, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.RightParenthesis, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '[': - tokens.Add(new Token(TokenType.LeftSquareBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.LeftSquareBracket, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case ']': - tokens.Add(new Token(TokenType.RightSquareBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.RightSquareBracket, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '{': - tokens.Add(new Token(TokenType.LeftCurlyBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.LeftCurlyBracket, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '}': - tokens.Add(new Token(TokenType.RightCurlyBracket, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.RightCurlyBracket, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '&': - tokens.Add(new Token(TokenType.Ampersand, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.Ampersand, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '|': - tokens.Add(new Token(TokenType.VerticalBar, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.VerticalBar, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '\\': - tokens.Add(new Token(TokenType.Backslash, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.Backslash, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '~': - tokens.Add(new Token(TokenType.Tilde, TokenTypeGroup.Symbol, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.Tilde, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; case '#': @@ -250,15 +249,11 @@ private void ReverseTo(int index) break; default: - Position errorStartPosition = _position.Copy(); - char unknownCharacter = _currentChar; - Advance(); - - return new EzrSyntaxError(EzrSyntaxError.UnexpectedCharacter, unknownCharacter.ToString(), errorStartPosition, _position); + return new EzrSyntaxError(EzrSyntaxError.UnexpectedCharacter, _currentChar.ToString(), _position, _position.Advance()); } } - tokens.Add(new Token(TokenType.EndOfFile, TokenTypeGroup.Special, string.Empty, _position.Copy())); + tokens.Add(new Token(TokenType.EndOfFile, TokenTypeGroup.Special, string.Empty, _position)); return null; } @@ -280,7 +275,7 @@ private void SkipComment() private Token CompileNumber() { StringBuilder numberValue = new(); - Position numberTokenStartPosition = _position.Copy(); + Position numberTokenStartPosition = _position; bool hasPeriod = false; while (!_reachedEnd && (char.IsDigit(_currentChar) || _currentChar == '.')) @@ -305,7 +300,7 @@ private Token CompileNumber() TokenTypeGroup.Value, numberValue.ToString(), numberTokenStartPosition, - _position.Copy() + _position ); } @@ -333,10 +328,10 @@ private Token CompileNewLines() } ReverseTo(lastNewLineIndex); - Position startPosition = _position.Copy(); + Position startPosition = _position; Advance(); - return new Token(TokenType.NewLine, TokenTypeGroup.Special, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.NewLine, TokenTypeGroup.Special, string.Empty, startPosition, _position); } /// @@ -349,7 +344,7 @@ private Token CompileStringLike(out EzrSyntaxError? error) char enclosingChar = _currentChar; StringBuilder toReturn = new(); - Position startPosition = _position.Copy(); + Position startPosition = _position; error = null; Advance(); @@ -371,10 +366,7 @@ private Token CompileStringLike(out EzrSyntaxError? error) if (_currentChar != enclosingChar) { - Position errorStartPosition = _position.Copy(); - _position.Advance(); - - error = new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, $"Expected '{enclosingChar}'!", errorStartPosition, _position); + error = new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, $"Expected '{enclosingChar}'!", _position, _position.Advance()); return Token.Empty; } @@ -399,7 +391,7 @@ private Token CompileStringLike(out EzrSyntaxError? error) TokenTypeGroup.Value, toReturn.ToString(), startPosition, - _position.Copy()); + _position); } /// @@ -409,7 +401,7 @@ private Token CompileStringLike(out EzrSyntaxError? error) /// Any that occurred in the process; if none occurred. private void ProcessEscapeSequence(StringBuilder builder, ref EzrSyntaxError? error) { - Position startPosition = _position.Copy(); + Position startPosition = _position; Advance(); switch (_currentChar) @@ -468,11 +460,11 @@ private void ProcessEscapeSequence(StringBuilder builder, ref EzrSyntaxError? er /// The UTF-16 character. private char[] ProcessUtf16Sequence(ref EzrSyntaxError? error) { + Advance(); + int characterCount = 0; string hexValue = string.Empty; - Position startPosition = _position.Copy(); - - Advance(); + Position startPosition = _position; while (characterCount < 4) { if (_currentChar is (>= 'a' and <= 'f') or (>= 'A' and <= 'F') or (>= '0' and <= '9')) @@ -483,10 +475,7 @@ private char[] ProcessUtf16Sequence(ref EzrSyntaxError? error) } else { - Position endPosition = _position.Copy(); - endPosition.Advance(); - - error = new EzrSyntaxError(EzrSyntaxError.InvalidHexValue, "UTF-16 hexadecimal values must be 4 characters long and only contain digits and the letters A to F!", startPosition, endPosition); + error = new EzrSyntaxError(EzrSyntaxError.InvalidHexValue, "UTF-16 hexadecimal values must be 4 characters long and only contain digits and the letters A to F!", startPosition, _position.Advance()); return []; } } @@ -501,11 +490,11 @@ private char[] ProcessUtf16Sequence(ref EzrSyntaxError? error) /// The UTF-32 character. private string ProcessUtf32Sequence(ref EzrSyntaxError? error) { + Advance(); + int characterCount = 0; string hexValue = string.Empty; - Position startPosition = _position.Copy(); - - Advance(); + Position startPosition = _position; while (characterCount < 6) { if (_currentChar is (>= 'a' and <= 'f') or (>= 'A' and <= 'F') or (>= '0' and <= '9')) @@ -516,10 +505,7 @@ private string ProcessUtf32Sequence(ref EzrSyntaxError? error) } else { - Position endPosition = _position.Copy(); - endPosition.Advance(); - - error = new EzrSyntaxError(EzrSyntaxError.InvalidHexValue, "UTF-32 hexadecimal values must be 6 characters long and only contain digits and the letters A to F!", startPosition, endPosition); + error = new EzrSyntaxError(EzrSyntaxError.InvalidHexValue, "UTF-32 hexadecimal values must be 6 characters long and only contain digits and the letters A to F!", startPosition, _position.Advance()); return string.Empty; } } @@ -540,46 +526,46 @@ private string ProcessUtf32Sequence(ref EzrSyntaxError? error) /// The created . private Token CompileColon() { - Position startPosition = _position.Copy(); + Position startPosition = _position; Advance(); switch (_currentChar) { case '+': Advance(); - return new Token(TokenType.AssignmentAddition, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentAddition, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); case '-': Advance(); - return new Token(TokenType.AssignmentSubtraction, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentSubtraction, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); case '*': Advance(); - return new Token(TokenType.AssignmentMultiplication, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentMultiplication, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); case '/': Advance(); - return new Token(TokenType.AssignmentDivision, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentDivision, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); case '%': Advance(); - return new Token(TokenType.AssignmentModulo, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentModulo, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); case '^': Advance(); - return new Token(TokenType.AssignmentPower, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentPower, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); case '&': Advance(); - return new Token(TokenType.AssignmentBitwiseAnd, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentBitwiseAnd, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); case '|': Advance(); - return new Token(TokenType.AssignmentBitwiseOr, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentBitwiseOr, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); case '\\': Advance(); - return new Token(TokenType.AssignmentBitwiseXOr, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentBitwiseXOr, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); case '<': Advance(); - return new Token(TokenType.AssignmentBitwiseLeftShift, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentBitwiseLeftShift, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); case '>': Advance(); - return new Token(TokenType.AssignmentBitwiseRightShift, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.AssignmentBitwiseRightShift, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); default: - return new Token(TokenType.Colon, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position.Copy()); + return new Token(TokenType.Colon, TokenTypeGroup.AssignmentSymbol, string.Empty, startPosition, _position); } } @@ -590,7 +576,7 @@ private Token CompileColon() /// The created . private Token CompileIdentifier(out EzrSyntaxError? error) { - Position startPosition = _position.Copy(); + Position startPosition = _position; error = null; bool isEscapedIdentifier = _currentChar == '#'; @@ -613,69 +599,69 @@ private Token CompileIdentifier(out EzrSyntaxError? error) string original = idValue.ToString(); return isEscapedIdentifier - ? new Token(TokenType.Identifier, TokenTypeGroup.Special, original, startPosition, _position.Copy()) + ? new Token(TokenType.Identifier, TokenTypeGroup.Special, original, startPosition, _position) : original.ToLower() switch { - "private" => new Token(TokenType.KeywordPrivate, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "constant" => new Token(TokenType.KeywordConstant, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "readonly" => new Token(TokenType.KeywordReadonly, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "item" => new Token(TokenType.KeywordItem, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "and" => new Token(TokenType.KeywordAnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "or" => new Token(TokenType.KeywordOr, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "invert" => new Token(TokenType.KeywordInvert, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "if" => new Token(TokenType.KeywordIf, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "else" => new Token(TokenType.KeywordElse, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "do" => new Token(TokenType.KeywordDo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "count" => new Token(TokenType.KeywordCount, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "for" => new Token(TokenType.KeywordFor, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "each" => new Token(TokenType.KeywordEach, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "from" => new Token(TokenType.KeywordFrom, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "as" => new Token(TokenType.KeywordAs, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "to" => new Token(TokenType.KeywordTo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "step" => new Token(TokenType.KeywordStep, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "while" => new Token(TokenType.KeywordWhile, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "function" => new Token(TokenType.KeywordFunction, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "private" => new Token(TokenType.KeywordPrivate, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "constant" => new Token(TokenType.KeywordConstant, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "readonly" => new Token(TokenType.KeywordReadonly, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "item" => new Token(TokenType.KeywordItem, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "and" => new Token(TokenType.KeywordAnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "or" => new Token(TokenType.KeywordOr, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "invert" => new Token(TokenType.KeywordInvert, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "if" => new Token(TokenType.KeywordIf, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "else" => new Token(TokenType.KeywordElse, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "do" => new Token(TokenType.KeywordDo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "count" => new Token(TokenType.KeywordCount, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "for" => new Token(TokenType.KeywordFor, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "each" => new Token(TokenType.KeywordEach, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "from" => new Token(TokenType.KeywordFrom, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "as" => new Token(TokenType.KeywordAs, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "to" => new Token(TokenType.KeywordTo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "step" => new Token(TokenType.KeywordStep, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "while" => new Token(TokenType.KeywordWhile, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "function" => new Token(TokenType.KeywordFunction, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), #pragma warning disable CS0618 - "special" => new Token(TokenType.KeywordSpecial, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), + "special" => new Token(TokenType.KeywordSpecial, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), #pragma warning restore CS0618 - "with" => new Token(TokenType.KeywordWith, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "more" => new Token(TokenType.KeywordMore, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "named" => new Token(TokenType.KeywordNamed, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "end" => new Token(TokenType.KeywordEnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "return" => new Token(TokenType.KeywordReturn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "last" => new Token(TokenType.KeywordLast, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "skip" => new Token(TokenType.KeywordSkip, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "stop" => new Token(TokenType.KeywordStop, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "try" => new Token(TokenType.KeywordTry, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "catch" => new Token(TokenType.KeywordCatch, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "not" => new Token(TokenType.KeywordNot, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "in" => new Token(TokenType.KeywordIn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "object" => new Token(TokenType.KeywordObject, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "global" => new Token(TokenType.KeywordGlobal, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "include" => new Token(TokenType.KeywordInclude, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "all" => new Token(TokenType.KeywordAll, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "static" => new Token(TokenType.KeywordStatic, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "define" => new Token(TokenType.KeywordDefine, TokenTypeGroup.Keyword, string.Empty, startPosition, _position.Copy()), - "f" => new Token(TokenType.QeywordF, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "l" => new Token(TokenType.QeywordL, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "e" => new Token(TokenType.QeywordE, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "c" => new Token(TokenType.QeywordC, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "p" => new Token(TokenType.QeywordP, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "t" => new Token(TokenType.QeywordT, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "n" => new Token(TokenType.QeywordN, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "w" => new Token(TokenType.QeywordW, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "fd" => new Token(TokenType.QeywordFd, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "sd" => new Token(TokenType.QeywordSd, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "sb" => new Token(TokenType.QeywordSb, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "od" => new Token(TokenType.QeywordOd, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "i" => new Token(TokenType.QeywordI, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "s" => new Token(TokenType.QeywordS, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "d" => new Token(TokenType.QeywordD, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "g" => new Token(TokenType.QeywordG, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - "v" => new Token(TokenType.QeywordV, TokenTypeGroup.Qeyword, original, startPosition, _position.Copy()), - _ => new Token(TokenType.Identifier, TokenTypeGroup.Special, original, startPosition, _position.Copy()), + "with" => new Token(TokenType.KeywordWith, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "more" => new Token(TokenType.KeywordMore, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "named" => new Token(TokenType.KeywordNamed, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "end" => new Token(TokenType.KeywordEnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "return" => new Token(TokenType.KeywordReturn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "last" => new Token(TokenType.KeywordLast, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "skip" => new Token(TokenType.KeywordSkip, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "stop" => new Token(TokenType.KeywordStop, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "try" => new Token(TokenType.KeywordTry, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "catch" => new Token(TokenType.KeywordCatch, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "not" => new Token(TokenType.KeywordNot, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "in" => new Token(TokenType.KeywordIn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "object" => new Token(TokenType.KeywordObject, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "global" => new Token(TokenType.KeywordGlobal, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "include" => new Token(TokenType.KeywordInclude, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "all" => new Token(TokenType.KeywordAll, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "static" => new Token(TokenType.KeywordStatic, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "define" => new Token(TokenType.KeywordDefine, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "f" => new Token(TokenType.QeywordF, TokenTypeGroup.Qeyword, original, startPosition, _position), + "l" => new Token(TokenType.QeywordL, TokenTypeGroup.Qeyword, original, startPosition, _position), + "e" => new Token(TokenType.QeywordE, TokenTypeGroup.Qeyword, original, startPosition, _position), + "c" => new Token(TokenType.QeywordC, TokenTypeGroup.Qeyword, original, startPosition, _position), + "p" => new Token(TokenType.QeywordP, TokenTypeGroup.Qeyword, original, startPosition, _position), + "t" => new Token(TokenType.QeywordT, TokenTypeGroup.Qeyword, original, startPosition, _position), + "n" => new Token(TokenType.QeywordN, TokenTypeGroup.Qeyword, original, startPosition, _position), + "w" => new Token(TokenType.QeywordW, TokenTypeGroup.Qeyword, original, startPosition, _position), + "fd" => new Token(TokenType.QeywordFd, TokenTypeGroup.Qeyword, original, startPosition, _position), + "sd" => new Token(TokenType.QeywordSd, TokenTypeGroup.Qeyword, original, startPosition, _position), + "sb" => new Token(TokenType.QeywordSb, TokenTypeGroup.Qeyword, original, startPosition, _position), + "od" => new Token(TokenType.QeywordOd, TokenTypeGroup.Qeyword, original, startPosition, _position), + "i" => new Token(TokenType.QeywordI, TokenTypeGroup.Qeyword, original, startPosition, _position), + "s" => new Token(TokenType.QeywordS, TokenTypeGroup.Qeyword, original, startPosition, _position), + "d" => new Token(TokenType.QeywordD, TokenTypeGroup.Qeyword, original, startPosition, _position), + "g" => new Token(TokenType.QeywordG, TokenTypeGroup.Qeyword, original, startPosition, _position), + "v" => new Token(TokenType.QeywordV, TokenTypeGroup.Qeyword, original, startPosition, _position), + _ => new Token(TokenType.Identifier, TokenTypeGroup.Special, original, startPosition, _position), }; } } \ No newline at end of file diff --git a/src/Syntax/Parser/Parser.cs b/src/Syntax/Parser/Parser.cs index 9f01088..06e2aaa 100644 --- a/src/Syntax/Parser/Parser.cs +++ b/src/Syntax/Parser/Parser.cs @@ -405,10 +405,7 @@ private void ParseQuickExpression(bool itemKeywordRequired = false) { if ((accessibilityModifiers & AccessMod.Global) == AccessMod.Global) { - Position errorStartPosition = startPosition.Copy(); - errorStartPosition.Advance(); - - _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "A variable, function or class cannot be declared 'global' and 'private' at the same time! It must be either 'global' , which means it is accessible to any code, or 'private' , which means it is only accessible to the current context.", errorStartPosition, _currentToken.EndPosition)); + _result.Failure(10, new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, "A variable, function or class cannot be declared 'global' and 'private' at the same time! It must be either 'global' , which means it is accessible to any code, or 'private' , which means it is only accessible to the current context.", startPosition.Advance(), _currentToken.EndPosition)); return; } diff --git a/src/Token.cs b/src/Token.cs index 8c4f3c8..9f0ca0e 100644 --- a/src/Token.cs +++ b/src/Token.cs @@ -3,7 +3,7 @@ /// /// The smallest component in the script identified by the , grouped together into objects to from source code constructs. /// -public class Token +public record Token { /// /// The identifying of the . @@ -50,13 +50,7 @@ public Token(TokenType type, TokenTypeGroup typeGroup, string value, Position st Value = value; StartPosition = startPosition; - if (endPosition is not null) - EndPosition = endPosition; - else - { - EndPosition = startPosition.Copy(); - EndPosition.Advance(); - } + EndPosition = endPosition is not null ? endPosition.Value : startPosition.Advance(); } /// diff --git a/src/TokenType.cs b/src/TokenType.cs index 5cdb481..d840a44 100644 --- a/src/TokenType.cs +++ b/src/TokenType.cs @@ -5,7 +5,7 @@ namespace EzrSquared; /// /// The identifying type of a . /// -public enum TokenType : ushort +public enum TokenType : byte { /// /// An integer, part of the type-group. diff --git a/src/TokenTypeGroup.cs b/src/TokenTypeGroup.cs index 804a503..5494aab 100644 --- a/src/TokenTypeGroup.cs +++ b/src/TokenTypeGroup.cs @@ -6,7 +6,7 @@ /// /// If you want to see which group a token type is in, check the documentation for that type. /// -public enum TokenTypeGroup : ushort +public enum TokenTypeGroup : byte { /// /// Groups primitive-type tokens, like integers or strings. From 5488fec351b4bb491dea3e9b667ba47a7ba83922 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 24 Dec 2024 19:54:21 +0530 Subject: [PATCH 110/113] Improved lexer performance. --- src/Syntax/Lexer.cs | 65 ++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 42 deletions(-) diff --git a/src/Syntax/Lexer.cs b/src/Syntax/Lexer.cs index 01f4f00..269fb98 100644 --- a/src/Syntax/Lexer.cs +++ b/src/Syntax/Lexer.cs @@ -274,8 +274,7 @@ private void SkipComment() /// The object. private Token CompileNumber() { - StringBuilder numberValue = new(); - Position numberTokenStartPosition = _position; + Position startPosition = _position; bool hasPeriod = false; while (!_reachedEnd && (char.IsDigit(_currentChar) || _currentChar == '.')) @@ -291,15 +290,14 @@ private Token CompileNumber() hasPeriod = true; } - numberValue.Append(_currentChar); Advance(); } return new Token( hasPeriod ? TokenType.FloatingPoint : TokenType.Integer, TokenTypeGroup.Value, - numberValue.ToString(), - numberTokenStartPosition, + _script[startPosition.Index.._position.Index], + startPosition, _position ); } @@ -314,17 +312,15 @@ private Token CompileNewLines() while (!_reachedEnd && (char.IsWhiteSpace(_currentChar) || _currentChar == ';')) { Advance(); - if (_currentChar is '\n' or ';' or '@') + if (_currentChar == '@') { - if (_currentChar == '@') - { - SkipComment(); - if (_reachedEnd) - break; - } + SkipComment(); + if (_reachedEnd) + break; + } + if (_currentChar is '\n' or ';') lastNewLineIndex = _position.Index; - } } ReverseTo(lastNewLineIndex); @@ -371,10 +367,10 @@ private Token CompileStringLike(out EzrSyntaxError? error) } Advance(); - if (enclosingChar == '`' && ((toReturn.Length > 1 is bool tooLong && tooLong) || toReturn.Length == 0)) + if (enclosingChar == '`' && (toReturn.Length > 1 || toReturn.Length == 0)) { error = new EzrSyntaxError(EzrSyntaxError.InvalidGrammar, - tooLong + toReturn.Length > 1 ? "Value too long to be a character!" : "A character cannot be empty!", startPosition, _position); @@ -462,25 +458,19 @@ private char[] ProcessUtf16Sequence(ref EzrSyntaxError? error) { Advance(); - int characterCount = 0; - string hexValue = string.Empty; Position startPosition = _position; - while (characterCount < 4) + for (int i = 0; i < 4; i++) { - if (_currentChar is (>= 'a' and <= 'f') or (>= 'A' and <= 'F') or (>= '0' and <= '9')) - { - characterCount++; - hexValue += _currentChar; - Advance(); - } - else + if (_currentChar is (not >= 'a' or not <= 'f') and (not >= 'A' or not <= 'F') and (not >= '0' or not <= '9')) { error = new EzrSyntaxError(EzrSyntaxError.InvalidHexValue, "UTF-16 hexadecimal values must be 4 characters long and only contain digits and the letters A to F!", startPosition, _position.Advance()); return []; } + + Advance(); } - return Encoding.Unicode.GetChars([Convert.ToByte(hexValue[2..4], 16), Convert.ToByte(hexValue[0..2], 16)]); + return Encoding.Unicode.GetChars([Convert.ToByte(_script[(startPosition.Index + 2).._position.Index], 16), Convert.ToByte(_script[startPosition.Index..(_position.Index - 2)], 16)]); } /// @@ -492,25 +482,19 @@ private string ProcessUtf32Sequence(ref EzrSyntaxError? error) { Advance(); - int characterCount = 0; - string hexValue = string.Empty; Position startPosition = _position; - while (characterCount < 6) + for (int i = 0; i < 6; i++) { - if (_currentChar is (>= 'a' and <= 'f') or (>= 'A' and <= 'F') or (>= '0' and <= '9')) - { - characterCount++; - hexValue += _currentChar; - Advance(); - } - else + if (_currentChar is (not >= 'a' or not <= 'f') and (not >= 'A' or not <= 'F') and (not >= '0' or not <= '9')) { error = new EzrSyntaxError(EzrSyntaxError.InvalidHexValue, "UTF-32 hexadecimal values must be 6 characters long and only contain digits and the letters A to F!", startPosition, _position.Advance()); return string.Empty; } + + Advance(); } - int unicodePoint = Convert.ToInt32(hexValue, 16); + int unicodePoint = Convert.ToInt32(_script[startPosition.Index.._position.Index], 16); if (unicodePoint > 0x10FFFF) { error = new EzrSyntaxError(EzrSyntaxError.InvalidHexValue, "UTF-32 hexadecimal values must be in range 000000 - 10FFFF!", startPosition, _position); @@ -590,14 +574,11 @@ private Token CompileIdentifier(out EzrSyntaxError? error) } } - StringBuilder idValue = new(); + Position actualStartPosition = _position; while (!_reachedEnd && (char.IsLetterOrDigit(_currentChar) || _currentChar == '_')) - { - idValue.Append(_currentChar); Advance(); - } - string original = idValue.ToString(); + string original = _script[actualStartPosition.Index.._position.Index]; return isEscapedIdentifier ? new Token(TokenType.Identifier, TokenTypeGroup.Special, original, startPosition, _position) : original.ToLower() switch From 68877eb5325a014e3bcd6d175548f197447da2a1 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 24 Dec 2024 21:56:19 +0530 Subject: [PATCH 111/113] Lexer refactoring. --- src/Syntax/Lexer.cs | 69 +++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/Syntax/Lexer.cs b/src/Syntax/Lexer.cs index 269fb98..69fbf80 100644 --- a/src/Syntax/Lexer.cs +++ b/src/Syntax/Lexer.cs @@ -24,7 +24,7 @@ public class Lexer /// The of the current lexing iteration in the script. /// private Position _position; - + /// /// The character in the of the current lexing iteration in the script. /// @@ -92,21 +92,16 @@ private void ReverseTo(int index) { switch (_currentChar) { - case '\r': - case '\t': - case ' ': + case '\r' or '\t' or ' ': Advance(); break; - case ';': - case '\n': + case ';' or '\n': tokens.Add(CompileNewLines()); break; case '@': SkipComment(); break; - case '"': - case '`': - case '\'': + case '"' or '`' or '\'': tokens.Add(CompileStringLike(out EzrSyntaxError? error)); if (error is not null) return error; @@ -236,8 +231,7 @@ private void ReverseTo(int index) tokens.Add(new Token(TokenType.Tilde, TokenTypeGroup.Symbol, string.Empty, _position)); Advance(); break; - case '#': - case '_': + case '#' or '_': case char current when char.IsLetter(current): tokens.Add(CompileIdentifier(out error)); if (error is not null) @@ -275,7 +269,7 @@ private void SkipComment() private Token CompileNumber() { Position startPosition = _position; - bool hasPeriod = false; + bool isFloat = false; while (!_reachedEnd && (char.IsDigit(_currentChar) || _currentChar == '.')) { @@ -284,17 +278,17 @@ private Token CompileNumber() int peekIndex = _position.Index + 1; char next = peekIndex < _script.Length ? _script[peekIndex] : '\0'; - if (hasPeriod || !char.IsDigit(next)) + if (isFloat || !char.IsDigit(next)) break; - hasPeriod = true; + isFloat = true; } Advance(); } return new Token( - hasPeriod ? TokenType.FloatingPoint : TokenType.Integer, + isFloat ? TokenType.FloatingPoint : TokenType.Integer, TokenTypeGroup.Value, _script[startPosition.Index.._position.Index], startPosition, @@ -349,15 +343,15 @@ private Token CompileStringLike(out EzrSyntaxError? error) { if (_currentChar == '\\') { - ProcessEscapeSequence(toReturn, ref error); + ProcessEscapeSequence(toReturn, out error); if (error is not null) return Token.Empty; + + continue; } - else - { - toReturn.Append(_currentChar); - Advance(); - } + + toReturn.Append(_currentChar); + Advance(); } if (_currentChar != enclosingChar) @@ -395,18 +389,19 @@ private Token CompileStringLike(out EzrSyntaxError? error) /// /// The to append the special character to. /// Any that occurred in the process; if none occurred. - private void ProcessEscapeSequence(StringBuilder builder, ref EzrSyntaxError? error) + private void ProcessEscapeSequence(StringBuilder builder, out EzrSyntaxError? error) { + error = null; Position startPosition = _position; Advance(); switch (_currentChar) { case 'u': - builder.Append(ProcessUtf16Sequence(ref error)); + builder.Append(ProcessUtf16Sequence(out error)); break; case 'U': - builder.Append(ProcessUtf32Sequence(ref error)); + builder.Append(ProcessUtf32Sequence(out error)); break; case 'n': builder.Append('\n'); @@ -436,10 +431,7 @@ private void ProcessEscapeSequence(StringBuilder builder, ref EzrSyntaxError? er builder.Append('\v'); Advance(); break; - case '"': - case '\'': - case '`': - case '\\': + case '"' or '\'' or '`' or '\\': builder.Append(_currentChar); Advance(); break; @@ -454,12 +446,15 @@ private void ProcessEscapeSequence(StringBuilder builder, ref EzrSyntaxError? er /// /// Any that occurred in the process; if none occurred. /// The UTF-16 character. - private char[] ProcessUtf16Sequence(ref EzrSyntaxError? error) + private char[] ProcessUtf16Sequence(out EzrSyntaxError? error) { + const int Utf16SequenceLength = 4; + + error = null; Advance(); Position startPosition = _position; - for (int i = 0; i < 4; i++) + for (int i = 0; i < Utf16SequenceLength; i++) { if (_currentChar is (not >= 'a' or not <= 'f') and (not >= 'A' or not <= 'F') and (not >= '0' or not <= '9')) { @@ -470,7 +465,10 @@ private char[] ProcessUtf16Sequence(ref EzrSyntaxError? error) Advance(); } - return Encoding.Unicode.GetChars([Convert.ToByte(_script[(startPosition.Index + 2).._position.Index], 16), Convert.ToByte(_script[startPosition.Index..(_position.Index - 2)], 16)]); + string upper = _script[(startPosition.Index + 2).._position.Index]; + string lower = _script[startPosition.Index..(_position.Index - 2)]; + + return Encoding.Unicode.GetChars([Convert.ToByte(upper, 16), Convert.ToByte(lower, 16)]); } /// @@ -478,12 +476,15 @@ private char[] ProcessUtf16Sequence(ref EzrSyntaxError? error) /// /// Any that occurred in the process; if none occurred. /// The UTF-32 character. - private string ProcessUtf32Sequence(ref EzrSyntaxError? error) + private string ProcessUtf32Sequence(out EzrSyntaxError? error) { + const int Utf32SequenceLength = 4; + + error = null; Advance(); Position startPosition = _position; - for (int i = 0; i < 6; i++) + for (int i = 0; i < Utf32SequenceLength; i++) { if (_currentChar is (not >= 'a' or not <= 'f') and (not >= 'A' or not <= 'F') and (not >= '0' or not <= '9')) { @@ -569,7 +570,7 @@ private Token CompileIdentifier(out EzrSyntaxError? error) Advance(); if (!char.IsLetterOrDigit(_currentChar) && _currentChar != '_') { - error = new EzrSyntaxError(EzrSyntaxError.UnexpectedCharacter, "The hash symbol should only be used before identifiers to escape keyword detection.", startPosition, _position); + error = new EzrSyntaxError(EzrSyntaxError.UnexpectedCharacter, "The hash (#) symbol should only be used before identifiers to escape keyword detection.", startPosition, _position); return Token.Empty; } } From c2d09d5b8399c87472cf97f0e82b9e00cd413688 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 24 Dec 2024 23:18:27 +0530 Subject: [PATCH 112/113] All nodes are records now! --- src/Runtime/Interpreter.cs | 60 ++++++++-------- src/Runtime/Nodes/BaseNodes.cs | 37 ++-------- .../Nodes/CollectionNodes/ArrayLikeNode.cs | 33 ++------- .../Nodes/CollectionNodes/DictionaryNode.cs | 26 ++----- .../Nodes/CollectionNodes/StatementsNode.cs | 22 ++---- .../DefineBlockNode.cs | 29 ++------ .../VariableAccessNode.cs | 29 ++------ .../VariableAssignmentNode.cs | 43 ++---------- .../ControlFlowStructureNodes/CountNode.cs | 50 +++----------- .../ControlFlowStructureNodes/ForEachNode.cs | 29 ++------ .../Nodes/ControlFlowStructureNodes/IfNode.cs | 33 ++------- .../ControlFlowStructureNodes/TryNode.cs | 42 ++--------- .../ControlFlowStructureNodes/WhileNode.cs | 29 ++------ src/Runtime/Nodes/ExecutableNodes/CallNode.cs | 33 ++------- .../ExecutableNodes/ClassDefinitionNode.cs | 54 +++------------ .../ExecutableNodes/FunctionDefinitionNode.cs | 69 +++---------------- .../Nodes/ExecutableNodes/IncludeNode.cs | 43 ++---------- .../Nodes/ExecutableNodes/ReturnNode.cs | 29 ++------ .../OperationNodes/BinaryOperationNode.cs | 36 ++-------- .../OperationNodes/UnaryOperationNode.cs | 29 ++------ src/Runtime/Nodes/SimpleNodes/NoValueNode.cs | 22 ++---- src/Runtime/Nodes/SimpleNodes/ValueNode.cs | 22 ++---- src/Syntax/Parser/Parser.cs | 12 ++-- 23 files changed, 152 insertions(+), 659 deletions(-) diff --git a/src/Runtime/Interpreter.cs b/src/Runtime/Interpreter.cs index 3db859a..bda5935 100644 --- a/src/Runtime/Interpreter.cs +++ b/src/Runtime/Interpreter.cs @@ -236,10 +236,9 @@ private void VisitStatementsNode(StatementsNode node, Context executionContext, private void VisitArrayLikeNodeList(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) { RuntimeEzrObjectList elementsReferences = new(node.Elements.Count); - for (int i = 0; i < node.Elements.Count; i++) + foreach (Node element in node.Elements) { - Node elementNode = node.Elements[i]; - VisitNode(elementNode, executionContext, callingContext, accessibilityModifiers); + VisitNode(element, executionContext, callingContext, accessibilityModifiers); if (RuntimeResult.ShouldReturn) return; @@ -259,10 +258,11 @@ private void VisitArrayLikeNodeList(ArrayLikeNode node, Context executionContext private void VisitArrayLikeNodeArray(ArrayLikeNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) { IEzrObject[] elements = new IEzrObject[node.Elements.Count]; - for (int i = 0; i < node.Elements.Count; i++) + using IEnumerator enumerator = node.Elements.GetEnumerator(); + + for (int i = 0; enumerator.MoveNext(); i++) { - Node elementNode = node.Elements[i]; - VisitNode(elementNode, executionContext, callingContext, accessibilityModifiers); + VisitNode(enumerator.Current, executionContext, callingContext, accessibilityModifiers); if (RuntimeResult.ShouldReturn) return; @@ -282,25 +282,23 @@ private void VisitArrayLikeNodeArray(ArrayLikeNode node, Context executionContex /// The accessibility modifiers for objects that will be assigned from the executing . private void VisitDictionaryNode(DictionaryNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) { - RuntimeEzrObjectDictionary dictionary = []; - List<(Node Key, Node Value)> pairs = node.KeyValuePairs; - - for (int i = 0; i < pairs.Count; i++) + RuntimeEzrObjectDictionary dictionary = new(node.KeyValuePairs.Count); + foreach ((Node key, Node value) in node.KeyValuePairs) { // Get the key. - VisitNode(pairs[i].Key, executionContext, callingContext, accessibilityModifiers); + VisitNode(key, executionContext, callingContext, accessibilityModifiers); if (RuntimeResult.ShouldReturn) return; - IEzrObject key = RuntimeResult.Reference.Object; + IEzrObject keyObject = RuntimeResult.Reference.Object; // Get the value. - VisitNode(pairs[i].Value, executionContext, callingContext, accessibilityModifiers); + VisitNode(value, executionContext, callingContext, accessibilityModifiers); if (RuntimeResult.ShouldReturn) return; // Add it to the dictionary! - dictionary.Update(key, RuntimeResult.Reference.Object, RuntimeResult); + dictionary.Update(keyObject, RuntimeResult.Reference.Object, RuntimeResult); if (RuntimeResult.ShouldReturn) return; } @@ -809,19 +807,19 @@ private void ExecuteBinaryOperation(IEzrObject first, IEzrObject second, Node no /// The accessibility modifiers for objects that will be assigned from the executing . private void VisitIfNode(IfNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) { - for (int i = 0; i < node.Cases.Count; i++) + foreach ((Node condition, Node body) in node.Cases) { - VisitNode(node.Cases[i].Condition, executionContext, callingContext, accessibilityModifiers); + VisitNode(condition, executionContext, callingContext, accessibilityModifiers); if (RuntimeResult.ShouldReturn) return; - bool condition = RuntimeResult.Reference.Object.EvaluateBoolean(RuntimeResult); + bool conditionEval = RuntimeResult.Reference.Object.EvaluateBoolean(RuntimeResult); if (RuntimeResult.ShouldReturn) return; - if (condition) + if (conditionEval) { - VisitNode(node.Cases[i].Body, executionContext, callingContext, accessibilityModifiers); + VisitNode(body, executionContext, callingContext, accessibilityModifiers); return; } } @@ -1165,10 +1163,8 @@ private void VisitTryNode(TryNode node, Context executionContext, Context callin IEzrRuntimeError error = RuntimeResult.Error!; RuntimeResult.Reset(); - for (int i = 0; i < node.Cases.Count; i++) + foreach ((Node errorType, Node? errorVariableNode, Node body) in node.Cases) { - (Node errorType, Node? errorVariableNode, Node body) = node.Cases[i]; - VisitNode(errorType, executionContext, callingContext, accessibilityModifiers); if (RuntimeResult.ShouldReturn) return; @@ -1248,9 +1244,11 @@ private void VisitFunctionDefinitionNode(FunctionDefinitionNode node, Context ex Context newContext = new($"", false, node.StartPosition, executionContext, executionContext.StaticContext); (string Name, Node Node)[] parameters = new (string, Node)[node.Parameters.Count]; - for (int i = 0; i < parameters.Length; i++) + using IEnumerator enumerator = node.Parameters.GetEnumerator(); + + for (int i = 0; enumerator.MoveNext(); i++) { - Node parameter = node.Parameters[i]; + Node parameter = enumerator.Current; VisitNode(parameter, newContext, callingContext, AccessMod.None, true); if (RuntimeResult.ShouldReturn) return; @@ -1262,7 +1260,7 @@ private void VisitFunctionDefinitionNode(FunctionDefinitionNode node, Context ex return; } - parameters[i] = (reference.Name, node.Parameters[i]); + parameters[i] = (reference.Name, parameter); } OptionalExtraArguments keywordArguments = null; @@ -1322,9 +1320,11 @@ private void VisitFunctionDefinitionNode(FunctionDefinitionNode node, Context ex private void VisitClassDefinitionNode(ClassDefinitionNode node, Context executionContext, Context callingContext, AccessMod accessibilityModifiers) { EzrClass[] parents = new EzrClass[node.Parents.Count]; - for (int i = 0; i < parents.Length; i++) + using IEnumerator enumerator = node.Parents.GetEnumerator(); + + for (int i = 0; enumerator.MoveNext(); i++) { - Node parentNode = node.Parents[i]; + Node parentNode = enumerator.Current; VisitNode(parentNode, executionContext, callingContext, accessibilityModifiers); if (RuntimeResult.ShouldReturn) return; @@ -1397,10 +1397,10 @@ private void VisitCallNode(CallNode node, Context executionContext, Context call Context argumentsContext = new($"<{receiver.TypeName} arguments>", false, receiver.StartPosition, callingContext, callingContext.StaticContext); arguments = new Reference[node.Arguments.Count]; - for (int i = 0; i < node.Arguments.Count; i++) + using IEnumerator enumerator = node.Arguments.GetEnumerator(); + for (int i = 0; enumerator.MoveNext(); i++) { - Node argument = node.Arguments[i]; - VisitNode(argument, argumentsContext, callingContext, accessibilityModifiers & ~AccessMod.LocalScope); + VisitNode(enumerator.Current, argumentsContext, callingContext, accessibilityModifiers & ~AccessMod.LocalScope); if (RuntimeResult.ShouldReturn) return; diff --git a/src/Runtime/Nodes/BaseNodes.cs b/src/Runtime/Nodes/BaseNodes.cs index f80134b..9b816e8 100644 --- a/src/Runtime/Nodes/BaseNodes.cs +++ b/src/Runtime/Nodes/BaseNodes.cs @@ -4,35 +4,16 @@ namespace EzrSquared.Runtime.Nodes; /// /// The representation of an ezr² source code construct. This is the base class of all nodes. Only for inheritance! /// -/// The starting of the . -/// The ending of the . -public abstract class Node(Position startPosition, Position endPosition) +/// The starting of the . +/// The ending of the . +public abstract record Node(Position StartPosition, Position EndPosition) { - /// - /// The starting of the . - /// - public Position StartPosition = startPosition; - - /// - /// The ending of the . - /// - public Position EndPosition = endPosition; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(Node)}()"; - } } /// /// The dummy invalid structure. For returning instead of if an occurs during parsing. /// -public class InvalidNode : Node +public record InvalidNode : Node { /// /// The static object. @@ -45,14 +26,4 @@ public class InvalidNode : Node /// The starting of the . /// The ending of the . InvalidNode(Position startPosition, Position endPosition) : base(startPosition, endPosition) { } - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(InvalidNode)}()"; - } } diff --git a/src/Runtime/Nodes/CollectionNodes/ArrayLikeNode.cs b/src/Runtime/Nodes/CollectionNodes/ArrayLikeNode.cs index ae3d7f5..396c08d 100644 --- a/src/Runtime/Nodes/CollectionNodes/ArrayLikeNode.cs +++ b/src/Runtime/Nodes/CollectionNodes/ArrayLikeNode.cs @@ -4,33 +4,10 @@ namespace EzrSquared.Runtime.Nodes; /// /// The structure for an arraylike (array or list). /// -/// The elements of the arraylike. -/// The check for if the should create a list instead of an array. -/// The starting of the . -/// The ending of the . -public class ArrayLikeNode(List elements, bool createList, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The elements of the arraylike. +/// The check for if the should create a list instead of an array. +/// The starting of the . +/// The ending of the . +public record ArrayLikeNode(IReadOnlyCollection Elements, bool CreateList, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The elements of the arraylike. - /// - public List Elements = elements; - - /// - /// The check for if the should create a list instead of an array. - /// - public bool CreateList = createList; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - string[] elements = new string[Elements.Count]; - for (int i = 0; i < Elements.Count; i++) - elements[i] = Elements[i].ToString(); - - return $"{nameof(ArrayLikeNode)}([{string.Join(", ", elements)}], {CreateList})"; - } } diff --git a/src/Runtime/Nodes/CollectionNodes/DictionaryNode.cs b/src/Runtime/Nodes/CollectionNodes/DictionaryNode.cs index 7242980..e4d2411 100644 --- a/src/Runtime/Nodes/CollectionNodes/DictionaryNode.cs +++ b/src/Runtime/Nodes/CollectionNodes/DictionaryNode.cs @@ -4,27 +4,9 @@ namespace EzrSquared.Runtime.Nodes; /// /// The structure for a dictionary. /// -/// The key-value pairs of the dictionary. -/// The starting of the . -/// The ending of the . -public class DictionaryNode(List<(Node Key, Node Value)> keyValuePairs, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The key-value pairs of the dictionary. +/// The starting of the . +/// The ending of the . +public record DictionaryNode(IReadOnlyCollection<(Node Key, Node Value)> KeyValuePairs, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The key-value pairs of the dictionary. - /// - public List<(Node Key, Node Value)> KeyValuePairs = keyValuePairs; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - string[] keyValuePairs = new string[KeyValuePairs.Count]; - for (int i = 0; i < KeyValuePairs.Count; i++) - keyValuePairs[i] = $"{KeyValuePairs[i].Key} : {KeyValuePairs[i].Value}"; - - return $"{nameof(DictionaryNode)}([{string.Join(", ", keyValuePairs)}])"; - } } diff --git a/src/Runtime/Nodes/CollectionNodes/StatementsNode.cs b/src/Runtime/Nodes/CollectionNodes/StatementsNode.cs index b96616f..2eb9460 100644 --- a/src/Runtime/Nodes/CollectionNodes/StatementsNode.cs +++ b/src/Runtime/Nodes/CollectionNodes/StatementsNode.cs @@ -4,23 +4,9 @@ namespace EzrSquared.Runtime.Nodes; /// /// The structure for holding multiple statements. /// -/// The statements. -/// The starting of the . -/// The ending of the . -public class StatementsNode(List statements, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The statements. +/// The starting of the . +/// The ending of the . +public record StatementsNode(IReadOnlyCollection Statements, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The statements being held by the node. - /// - public List Statements = statements; - - /// - public override string ToString() - { - string[] elements = new string[Statements.Count]; - for (int i = 0; i < Statements.Count; i++) - elements[i] = Statements[i].ToString(); - - return $"{nameof(StatementsNode)}([{string.Join(", ", elements)}])"; - } } diff --git a/src/Runtime/Nodes/ContextManipulationNodes/DefineBlockNode.cs b/src/Runtime/Nodes/ContextManipulationNodes/DefineBlockNode.cs index e8ab996..ffe5911 100644 --- a/src/Runtime/Nodes/ContextManipulationNodes/DefineBlockNode.cs +++ b/src/Runtime/Nodes/ContextManipulationNodes/DefineBlockNode.cs @@ -3,29 +3,10 @@ /// /// The structure for a define block. /// -/// The body of the block. -/// The accessibility modifiers for the define block. -/// The starting of the . -/// The ending of the . -public class DefineBlockNode(Node body, AccessMod accessibilityModifiers, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The body of the block. +/// The accessibility modifiers for the define block. +/// The starting of the . +/// The ending of the . +public record DefineBlockNode(Node Body, AccessMod AccessibilityModifiers, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The body of the block. - /// - public Node Body = body; - - /// - /// The accessibility modifiers of the define block. - /// - public AccessMod AccessibilityModifiers = accessibilityModifiers; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(DefineBlockNode)}({Body}, {AccessibilityModifiers})"; - } } diff --git a/src/Runtime/Nodes/ContextManipulationNodes/VariableAccessNode.cs b/src/Runtime/Nodes/ContextManipulationNodes/VariableAccessNode.cs index 0ebe1b5..f322c7e 100644 --- a/src/Runtime/Nodes/ContextManipulationNodes/VariableAccessNode.cs +++ b/src/Runtime/Nodes/ContextManipulationNodes/VariableAccessNode.cs @@ -3,29 +3,10 @@ /// /// The structure for accesing a variable from the context. /// -/// The name of the variable, a object of type . -/// The accessibility modifiers for the variable access operation. -/// The starting of the . -/// The ending of the . -public class VariableAccessNode(Token name, AccessMod accessibilityModifiers, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The name of the variable, a object of type . +/// The accessibility modifiers for the variable access operation. +/// The starting of the . +/// The ending of the . +public record VariableAccessNode(Token Name, AccessMod AccessibilityModifiers, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The name of the variable to access. - /// - public Token Name = name; - - /// - /// The accessibility modifiers for the variable access operation. - /// - public AccessMod AccessibilityModifiers = accessibilityModifiers; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(VariableAccessNode)}({Name}, {AccessibilityModifiers})"; - } } diff --git a/src/Runtime/Nodes/ContextManipulationNodes/VariableAssignmentNode.cs b/src/Runtime/Nodes/ContextManipulationNodes/VariableAssignmentNode.cs index abe0e5f..37bb2c8 100644 --- a/src/Runtime/Nodes/ContextManipulationNodes/VariableAssignmentNode.cs +++ b/src/Runtime/Nodes/ContextManipulationNodes/VariableAssignmentNode.cs @@ -3,41 +3,12 @@ /// /// The structure for assigning a value to a variable in the context. /// -/// The variable to be assigned to. -/// The operation , if not , between the existing value of and . The result of the operation will be assigned to . -/// The value to be assigned to . -/// The accessibility modifiers for the variable assignment operation. -/// The starting of the . -/// The ending of the . -public class VariableAssignmentNode(Node variable, TokenType assignmentOperator, Node value, AccessMod accessibilityModifiers, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The variable to be assigned to. +/// The operation , if not , between the existing value of and . The result of the operation will be assigned to . +/// The value to be assigned to . +/// The accessibility modifiers for the variable assignment operation. +/// The starting of the . +/// The ending of the . +public record VariableAssignmentNode(Node Variable, TokenType AssignmentOperator, Node Value, AccessMod AccessibilityModifiers, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The variable to be assigned to. - /// - public Node Variable = variable; - - /// - /// The operation , if not , between the existing value of and . The result of the operation will be assigned to . - /// - public TokenType AssignmentOperator = assignmentOperator; - - /// - /// The value to be assigned to . - /// - public Node Value = value; - - /// - /// The accessibility modifiers for the variable assignment operation. - /// - public AccessMod AccessibilityModifiers = accessibilityModifiers; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(VariableAssignmentNode)}({Variable}, {AssignmentOperator}, {Value}, {AccessibilityModifiers})"; - } } diff --git a/src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs b/src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs index d2bd754..127d706 100644 --- a/src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs +++ b/src/Runtime/Nodes/ControlFlowStructureNodes/CountNode.cs @@ -3,47 +3,13 @@ /// /// The structure for a count expression. /// -/// The amount to count to. -/// The amount to count from - optional. -/// The increment of each iteration - optional. -/// The variable to store the iteration number in - optional. -/// The body of the count loop. -/// The starting of the . -/// The ending of the . -public class CountNode(Node to, Node? from, Node? step, Node? iterationVariable, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The amount to count to. +/// The amount to count from - optional. +/// The increment of each iteration - optional. +/// The variable to store the iteration number in - optional. +/// The body of the count loop. +/// The starting of the . +/// The ending of the . +public record CountNode(Node To, Node? From, Node? Step, Node? IterationVariable, Node Body, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The amount to count to. - /// - public Node To = to; - - /// - /// The amount to count from - optional. - /// - public Node? From = from; - - /// - /// The increment of each iteration - optional. - /// - public Node? Step = step; - - /// - /// The variable to store the iteration number in - optional. - /// - public Node? IterationVariable = iterationVariable; - - /// - /// The body of the count loop. - /// - public Node Body = body; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(CountNode)}({To}, {From?.ToString() ?? "null"}, {Step?.ToString() ?? "null"}, {IterationVariable?.ToString() ?? "null"}, {Body})"; - } } diff --git a/src/Runtime/Nodes/ControlFlowStructureNodes/ForEachNode.cs b/src/Runtime/Nodes/ControlFlowStructureNodes/ForEachNode.cs index f4fe64e..7c6bd53 100644 --- a/src/Runtime/Nodes/ControlFlowStructureNodes/ForEachNode.cs +++ b/src/Runtime/Nodes/ControlFlowStructureNodes/ForEachNode.cs @@ -3,29 +3,10 @@ /// /// The structure for a for-each expression. /// -/// A check-in expression, where the LHS is the variable to store the iterated values and RHS is the collection to iterate. -/// The body of the loop. -/// The starting of the . -/// The ending of the . -public class ForEachNode(BinaryOperationNode expression, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// A check-in expression, where the LHS is the variable to store the iterated values and RHS is the collection to iterate. +/// The body of the loop. +/// The starting of the . +/// The ending of the . +public record ForEachNode(BinaryOperationNode Expression, Node Body, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// A check-in expression, where the LHS is the variable to store the iterated values and RHS is the collection to iterate. - /// - public BinaryOperationNode Expression = expression; - - /// - /// The body of the count loop. - /// - public Node Body = body; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(ForEachNode)}({Expression}, {Body})"; - } } diff --git a/src/Runtime/Nodes/ControlFlowStructureNodes/IfNode.cs b/src/Runtime/Nodes/ControlFlowStructureNodes/IfNode.cs index ceb0de3..3a490eb 100644 --- a/src/Runtime/Nodes/ControlFlowStructureNodes/IfNode.cs +++ b/src/Runtime/Nodes/ControlFlowStructureNodes/IfNode.cs @@ -4,33 +4,10 @@ namespace EzrSquared.Runtime.Nodes; /// /// The structure for an if expression. /// -/// The cases of the if expression. -/// The body of the else case. -/// The starting of the . -/// The ending of the . -public class IfNode(List<(Node Condition, Node Body)> cases, Node? elseCase, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The cases of the if expression. +/// The body of the else case. +/// The starting of the . +/// The ending of the . +public record IfNode(IReadOnlyCollection<(Node Condition, Node Body)> Cases, Node? ElseCase, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The cases of the if expression. - /// - public List<(Node Condition, Node Body)> Cases = cases; - - /// - /// The body of the else case. - /// - public Node? ElseCase = elseCase; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - string?[] cases = new string[Cases.Count]; - for (int i = 0; i < Cases.Count; i++) - cases[i] = $"({Cases[i].Condition}, {Cases[i].Body})"; - - return $"{nameof(IfNode)}([{string.Join(", ", cases)}], {ElseCase?.ToString() ?? "null"})"; - } } diff --git a/src/Runtime/Nodes/ControlFlowStructureNodes/TryNode.cs b/src/Runtime/Nodes/ControlFlowStructureNodes/TryNode.cs index 18bad2a..9b694f1 100644 --- a/src/Runtime/Nodes/ControlFlowStructureNodes/TryNode.cs +++ b/src/Runtime/Nodes/ControlFlowStructureNodes/TryNode.cs @@ -4,41 +4,11 @@ namespace EzrSquared.Runtime.Nodes; /// /// The structure for a try expression. /// -/// The try block. -/// The error cases of the try expression. -/// The (optional) where the error will be stored and the body of the empty else case. -/// The starting of the . -/// The ending of the . -public class TryNode(Node block, List<(Node ErrorType, Node? Variable, Node Body)> cases, (Node? Variable, Node Body)? emptyCase, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The try block. +/// The error cases of the try expression. +/// The (optional) where the error will be stored and the body of the empty else case. +/// The starting of the . +/// The ending of the . +public record TryNode(Node Block, IReadOnlyCollection<(Node ErrorType, Node? Variable, Node Body)> Cases, (Node? Variable, Node Body)? EmptyCase, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The try block. - /// - public Node Block = block; - - /// - /// The error cases of the try expression. - /// - public List<(Node ErrorType, Node? Variable, Node Body)> Cases = cases; - - /// - /// The (optional) where the error will be stored and the body of the empty else case. - /// - public (Node? Variable, Node Body)? EmptyCase = emptyCase; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - string?[] cases = new string[Cases.Count]; - for (int i = 0; i < Cases.Count; i++) - cases[i] = $"({Cases[i].ErrorType}, {Cases[i].Variable?.ToString() ?? "null"}, {Cases[i].Body})"; - - return (EmptyCase is not null) - ? $"{nameof(TryNode)}({Block}, [{string.Join(", ", cases)}], ({EmptyCase?.Variable?.ToString() ?? "null"}, {EmptyCase?.Body}))" - : $"{nameof(TryNode)}({Block}, [{string.Join(", ", cases)}])"; - } } diff --git a/src/Runtime/Nodes/ControlFlowStructureNodes/WhileNode.cs b/src/Runtime/Nodes/ControlFlowStructureNodes/WhileNode.cs index 4d6c9c3..1669f1d 100644 --- a/src/Runtime/Nodes/ControlFlowStructureNodes/WhileNode.cs +++ b/src/Runtime/Nodes/ControlFlowStructureNodes/WhileNode.cs @@ -3,29 +3,10 @@ /// /// The structure for an while expression. /// -/// The condition of the while loop. -/// The body of the while loop. -/// The starting of the . -/// The ending of the . -public class WhileNode(Node condition, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The condition of the while loop. +/// The body of the while loop. +/// The starting of the . +/// The ending of the . +public record WhileNode(Node Condition, Node Body, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The condition of the while loop. - /// - public Node Condition = condition; - - /// - /// The body of the while loop. - /// - public Node Body = body; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(WhileNode)}({Condition}, {Body})"; - } } diff --git a/src/Runtime/Nodes/ExecutableNodes/CallNode.cs b/src/Runtime/Nodes/ExecutableNodes/CallNode.cs index b63c43d..d690282 100644 --- a/src/Runtime/Nodes/ExecutableNodes/CallNode.cs +++ b/src/Runtime/Nodes/ExecutableNodes/CallNode.cs @@ -4,33 +4,10 @@ namespace EzrSquared.Runtime.Nodes; /// /// The structure for a function call. /// -/// The function/object to be called. -/// The array of arguments. -/// The starting of the . -/// The ending of the . -public class CallNode(Node receiver, List arguments, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The function/object to be called. +/// The array of arguments. +/// The starting of the . +/// The ending of the . +public record CallNode(Node Receiver, IReadOnlyCollection Arguments, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The function/object to be called. - /// - public Node Receiver = receiver; - - /// - /// The array of arguments. - /// - public List Arguments = arguments; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - string[] arguments = new string[Arguments.Count]; - for (int i = 0; i < Arguments.Count; i++) - arguments[i] = Arguments[i].ToString(); - - return $"{nameof(CallNode)}({Receiver}, [{string.Join(", ", arguments)}])"; - } } diff --git a/src/Runtime/Nodes/ExecutableNodes/ClassDefinitionNode.cs b/src/Runtime/Nodes/ExecutableNodes/ClassDefinitionNode.cs index e39e1fe..a8c9c8b 100644 --- a/src/Runtime/Nodes/ExecutableNodes/ClassDefinitionNode.cs +++ b/src/Runtime/Nodes/ExecutableNodes/ClassDefinitionNode.cs @@ -4,51 +4,13 @@ namespace EzrSquared.Runtime.Nodes; /// /// The structure for a class definition. /// -/// The (optional) name of the class. -/// The accessibility modifiers for the class definition. -/// The check for if the class should be declared read-only. -/// The parents of the class. -/// The body of the class. -/// The starting of the . -/// The ending of the . -public class ClassDefinitionNode(Node? name, AccessMod accessibilityModifiers, bool @readonly, List parents, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The (optional) name of the class. +/// The accessibility modifiers for the class definition. +/// The check for if the class should be declared read-only. +/// The parents of the class. +/// The body of the class. +/// The starting of the . +/// The ending of the . +public record ClassDefinitionNode(Node? Name, AccessMod AccessibilityModifiers, bool Readonly, IReadOnlyCollection Parents, Node Body, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The name of the class. May be . - /// - public Node? Name = name; - - /// - /// The accessibility modifiers for the class definition. - /// - public AccessMod AccessibilityModifiers = accessibilityModifiers; - - /// - /// The check for if the class should be declared read-only. - /// - public bool Readonly = @readonly; - - /// - /// The parents of the class. - /// - public List Parents = parents; - - /// - /// The body of the class. - /// - public Node Body = body; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - string?[] parents = new string[Parents.Count]; - for (int i = 0; i < Parents.Count; i++) - parents[i] = Parents[i].ToString(); - - return $"{nameof(ClassDefinitionNode)}({Name?.ToString() ?? "null"}, {AccessibilityModifiers}, {Readonly}, [{string.Join(", ", parents)}], {Body})"; - } } diff --git a/src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs b/src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs index a3fe011..e056866 100644 --- a/src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs +++ b/src/Runtime/Nodes/ExecutableNodes/FunctionDefinitionNode.cs @@ -4,64 +4,15 @@ namespace EzrSquared.Runtime.Nodes; /// /// The structure for a function definition. /// -/// The (optional) name of the function. -/// The accessibility modifiers for the function definition. -/// The check for if the last expression of the function should be returned as its result. Only used in oneliners. -/// The parameters of the function. -/// The reference to store the extra keyword arguments in. -/// The reference to store the extra positional arguments in. -/// The body of the function. -/// The starting of the . -/// The ending of the . -public class FunctionDefinitionNode(Node? name, AccessMod accessibilityModifiers, bool returnLast, List parameters, Node? extraKeywordArguments, Node? extraPositionalArguments, Node body, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The (optional) name of the function. +/// The accessibility modifiers for the function definition. +/// The check for if the last expression of the function should be returned as its result. Only used in oneliners. +/// The parameters of the function. +/// The reference to store the extra keyword arguments in. +/// The reference to store the extra positional arguments in. +/// The body of the function. +/// The starting of the . +/// The ending of the . +public record FunctionDefinitionNode(Node? Name, AccessMod AccessibilityModifiers, bool ReturnLast, IReadOnlyCollection Parameters, Node? ExtraKeywordArguments, Node? ExtraPositionalArguments, Node Body, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The (optional) name of the function. - /// - public Node? Name = name; - - /// - /// The accessibility modifiers for the function definition. - /// - public AccessMod AccessibilityModifiers = accessibilityModifiers; - - /// - /// The check for if the last expression of the function should be returned as its result. - /// Only used in oneliners. - /// - public bool ReturnLast = returnLast; - - /// - /// The parameters of the function. - /// - public List Parameters = parameters; - - /// - /// The reference to store the extra keyword arguments in. - /// - public Node? ExtraKeywordArguments = extraKeywordArguments; - - /// - /// The reference to store the extra positional arguments in. - /// - public Node? ExtraPositionalArguments = extraPositionalArguments; - - /// - /// The body of the function. - /// - public Node Body = body; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - string?[] parameters = new string[Parameters.Count]; - for (int i = 0; i < Parameters.Count; i++) - parameters[i] = Parameters[i].ToString(); - - return $"{nameof(FunctionDefinitionNode)}({Name?.ToString() ?? "null"}, {AccessibilityModifiers}, {ReturnLast}, [{string.Join(", ", parameters)}], {ExtraKeywordArguments?.ToString() ?? "null"}, {ExtraPositionalArguments?.ToString() ?? "null"}, {Body})"; - } } diff --git a/src/Runtime/Nodes/ExecutableNodes/IncludeNode.cs b/src/Runtime/Nodes/ExecutableNodes/IncludeNode.cs index 3d62f0c..73e4471 100644 --- a/src/Runtime/Nodes/ExecutableNodes/IncludeNode.cs +++ b/src/Runtime/Nodes/ExecutableNodes/IncludeNode.cs @@ -3,41 +3,12 @@ /// /// The structure for an include expression. /// -/// The script to include. -/// The (optional) specific sub-structure or object to be included from the script. -/// Specifies if all contents of the script need to be dumped into the current context. -/// The (optional) nickname of the object to be included. -/// The starting of the . -/// The ending of the . -public class IncludeNode(Node script, Node? subStructure, bool isDumped, Node? nickname, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The script to include. +/// The (optional) specific sub-structure or object to be included from the script. +/// Specifies if all contents of the script need to be dumped into the current context. +/// The (optional) nickname of the object to be included. +/// The starting of the . +/// The ending of the . +public record IncludeNode(Node Script, Node? SubStructure, bool IsDumped, Node? Nickname, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The script to include. - /// - public readonly Node Script = script; - - /// - /// The (optional) specific sub-structure or object to be included from the script. - /// - public readonly Node? SubStructure = subStructure; - - /// - /// Specifies if all contents of the script need to be dumped into the current context. - /// - public readonly bool IsDumped = isDumped; - - /// - /// The (optional) nickname of the object to be included. - /// - public readonly Node? Nickname = nickname; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(IncludeNode)}({Script}, {SubStructure?.ToString() ?? "null"}, {IsDumped}, {Nickname?.ToString() ?? "null"})"; - } } diff --git a/src/Runtime/Nodes/ExecutableNodes/ReturnNode.cs b/src/Runtime/Nodes/ExecutableNodes/ReturnNode.cs index 5e331db..a8bbf81 100644 --- a/src/Runtime/Nodes/ExecutableNodes/ReturnNode.cs +++ b/src/Runtime/Nodes/ExecutableNodes/ReturnNode.cs @@ -3,29 +3,10 @@ /// /// The structure for a return statement. /// -/// The optional value to be returned. -/// Return the last element of , which should be a list or array. -/// The starting of the . -/// The ending of the . -public class ReturnNode(Node? value, bool returnLast, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The optional value to be returned. +/// Return the last element of , which should be a list or array. +/// The starting of the . +/// The ending of the . +public record ReturnNode(Node? Value, bool ReturnLast, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The optional value to be returned. - /// - public Node? Value = value; - - /// - /// Return the last element of , which should be a list or array. - /// - public bool ReturnLast = returnLast; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(ReturnNode)}({Value?.ToString() ?? "null"})"; - } } diff --git a/src/Runtime/Nodes/OperationNodes/BinaryOperationNode.cs b/src/Runtime/Nodes/OperationNodes/BinaryOperationNode.cs index edbedfd..71b98a8 100644 --- a/src/Runtime/Nodes/OperationNodes/BinaryOperationNode.cs +++ b/src/Runtime/Nodes/OperationNodes/BinaryOperationNode.cs @@ -3,35 +3,11 @@ /// /// The structure for a binary operation. /// -/// The first operand of the binary operation. -/// The second operand of the binary operation. -/// The operator of the binary operation. -/// The starting of the . -/// The ending of the . -public class BinaryOperationNode(Node left, Node right, TokenType @operator, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The first operand of the binary operation. +/// The second operand of the binary operation. +/// The operator of the binary operation. +/// The starting of the . +/// The ending of the . +public record BinaryOperationNode(Node Left, Node Right, TokenType Operator, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The first operand of the binary operation. - /// - public Node Left = left; - - /// - /// The second operand of the binary operation. - /// - public Node Right = right; - - /// - /// The operator of the binary operation. - /// - public TokenType Operator = @operator; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(BinaryOperationNode)}({Left}, {Operator}, {Right})"; - } } diff --git a/src/Runtime/Nodes/OperationNodes/UnaryOperationNode.cs b/src/Runtime/Nodes/OperationNodes/UnaryOperationNode.cs index 4bedf6d..179d3bf 100644 --- a/src/Runtime/Nodes/OperationNodes/UnaryOperationNode.cs +++ b/src/Runtime/Nodes/OperationNodes/UnaryOperationNode.cs @@ -3,29 +3,10 @@ /// /// The structure for a unary operation. /// -/// The operand of the unary operation. -/// The operator of the unary operation. -/// The starting of the . -/// The ending of the . -public class UnaryOperationNode(Node operand, TokenType @operator, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The operand of the unary operation. +/// The operator of the unary operation. +/// The starting of the . +/// The ending of the . +public record UnaryOperationNode(Node Operand, TokenType Operator, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The operand of the unary operation. - /// - public Node Operand = operand; - - /// - /// The operator of the unary operation. - /// - public TokenType Operator = @operator; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(UnaryOperationNode)}({Operand}, {Operator})"; - } } diff --git a/src/Runtime/Nodes/SimpleNodes/NoValueNode.cs b/src/Runtime/Nodes/SimpleNodes/NoValueNode.cs index 2cfa002..a5d521e 100644 --- a/src/Runtime/Nodes/SimpleNodes/NoValueNode.cs +++ b/src/Runtime/Nodes/SimpleNodes/NoValueNode.cs @@ -3,23 +3,9 @@ /// /// The structure for a statement or expression without any value (used as skip and stop statement nodes). /// -/// The identifying of the . -/// The starting of the . -/// The ending of the . -public class NoValueNode(TokenType valueType, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The identifying of the . +/// The starting of the . +/// The ending of the . +public record NoValueNode(TokenType ValueType, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The identifying of the . - /// - public TokenType ValueType = valueType; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(NoValueNode)}({ValueType})"; - } } diff --git a/src/Runtime/Nodes/SimpleNodes/ValueNode.cs b/src/Runtime/Nodes/SimpleNodes/ValueNode.cs index bcf6634..8ddd431 100644 --- a/src/Runtime/Nodes/SimpleNodes/ValueNode.cs +++ b/src/Runtime/Nodes/SimpleNodes/ValueNode.cs @@ -3,23 +3,9 @@ /// /// The structure of a simple value like literals and variables. /// -/// The value the represents. -/// The starting of the . -/// The ending of the . -public class ValueNode(Token value, Position startPosition, Position endPosition) : Node(startPosition, endPosition) +/// The value the represents. +/// The starting of the . +/// The ending of the . +public record ValueNode(Token Value, Position StartPosition, Position EndPosition) : Node(StartPosition, EndPosition) { - /// - /// The value the represents. - /// - public Token Value = value; - - /// - /// Creates a representation of the .
- /// All fields excluding the start and end positions are included in the representation, like "ExampleNode(Property1, Property2)". - ///
- /// The representation. - public override string ToString() - { - return $"{nameof(ValueNode)}({Value})"; - } } diff --git a/src/Syntax/Parser/Parser.cs b/src/Syntax/Parser/Parser.cs index 06e2aaa..cfbc339 100644 --- a/src/Syntax/Parser/Parser.cs +++ b/src/Syntax/Parser/Parser.cs @@ -1086,13 +1086,11 @@ private void ParseArrayOrParentheticalExpression() Advance(); } - if (!isArray && elements.Count > 0) - { - _result.Node.StartPosition = startPosition; - _result.Node.EndPosition = endPosition; - } - else - _result.Success(new ArrayLikeNode(elements, false, startPosition, endPosition)); + _result.Success( + !isArray && elements.Count > 0 + ? new StatementsNode([_result.Node], startPosition, endPosition) + : new ArrayLikeNode(elements, false, startPosition, endPosition) + ); } /// From b97e4fbc0b5ec1260ba9bd608e6d206659ce8b11 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Tue, 24 Dec 2024 23:47:46 +0530 Subject: [PATCH 113/113] Fixed lexer. --- src/Syntax/Lexer.cs | 114 ++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/src/Syntax/Lexer.cs b/src/Syntax/Lexer.cs index 69fbf80..e9b9a4a 100644 --- a/src/Syntax/Lexer.cs +++ b/src/Syntax/Lexer.cs @@ -77,7 +77,7 @@ private void Advance() private void ReverseTo(int index) { _currentChar = _script[index]; - _position.ReverseTo(index, _currentChar == '\n' ? 1 : 0); + _position = _position.ReverseTo(index, _currentChar == '\n' ? 1 : 0); } /// @@ -584,66 +584,66 @@ private Token CompileIdentifier(out EzrSyntaxError? error) ? new Token(TokenType.Identifier, TokenTypeGroup.Special, original, startPosition, _position) : original.ToLower() switch { - "private" => new Token(TokenType.KeywordPrivate, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "constant" => new Token(TokenType.KeywordConstant, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "readonly" => new Token(TokenType.KeywordReadonly, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "item" => new Token(TokenType.KeywordItem, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "and" => new Token(TokenType.KeywordAnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "or" => new Token(TokenType.KeywordOr, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "invert" => new Token(TokenType.KeywordInvert, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "if" => new Token(TokenType.KeywordIf, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "else" => new Token(TokenType.KeywordElse, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "do" => new Token(TokenType.KeywordDo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "count" => new Token(TokenType.KeywordCount, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "for" => new Token(TokenType.KeywordFor, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "each" => new Token(TokenType.KeywordEach, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "from" => new Token(TokenType.KeywordFrom, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "as" => new Token(TokenType.KeywordAs, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "to" => new Token(TokenType.KeywordTo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "step" => new Token(TokenType.KeywordStep, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "while" => new Token(TokenType.KeywordWhile, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "function" => new Token(TokenType.KeywordFunction, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "private" => new Token(TokenType.KeywordPrivate, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "constant" => new Token(TokenType.KeywordConstant, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "readonly" => new Token(TokenType.KeywordReadonly, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "item" => new Token(TokenType.KeywordItem, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "and" => new Token(TokenType.KeywordAnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "or" => new Token(TokenType.KeywordOr, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "invert" => new Token(TokenType.KeywordInvert, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "if" => new Token(TokenType.KeywordIf, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "else" => new Token(TokenType.KeywordElse, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "do" => new Token(TokenType.KeywordDo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "count" => new Token(TokenType.KeywordCount, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "for" => new Token(TokenType.KeywordFor, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "each" => new Token(TokenType.KeywordEach, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "from" => new Token(TokenType.KeywordFrom, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "as" => new Token(TokenType.KeywordAs, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "to" => new Token(TokenType.KeywordTo, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "step" => new Token(TokenType.KeywordStep, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "while" => new Token(TokenType.KeywordWhile, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "function" => new Token(TokenType.KeywordFunction, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), #pragma warning disable CS0618 - "special" => new Token(TokenType.KeywordSpecial, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "special" => new Token(TokenType.KeywordSpecial, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), #pragma warning restore CS0618 - "with" => new Token(TokenType.KeywordWith, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "more" => new Token(TokenType.KeywordMore, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "named" => new Token(TokenType.KeywordNamed, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "end" => new Token(TokenType.KeywordEnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "return" => new Token(TokenType.KeywordReturn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "last" => new Token(TokenType.KeywordLast, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "skip" => new Token(TokenType.KeywordSkip, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "stop" => new Token(TokenType.KeywordStop, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "try" => new Token(TokenType.KeywordTry, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "catch" => new Token(TokenType.KeywordCatch, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "not" => new Token(TokenType.KeywordNot, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "in" => new Token(TokenType.KeywordIn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "object" => new Token(TokenType.KeywordObject, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "global" => new Token(TokenType.KeywordGlobal, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "include" => new Token(TokenType.KeywordInclude, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "all" => new Token(TokenType.KeywordAll, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "static" => new Token(TokenType.KeywordStatic, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "define" => new Token(TokenType.KeywordDefine, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), - "f" => new Token(TokenType.QeywordF, TokenTypeGroup.Qeyword, original, startPosition, _position), - "l" => new Token(TokenType.QeywordL, TokenTypeGroup.Qeyword, original, startPosition, _position), - "e" => new Token(TokenType.QeywordE, TokenTypeGroup.Qeyword, original, startPosition, _position), - "c" => new Token(TokenType.QeywordC, TokenTypeGroup.Qeyword, original, startPosition, _position), - "p" => new Token(TokenType.QeywordP, TokenTypeGroup.Qeyword, original, startPosition, _position), - "t" => new Token(TokenType.QeywordT, TokenTypeGroup.Qeyword, original, startPosition, _position), - "n" => new Token(TokenType.QeywordN, TokenTypeGroup.Qeyword, original, startPosition, _position), - "w" => new Token(TokenType.QeywordW, TokenTypeGroup.Qeyword, original, startPosition, _position), - "fd" => new Token(TokenType.QeywordFd, TokenTypeGroup.Qeyword, original, startPosition, _position), - "sd" => new Token(TokenType.QeywordSd, TokenTypeGroup.Qeyword, original, startPosition, _position), - "sb" => new Token(TokenType.QeywordSb, TokenTypeGroup.Qeyword, original, startPosition, _position), - "od" => new Token(TokenType.QeywordOd, TokenTypeGroup.Qeyword, original, startPosition, _position), - "i" => new Token(TokenType.QeywordI, TokenTypeGroup.Qeyword, original, startPosition, _position), - "s" => new Token(TokenType.QeywordS, TokenTypeGroup.Qeyword, original, startPosition, _position), - "d" => new Token(TokenType.QeywordD, TokenTypeGroup.Qeyword, original, startPosition, _position), - "g" => new Token(TokenType.QeywordG, TokenTypeGroup.Qeyword, original, startPosition, _position), - "v" => new Token(TokenType.QeywordV, TokenTypeGroup.Qeyword, original, startPosition, _position), - _ => new Token(TokenType.Identifier, TokenTypeGroup.Special, original, startPosition, _position), + "with" => new Token(TokenType.KeywordWith, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "more" => new Token(TokenType.KeywordMore, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "named" => new Token(TokenType.KeywordNamed, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "end" => new Token(TokenType.KeywordEnd, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "return" => new Token(TokenType.KeywordReturn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "last" => new Token(TokenType.KeywordLast, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "skip" => new Token(TokenType.KeywordSkip, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "stop" => new Token(TokenType.KeywordStop, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "try" => new Token(TokenType.KeywordTry, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "catch" => new Token(TokenType.KeywordCatch, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "not" => new Token(TokenType.KeywordNot, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "in" => new Token(TokenType.KeywordIn, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "object" => new Token(TokenType.KeywordObject, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "global" => new Token(TokenType.KeywordGlobal, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "include" => new Token(TokenType.KeywordInclude, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "all" => new Token(TokenType.KeywordAll, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "static" => new Token(TokenType.KeywordStatic, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "define" => new Token(TokenType.KeywordDefine, TokenTypeGroup.Keyword, string.Empty, startPosition, _position), + "f" => new Token(TokenType.QeywordF, TokenTypeGroup.Qeyword, original, startPosition, _position), + "l" => new Token(TokenType.QeywordL, TokenTypeGroup.Qeyword, original, startPosition, _position), + "e" => new Token(TokenType.QeywordE, TokenTypeGroup.Qeyword, original, startPosition, _position), + "c" => new Token(TokenType.QeywordC, TokenTypeGroup.Qeyword, original, startPosition, _position), + "p" => new Token(TokenType.QeywordP, TokenTypeGroup.Qeyword, original, startPosition, _position), + "t" => new Token(TokenType.QeywordT, TokenTypeGroup.Qeyword, original, startPosition, _position), + "n" => new Token(TokenType.QeywordN, TokenTypeGroup.Qeyword, original, startPosition, _position), + "w" => new Token(TokenType.QeywordW, TokenTypeGroup.Qeyword, original, startPosition, _position), + "fd" => new Token(TokenType.QeywordFd, TokenTypeGroup.Qeyword, original, startPosition, _position), + "sd" => new Token(TokenType.QeywordSd, TokenTypeGroup.Qeyword, original, startPosition, _position), + "sb" => new Token(TokenType.QeywordSb, TokenTypeGroup.Qeyword, original, startPosition, _position), + "od" => new Token(TokenType.QeywordOd, TokenTypeGroup.Qeyword, original, startPosition, _position), + "i" => new Token(TokenType.QeywordI, TokenTypeGroup.Qeyword, original, startPosition, _position), + "s" => new Token(TokenType.QeywordS, TokenTypeGroup.Qeyword, original, startPosition, _position), + "d" => new Token(TokenType.QeywordD, TokenTypeGroup.Qeyword, original, startPosition, _position), + "g" => new Token(TokenType.QeywordG, TokenTypeGroup.Qeyword, original, startPosition, _position), + "v" => new Token(TokenType.QeywordV, TokenTypeGroup.Qeyword, original, startPosition, _position), + _ => new Token(TokenType.Identifier, TokenTypeGroup.Special, original, startPosition, _position), }; } } \ No newline at end of file