Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@
- this works inside normal scopes (introduced by while loops) and functions scopes, but not for closures
- VM stack size is now 4096 instead of 8192
- `Ark::CodeError` now takes a `CodeErrorContext` to store the source (filename, line, column, expression) of an error
- renamed `string:format` to `format`
- `io:removeFiles` is now `io:removeFile` and works on a single file/path
- renamed almost all builtins to prefix them with `builtin__`, to have them proxied in the standard library (to be able to import and scope them properly)
- new super instruction `CALL_BUILTIN_WITHOUT_RETURN_ADDRESS` to optimize the proxied builtins, skipping the return address deletion

### Removed
- removed unused `NodeType::Closure`
Expand Down
3 changes: 3 additions & 0 deletions examples/collatz.ark
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
(import std.Sys)
(import std.Math)

# If the number is even, divide it by two.
# If the number is odd, triple it and add one.
(let get? (fun (seq idx default)
Expand Down
1 change: 1 addition & 0 deletions examples/games/game_of_life.ark
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(import std.List)
(import std.String)
(import std.Switch)
(import std.Math)

(let board [0 0 0 1 1 1 0 0 0])
(let width 3)
Expand Down
6 changes: 4 additions & 2 deletions examples/show_ascii_table.ark
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
(import std.String :chr)

(mut i 0)
(while (< i 16) {
(mut j (+ 32 i))
Expand All @@ -7,8 +9,8 @@
"Spc"
(if (= 127 j)
"Del"
(string:chr j))))
(puts (string:format "{:3} : {:<3}" j k))
(chr j))))
(puts (format "{:3} : {:<3}" j k))
(set j (+ 16 j)) })
(print "")

Expand Down
85 changes: 43 additions & 42 deletions include/Ark/Builtins/Builtins.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace Ark::internal::Builtins
extern const Value falseSym;
extern const Value trueSym;
extern const Value nil;
extern const Value platform;

ARK_API extern const std::vector<std::pair<std::string, Value>> builtins;

Expand All @@ -34,27 +35,27 @@ namespace Ark::internal::Builtins
// ------------------------------
namespace List
{
Value reverseList(std::vector<Value>& n, VM* vm); // list:reverse, single arg
Value findInList(std::vector<Value>& n, VM* vm); // list:find, 2 arguments
Value sliceList(std::vector<Value>& n, VM* vm); // list:slice, 4 arguments
Value sort_(std::vector<Value>& n, VM* vm); // list:sort, 1 argument
Value fill(std::vector<Value>& n, VM* vm); // list:fill, 2 arguments
Value setListAt(std::vector<Value>& n, VM* vm); // list:setAt, 3 arguments
Value reverseList(std::vector<Value>& n, VM* vm); // builtin__list:reverse, single arg
Value findInList(std::vector<Value>& n, VM* vm); // builtin__list:find, 2 arguments
Value sliceList(std::vector<Value>& n, VM* vm); // builtin__list:slice, 4 arguments
Value sort_(std::vector<Value>& n, VM* vm); // builtin__list:sort, 1 argument
Value fill(std::vector<Value>& n, VM* vm); // builtin__list:fill, 2 arguments
Value setListAt(std::vector<Value>& n, VM* vm); // builtin__list:setAt, 3 arguments
}

