55#ifndef INTERPRETER_RUNTIME_H
56#define INTERPRETER_RUNTIME_H
126 return "HostFunction";
146 return "RuntimeError";
242 value.bool_value = b;
251 value.integer_value = i;
260 value.string_value = std::move(text);
287 value.callable_name =
fn !=
nullptr ?
fn->name :
"<null-function>";
298 value.host_function = callback;
300 value.callable_name = std::move(name);
335 : elements(
std::move(values))
346 if (
other.tuple_storage !=
nullptr)
351 : kind(
other.kind), bool_value(
other.bool_value), integer_value(
other.integer_value),
352 character_value(
other.character_value), string_value(std::move(
other.string_value)),
353 tuple_storage(std::move(
other.tuple_storage)), function(
other.function),
354 closure_environment(
other.closure_environment), host_function(
other.host_function),
355 host_user_data(
other.host_user_data), callable_name(std::move(
other.callable_name))
367 tuple_storage.reset();
370 bool_value =
other.bool_value;
371 integer_value =
other.integer_value;
372 character_value =
other.character_value;
373 string_value =
other.string_value;
374 function =
other.function;
375 closure_environment =
other.closure_environment;
376 host_function =
other.host_function;
377 host_user_data =
other.host_user_data;
378 callable_name =
other.callable_name;
380 if (
other.tuple_storage !=
nullptr)
381 tuple_storage = std::make_unique<Interpreter_Tuple_Storage>(*
other.tuple_storage);
391 bool_value =
other.bool_value;
392 integer_value =
other.integer_value;
393 character_value =
other.character_value;
394 string_value = std::move(
other.string_value);
395 tuple_storage = std::move(
other.tuple_storage);
396 function =
other.function;
397 closure_environment =
other.closure_environment;
398 host_function =
other.host_function;
399 host_user_data =
other.host_user_data;
400 callable_name = std::move(
other.callable_name);
410 value.tuple_storage = std::make_unique<Interpreter_Tuple_Storage>(elements);
418 value.tuple_storage = std::make_unique<Interpreter_Tuple_Storage>(std::move(elements));
487 auto escape_text = [](std::string_view text)
491 for (
const char ch : text)
518 std::ostringstream
out;
530 out <<
"Bool(" << (
value.bool_value ?
"true" :
"false") <<
")";
534 out <<
"Int(" <<
value.integer_value <<
")";
538 out <<
"String(\"" << escape_text(
value.string_value) <<
"\")";
542 out <<
"Char('" << escape_text(std::string(1,
value.character_value)) <<
"')";
547 for (
size_t i = 0; i <
value.tuple_elements().
size(); ++i)
557 out <<
"Function(" <<
value.callable_name <<
")";
561 out <<
"HostFunction(" <<
value.callable_name <<
")";
583 for (
size_t i =
bindings_.size(); i > 0; --i)
584 if (
bindings_.access(i - 1).name == name)
591 for (
size_t i =
bindings_.size(); i > 0; --i)
592 if (
bindings_.access(i - 1).name == name)
768 const std::string &
code,
770 const std::string ¬e =
"",
771 const std::string &help =
"")
const
776 if (
not note.empty())
778 if (
not help.empty())
790 static bool strip_quotes(std::string_view text,
const char quote, std::string_view &body)
noexcept
794 if (text.front() != quote
or text.back() != quote)
796 body = text.substr(1, text.size() - 2);
803 out.reserve(body.size());
805 for (
size_t i = 0; i < body.size(); ++i)
807 const char ch = body[i];
814 if (i + 1 >= body.size())
816 error =
"unterminated escape sequence";
820 switch (
const char esc = body[++i])
844 error = std::string(
"unsupported escape sequence \\") +
esc;
856 for (
const char ch : node->
text)
865 const long long value = std::strtoll(
digits.c_str(), &end, 10);
869 "integer literal is out of range for the interpreter");
876 std::string_view body;
889 std::string_view body;
900 "character literals must decode to exactly one character");
907 const std::string &context)
const
914 context +
" requires Int but received "
920 const std::string &context)
const
927 context +
" requires Bool but received "
945 switch (node->constant_kind)
958 return runtime_error(node->span,
"RUN001",
"unknown HIR constant kind");
968 "unknown runtime identifier '" + node->name +
"'");
975 if (
not operand.ok())
1002 "unsupported unary operator '"
1042 "assignment requires a variable on the left-hand side");
1051 if (
not env.assign(lhs->name, rhs.value))
1054 "unknown runtime identifier '" + lhs->name +
"'");
1055 return ok(rhs.value);
1062 "unknown runtime identifier '" + lhs->name +
"'");
1065 if (
not current.ok())
1075 long long updated = current.value.integer_value;
1088 if (
rhs_int.value.integer_value == 0)
1089 return runtime_error(node->span,
"RUN007",
"division by zero");
1093 if (
rhs_int.value.integer_value == 0)
1094 return runtime_error(node->span,
"RUN007",
"modulo by zero");
1100 "unsupported compound assignment operator");
1104 (
void)
env.assign(lhs->name, result);
1126 auto lhs =
require_integer(left.value, node->left->span,
"binary operator");
1129 auto rhs =
require_integer(right.value, node->right->span,
"binary operator");
1137 + rhs.value.integer_value));
1140 - rhs.value.integer_value));
1143 * rhs.value.integer_value));
1145 if (rhs.value.integer_value == 0)
1146 return runtime_error(node->span,
"RUN007",
"division by zero");
1148 / rhs.value.integer_value));
1150 if (rhs.value.integer_value == 0)
1151 return runtime_error(node->span,
"RUN007",
"modulo by zero");
1153 % rhs.value.integer_value));
1156 & rhs.value.integer_value));
1159 | rhs.value.integer_value));
1162 ^ rhs.value.integer_value));
1166 "unsupported arithmetic operator '"
1176 auto lhs =
require_integer(left.value, node->left->span,
"comparison");
1179 auto rhs =
require_integer(right.value, node->right->span,
"comparison");
1183 bool result =
false;
1187 result = lhs.value.integer_value < rhs.value.integer_value;
1190 result = lhs.value.integer_value <= rhs.value.integer_value;
1193 result = lhs.value.integer_value > rhs.value.integer_value;
1196 result = lhs.value.integer_value >= rhs.value.integer_value;
1216 "unsupported binary operator '"
1225 if (
not callee.ok())
1229 for (
size_t i = 0; i < node->arguments.size(); ++i)
1237 return call_value(callee.value, arguments, node->span);
1247 if (stmt ==
nullptr)
1268 if (node->initializer !=
nullptr)
1279 "duplicate runtime binding '" + node->name +
"'");
1286 if (node->value ==
nullptr)
1298 for (
size_t i = 0; i < node->statements.size(); ++i)
1363 const auto *function = callee.
function;
1364 if (function ==
nullptr)
1370 "function '" + function->
name +
"' expects "
1371 + std::to_string(function->
parameters.size())
1372 +
" arguments but received " + std::to_string(arguments.
size()));
1377 "maximum call depth exceeded while calling '" + function->
name +
"'");
1384 for (
size_t i = 0; i < function->
parameters.size(); ++i)
1392 return ok(result.value);
1397 "control-flow escaped function '" + function->
name +
"'");
1413 auto code =
error.code.empty() ? std::string(
"RUN004") :
error.code;
1423 switch (callee.
kind)
1434 "attempted to call a non-callable value of kind "
1441 if (function ==
nullptr)
1501 <<
"Interpreter_Runtime::bind_host_function(): callback is null";
1515 if (module ==
nullptr)
1520 for (
size_t i = 0; i <
module->functions.size(); ++i)
1524 "duplicate global function '" + module->
functions.access(i)->name
1527 for (
size_t i = 0; i <
module->statements.size(); ++i)
1537 "top-level control-flow statement is not allowed");
1558 return runtime_error({},
"RUN002",
"unknown runtime identifier '" + name +
"'");
1569 std::ostringstream
out;
1570 out <<
"Environment\n";
1571 for (
size_t i = 0; i <
env.bindings().
size(); ++i)
1573 const auto &binding =
env.bindings().access(i);
1582 std::ostringstream
out;
1584 const auto &
env =
runtime.global_environment();
1585 for (
size_t i = 0; i <
env.bindings().
size(); ++i)
1587 const auto &binding =
env.bindings().access(i);
Reusable typed high-level IR model independent from any concrete frontend.
Plain-text diagnostic engine for compiler-style tooling.
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
size_t size_t int32_t value
size_t size_t int32_t * out
Diagnostic_Builder & code(const std::string &value)
Sets the stable diagnostic code.
size_t emit() const noexcept
Finalizes the builder and returns the diagnostic index.
Diagnostic_Builder & help(const std::string &msg)
Appends a help line.
Diagnostic_Builder & note(const std::string &msg)
Appends a note line.
Diagnostic accumulator and renderer.
Diagnostic_Builder error(const Source_Span &span, const std::string &msg)
Starts an error diagnostic.
size_t size() const noexcept
Return the current dimension of array.
T & access(const size_t i) const noexcept
Fast access without checking allocation and bound_min_clock checking.
T & append()
Allocate a new entry to the end of array.
Nested runtime environment with lexical lookup semantics.
void clear() noexcept
Drops all bindings from this environment only.
Interpreter_Environment(Interpreter_Environment *parent=nullptr) noexcept
Builds an environment with optional lexical parent.
const Interpreter_Value * find_local(const std::string &name) const noexcept
size_t size() const noexcept
Returns the number of bindings in this environment.
Interpreter_Value * lookup(const std::string &name) noexcept
Finds a visible binding recursively.
bool define(const std::string &name, const Interpreter_Value &value)
Defines one local binding.
void set_parent(Interpreter_Environment *parent) noexcept
Changes the lexical parent for this environment.
bool assign(const std::string &name, const Interpreter_Value &value)
Assigns an existing visible binding.
DynArray< Interpreter_Binding > bindings_
const Interpreter_Value * lookup(const std::string &name) const noexcept
Finds a visible binding recursively.
Interpreter_Environment * parent() const noexcept
Returns the lexical parent, if any.
const DynArray< Interpreter_Binding > & bindings() const noexcept
Returns read-only access to the local bindings.
Interpreter_Value * find_local(const std::string &name) noexcept
Interpreter_Environment * parent_env
bool is_empty() const noexcept
Returns whether this environment is empty.
Structured runtime for executing typed HIR.
Interpreter_Execution_Result parse_integer_literal(const Compiler_HIR_Constant_Expr *node) const
Interpreter_Environment prelude
static Interpreter_Execution_Result control(const Interpreter_Control_Flow_Kind flow, const Interpreter_Value &value=Interpreter_Value::make_unit())
Interpreter_Environment globals
Interpreter_Execution_Result parse_string_literal(const Compiler_HIR_Constant_Expr *node) const
DynArray< Interpreter_Call_Frame > call_stack
Interpreter_Execution_Result call_hir_function(const Interpreter_Value &callee, const DynArray< Interpreter_Value > &arguments, const Source_Span &span)
Interpreter_Execution_Result require_integer(const Interpreter_Value &value, const Source_Span &span, const std::string &context) const
void set_diagnostics(Diagnostic_Engine *dx) noexcept
Sets the optional diagnostic sink for runtime failures.
Interpreter_Execution_Result call_value(const Interpreter_Value &callee, const DynArray< Interpreter_Value > &arguments, const Source_Span &span)
Interpreter_Runtime(Diagnostic_Engine *dx=nullptr, const Interpreter_Runtime_Options &opts={}) noexcept
Builds a fresh interpreter runtime.
size_t call_depth() const noexcept
Returns the current call depth.
Interpreter_Execution_Result require_bool(const Interpreter_Value &value, const Source_Span &span, const std::string &context) const
const Interpreter_Environment & global_environment() const noexcept
Returns the globals environment for the last evaluated module.
Interpreter_Execution_Result runtime_error(const Source_Span &span, const std::string &code, const std::string &message, const std::string ¬e="", const std::string &help="") const
bool bind_host_function(const std::string &name, const Interpreter_Host_Function callback, void *user_data=nullptr)
Defines one host function in the persistent prelude.
Interpreter_Execution_Result call(const std::string &name, const DynArray< Interpreter_Value > &arguments)
Calls one visible function by name.
static Interpreter_Execution_Result ok(const Interpreter_Value &value=Interpreter_Value::make_unit())
void reset() noexcept
Clears globals and the call stack while preserving host bindings.
Interpreter_Execution_Result evaluate_expr(const Compiler_HIR_Expr *expr, Interpreter_Environment &env)
bool install_module_function(const Compiler_HIR_Function *function)
static bool strip_quotes(std::string_view text, const char quote, std::string_view &body) noexcept
static bool decode_escaped_text(const std::string_view body, std::string &out, std::string &error)
const Interpreter_Environment & prelude_environment() const noexcept
Returns the persistent prelude environment.
Interpreter_Execution_Result evaluate_stmt(const Compiler_HIR_Stmt *stmt, Interpreter_Environment &env)
Interpreter_Execution_Result evaluate_module(const Compiler_HIR_Module *module)
Evaluates one HIR module and leaves its globals installed.
Interpreter_Runtime_Options options
Interpreter_Execution_Result call_host_function(const Interpreter_Value &callee, const DynArray< Interpreter_Value > &arguments, const Source_Span &span) const
Diagnostic_Engine * diagnostics
Interpreter_Execution_Result parse_char_literal(const Compiler_HIR_Constant_Expr *node) const
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Main namespace for Aleph-w library functions.
@ Runtime_Error
Execution failed with a structured runtime error.
@ Return
Return one register value.
@ String
String literal payload.
@ Character
Character literal payload.
@ Invalid
Uninitialized register/slot or explicit invalid placeholder.
void message(const char *file, int line, const char *format,...)
Print an informational message with file and line info.
size_t size(Node *root) noexcept
Interpreter_Value_Kind
Runtime categories supported by the interpreter MVP.
const char * interpreter_value_kind_name(const Interpreter_Value_Kind kind) noexcept
Stable debug name for one runtime value kind.
const char * compiler_operator_name(const Compiler_Operator_Kind kind) noexcept
Returns a stable debug name for one operator kind.
@ Continue
Skip to the next iteration of the innermost loop.
@ Break
Immediate exit from the innermost loop.
bool interpreter_values_equal(const Interpreter_Value &lhs, const Interpreter_Value &rhs)
Returns whether two runtime values compare equal.
and
Check uniqueness with explicit hash + equality functors.
std::string code(Node *root)
Compute a string with the Lukasiewicz`s word of a tree.
const char * interpreter_control_flow_name(const Interpreter_Control_Flow_Kind kind) noexcept
Stable debug name for one control-flow outcome.
std::string interpreter_dump_environment(const Interpreter_Environment &env)
Dumps one environment deterministically.
void error(const char *file, int line, const char *format,...)
Print an error message with file and line info.
Interpreter_Control_Flow_Kind
Structured control-flow outcomes during evaluation.
bool compiler_operator_is_compound_assignment(const Compiler_Operator_Kind kind) noexcept
Returns whether kind is one compound-assignment operator.
static std::atomic< bool > init
bool(*)(void *user_data, const DynArray< Interpreter_Value > &arguments, Interpreter_Value &result, Interpreter_Runtime_Error &error) Interpreter_Host_Function
Host callback signature used by runtime built-ins or embeddings.
std::string interpreter_dump_globals(const Interpreter_Runtime &runtime)
Dumps the globals currently installed in one runtime.
std::string interpreter_value_to_string(const Interpreter_Value &value)
Formats one runtime value deterministically for dumps and tests.
@ Function
Function type such as fn(Int) -> Bool.
@ Tuple
Tuple type such as (Int, Bool).
Structured block statement.
Typed function call expression.
Typed constant expression.
std::string text
Original or normalized constant spelling.
Expression statement in HIR.
Base class for HIR expressions.
Compiler_HIR_Expr_Kind kind
Runtime node kind.
std::string name
Function name.
DynArray< Compiler_HIR_Param > parameters
Parameters in declaration order.
Compiler_HIR_Block_Stmt * body
Function body.
Structured conditional statement.
Typed lexical binding statement.
DynArray< Compiler_HIR_Function * > functions
Lowered top-level functions.
DynArray< Compiler_HIR_Stmt * > statements
Lowered top-level statements.
Source_Span span
Source region associated with the HIR node.
Base class for HIR statements.
Compiler_HIR_Stmt_Kind kind
Runtime node kind.
Typed variable reference expression.
Structured while-loop statement.
One lexical binding inside an interpreter environment.
std::string name
Binding name.
Interpreter_Value value
Stored runtime value.
Result of evaluating one expression, statement, module, or call.
bool has_control_flow() const noexcept
Returns whether this result carries non-local control flow.
Interpreter_Runtime_Error error
Structured runtime failure when flow == Runtime_Error.
Interpreter_Value value
Produced runtime value when relevant.
Interpreter_Control_Flow_Kind flow
Control-flow outcome.
bool ok() const noexcept
Returns whether this result represents a runtime failure.
Interpreter_Environment locals
const Compiler_HIR_Function * function
Structured runtime error.
Source_Span span
Source region associated with the failure.
std::string code
Stable runtime code such as RUN004.
std::string message
Human-readable runtime message.
bool has_error() const noexcept
Returns whether this error object is populated.
Runtime options for the HIR evaluator.
size_t max_call_depth
Maximum nested HIR calls before RUN010.
Heap-owned tuple payload for recursive runtime values.
Interpreter_Tuple_Storage()=default
DynArray< Interpreter_Value > elements
Tuple members in lexical order.
Interpreter_Tuple_Storage(DynArray< Interpreter_Value > &&values)
Interpreter_Tuple_Storage(const DynArray< Interpreter_Value > &values)
std::string callable_name
Stable debug name for callable values.
void * host_user_data
Embedding-specific payload for host functions.
Interpreter_Environment * closure_environment
Captured lexical parent for function values.
static Interpreter_Value make_tuple(const DynArray< Interpreter_Value > &elements)
Builds a tuple runtime value by copying elements.
bool is_unit() const noexcept
Returns whether this value is the Unit singleton.
Interpreter_Host_Function host_function
Payload for host function values.
std::string string_value
Payload for String values.
char character_value
Payload for Char values.
const Compiler_HIR_Function * function
Payload for HIR function values.
long long integer_value
Payload for Int values.
static Interpreter_Value make_bool(const bool b)
Builds a boolean runtime value.
Interpreter_Value & operator=(const Interpreter_Value &other)
Assigns one runtime value by deep copy.
bool is_callable() const noexcept
Returns whether this value is callable.
static Interpreter_Value make_character(const char ch)
Builds a character runtime value.
static Interpreter_Value make_invalid()
Builds an invalid value placeholder.
std::unique_ptr< Interpreter_Tuple_Storage > tuple_storage
Payload for Tuple values.
~Interpreter_Value() noexcept
Releases tuple storage if present.
static Interpreter_Value make_function(const Compiler_HIR_Function *fn, Interpreter_Environment *env=nullptr)
Builds a callable value backed by HIR function code.
bool bool_value
Payload for Bool values.
Interpreter_Value_Kind kind
Active value kind.
Interpreter_Value()=default
Builds a fresh value with no tuple storage.
static Interpreter_Value make_host_function(std::string name, const Interpreter_Host_Function callback, void *user_data=nullptr)
Builds a callable value backed by host code.
static Interpreter_Value make_integer(const long long i)
Builds an integer runtime value.
const DynArray< Interpreter_Value > & tuple_elements() const noexcept
Returns the tuple payload.
static Interpreter_Value make_unit()
Builds the Unit value.
static Interpreter_Value make_string(std::string text)
Builds a string runtime value.
Represents a missing value.
Half-open byte range inside a source file.
Lazy and scalable dynamic array implementation.