tag:github.com,2008:https://github.com/ArkScript-lang/Ark/releasesRelease notes from Ark2026-03-13T13:12:41Ztag:github.com,2008:Repository/189978997/v4.4.02026-03-13T13:20:30ZArkScript v4.4.0<h3>Deprecations</h3>
<ul>
<li><code>list:permutations</code> is deprecated in favor of <code>list:combinations</code></li>
<li><code>list:permutationsWithReplacement</code> is deprecated in favor of <code>list:combinationsWithReplacement</code></li>
</ul>
<h3>Added</h3>
<ul>
<li>new debugger commands: <code>stack <n></code> and <code>locals <n></code> to print the values on the stack and in the current locals scope</li>
<li>custom format specifiers for lists:
<ul>
<li><code>:n</code> to remove surrounding brackets,</li>
<li><code>:c</code> / <code>:nc</code> to use <code>, </code> as a separator instead of <code> </code>,</li>
<li><code>:l</code> / <code>:nl</code> to use <code>\n</code> as a separator,</li>
<li><code>:?s</code> to format as an escaped quoted string,</li>
<li><code>:s</code> to format as a quoted string</li>
</ul>
</li>
<li><code>format</code> can use format specifiers for integers: <code>b</code>, <code>#b</code>, <code>B</code>, <code>#B</code>, <code>c</code>, <code>d</code>, <code>o</code>, <code>x</code>, <code>#x</code>, <code>X</code>, and <code>#X</code> if the argument is an integer</li>
<li>display a warning to <code>stderr</code> when using a deprecated function/value (checks for <code>@deprecated</code> inside the attached comment of functions / values)</li>
</ul>
<h3>Changed</h3>
<ul>
<li><code>pop!</code> can return the removed value</li>
<li><code>@=</code> and <code>@@=</code> return the inserted value</li>
<li><code>append!</code> and <code>concat!</code> return the modified list</li>
<li><code>let</code>, <code>mut</code> and <code>set</code> can return the assigned value</li>
<li>fix formatter: when the condition of a <code>while</code> loop is on multiple lines, add the right amount of indentation before it</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/189978997/v4.3.32026-03-01T11:29:06ZArkScript v4.3.3<h3>Changed</h3>
<ul>
<li>runtime type checking errors are on stderr instead of stdout</li>
<li>runtime exceptions are on stderr instead of stdout</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/189978997/v4.3.22026-02-28T17:33:51ZArkScript v4.3.2<h3>Changed</h3>
<ul>
<li>VM error outputs are on stderr instead of stdout</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/189978997/v4.3.12026-02-28T16:32:40ZArkScript v4.3.1<h3>Added</h3>
<ul>
<li>new <code>TAIL_CALL_SELF</code> instruction to take care of tail calls in functions: jumps to address 0 in the current page, and reset the scope</li>
</ul>
<h3>Changed</h3>
<ul>
<li>error outputs are on stderr instead of stdout</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/189978997/v4.3.02026-02-26T16:56:13ZArkScript v4.3.0<h3>Breaking change</h3>
<ul>
<li>in macros, <code>len</code>, <code>empty?</code>, <code>head</code>, <code>tail</code>, <code>@</code> have been renamed to <code>$len</code>, <code>$empty?</code>, <code>$head</code>, <code>$tail</code> and <code>$at</code>. Those versions only work inside macros too, inside of having a weird dichotomy where they sometimes got applied and sometimes not</li>
</ul>
<h3>Added</h3>
<ul>
<li><code>apply</code> function: <code>(apply func [args...])</code>, to call a function with a set of arguments stored in a list. Works with functions, closures and builtins</li>
<li><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code> and many other operators can now be passed around, like builtins. This now works: <code>(list:reduce [1 2 3] +)</code>, where before we would get a compile time error about a "freestanding operator '+'"</li>
<li><code>builtin__slice</code> builtin, for strings and lists: <code>(builtin__slice data start end [step=1])</code> ; <strong>this is an experimentation and may be removed in future versions</strong></li>
<li>arguments of builtin macros are properly type-checked and will now raise runtime errors if the type is incorrect</li>
<li><code>-fno-cache</code> cli option to disable the creation of the bytecode cache folder <code>__arkscript__</code></li>
<li>in the CLI, <code>file</code> can be <code>-</code> to read code from stdin</li>
</ul>
<h3>Changed</h3>
<ul>
<li>when using the cli flag <code>-fdump-ir</code>, the IR is dumped in the cache folder</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/189978997/v4.2.02026-02-04T19:05:13ZArkScript v4.2.0<h3>Breaking changes</h3>
<ul>
<li><code>assert</code> is no longer an instruction but a builtin</li>
<li>when comparing values of different types using <code><</code>, <code>></code>, <code><=</code>, <code>>=</code> and <code>=</code>, the result will always be <code>false</code> (it used to rely on the type index)</li>
</ul>
<h3>Added</h3>
<ul>
<li>added <code>BREAKPOINT</code> instruction</li>
<li>breakpoints can be placed using <code>(breakpoint)</code> and <code>(breakpoint condition)</code></li>
<li>added a debugger that can be triggered on error or on breakpoint by passing <code>-fdebugger</code> to the CLI (see <a href="https://arkscript-lang.dev/docs/tutorials/debugging/" rel="nofollow">the docs for the debugger</a>)</li>
<li>diagnostics can now be generated when using <code>State.doString</code>, using <code>Diagnostics::generateWithCode</code> (as the original code must be passed to the diagnostics generator)</li>
<li><code>empty?</code> can now take a dict, and returns <code>true</code> if it has no key/value pairs</li>
<li><code>len</code> can now work on dictionaries, counting the number of keys</li>
</ul>
<h3>Changed</h3>
<ul>
<li>changed the runpath of <code>arkscript</code> to look for <code>libArkReactor</code> under its (arkscript's) directory, {arkscript}/bin, {arkscript}/lib, and {arkscript}/../lib</li>
<li><code>and</code> and <code>or</code> require valid expressions, so <code>(or 1 (mut x 3))</code> is no longer valid code, as <code>(mut x 3)</code> doesn't return a value</li>
<li><code>(not (dict "a" 2))</code> now returns <code>false</code>, as <code>not</code> checks if the dict is empty</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/189978997/v4.1.22026-01-09T14:10:36ZArkScript v4.1.2<h3>Added</h3>
<ul>
<li>the repl prints the output of the last expression it ran</li>
<li>new super instructions: <code>MUL_BY</code>, <code>MUL_BY_INDEX</code>, <code>MUL_SET_VAL</code> that can do multiplications (and optional storing in vars) in place</li>
<li>new super instruction: <code>FUSED_MATH</code>, which can fuse 2 to 3 math operations in one go (ADD, SUB, MUL, DIV)</li>
<li>new <code>LOAD_SYMBOL</code> instruction that avoids creating a reference</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>the REPL doesn't color <code>import</code> in two colors (red for <code>imp__t</code> and blue for <code>___or_</code>), it keeps the first color that matched (red for import here)</li>
<li>page numbers are correctly counted when using the bytecode reader with '--only-names', instead of displaying <code>0</code> every time</li>
</ul>
<h3>Changed</h3>
<ul>
<li>quotes are added around strings in type errors</li>
<li><code>disassemble</code> can show a file bytecode</li>
<li><code>empty?</code> now accepts <code>nil</code> and returns <code>true</code> for this value</li>
<li>the REPL adds <code>(repl:history)</code> and <code>(repl:save filename)</code> as builtins</li>
<li>the REPL attempts to load a file from <code>ARKSCRIPT_REPL_STARTUP</code> environment variable, to preload code</li>
<li>rename LOAD_SYMBOL and LOAD_SYMBOL_BY_INDEX to LOAD_FAST and LOAD_FAST_BY_INDEX to emphasize they load refs</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/189978997/v4.1.12025-12-13T13:51:17ZArkScript v4.1.1<h3>Fixed</h3>
<ul>
<li>the formatter was breaking functions' arguments list containing argument attributes on multiple lines for no reason</li>
<li>the formatter was formatting begin nodes inside conditions badly, putting the <code>{</code> on the same line as the condition, making it hard to know if the condition had <code>then</code> and <code>else</code> nodes or a single multi nodes <code>then</code> node</li>
</ul>
<h3>Changed</h3>
<ul>
<li>long function calls are split on multiple lines</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/189978997/v4.1.02025-12-12T19:25:07ZArkScript v4.1.0<h3>Breaking changes</h3>
<ul>
<li>Function arguments are now immutable by default and an argument attribute <code>mut</code> must be added: <code>(fun (a b c) (set b 5))</code> -> <code>(fun (a (mut b) c) (set b 5))</code></li>
</ul>
<h3>Deprecated</h3>
<ul>
<li><code>dict:contains</code>, use <code>dict:contains?</code></li>
<li><code>math:even</code>, use <code>math:even?</code></li>
<li><code>math:odd</code>, use <code>math:odd?</code></li>
</ul>
<h3>Added</h3>
<ul>
<li>new builtin <code>disassemble</code> to print the bytecode of a function</li>
<li>new builtin <code>io:readFileLines</code> to read lines from a file as a list of strings</li>
</ul>
<h3>Changed</h3>
<ul>
<li>the formatter properly formats dictionaries (key-value pairs on their own line, always)</li>
<li>renamed <code>dict:contains</code> to <code>dict:contains?</code> so that all functions returning booleans have <code>?</code> suffix ; added temporary alias <code>dict:contains</code></li>
<li>renamed <code>math:even</code> to <code>math:even?</code>, and <code>math:odd</code> to <code>math:odd?</code></li>
<li><code>string:removeAt</code> can work with negative indexes</li>
</ul>github-actions[bot]tag:github.com,2008:Repository/189978997/v4.0.02025-11-20T11:54:39ZArkScript v4.0.0<h2>Changes for you, as a user</h2>
<ul>
<li>macros are defined using <code>(macro name value)</code> and <code>(macro name (foo bar ...args) body)</code> instead of <code>!{name value}</code> and <code>!{name (foo bar ...args) body}</code></li>
<li><code>quote</code> keyword got removed. You can emulate it with a macro: <code>(macro quote (value) (fun () value))</code> (it wasn't really a Lisp <code>quote</code> in the first place...)</li>
<li>while loops have their own scope</li>
<li>imports changed a lot: from <code>(import "path/to/file.ark")</code> to java like imports (the root is deduced from the main script emplacement): <code>(import path.to.file :foo :bar)</code>
<ul>
<li>for more details, see <a href="https://arkscript-lang.dev/docs/tutorials/language/#importing-code" rel="nofollow">the documentation</a></li>
</ul>
</li>
<li>you can format your code using the cli: <code>arkscript -f myfile.ark</code></li>
<li>new <code>dict</code> datatype: <a href="https://arkscript-lang.dev/docs/std/dict/" rel="nofollow">https://arkscript-lang.dev/docs/std/dict/</a></li>
</ul>
<p>For more information, check the <strong><a href="https://arkscript-lang.dev/docs/prologue/getting_started/" rel="nofollow">language documentation</a>!</strong></p>
<h2>Technical changelog</h2>
<details>
<summary>Added</summary>
<ul>
<li>more tests for the io builtins</li>
<li>added lines and code coloration in the error context</li>
<li>new dependency: <code>fmtlib</code></li>
<li>added the padding/instruction/argumentation values when displaying instructions in the bytecode reader</li>
<li><code>$repr</code> macro to get a string representation of a given node</li>
<li>added boost-ext/ut to write unit tests in C++</li>
<li>basic ArkScript code formatter, available through the CLI: <code>arkscript -f|--format</code></li>
<li>comments are now tracked in the AST and attached to the nearest node below them</li>
<li><code>VM::forceReloadPlugins</code>, to be used by the REPL to force reload the plugins and be sure that their symbols are all defined</li>
<li>added <code>help</code>, <code>save</code> (save history to disk), <code>history</code> (print history), <code>reset</code> (reset vm and code) commands to the REPL</li>
<li>REPL can now show when a code block isn't terminated (prompt changes from <code>></code> to <code>:</code>)</li>
<li>more controls available inside the REPL</li>
<li>fuzzing step in the CI</li>
<li>better error reporting on unknown import</li>
<li>check on the number of arguments passed to <code>type</code></li>
<li>warning when the formatter deletes comment(s) by mistake</li>
<li>check on arguments passed to <code>list</code>, <code>concat</code>, <code>append</code> and friends to only push valid nodes (that produce a value)</li>
<li>introduced <code>Ark::internal::Pass</code> to describe compiler passes: they all output an AST (parser, import solver, macro processor, and optimizer for now)</li>
<li>add <code>-f(no-)importsolver</code>, <code>-f(no-)macroprocessor</code> and <code>-f(no-)optimizer</code> to toggle on and off those compiler passes</li>
<li>added resolving <code>empty?</code> as a macro when possible</li>
<li>added short-circuiting to <code>and</code> and <code>or</code> implementation</li>
<li>added <code>--check</code> to the formatter as an option: returns 0 if the code is correctly formatted, 1 otherwise</li>
<li>the name & scope resolution pass now checks for mutability errors</li>
<li>compile-time checks for mutability errors with <code>append!</code>, <code>concat!</code> and <code>pop!</code></li>
<li>new <code>MAKE_CLOSURE <page addr></code> instruction, generated in place of a <code>LOAD_CONST</code> when a closure is made</li>
<li>added <code>-fdump-ir</code> to dump the IR entities to a file named <code>{file}.ark.ir</code></li>
<li>added 11 super instructions and their implementation to the VM</li>
<li>support for the glob import syntax and symbol import syntax</li>
<li>modify list and return a copy <code>(string:setAt string index char)</code> (bound checked)</li>
<li>added in place list mutation: <code>(@= list|string index new_value)</code>, <code>(@@= list|list<string> index1 index2 new_value|char)</code> (bound checked)</li>
<li>compile time argument count check for <code>and</code> and <code>or</code></li>
<li>basic dead code elimination in the AST optimizer</li>
<li>new operator <code>@@</code> to get elements in list of lists / list of strings</li>
<li>new builtin <code>random</code>, returning a random number between INT_MIN and INT_MAX, or in a custom range</li>
<li><code>$as-is</code> to paste a node inside a maro without evaluating it further; useful to stop recursive evaluation of nodes inside function macros</li>
<li><code>LOAD_SYMBOL_BY_INDEX</code> instruction, loading a local from the current scope by an index (0 being the last element added to the scope)</li>
<li><code>STORE_FROM_INDEX</code> and <code>SET_VAL_FROM_INDEX</code> instructions for parity with the super instructions not using load by index</li>
<li><code>INCREMENT_BY_INDEX</code> and <code>DECREMENT_BY_INDEX</code> instructions for parity with the super instructions not using load by index</li>
<li><code>STORE_TAIL_BY_INDEX</code>, <code>STORE_HEAD_BY_INDEX</code>, <code>SET_VAL_TAIL_BY_INDEX</code>, <code>SET_VAL_HEAD_BY_INDEX</code> super instructions added for parity with the super instructions not using load by index</li>
<li><code>RESET_SCOPE_JUMP</code> instruction emitted at the end of a while loop to reset a scope so that we can create multiple variables and use <code>LOAD_SYMBOL_BY_INDEX</code></li>
<li>instruction source location; two new bytecode tables were added: one for filenames, another for (page pointer, instruction pointer, file id, line), allowing the VM to display better error messages when the source is available</li>
<li>show source location when a runtime error is thrown in the VM</li>
<li><code>LT_CONST_JUMP_IF_FALSE</code> and <code>LT_SYM_JUMP_IF_FALSE</code> to compare a symbol to a const and a symbol to a symbol (respectively), then jump to an address if false (useful for while loops that check a simple <code>(< x n)</code> condition)</li>
<li><code>LT_CONST_JUMP_IF_TRUE</code>, counterpart of <code>LT_CONST_JUMP_IF_FALSE</code></li>
<li><code>GT_CONST_JUMP_IF_TRUE</code>, counterpart of <code>LT_CONST_JUMP_IF_TRUE</code></li>
<li><code>GT_CONST_JUMP_IF_FALSE</code>, counterpart of <code>LT_CONST_JUMP_IF_FALSE</code></li>
<li><code>GT_SYM_JUMP_IF_FALSE</code>, counterpart of <code>LT_SYM_JUMP_IF_FALSE</code></li>
<li><code>CALL_SYMBOL</code> super instruction to load and call a symbol in a single instruction</li>
<li><code>GET_FIELD_FROM_SYMBOL</code> and <code>GET_FIELD_FROM_SYMBOL_INDEX</code> super instructions to get a field from a closure and push it to the stack</li>
<li><code>EQ_CONST_JUMP_IF_TRUE</code> and <code>EQ_SYM_INDEX_JUMP_IF_TRUE</code> to compare a symbol to a const and a symbol to a symbol (respectively), then jump to an address if true (useful for conditions that check a simple <code>(= x n)</code> condition)</li>
<li><code>NEQ_CONST_JUMP_IF_TRUE</code> as a super instruction counterpart to <code>EQ_CONST_JUMP_IF_TRUE</code></li>
<li><code>NEQ_SYM_JUMP_IF_FALSE</code>, counterpart of <code>LT_SYM_JUMP_IF_FALSE</code> for inequality</li>
<li><code>AT_SYM_SYM</code> and <code>AT_SYM_INDEX_SYM_INDEX</code> super instructions, to get an element from a list in a single instruction, avoiding 2 push and 2 pop</li>
<li><code>CHECK_TYPE_OF</code> and <code>CHECK_TYPE_OF_BY_INDEX</code> super instructions, to check the type of variable against a constant in a single instruction</li>
<li><code>INCREMENT_STORE</code> and <code>DECREMENT_STORE</code> super instructions, to update a value in place when incrementing/decrementing it by a set amount</li>
<li><code>APPEND_IN_PLACE_SYM</code> and <code>APPEND_IN_PLACE_SYM_INDEX</code> super instructions</li>
<li><code>PUSH_RETURN_ADDRESS</code> instruction now replaces the VM auto push of IP/PP</li>
<li>remove the stack swapping by pushing arguments in the reverse order by which they are loaded</li>
<li>wasm export: we can now run ArkScript code on the web!</li>
<li><code>GET_CURRENT_PAGE_ADDRESS</code> instruction to push the current page address to the stack</li>
<li><code>CALL_CURRENT_PAGE</code> super instruction, calling the current page with a given number of arguments (avoid loading a page address on the stack, then popping it to perform the call)</li>
<li>new data type <code>Dict</code>, which can be created with <code>(dict "key" "value" ...)</code>, and manipulated with <code>dict:get</code>, <code>dict:add</code>, <code>dict:contains</code>, <code>dict:remove</code>, <code>dict:keys</code> and <code>dict:size</code></li>
<li>added program name under `builtin__sys:programName</li>
<li><code>STORE_LEN</code> super instruction, to load a symbol by index and store its length (if it's a string or list) in a new variable</li>
<li><code>AT_SYM_INDEX_CONST</code> super instruction, to load a value from a container using a constant as the index</li>
</ul>
</details>
<details>
<summary>Changed</summary>
<ul>
<li>instructions are on 4 bytes: 1 byte for the instruction, 1 byte of padding, 2 bytes for an immediate argument</li>
<li>enhanced the bytecode reader and its command line interface</li>
<li>added the padding/instruction/argumentation values when displaying instructions in the bytecode reader</li>
<li>fixed underline bug in the error context</li>
<li>the str:format functions now expect strings following this syntax: <a href="https://fmt.dev/latest/syntax.html" rel="nofollow">https://fmt.dev/latest/syntax.html</a></li>
<li>more documentation about the compiler implementation</li>
<li>more documentation about the virtual machine</li>
<li>closures can be now be compared field per field: <code>(= closure1 closure2)</code> will work only if they have the same fields (name) and if the values match</li>
<li>macros are now defined like <code>(macro name value)</code> / <code>(macro name (args args args) body)</code> / <code>($if cond then else)</code></li>
<li>upgraded from C++17 to C++20</li>
<li>new parser, new syntax for imports: <code>(import package.sub.file)</code></li>
<li>allow nodes to be empty when dumping the AST to JSON</li>
<li>Macros can be declared inside a <code>begin</code> block within a cond macro and used in the scope surrounding the cond macro</li>
<li><code>arkscript --version</code> and <code>arkscript --help</code> now output ArkScript version with the commit hash</li>
<li><code>void Value::toString(std::ostream&, VM&)</code> now becomes <code>std::string Value::toString(VM&)</code></li>
<li>removed <code>Node::operator<<</code> to replace it with <code>Node::debugPrint</code></li>
<li>fixed a bug in the compiler where one could pass a non-symbol to <code>let</code>, <code>mut</code> or <code>set</code>, resulting in a compiler crash</li>
<li>fixed a bug in the macro processor where one could pass an unknown symbol to <code>argcount</code> and crash the processor</li>
<li>fixed a bug in the compiler where one could pass something other than a list to <code>(fun)</code> as the argument block, resulting in a crash</li>
<li>fixed a bug in the compiler generating non-callable functions</li>
<li>fixed a bug in the macro processor generating invalid <code>let</code> / <code>mut</code> / <code>set</code> nodes</li>
<li>fixed a bug in the macro processor allowing out-of-bounds access with <code>(macro test (@ [1 2 3] -5))</code></li>
<li>fixed a bug in the VM which wrongfully allowed self concat in place: <code>(concat! lst lst)</code></li>
<li>fixed a bug in the compiler where one could "use" operators without calling them: <code>(print nil?)</code></li>
<li>fixed a bug in the compiler allowing the use of operators without any argument: <code>(+)</code></li>
<li>fixed a bug in the VM during error reporting when a non-function was used as a function</li>
<li>refactored code inside the bytecode reader to promote code reuse</li>
<li>fixed a bug in the compiler generating invalid <code>while</code> nodes</li>
<li>fixed a bug when passing the wrong number of arguments to a function inside an async call was crashing the VM because the function couldn't be named</li>
<li>fixed a bug in the compiler generating invalid <code>fun</code> nodes</li>
<li>fixed a bug when generating <code>let</code>, <code>mut</code> or <code>set</code> nodes inside macros with an invalid node type</li>
<li>fixed a bug when reading invalid UTF8 codepoints in the parser caused out-of-bounds reads</li>
<li>fixed a bug with recursive macros, exhausting the stack space due to recursive evaluation</li>
<li>Futures can be awaited again; they will return nil on all the tries</li>
<li>checking for reused argument name in macros during parsing</li>
<li>enhanced comment after node handling in macros</li>
<li>adding a hard limit on package names' length (255 characters, to comply with POSIX limits)</li>
<li>disallow passing invalid nodes as arguments to functions and operators</li>
<li>checking for unevaluated spread inside macros</li>
<li>checking for invalid symbols when defining a function through a macro</li>
<li>added a max macro unification depth (256)</li>
<li>added a max macro evaluation depth (256)</li>
<li>introduced <code>internal::listInstructions</code> with the different instructions, to be used by the compiler and name resolution pass</li>
<li>checking for forbidden variable/constant name in the name & scope resolution pass, to give errors to the user before compiling some weird code</li>
<li>repl completion and colors are now generated automatically from the builtins, keywords & operators</li>
<li>fixed formatting of comments inside function declarations</li>
<li>renamed the macros <code>symcat</code> and <code>argcount</code> to <code>$symcat</code> and <code>$argcount</code> for uniformity</li>
<li>the <code>Ark::VM</code> class is now <code>final</code></li>
<li>the <code>STORE</code> instruction has been renamed <code>SET_VAL</code></li>
<li>the <code>STORE</code> instruction is emitted in place of the <code>LET</code> and <code>MUT</code> instructions, without any mutability checking now</li>
<li><code>io:writeFile</code> no longer takes a mode and has been split into <code>io:writeFile</code> and <code>io:appendToFile</code></li>
<li>instructions are now positioned like this: <code>inst byte1 byte2 byte3</code>
<ul>
<li>byte1 is 0 if the instruction takes a single argument on 16 bits, split on byte2 and byte3</li>
<li>if the instruction takes two arguments, they each have 12 bits ; the second one is on byte1 and the upper half of byte2, the first on lower half of byte2 and then byte3</li>
</ul>
</li>
<li>ast-to-json dump now supports macros</li>
<li>The parser can detect ill-formed macros (that are seen as function macros while being value macros)</li>
<li>adding a <code>CALL_BUILTIN <builtin> <arg count></code> super instruction</li>
<li>fixed formatting of comments after the last symbol in an import node</li>
<li>renamed <code>str:xyz</code> builtins to <code>string:xyz</code> for uniformity with the standard library</li>
<li><code>string:find</code> takes an optional third argument, startIndex (where to start the lookup from, default 0</li>
<li><code>list:setAt</code> can work with negative indexes, and is now bound checked</li>
<li>re-enabled the AST optimizer, only used for the main <code>arkscript</code> executable (not enabled when embedding arkscript, so that one can grab variables from the VM)</li>
<li>loops have their own scope: variables created inside a loop won't leak outside it</li>
<li>upgraded <code>fmtlib</code> to 11.1.3-13</li>
<li>allow capture in nested scope (before it was targeting only the current scope)</li>
<li><code>-bcr</code> option can be given a source file, it will then be compiled before its bytecode is shown</li>
<li>magic numbers for tables start in bytecode files have been changed from 0x01, 0x02, 0x03 to 0xA1, 0xA2, 0xA3 (symbols, values, code) to make them stand out in hex editors</li>
<li>magic numbers for value types in bytecode files have been changed from 0x01, 0x02, 0x03 to 0xF1, 0xF2, 0xF3 (number, string, function)</li>
<li>numbers in the values table in bytecode files are no longer turned to string, but their IEEE754 representation is now encoded on 12 bytes (4 for the exponent, 8 for the mantissa)</li>
<li>changed how scopes are stored inside the VM to enhance performance. All scope data are now contiguous!</li>
<li>when possible, accessing variables from the current scope is compiled to a new instruction <code>LOAD_SYMBOL_BY_INDEX</code>, to avoid the sometimes expensive lookup by id
<ul>
<li>This works inside normal scopes (introduced by while loops) and function scopes, but not for closures</li>
</ul>
</li>
<li>VM stack size is now 4096 instead of 8192</li>
<li><code>Ark::CodeError</code> now takes a <code>CodeErrorContext</code> to store the source (filename, line, column, expression) of an error</li>
<li>renamed <code>string:format</code> to <code>format</code></li>
<li><code>io:removeFiles</code> is now <code>io:removeFile</code> and works on a single file/path</li>
<li>renamed almost all builtins to prefix them with <code>builtin__</code>, to have them proxied in the standard library (to be able to import and scope them properly)</li>
<li>new super instruction <code>CALL_BUILTIN_WITHOUT_RETURN_ADDRESS</code> to optimize the proxied builtins, skipping the return address deletion</li>
<li>The VM no longer stores a reference to the current function being called in the newly created scope</li>
<li>execution contexts can be reused for async calls if they are not active, to avoid constantly requesting memory and creating (heavy) contexts
<ul>
<li>If there are more than 5 contexts, the 6th one will be destroyed once it completes</li>
</ul>
</li>
<li>execution contexts are now marked as free to be reused (or deleted) once a value has been computed, without waiting for a call to <code>await</code></li>
<li>captures are not renamed anymore by the NameResolutionPass (which used to fully qualify captured names when possible, which isn't desirable: when you capture <code>&foo</code>, you expect to be able to use <code>.foo</code> not <code>.module:foo</code>)</li>
<li>when loading a module, its mappings are loaded in the current scope instead of the global scope</li>
<li>argument order in the CLI changed: the file to run (and its optional script arguments) are now last, to be more consistent with all the other existing tooling (Python, Docker...)</li>
<li>VM stack size has been upped to 4096 + 256, to have a buffer to be able to catch stack overflows without hindering performances too much</li>
<li>can not create a variable in a function shadowing said function, to prevent weird bugs when trying to do recursion for example</li>
</ul>
</details>
<details>
<summary>Removed</summary>
<ul>
<li>removed unused <code>NodeType::Closure</code></li>
<li>removing the custom string, replacing it with std::string (the format engine of the custom string had a lot of memory leaks)</li>
<li><code>Utils::digPlaces</code> and <code>Utils::decPlaces</code> got removed as they were no longer needed</li>
<li>removed deprecated code (<code>list:removeAt</code>, <code>ark</code> executable now replaced by <code>arkscript</code>)</li>
<li>removed <code>VM::getUserPointer</code> and <code>VM::setUserPointer</code></li>
<li>removed <code>ARK_PROFILER_COUNT</code> define</li>
<li>removed useless <code>\0</code> escape in strings</li>
<li>removed <code>termcolor</code> dependency to rely on <code>fmt</code> for coloring outputs</li>
<li>removed <code>and</code> and <code>or</code> instructions in favor of a better implementation to support short-circuiting</li>
<li>removed <code>LET</code> and <code>MUT</code> instructions in favor of a single new <code>STORE</code> instruction</li>
<li>removed <code>SAVE_ENV</code> instruction</li>
<li>removed <code>Value VM::resolve(const Value* val, Args&&... args)</code>, which has been deprecated in ArkScript v3.4.0</li>
</ul>
</details>github-actions[bot]