namespace IO
{
Value print(std::vector<Value>& n, VM* vm); // print, multiple arguments
Value puts_(std::vector<Value>& n, VM* vm); // puts, multiple arguments
Value input(std::vector<Value>& n, VM* vm); // input, 0 or 1 argument
Value writeFile(std::vector<Value>& n, VM* vm); // io:writeFile, 2 arguments
Value appendToFile(std::vector<Value>& n, VM* vm); // io:appendToFile, 2 arguments
Value readFile(std::vector<Value>& n, VM* vm); // io:readFile, 1 argument
Value fileExists(std::vector<Value>& n, VM* vm); // io:fileExists?, 1 argument
Value listFiles(std::vector<Value>& n, VM* vm); // io:listFiles, 1 argument
Value isDirectory(std::vector<Value>& n, VM* vm); // io:isDir?, 1 argument
Value makeDir(std::vector<Value>& n, VM* vm); // io:makeDir, 1 argument
Value removeFiles(std::vector<Value>& n, VM* vm); // io:removeFiles, multiple arguments
Value writeFile(std::vector<Value>& n, VM* vm); // builtin__io:writeFile, 2 arguments
Value appendToFile(std::vector<Value>& n, VM* vm); // builtin__io:appendToFile, 2 arguments
Value readFile(std::vector<Value>& n, VM* vm); // builtin__io:readFile, 1 argument
Value fileExists(std::vector<Value>& n, VM* vm); // builtin__io:fileExists?, 1 argument
Value listFiles(std::vector<Value>& n, VM* vm); // builtin__io:listFiles, 1 argument
Value isDirectory(std::vector<Value>& n, VM* vm); // builtin__io:isDir?, 1 argument
Value makeDir(std::vector<Value>& n, VM* vm); // builtin__io:makeDir, 1 argument
Value removeFile(std::vector<Value>& n, VM* vm); // builtin__io:removeFile, multiple arguments
}

namespace Time
Expand All @@ -64,49 +65,49 @@ namespace Ark::internal::Builtins

namespace System
{
Value system_(std::vector<Value>& n, VM* vm); // sys:exec, 1 argument
Value sleep(std::vector<Value>& n, VM* vm); // sleep, 1 argument
Value exit_(std::vector<Value>& n, VM* vm); // sys:exit, 1 argument
Value system_(std::vector<Value>& n, VM* vm); // builtin__sys:exec, 1 argument
Value sleep(std::vector<Value>& n, VM* vm); // builtin__sys:sleep, 1 argument
Value exit_(std::vector<Value>& n, VM* vm); // builtin__sys:exit, 1 argument
}

namespace String
{
Value format(std::vector<Value>& n, VM* vm); // string:format, multiple arguments
Value findSubStr(std::vector<Value>& n, VM* vm); // string:find, 2 arguments
Value removeAtStr(std::vector<Value>& n, VM* vm); // string:removeAt, 2 arguments
Value ord(std::vector<Value>& n, VM* vm); // string:ord, 1 arguments
Value chr(std::vector<Value>& n, VM* vm); // string:chr, 1 arguments
Value setStringAt(std::vector<Value>& n, VM* vm); // string::setAt, 3 arguments
Value format(std::vector<Value>& n, VM* vm); // format, multiple arguments
Value findSubStr(std::vector<Value>& n, VM* vm); // builtin__string:find, 2 arguments
Value removeAtStr(std::vector<Value>& n, VM* vm); // builtin__string:removeAt, 2 arguments
Value ord(std::vector<Value>& n, VM* vm); // builtin__string:ord, 1 arguments
Value chr(std::vector<Value>& n, VM* vm); // builtin__string:chr, 1 arguments
Value setStringAt(std::vector<Value>& n, VM* vm); // builtin__string::setAt, 3 arguments
}

