// present in this list when generating CTags.
bh_arr(AstNode *) tag_locations;
- b32 cycle_almost_detected : 1;
+ u32 cycle_almost_detected : 2;
b32 cycle_detected : 1;
};
AstCodeBlock* code_block = (AstCodeBlock *) insert->code_expr;
code_block = (AstCodeBlock *) strip_aliases((AstNode *) code_block);
- assert(code_block->kind == Ast_Kind_Code_Block);
+ if (code_block->kind != Ast_Kind_Code_Block) {
+ ERROR(insert->token->pos, "Expected compile-time known expression of type 'Code'.");
+ }
AstNode* cloned_block = ast_clone(context.ast_alloc, code_block->code);
cloned_block->next = insert->next;
if (ent->macro_attempts > highest_watermark) {
entity_heap_insert_existing(&context.entities, ent);
- if (context.cycle_almost_detected) {
+ if (context.cycle_almost_detected == 3) {
dump_cycles();
} else {
- context.cycle_almost_detected = 1;
+ context.cycle_almost_detected += 1;
}
}
}
}
}
else if (force_a_lookup) {
- if (context.cycle_detected || context.cycle_almost_detected) {
+ if (context.cycle_detected || context.cycle_almost_detected >= 2) {
onyx_report_error((*fa)->token->pos, Error_Critical, "'%b' does not exist here. This is a bad error message.",
(*fa)->token->text,
(*fa)->token->length);
static SymresStatus symres_directive_defined(AstDirectiveDefined** pdefined) {
AstDirectiveDefined* defined = *pdefined;
- b32 has_to_be_resolved = context.cycle_almost_detected;
+ b32 has_to_be_resolved = context.cycle_almost_detected >= 1;
onyx_errors_disable();
resolved_a_symbol = 0;
// Things that work with slices and arrays
+use core.intrinsics.types {type_is_struct}
+
transplant :: (arr: [] $T, old_index: i32, new_index: i32) -> bool {
if old_index < 0 || old_index >= arr.count do return false;
if new_index < 0 || new_index >= arr.count do return false;
macro (arr: [] $T, data: $R, f: (T, R) -> T) do for ^it: arr do *it = f(*it, data);,
}
-every :: #match #locked {
- macro (arr: [] $T, predicate: (T) -> bool) -> bool {
- every :: every
- return every(arr, #(predicate(it)));
- },
+every :: #match #local {}
- macro (arr: [] $T, predicate_body: Code) -> bool {
- for arr {
- if !(#unquote predicate_body) do return false;
- }
- return true;
+#overload
+every :: macro (arr: [] $T, predicate: (T) -> bool) -> bool {
+ every :: every
+ return every(arr, #(predicate(it)));
+}
+
+#overload
+every :: macro (arr: [] $T, predicate_body: Code) -> bool {
+ for arr {
+ if !(#unquote predicate_body) do return false;
}
+ return true;
}
-some :: #match #locked {
- macro (arr: [] $T, predicate: (T) -> bool) -> bool {
- some :: some
- return every(arr, #(predicate(it)));
- },
+some :: #match #local {}
- macro (arr: [] $T, predicate_body: Code) -> bool {
- for arr {
- if #unquote predicate_body do return true;
- }
- return false;
+#overload
+some :: macro (arr: [] $T, predicate: (T) -> bool) -> bool {
+ some :: some
+ return every(arr, #(predicate(it)));
+}
+
+#overload
+some :: macro (arr: [] $T/type_is_struct, predicate_body: Code) -> bool {
+ for ^ arr {
+ if #unquote predicate_body do return true;
}
+ return false;
+}
+
+#overload
+some :: macro (arr: [] $T, predicate_body: Code) -> bool {
+ for arr {
+ if #unquote predicate_body do return true;
+ }
+ return false;
}
fill :: (arr: [] $T, value: T) {
}
#overload
-find :: macro (arr: [] $T, pred: Code) -> i32 {
+find :: macro (arr: [] $T/type_is_struct, pred: Code) -> i32 {
for i: arr.count {
it := ^arr[i];
if #unquote pred do return i;
return -1;
}
+#overload
+find :: macro (arr: [] $T, pred: Code) -> i32 {
+ for i: arr.count {
+ it := arr[i];
+ if #unquote pred do return i;
+ }
+
+ return -1;
+}
+
find_ptr :: (arr: [] $T, value: T) -> ^T {
for ^it: arr {
if value == *it do return it;
return first(arr, #(predicate(it)));
},
+ macro (arr: [] $T/type_is_struct, predicate_body: Code) -> ^T {
+ for ^ arr {
+ if #unquote predicate_body do return it;
+ }
+
+ return null;
+ },
+
macro (arr: [] $T, predicate_body: Code) -> ^T {
// This is to preserve the semantics that "it" is
- // not a pointer (same as contains)
+ // not a pointer (same as contains), when T is not a
+ // structure.
for ^it_ptr: arr {
it := *it_ptr;
if #unquote predicate_body do return it_ptr;
package core.hash
to_u32 :: #match {
+ // Does this need to have a higher precedence value?
+ // Because if I wanted to have a custom type as the key
+ // of a map that only looks at some of the members of the
+ // struct to determine its hash, that would not be possible
+ // as any pointer would match this case instead of the actual
+ // one defined for the type...
(key: rawptr) -> u32 { return 0xcbf29ce7 ^ cast(u32) key; },
+
(key: i8) -> u32 { return ~~ key; },
(key: i16) -> u32 { return 0x9ce7 ^ cast(u32) key; },
(key: i32) -> u32 { return 0xcbf29ce7 ^ cast(u32) key; },
get_struct_member
}
-use core { iter, array }
+use core { iter, array, string }
+// Either to_any or as_any will work. I prefer `as_any` because
+// much of the rest of the standard library uses `as_...` for
+// conversion.
+as_any :: to_any
to_any :: macro (x: ^$T) => any.{x, T};
any_as :: (a: any, $T: type_expr) -> ^T {
return .{null, void};
}
+// This selector works with selecting "foo.bar.joe"
+any_nested_selector :: (v: any, member_name: str) -> any {
+ t := get_type_info(v.type);
+ if t.kind != .Struct do return .{};
+
+ part_name, next_name := string.bisect(member_name, #char ".");
+
+ member := get_struct_member(v.type, part_name);
+ if member {
+ if next_name {
+ return any_nested_selector(any.{cast(^u8) v.data + member.offset, member.type}, next_name);
+ }
+
+ return any.{
+ cast(^u8, v.data) + member.offset, member.type
+ };
+ }
+
+ return .{null, void};
+}
+
any_to_map :: (v: any) -> (Map(str, any), success: bool) {
vals := v;
if get_type_info(vals.type).kind == .Pointer {
#load "./test/testing"
#load "./misc/arg_parse"
-#load "./misc/any_utils"
#load "./misc/method_ops"
-#local runtime :: package runtime
#if runtime.runtime == .Wasi || runtime.runtime == .Onyx {
#load "./os/file"
#load "./os/os"
#load "./encoding/base64"
#load "./encoding/csv"
+ #load "./misc/any_utils"
}
#if runtime.Multi_Threading_Enabled {
bh_arena tmp_arena;
bh_allocator tmp_alloc;
+ char *listen_path;
+
debug_info_t *info;
struct ovm_engine_t *ovm_engine;
struct wasm_config_t {
bool debug_enabled;
+ char *listen_path;
};
void wasm_config_enable_debug(wasm_config_t *config, bool enabled);
+void wasm_config_set_listen_path(wasm_config_t *config, char *listen_path);
struct wasm_engine_t {
wasm_config_t *config;
struct sockaddr_un local_addr, remote_addr;
local_addr.sun_family = AF_UNIX;
- strcpy(local_addr.sun_path, "/tmp/ovm-debug.0000"); // TODO: Make this dynamic so mulitple servers can exist at a time.
- unlink(local_addr.sun_path); // TODO: Remove this line for the same reason.
+ strcpy(local_addr.sun_path, debug->listen_path); // TODO: Make this dynamic so mulitple servers can exist at a time.
+ unlink(local_addr.sun_path); // TODO: Remove this line for the same reason.
int len = strlen(local_addr.sun_path) + sizeof(local_addr.sun_family);
bind(debug->listen_socket_fd, (struct sockaddr *)&local_addr, len);
#define OVMI_FUNC_NAME(n) ovmi_exec_debug_##n
#define OVMI_DISPATCH_NAME ovmi_debug_dispatch
-#define OVMI_DEBUG_HOOK if (state->debug) __ovm_debug_hook(state->engine, state)
+#define OVMI_DEBUG_HOOK __ovm_debug_hook(state->engine, state)
#define OVMI_EXCEPTION_HOOK __ovm_trigger_exception(state)
#include "./vm_instrs.h"
wasm_config_t *wasm_config_new() {
wasm_config_t *config = malloc(sizeof(*config));
config->debug_enabled = false;
+ config->listen_path = "/tmp/ovm-debug.0000";
return config;
}
config->debug_enabled = enabled;
}
+void wasm_config_set_listen_path(wasm_config_t *config, char *listen_path) {
+ config->listen_path = listen_path;
+}
engine->engine->debug = debug;
debug_host_init(engine->engine->debug, engine->engine);
+ debug->listen_path = config->listen_path;
+
debug_host_start(engine->engine->debug);
}
command_procedures := runtime.info.get_procedures_with_tag(Command);
defer delete(^command_procedures);
- for command_procedures {
- if it.tag.command == command {
- if it.tag.require_config_file {
- if !load_config_file() {
- eprintf("Failed to open {}.\n", global_arguments.config_file);
- os.exit(1);
- }
- loaded_config_file = true;
- }
+ command_tag := array.first(command_procedures, #(it.tag.command == command));
+ if !command_tag {
+ run_help_command(arguments);
+ return;
+ }
- assert(it.type == #type ([] cstr) -> void, "BAD TYPE FOR COMMAND PROCEDURE!");
- (*cast(^([] cstr) -> void) ^it.func)(arguments);
- break;
+ if command_tag.tag.require_config_file {
+ if !load_config_file() {
+ eprintf("Failed to open {}.\n", global_arguments.config_file);
+ os.exit(1);
}
+
+ loaded_config_file = true;
}
+
+ assert(command_tag.type == #type ([] cstr) -> void, "BAD TYPE FOR COMMAND PROCEDURE!");
+ (*cast(^([] cstr) -> void) ^command_tag.func)(arguments);
}
Command :: struct {
package-or-url Git repository name or package name on disk to remove.
"""
}
-run_rebuild_command :: (args: [] cstr) {
+run_rebuild_command :: (args: [] cstr) {
if args.count < 1 {
eprintf("Expected package name.");
return;
}
}
+#tag Command.{ "new", "Create a new project from an installed template." }
+run_new_command :: (args: [] cstr) {
+
+}
+
#local {
#if runtime.compiler_os == .Linux {
version_str := tprintf("v{}", version);
full_dest := tprintf("{}/{}", config.config.lib_source_directory, ".cloned");
+ os.remove_directory(full_dest);
+
// Use 'git clone' to clone the bare minimum amount to get the released version.
git_proc := os.process_spawn(git_path, .["clone", "--depth", "1", "-b", version_str, repo, full_dest]);
result := os.process_wait(^git_proc);