NODE(ForeignBlock) \
\
NODE(Package) \
+ NODE(Import) \
\
NODE(ZeroValue)
Ast_Kind_Load_Path,
Ast_Kind_Load_All,
Ast_Kind_Library_Path,
+ Ast_Kind_Import,
Ast_Kind_Memres,
Ast_Kind_Binding,
Package* package;
};
+struct AstImport {
+ AstNode_base;
+
+ AstPackage *imported_package;
+};
+
+
//
// Polymorphic procedures
//
Entity_Type_Load_File,
Entity_Type_Binding,
Entity_Type_Use_Package,
+ Entity_Type_Import,
Entity_Type_Static_If,
Entity_Type_String_Literal,
Entity_Type_File_Contents,
union {
AstDirectiveError *error;
AstInclude *include;
+ AstImport *import;
AstBinding *binding;
AstIf *static_if;
AstFunction *function;
"INCLUDE FOLDER",
"INCLUDE ALL IN FOLDER",
"INCLUDE LIBRARY PATH",
+ "IMPORT",
"MEMORY RESERVATION",
"BINDING",
break;
}
+ case Ast_Kind_Import: {
+ ent.type = Entity_Type_Import;
+ ent.import = (AstImport *) node;
+ ent.state = Entity_State_Resolve_Symbols;
+ ENTITY_INSERT(ent);
+ break;
+ }
+
default: {
ent.type = Entity_Type_Expression;
ent.expr = (AstTyped *) node;
"macro",
"interface",
"where",
+ "import",
"", // end
"->",
static void parse_top_level_statement(OnyxParser* parser);
static AstPackage* parse_package_expression(OnyxParser* parser);
static void parse_top_level_statements_until(OnyxParser* parser, TokenType tt);
+static AstImport* parse_import_statement(OnyxParser* parser, OnyxToken *token);
static void consume_token(OnyxParser* parser) {
if (parser->hit_unexpected_token) return;
expect_token(parser, Token_Type_Literal_String);
return;
}
+ else if (parse_possible_directive(parser, "import")) {
+ AstImport *import = parse_import_statement(parser, dir_token);
+ ENTITY_SUBMIT(import);
+ return;
+ }
else {
OnyxToken* directive_token = expect_token(parser, '#');
OnyxToken* symbol_token = parser->curr;
}
}
-static AstPackage* parse_package_expression(OnyxParser* parser) {
- AstPackage* package_node = make_node(AstPackage, Ast_Kind_Package);
- package_node->flags |= Ast_Flag_Comptime;
- package_node->type_node = builtin_package_id_type;
- package_node->token = expect_token(parser, Token_Type_Keyword_Package);
-
- bh_arr_new(global_heap_allocator, package_node->path, 2);
+static b32 parse_package_name(OnyxParser *parser, AstPackage *package) {
+ bh_arr_new(global_heap_allocator, package->path, 2);
while (parser->curr->type == Token_Type_Symbol) {
- if (parser->hit_unexpected_token) return package_node;
+ if (parser->hit_unexpected_token) return 0;
OnyxToken* symbol = expect_token(parser, Token_Type_Symbol);
+ bh_arr_push(package->path, symbol);
- bh_arr_push(package_node->path, symbol);
-
- if (consume_token_if_next(parser, '.'));
- else break;
+ if (!consume_token_if_next(parser, '.')) break;
}
i32 total_package_name_length = 0;
- bh_arr_each(OnyxToken *, token, package_node->path) {
+ bh_arr_each(OnyxToken *, token, package->path) {
total_package_name_length += (*token)->length + 1;
}
char* package_name = bh_alloc_array(context.ast_alloc, char, total_package_name_length);
*package_name = '\0';
- bh_arr_each(OnyxToken *, token, package_node->path) {
+ bh_arr_each(OnyxToken *, token, package->path) {
token_toggle_end(*token);
strncat(package_name, (*token)->text, total_package_name_length - 1);
token_toggle_end(*token);
- if (token != &bh_arr_last(package_node->path)) {
+ if (token != &bh_arr_last(package->path)) {
strncat(package_name, ".", total_package_name_length - 1);
}
}
- package_node->package_name = package_name;
- package_node->package = package_lookup(package_name);
+ package->package_name = package_name;
+ return 1;
+}
+
+static AstPackage* parse_package_expression(OnyxParser* parser) {
+ AstPackage* package_node = make_node(AstPackage, Ast_Kind_Package);
+ package_node->flags |= Ast_Flag_Comptime;
+ package_node->type_node = builtin_package_id_type;
+ package_node->token = expect_token(parser, Token_Type_Keyword_Package);
+
+ if (!parse_package_name(parser, package_node)) return NULL;
return package_node;
}
+static AstImport* parse_import_statement(OnyxParser* parser, OnyxToken *token) {
+ AstImport* import_node = make_node(AstImport, Ast_Kind_Import);
+ import_node->flags |= Ast_Flag_Comptime;
+ import_node->token = token;
+
+ AstPackage* package_node = make_node(AstPackage, Ast_Kind_Package);
+ package_node->flags |= Ast_Flag_Comptime;
+ package_node->type_node = builtin_package_id_type;
+ package_node->token = token;
+
+ if (!parse_package_name(parser, package_node)) return NULL;
+
+ import_node->imported_package = package_node;
+
+ return import_node;
+}
+
static Package* parse_file_package(OnyxParser* parser) {
if (parser->curr->type != Token_Type_Keyword_Package) {
return package_lookup_or_create("main", context.global_scope, parser->allocator, parser->curr->pos);
return Symres_Success;
}
+static SymresStatus symres_import(AstImport* import) {
+ SYMRES(package, import->imported_package);
+
+ symbol_introduce(
+ current_entity->scope,
+ bh_arr_last(import->imported_package->path),
+ (AstNode *) import->imported_package);
+
+ return Symres_Complete;
+}
+
void symres_entity(Entity* ent) {
current_entity = ent;
if (ent->scope) scope_enter(ent->scope);
next_state = Entity_State_Finalized;
break;
+ case Entity_Type_Import: ss = symres_import(ent->import); break;
+
+
case Entity_Type_Polymorphic_Proc: ss = symres_polyproc(ent->poly_proc);
next_state = Entity_State_Finalized;
break;
shput(context.packages, pac_name, package);
- if (!charset_contains(pac_name, '.')) {
+ // if (!charset_contains(pac_name, '.')) {
+ // AstPackage* package_node = onyx_ast_node_new(alloc, sizeof(AstPackage), Ast_Kind_Package);
+ // package_node->package_name = package->name;
+ // package_node->package = package;
+ // package_node->type_node = builtin_package_id_type;
+ // package_node->flags |= Ast_Flag_Comptime;
+
+ // symbol_raw_introduce(context.global_scope, pac_name, pos, (AstNode *) package_node);
+ // }
+
+ if (!strcmp(pac_name, "builtin")) {
AstPackage* package_node = onyx_ast_node_new(alloc, sizeof(AstPackage), Ast_Kind_Package);
package_node->package_name = package->name;
package_node->package = package;
package core.alloc.arena
+#import core
+
// This allocator is mostly used for making many fixed-size
// allocation (i.e. allocations that will not need to change
// in size, such as game entities or position structs). The
// is not needed for the general purpose heap allocator,
// as that already has a thread-safe implementation.
-use core {sync}
+#import core.sync
AtomicAllocator :: struct {
a: Allocator;
package core.alloc.fixed
+#import core
+
// This allocator is very simple and always returns the same pointer,
// unless too much memory is asked for, in which case it returns null.
//
// // Every allocation here will automatically be freed
// }
+#import core
+
GCState :: struct {
backing_allocator: Allocator;
first: &GCLink;
package core.alloc.heap
+#import runtime
+#import core
+
// This is the implementation for the general purpose heap allocator.
// It is a simple bump allocator, with a free list. It is not very good
// prints every allocation/deallocation made by that
// allocator.
+#import core
+
#local
Allocation_Action_Strings := str.[
" alloc",
package core.alloc.pool
+#import core
+
// A pool allocator is an O(1) allocator that is capable of allocating and freeing.
// It is able to do both in constant time because it maintains a linked list of all
// the free elements in the pool. When an element is requested the first element of
package core.alloc.ring
+#import core
+
// This allocator is great for temporary memory, such as returning
// a pointer from a function, or storing a formatted string. The
// memory allocated using this allocator does not need to be freed.
package builtin
+#import runtime
+
+#if #defined(package core) {
+ #import core
+}
+
//
// Explanation of `package builtin`
//
package core.array
+#import core
+
// [..] T == Array(T)
// where
// Array :: struct (T: type_expr) {
#overload
__make_overload :: macro (_: &[..] $T, allocator := context.allocator) -> [..] T {
- return core.array.make(T, allocator=allocator);
+ return #this_package.make(T, allocator=allocator);
}
#overload
__make_overload :: macro (_: &[..] $T, capacity: u32, allocator := context.allocator) -> [..] T {
- return core.array.make(T, capacity, allocator);
+ return #this_package.make(T, capacity, allocator);
}
init :: (arr: &[..] $T, capacity := 4, allocator := context.allocator) {
#overload
builtin.delete :: macro (x: &[..] $T) {
- core.array.free(x);
+ #this_package.free(x);
}
copy :: #match #locked {
}
// Semi-useful shortcut for adding something to an array.
-#operator << macro (arr: [..] $T, v: T) do core.array.push(&arr, v);
+#operator << macro (arr: [..] $T, v: T) do #this_package.push(&arr, v);
insert :: #match #local {}
package core.avl_tree
-use core {math}
+#import core
+#import core.math
AVL_Tree :: struct (T: type_expr) {
data: T;
package core.bucket_array
-use core {array, iter}
+#import core
+#import core.array
+#import core.iter
Bucket_Array :: struct (T: type_expr) {
allocator : Allocator;
}
}
-#operator << macro (b: Bucket_Array($T), elem: T) do core.bucket_array.push(&b, elem);
+#operator << macro (b: Bucket_Array($T), elem: T) do #this_package.push(&b, elem);
pop :: (use b: &Bucket_Array($T)) {
last_bucket := &buckets[buckets.count - 1];
package core.heap
-use core {array}
+#import core.array
Heap :: struct (T: type_expr) {
data: [..] T;
shift_up(heap, data.count - 1);
}
-#operator << macro (heap: Heap($T), v: T) do core.heap.insert(&heap, v);
+#operator << macro (heap: Heap($T), v: T) do #this_package.insert(&heap, v);
remove_top :: (use heap: &Heap) -> heap.T {
x := data[0];
package core.iter
-use core {memory, alloc, array, Pair}
+#import core
+#import core.memory
+#import core.alloc
+#import core.array
+#import runtime
+
+use core {Pair}
use core.intrinsics.types {type_is_struct}
package core.list
+#import core
+
ListElem :: struct (T: type_expr) {
next: &ListElem(T) = null;
prev: &ListElem(T) = null;
package core.map
-use core {array, hash, memory, math, conv, Optional}
+#import core
+#import core.array
+#import core.hash
+#import core.memory
+#import core.math
+#import core.conv
+
+use core {Optional}
use core.intrinsics.onyx { __initialize }
//
package core
+
//
// A `Pair` represents a pair of values of heterogenous types.
// This structure does not do much on its own; however, it
}
#overload
-core.hash.hash :: (p: Pair($First_Type/hash.Hashable, $Second_Type/hash.Hashable)) => {
+hash.hash :: (p: Pair($First_Type/hash.Hashable, $Second_Type/hash.Hashable)) => {
h := 7;
h += h << 5 + hash.hash(p.first);
h += h << 5 + hash.hash(p.second);
// helper methods that make it easier to work with Results.
//
+#import core
+#import core.conv
-use core {Optional, conv}
+use core {Optional}
#doc """
Result(T, E) is a structure that represents either an Ok value
package core.set
-use core {array, hash, memory, math, Optional}
+#import core
+#import core.array
+#import core.hash
+#import core.memory
+#import core.math
+
+use core {Optional}
#local SetValue :: interface (t: $T) {
{ hash.hash(t) } -> u32;
}
#overload
-builtin.__make_overload :: macro (x: &Set, allocator: Allocator) => core.set.make(x.Elem_Type, allocator = allocator);
+builtin.__make_overload :: macro (x: &Set, allocator: Allocator) => #this_package.make(x.Elem_Type, allocator = allocator);
init :: (set: &Set($T), default := T.{}, allocator := context.allocator) {
set.allocator = allocator;
}
#overload
-builtin.delete :: core.set.free
+builtin.delete :: #this_package.free
insert :: (use set: &Set, value: set.Elem_Type) {
if hashes.data == null do init(set);
if full(set) do grow(set);
}
-#operator << macro (set: Set($T), value: T) do core.set.insert(&set, value);
+#operator << macro (set: Set($T), value: T) do #this_package.insert(&set, value);
has :: (use set: &Set, value: set.Elem_Type) -> bool {
lr := lookup(set, value);
Enable_Custom_Formatters :: true
-use core {string, math}
+#import core.string
+#import core.math
//
// Converts a string into an integer. Works with positive and
#overload
str_to_i64 :: (s: &str, base: u32 = 10) -> i64 {
- use package core
-
string.strip_leading_whitespace(s);
value: i64 = 0;
#overload
str_to_f64 :: (s: &str) -> f64 {
- use package core
-
string.strip_leading_whitespace(s);
sign := parse_sign(s);
package core.conv
-use core {map, string, array, math}
+#import core.map
+#import core.string
+#import core.array
+#import core.math
+#import core.io
+#import runtime
#package {
custom_formatters: Map(type_expr, #type (&Format_Output, &Format, rawptr) -> void);
// If a custom formatter is specified for the type, that is used instead.
// This procedure is generally not used directly; instead, through format or format_va.
format_any :: (output: &Format_Output, formatting: &Format, v: any) {
- use package runtime.info
- array :: package core.array;
+ use runtime.info;
//
// Dereference the any if the '*' format specifier was given.
case type_expr {
value := *(cast(&type_expr) v.data);
- io :: package core.io
-
buf : [256] u8;
// This is a little gross but the only way to output the type name for a type_expr
package core.conv
-use core {map, string, array, math}
+#import core.map
+#import core.string
+#import core.array
+#import core.math
+#import runtime
//
// Parses many different types from a string into a value.
package core.encoding.base64
-use core {array}
+#import core.array
//
// A simple Base64 encoding and decoding library. Currently
// it ergonomic to work with.
//
-use core {string, array, iter, conv, io}
+#import core
+#import core.string
+#import core.array
+#import core.iter
+#import core.conv
+#import core.io
+#import core.test
+#import runtime
+
use core.misc {any_as}
use runtime.info {
get_type_info,
// Example and test case
//
-@core.test.test.{"CSV Test"}
-(t: &core.test.T) {
+@test.test.{"CSV Test"}
+(t: &test.T) {
data := """first,second,third
1,test 1,1.2
2,test 2,2.4
// display_name=Player
//
-use core {
- alloc, conv, string, io,
- aprintf
-}
-use core.intrinsics.types {
- type_is_struct
-}
+#import core.alloc
+#import core.conv
+#import core.string
+#import core.io
+
+use core { aprintf }
+use core.intrinsics.types { type_is_struct }
//
// Represents if the parsing was successful or encountered an error.
package core.encoding.osad
+#import core.io
+#import core.string
+#import core.array
+#import core.memory
+#import runtime
-use core {io, string, array, memory}
use runtime {
type_info :: info
}
package core.encoding.utf8
-use core {string, array, iter}
+#import core.string
+#import core.array
+#import core.iter
rune :: i32
package core.io
-use core
+#import core.memory
+
BinaryWriter :: struct {
stream: &Stream;
// reader could not, like 'read the next line',
// or 'read until a period'.
-use core {memory, math, array, iter}
+#import core.memory
+#import core.math
+#import core.array
+#import core.iter
Reader :: struct {
stream: &Stream;
// in anyway.
package core
+#import runtime
+
//
// Ensure this file did not get included in a custom runtime, as it is
package core.io
+#import core
use core
Stream :: struct {
package core.io
-use core {conv, string, memory}
+#import core.conv
+#import core.string
+#import core.memory
// io.Writer is a buffered-writer. The important thing to not forget
// when using io.Writer is that it has to be flushed when you are done
package core.math
-use core.intrinsics {wasm}
+#import core
+#import core.intrinsics.wasm
// Things that are useful in any math library:
// - Trigonometry
//
// Allows for make([] i32).
#overload
-builtin.__make_overload :: macro (_: &[] $T, count: u32, allocator := context.allocator) -> [] T {
+__make_overload :: macro (_: &[] $T, count: u32, allocator := context.allocator) -> [] T {
ret := #this_package.make_slice(T, count, allocator);
#this_package.set(ret.data, 0, sizeof T * count);
return ret;
package core.misc
+#import runtime
+#import core.iter
+#import core.array
+#import core.string
+
use runtime.info {
get_type_info,
Type_Info_Pointer,
get_struct_member
}
-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.
// false and are true if one or more of the option values are present.
//
-use core
+#import core
+#import core.iter
+#import core.conv
+#import core.string
+#import runtime
+
+use core {printf}
arg_parse :: (c_args: [] cstr, output: any) -> bool {
arg_iter := iter.as_iter(c_args)
#error "Cannot include this file. Platform not supported.";
}
+#import core
+#import runtime
+
use core
Socket :: struct {
#error "Cannot include this file. Platform not supported.";
}
-use core {sync, thread, array, memory, alloc, os, iter}
+#import core.sync
+#import core.thread
+#import core.array
+#import core.memory
+#import core.alloc
+#import core.os
+#import core.iter
+#import runtime
#if !runtime.Multi_Threading_Enabled {
#error "Expected multi-threading to be enabled for TCP server.";
}
}
- status_buffer := alloc.array_from_stack(core.net.Socket_Poll_Status, client_count);
+ status_buffer := alloc.array_from_stack(Socket_Poll_Status, client_count);
socket_poll_all(cast([] &Socket) active_clients, pulse_time_ms, status_buffer);
recv_clients: [..] &TCP_Server.Client;
#if #defined (runtime.Generated_Foreign_Info) {
+#import core
+#import runtime
+
#if runtime.compiler_os == .Linux {
#if #defined (runtime.vars.CC) {
Linux_Compiler :: runtime.vars.CC
#error "Cannot include this file. Platform not supported.";
}
-use core {string}
+#import core.string
+#import runtime
+
#local fs :: runtime.platform
Directory :: fs.DirectoryData;
#error "Cannot include this file. Platform not supported.";
}
+#import core
+#import runtime
+
use core
+
#local fs :: package runtime.platform
package core.os
-use core {string}
+#import runtime
#if !runtime.platform.Supports_Os {
#error "Cannot include this file. Platform not supported.";
#error "Cannot include this file. Platform not supported.";
}
-use core {io}
+#import core.io
+#import runtime
+
use runtime.platform {
__process_spawn,
__process_destroy,
package runtime
+#import core
+
use core
use core.intrinsics.onyx { __initialize }
use platform { __output_string }
package runtime.info
-use core {io}
+#import core
+#import core.io
write_type_name :: (writer: &io.Writer, t: type_expr) {
info := get_type_info(t);
package runtime.info
-use core {array}
+#import core.array
tagged_procedures: [] &Tagged_Procedure
package runtime.platform
+#import core
+#import runtime
+
use core
use runtime {
__runtime_initialize,
package runtime.platform
+#import core
use core
FileData :: #distinct i64
package runtime.platform
+#import core
+#import runtime
+
use core
use runtime {
__runtime_initialize,
#load "./wasi_defs"
#load "./wasi_fs"
+#import core
+#import wasi
+#import runtime
+
use core
use wasi {
IOVec, SubscriptionTagged, Subscription, Event, Size,
package core
+#import runtime
+
#load "./alloc/alloc"
#load "./memory/memory"
package core.string
-use core {math}
+#import core.math
String_Buffer :: struct {
data : [&] u8;
package core.string
+#import core
+
use core
#doc "Generic procedure for turning something into a string."
package core.string
-use core { alloc, memory }
-use core.alloc { arena }
+#import core.alloc
+#import core.alloc.arena
+#import core.memory
//
// Many times, storing strings is annoying because you need
package core.sync
+#import runtime
+#import core
+
use core.intrinsics.atomics
use core.thread { Thread_ID }
package core.sync
+#import runtime
+#import core
+
use core.intrinsics.atomics
//
package core.test
-use core {array, string, printf}
+#import core
+#import core.array
+#import core.string
+#import runtime
+
+use core {printf}
#doc """
Test tag. Use this to mark a function as a test.
package core.thread
+#import core
+#import runtime
+
use core
use core.intrinsics.atomics
package core.time
+#import core
+#import runtime
use core
Date :: struct {
package core.time
-use core {os, conv}
+#import core
+#import core.os
+#import core.conv
+#import runtime
+
use runtime.platform {
__time_gmtime,
__time_localtime,
#load "core/std"
+#import core
+#import runtime
+
use core
use core.intrinsics.onyx { init }
#load "core/std"
+#import core
use core
OverloadsEqual :: interface (t: $T) {
PART :: 2
+#import core
+
use core
use core.alloc {arena}
+#import core
use core
PART :: 1
#load "core/std"
-use core
+#import core
+#import core.conv
+
+use core {println}
#tag conv.Custom_Format.{format}
V2 :: struct {
+#import core
use core
f :: ctx => {
-#load "core/std"
-
+#import core
use core
q :: (v: &$C, g: (&C) -> $T) {
-#load "core/std"
-
+#import core
use core
Foo :: struct {
-use core
+#import core
+use core {printf}
main :: () {
printf("{\n");
-use core
+#import core.string
+#import core.conv
+#import core
+
+use core {
+ println
+}
main :: () {
-use core
+#import core
+use core {println}
foo :: (x: ?i32) -> i32 {
return x? + 10;
-use core
+#import core
+#import core.list
+
+use core {println}
main :: () {
l := list.make(i32);
#load "core/std"
+#import core
use core
main :: () {
-use core
-use core.encoding {osad}
+#import core
+#import core.encoding.osad
+
+use core {printf}
Foo :: struct {
nums: [] i32;
-use core
+#import core
+use core { println }
main :: () {
overloaded_proc(i32.{}) |> println();
-use core.encoding
+#import core
+#import core.encoding.base64
decode_test :: () {
for .[
-use core
-use core.encoding {utf8}
+#import core
+#import core.encoding.utf8
+#import runtime
+
+use core {print, println, printf}
#inject runtime.vars.Enable_Heap_Debug :: true