namespace Mathematics
{
Value exponential(std::vector<Value>& n, VM* vm); // math:exp, 1 argument
Value logarithm(std::vector<Value>& n, VM* vm); // math:ln, 1 argument
Value ceil_(std::vector<Value>& n, VM* vm); // math:ceil, 1 argument
Value floor_(std::vector<Value>& n, VM* vm); // math:floor, 1 argument
Value round_(std::vector<Value>& n, VM* vm); // math:round, 1 argument
Value isnan_(std::vector<Value>& n, VM* vm); // math:NaN?, 1 argument
Value isinf_(std::vector<Value>& n, VM* vm); // math:Inf?, 1 argument
Value exponential(std::vector<Value>& n, VM* vm); // builtin__math:exp, 1 argument
Value logarithm(std::vector<Value>& n, VM* vm); // builtin__math:ln, 1 argument
Value ceil_(std::vector<Value>& n, VM* vm); // builtin__math:ceil, 1 argument
Value floor_(std::vector<Value>& n, VM* vm); // builtin__math:floor, 1 argument
Value round_(std::vector<Value>& n, VM* vm); // builtin__math:round, 1 argument
Value isnan_(std::vector<Value>& n, VM* vm); // builtin__math:NaN?, 1 argument
Value isinf_(std::vector<Value>& n, VM* vm); // builtin__math:Inf?, 1 argument

extern const Value pi_;
extern const Value e_;
extern const Value tau_;
extern const Value inf_;
extern const Value nan_;

Value cos_(std::vector<Value>& n, VM* vm); // math:cos, 1 argument
Value sin_(std::vector<Value>& n, VM* vm); // math:sin, 1 argument
Value tan_(std::vector<Value>& n, VM* vm); // math:tan, 1 argument
Value acos_(std::vector<Value>& n, VM* vm); // math:arccos, 1 argument
Value asin_(std::vector<Value>& n, VM* vm); // math:arcsin, 1 argument
Value atan_(std::vector<Value>& n, VM* vm); // math:arctan, 1 argument
Value cosh_(std::vector<Value>& n, VM* vm); // math:cosh, 1 argument
Value sinh_(std::vector<Value>& n, VM* vm); // math:sinh, 1 argument
Value tanh_(std::vector<Value>& n, VM* vm); // math:tanh, 1 argument
Value acosh_(std::vector<Value>& n, VM* vm); // math:acosh, 1 argument
Value asinh_(std::vector<Value>& n, VM* vm); // math:asinh, 1 argument
Value atanh_(std::vector<Value>& n, VM* vm); // math:atanh, 1 argument
Value cos_(std::vector<Value>& n, VM* vm); // builtin__math:cos, 1 argument
Value sin_(std::vector<Value>& n, VM* vm); // builtin__math:sin, 1 argument
Value tan_(std::vector<Value>& n, VM* vm); // builtin__math:tan, 1 argument
Value acos_(std::vector<Value>& n, VM* vm); // builtin__math:arccos, 1 argument
Value asin_(std::vector<Value>& n, VM* vm); // builtin__math:arcsin, 1 argument
Value atan_(std::vector<Value>& n, VM* vm); // builtin__math:arctan, 1 argument
Value cosh_(std::vector<Value>& n, VM* vm); // builtin__math:cosh, 1 argument
Value sinh_(std::vector<Value>& n, VM* vm); // builtin__math:sinh, 1 argument
Value tanh_(std::vector<Value>& n, VM* vm); // builtin__math:tanh, 1 argument
Value acosh_(std::vector<Value>& n, VM* vm); // builtin__math:acosh, 1 argument
Value asinh_(std::vector<Value>& n, VM* vm); // builtin__math:asinh, 1 argument
Value atanh_(std::vector<Value>& n, VM* vm); // builtin__math:atanh, 1 argument

Value random(std::vector<Value>& n, VM* vm); // random, 0-2 args
}
Expand Down
3 changes: 1 addition & 2 deletions include/Ark/Compiler/Common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ namespace Ark::internal
SetAt2InPlace
};

constexpr std::string_view SysArgs = "sys:args";
constexpr std::string_view SysPlatform = "sys:platform";
constexpr std::string_view SysArgs = "builtin__sys:args";

constexpr std::string_view And = "and";
constexpr std::string_view Or = "or";
Expand Down
43 changes: 24 additions & 19 deletions include/Ark/Compiler/Instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,81 +321,85 @@ namespace Ark::internal
// @role Call a builtin by its id in #[code primary], with #[code secondary] arguments. Bypass the stack size check because we do not push IP/PP since builtins calls do not alter the stack
CALL_BUILTIN = 0x50,

// @args builtin id, argument count
// @role Call a builtin by its id in #[code primary], with #[code secondary] arguments. Bypass the stack size check because we do not push IP/PP since builtins calls do not alter the stack, as well as the return address removal
CALL_BUILTIN_WITHOUT_RETURN_ADDRESS = 0x51,

// @args constant id, absolute address to jump to
// @role Compare #[code TS < constant], if the comparison fails, jump to the given address. Otherwise, does nothing
LT_CONST_JUMP_IF_FALSE = 0x51,
LT_CONST_JUMP_IF_FALSE = 0x52,

// @args constant id, absolute address to jump to
// @role Compare #[code TS < constant], if the comparison succeeds, jump to the given address. Otherwise, does nothing
LT_CONST_JUMP_IF_TRUE = 0x52,
LT_CONST_JUMP_IF_TRUE = 0x53,

// @args symbol id, absolute address to jump to
// @role Compare #[code TS < symbol], if the comparison fails, jump to the given address. Otherwise, does nothing
LT_SYM_JUMP_IF_FALSE = 0x53,
LT_SYM_JUMP_IF_FALSE = 0x54,

// @args constant id, absolute address to jump to
// @role Compare #[code TS > constant], if the comparison succeeds, jump to the given address. Otherwise, does nothing
GT_CONST_JUMP_IF_TRUE = 0x54,
GT_CONST_JUMP_IF_TRUE = 0x55,

// @args constant id, absolute address to jump to
// @role Compare #[code TS > constant], if the comparison fails, jump to the given address. Otherwise, does nothing
GT_CONST_JUMP_IF_FALSE = 0x55,
GT_CONST_JUMP_IF_FALSE = 0x56,

// @args symbol id, absolute address to jump to
// @role Compare #[code TS > symbol], if the comparison fails, jump to the given address. Otherwise, does nothing
GT_SYM_JUMP_IF_FALSE = 0x56,
GT_SYM_JUMP_IF_FALSE = 0x57,

// @args constant id, absolute address to jump to
// @role Compare #[code TS == constant], if the comparison succeeds, jump to the given address. Otherwise, does nothing
EQ_CONST_JUMP_IF_TRUE = 0x57,
EQ_CONST_JUMP_IF_TRUE = 0x58,

// @args symbol index, absolute address to jump to
// @role Compare #[code TS == symbol], if the comparison succeeds, jump to the given address. Otherwise, does nothing
EQ_SYM_INDEX_JUMP_IF_TRUE = 0x58,
EQ_SYM_INDEX_JUMP_IF_TRUE = 0x59,

// @args constant id, absolute address to jump to
// @role Compare #[code TS != constant], if the comparison succeeds, jump to the given address. Otherwise, does nothing
NEQ_CONST_JUMP_IF_TRUE = 0x59,
NEQ_CONST_JUMP_IF_TRUE = 0x5a,

// @args symbol id, absolute address to jump to
// @role Compare #[code TS != symbol], if the comparison fails, jump to the given address. Otherwise, does nothing
NEQ_SYM_JUMP_IF_FALSE = 0x5a,
NEQ_SYM_JUMP_IF_FALSE = 0x5b,

// @args symbol id, argument count
// @role Call a symbol by its id in #[code primary], with #[code secondary] arguments
CALL_SYMBOL = 0x5b,
CALL_SYMBOL = 0x5c,

// @args symbol id, field id in symbols table
// @role Push the field of a given symbol (which has to be a closure) on the stack
GET_FIELD_FROM_SYMBOL = 0x5c,
GET_FIELD_FROM_SYMBOL = 0x5d,

// @args symbol index, field id in symbols table
// @role Push the field of a given symbol (which has to be a closure) on the stack
GET_FIELD_FROM_SYMBOL_INDEX = 0x5d,
GET_FIELD_FROM_SYMBOL_INDEX = 0x5e,

// @args symbol id, symbol id2
// @role Push symbol[symbol2]
AT_SYM_SYM = 0x5e,
AT_SYM_SYM = 0x5f,

// @args symbol index, symbol index2
// @role Push symbol[symbol2]
AT_SYM_INDEX_SYM_INDEX = 0x5f,
AT_SYM_INDEX_SYM_INDEX = 0x60,

// @args symbol id, constant id
// @role Check that the type of symbol is the given constant, push true if so, false otherwise
CHECK_TYPE_OF = 0x60,
CHECK_TYPE_OF = 0x61,

// @args symbol index, constant id
// @role Check that the type of symbol is the given constant, push true if so, false otherwise
CHECK_TYPE_OF_BY_INDEX = 0x61,
CHECK_TYPE_OF_BY_INDEX = 0x62,

// @args symbol id, number of elements
// @role Append N elements to a reference to a list (symbol id), the list is being mutated in-place, no new object created. Elements are stored in TS(1)..TS(N). Follows the function calling convention
APPEND_IN_PLACE_SYM = 0x62,
APPEND_IN_PLACE_SYM = 0x63,

// @args symbol index, number of elements
// @role Append N elements to a reference to a list (symbol index), the list is being mutated in-place, no new object created. Elements are stored in TS(1)..TS(N). Follows the function calling convention
APPEND_IN_PLACE_SYM_INDEX = 0x63,
APPEND_IN_PLACE_SYM_INDEX = 0x64,

InstructionsCount
};
Expand Down Expand Up @@ -484,6 +488,7 @@ namespace Ark::internal
"SET_VAL_HEAD",
"SET_VAL_HEAD_BY_INDEX",
"CALL_BUILTIN",
"CALL_BUILTIN_WITHOUT_RETURN_ADDRESS",
"LT_CONST_JUMP_IF_FALSE",
"LT_CONST_JUMP_IF_TRUE",
"LT_SYM_JUMP_IF_FALSE",
Expand Down
3 changes: 2 additions & 1 deletion include/Ark/VM/VM.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,9 @@ namespace Ark
* @param context
* @param builtin the builtin to call
* @param argc number of arguments already sent
* @param remove_return_address remove the return address pushed by the compiler
*/
inline void callBuiltin(internal::ExecutionContext& context, const Value& builtin, uint16_t argc);
inline void callBuiltin(internal::ExecutionContext& context, const Value& builtin, uint16_t argc, bool remove_return_address = true);
};

#include "VM.inl"
Expand Down
13 changes: 11 additions & 2 deletions include/Ark/VM/VM.inl
Original file line number Diff line number Diff line change
Expand Up @@ -309,11 +309,20 @@ inline void VM::call(internal::ExecutionContext& context, const uint16_t argc, V
index += 4; // instructions are on 4 bytes
}

// no store? check for CALL_BUILTIN_WITHOUT_RETURN_ADDRESS
if (index == 0 && m_state.m_pages[context.pp][0] == CALL_BUILTIN_WITHOUT_RETURN_ADDRESS)
{
const uint8_t padding = m_state.m_pages[context.pp][context.ip + 1];
const uint16_t arg = static_cast<uint16_t>((m_state.m_pages[context.pp][context.ip + 2] << 8) +
m_state.m_pages[context.pp][context.ip + 3]);
needed_argc = static_cast<uint16_t>((padding << 4) | (arg & 0xf000) >> 12);
}

if (std::cmp_not_equal(needed_argc, argc)) [[unlikely]]
throwArityError(argc, needed_argc, context);
}

inline void VM::callBuiltin(internal::ExecutionContext& context, const Value& builtin, const uint16_t argc)
inline void VM::callBuiltin(internal::ExecutionContext& context, const Value& builtin, const uint16_t argc, const bool remove_return_address)
{
// drop arguments from the stack
std::vector<Value> args;
Expand All @@ -330,7 +339,7 @@ inline void VM::callBuiltin(internal::ExecutionContext& context, const Value& bu
args.emplace_back(*val);
}
// +2 to skip PP/IP that were pushed by PUSH_RETURN_ADDRESS
context.sp -= argc + 2;
context.sp -= argc + (remove_return_address ? 2 : 0);
// call proc
push(builtin.proc()(args, this), context);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/modules
2 changes: 1 addition & 1 deletion lib/std
Loading
Loading