str :: #type []u8;
cstr :: #type ^u8;
-// CLEANUP: Remove the buffer type from builtin
-Buffer :: #type []void;
-
// NOTE: Because of many implementation details, all fields of this
// struct are required to be i32's.
range :: struct {
cmp_dec :: proc (a: $T, b: T) -> i32 do return cast(i32) (b - a);
context : struct {
- allocator : Allocator;
- temp_allocator : Allocator;
+ allocator : Allocator;
+ temp_allocator : Allocator;
}
--- /dev/null
+package core.conv
+
+i64_to_str :: proc (n_: i64, base: u64, buf: [] u8) -> str {
+ n := cast(u64) n_;
+
+ is_neg := false;
+ if n_ < 0 && base == 10 {
+ is_neg = true;
+ n = cast(u64) -n_;
+ }
+
+ c := ^buf[buf.count - 1];
+ len := 0;
+
+ s :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+
+ while n > 0 {
+ m :: n % base;
+
+ *c = s[cast(u32) m];
+ len += 1;
+ c -= 1;
+
+ n /= base;
+
+ } else {
+ *c = #char "0";
+ len += 1;
+ c -= 1;
+ }
+
+ if base == 16 {
+ *c = #char "x";
+ len += 1;
+ c -= 1;
+ *c = #char "0";
+ len += 1;
+ c -= 1;
+ }
+
+ if base == 2 {
+ *c = #char "b";
+ len += 1;
+ c -= 1;
+ *c = #char "0";
+ len += 1;
+ c -= 1;
+ }
+
+ if is_neg {
+ *c = #char "-";
+ len += 1;
+ c -= 1;
+ }
+
+ return str.{ data = c + 1, count = len };
+}
+
+// NOTE: This is a big hack but it will work for now
+f64_to_str :: proc (f: f64, buf: [] u8) -> str {
+ a := f;
+ a *= 10000.0;
+ v := cast(i64) a;
+
+ len := 0;
+
+ s1 := i64_to_str(v / 10000, 10, buf);
+ for i: 0 .. s1.count do buf.data[i] = s1.data[i];
+ buf.data[s1.count] = #char ".";
+ len = s1.count + 1;
+
+ if v < ~~0 do v = -v;
+ s2 := i64_to_str(v % 10000, 10, buf);
+ for i: 0 .. s2.count do buf.data[s1.count + 1 + i] = s2.data[i];
+ len += s2.count;
+
+ return str.{ buf.data, len };
+}
+
+str_format :: proc (format: str, buffer: [] u8, va: ...) -> str {
+ return str_format_va(format, buffer, va);
+}
+
+str_format_va :: proc (format: str, buffer: [] u8, va: vararg) -> str {
+ len := 0;
+ state := 0;
+
+ for ch: format do switch (state) {
+ case 0 {
+ if ch == #char "%" do state = 1;
+ else {
+ buffer[len] = ch;
+ len += 1;
+ }
+ }
+
+ case #default {
+ switch (ch) {
+ case #char "%" { buffer[len] = ch; len += 1; }
+
+ case #char "i" {
+ n : i32;
+ if !vararg_get(va, ^n) do return;
+
+ ibuf : [128] u8;
+ istr := i64_to_str(~~n, 10, ibuf[0 .. 128]);
+
+ for a: istr {
+ buffer[len] = a;
+ len += 1;
+ }
+ }
+
+ case #char "l" {
+ n : i64;
+ if !vararg_get(va, ^n) do return;
+
+ ibuf : [128] u8;
+ istr := i64_to_str(n, 10, ibuf[0 .. 128]);
+
+ for a: istr {
+ buffer[len] = a;
+ len += 1;
+ }
+ }
+
+ case #char "f" {
+ n : f32;
+ if !vararg_get(va, ^n) do return;
+
+ fbuf : [128] u8;
+ fstr := f64_to_str(~~n, fbuf[0 .. 128]);
+
+ for a: fstr {
+ buffer[len] = a;
+ len += 1;
+ }
+ }
+
+ case #char "d" {
+ n : f64;
+ if !vararg_get(va, ^n) do return;
+
+ fbuf : [128] u8;
+ fstr := f64_to_str(n, fbuf[0 .. 128]);
+
+ for a: fstr {
+ buffer[len] = a;
+ len += 1;
+ }
+ }
+
+ case #char "s" {
+ s : str;
+ if !vararg_get(va, ^s) do return;
+
+ for a: s {
+ buffer[len] = a;
+ len += 1;
+ }
+ }
+
+ case #char "p" {
+ n : rawptr;
+ if !vararg_get(va, ^n) do return;
+
+ ibuf : [128] u8;
+ istr := i64_to_str(~~n, 16, ibuf[0 .. 128]);
+
+ for a: istr {
+ buffer[len] = a;
+ len += 1;
+ }
+ }
+
+ case #char "c" {
+ c : u8;
+ if !vararg_get(va, ^c) do return;
+
+ buffer[len] = c;
+ len += 1;
+ }
+ }
+
+ state = 0;
+ }
+ }
+
+ return str.{ ~~buffer.data, len };
+}
blendFunc :: proc (sfactor: GLenum, dfactor: GLenum) #foreign "gl" "blendFunc" ---
blendFuncSeparate :: proc (srcRGB: GLenum, dstRGB: GLenum, srcAlpha: GLenum, dstAlpha: GLenum) #foreign "gl" "blendFuncSeparate" ---
blitFramebuffer :: proc (sx0: GLint, sy0: GLint, sx1: GLint, sy1: GLint, dx0: GLint, dy0: GLint, dx1: GLint, dy1: GLint, mask: GLbitfield, filter: GLenum) #foreign "gl" "blitFramebuffer" ---
-bufferDataWithData :: proc (target: GLenum, buffer: Buffer, usage: GLenum) #foreign "gl" "bufferDataWithData" ---
+bufferDataWithData :: proc (target: GLenum, buffer: [] void, usage: GLenum) #foreign "gl" "bufferDataWithData" ---
bufferDataNoData :: proc (target: GLenum, size: GLsizeiptr, usage: GLenum) #foreign "gl" "bufferDataNoData" ---
bufferData :: proc { bufferDataWithData, bufferDataNoData }
-bufferSubData :: proc (target: GLenum, offset: GLsizei, data: Buffer) #foreign "gl" "bufferSubData" ---
+bufferSubData :: proc (target: GLenum, offset: GLsizei, data: [] void) #foreign "gl" "bufferSubData" ---
canvasSize :: proc (width: GLsizei, height: GLsizei) #foreign "gl" "canvasSize" ---
checkFrameBufferStatus :: proc (target: GLenum) -> GLenum #foreign "gl" "checkFrameBufferStatus" ---
clear :: proc (mask: GLbitfield) #foreign "gl" "clear" ---
#include_file "core/alloc"
#include_file "core/array"
+#include_file "core/conv"
#include_file "core/intrinsics"
#include_file "core/map"
#include_file "core/math"
#include_file "core/random"
#include_file "core/stdio"
#include_file "core/string"
+#include_file "core/string/builder"
#include_file "core/string/reader"
#include_file "core/sys/js"
#include_file "core/alloc"
#include_file "core/array"
+#include_file "core/conv"
#include_file "core/file"
#include_file "core/intrinsics"
#include_file "core/map"
#include_file "core/random"
#include_file "core/stdio"
#include_file "core/string"
+#include_file "core/string/builder"
#include_file "core/string/reader"
#include_file "core/wasi"
// of the system package
use package system as system
-#private_file print_buffer : string.StringBuilder;
+#private_file print_buffer : string.builder.Builder;
stdio_init :: proc () {
- print_buffer = string.builder_make(2048);
+ print_buffer = string.builder.make(2048);
}
print_str :: proc (s: str) {
- string.builder_append(^print_buffer, s);
+ string.builder.append(^print_buffer, s);
if s.data[s.count - 1] == #char "\n" do print_buffer_flush();
}
-print_cstr :: proc (s: cstr) do string.builder_append(^print_buffer, s);
-print_i64 :: proc (n: i64, base: u64 = 10) do string.builder_append(^print_buffer, n, base);
-print_i32 :: proc (n: i32, base: u32 = 10) do string.builder_append(^print_buffer, cast(i64) n, cast(u64) base);
-print_f64 :: proc (n: f64) do string.builder_append(^print_buffer, n);
-print_f32 :: proc (n: f32) do string.builder_append(^print_buffer, cast(f64) n);
-print_bool :: proc (b: bool) do string.builder_append(^print_buffer, b);
-print_ptr :: proc (p: ^void) do string.builder_append(^print_buffer, cast(i64) p, cast(u64) 16);
+print_cstr :: proc (s: cstr) do string.builder.append(^print_buffer, s);
+print_i64 :: proc (n: i64, base: u64 = 10) do string.builder.append(^print_buffer, n, base);
+print_i32 :: proc (n: i32, base: u32 = 10) do string.builder.append(^print_buffer, cast(i64) n, cast(u64) base);
+print_f64 :: proc (n: f64) do string.builder.append(^print_buffer, n);
+print_f32 :: proc (n: f32) do string.builder.append(^print_buffer, cast(f64) n);
+print_bool :: proc (b: bool) do string.builder.append(^print_buffer, b);
+print_ptr :: proc (p: ^void) do string.builder.append(^print_buffer, cast(i64) p, cast(u64) 16);
print_range :: proc (r: range, sep := " ") {
for i: r {
printf :: proc (format: str, va: ...) {
buffer: [2048] u8;
- len := 0;
-
- state := 0;
- for ch: format do switch (state) {
- case 0 {
- if ch == #char "%" do state = 1;
- else {
- buffer[len] = ch;
- len += 1;
- }
- }
-
- case #default {
- switch (ch) {
- case #char "%" { buffer[len] = ch; len += 1; }
-
- case #char "i" {
- n : i32;
- if !vararg_get(va, ^n) do return;
-
- ibuf : [128] u8;
- istr := string.i64_to_str(~~n, 10, Buffer.{ ~~ibuf, 128 });
-
- for a: istr {
- buffer[len] = a;
- len += 1;
- }
- }
-
- case #char "l" {
- n : i64;
- if !vararg_get(va, ^n) do return;
-
- ibuf : [128] u8;
- istr := string.i64_to_str(n, 10, Buffer.{ ~~ibuf, 128 });
-
- for a: istr {
- buffer[len] = a;
- len += 1;
- }
- }
-
- case #char "f" {
- n : f32;
- if !vararg_get(va, ^n) do return;
-
- fbuf : [128] u8;
- fstr := string.f64_to_str(~~n, fbuf[0 .. 128]);
-
- for a: fstr {
- buffer[len] = a;
- len += 1;
- }
- }
-
- case #char "d" {
- n : f64;
- if !vararg_get(va, ^n) do return;
-
- fbuf : [128] u8;
- fstr := string.f64_to_str(n, fbuf[0 .. 128]);
-
- for a: fstr {
- buffer[len] = a;
- len += 1;
- }
- }
-
- case #char "s" {
- s : str;
- if !vararg_get(va, ^s) do return;
-
- for a: s {
- buffer[len] = a;
- len += 1;
- }
- }
-
- case #char "p" {
- n : rawptr;
- if !vararg_get(va, ^n) do return;
-
- ibuf : [128] u8;
- istr := string.i64_to_str(~~n, 16, Buffer.{ ~~ibuf, 128 });
-
- for a: istr {
- buffer[len] = a;
- len += 1;
- }
- }
-
- case #char "c" {
- c : u8;
- if !vararg_get(va, ^c) do return;
-
- buffer[len] = c;
- len += 1;
- }
- }
-
- state = 0;
- }
- }
-
- print(str.{ ~~buffer, len });
+ print(conv.str_format_va(format, buffer[0 .. 2048], va));
}
// This works on both slices and arrays
}
print_buffer_flush :: proc () {
- if print_buffer.len == 0 do return;
+ if print_buffer.data.count == 0 do return;
^print_buffer
- |> string.builder_to_str()
+ |> string.builder.to_str()
|> system.output_str();
- ^print_buffer |> string.builder_clear();
+ ^print_buffer |> string.builder.clear();
}
}
-
-
-//
-// String Builder
-//
-StringBuilder :: struct {
- alloc : Allocator;
-
- data : ^u8 = null;
- len : u32 = 0;
- cap : u32 = 0;
-}
-
-builder_make :: proc (initial_cap: u32) -> StringBuilder {
- data: ^u8 = null;
-
- if initial_cap > 0 {
- data = cast(^u8) calloc(initial_cap);
- }
-
- return StringBuilder.{
- alloc = context.allocator,
- data = data,
- cap = initial_cap,
- };
-}
-
-builder_add_str :: proc (use sb: ^StringBuilder, s: str) -> ^StringBuilder {
- len_total :: len + s.count;
-
- if cap >= len_total {
- for i: 0 .. s.count do data[len + i] = s[i];
- len += s.count;
- return sb;
- }
-
- new_cap := cap;
- while new_cap < len_total do new_cap <<= 1;
-
- new_data := cast(^u8) resize(alloc, data, new_cap);
- if new_data == null do return sb;
-
- data = new_data;
- cap = new_cap;
-
- for i: 0 .. s.count do data[len + i] = s[i];
- len += s.count;
- return sb;
-}
-
-builder_add_cstr :: proc (use sb: ^StringBuilder, cstring: cstr) -> ^StringBuilder {
- s := make(cstring);
- return builder_add_str(sb, s);
-}
-
-i64_to_str :: proc (n_: i64, base: u64, buf: Buffer) -> str {
- n := cast(u64) n_;
-
- is_neg := false;
- if n_ < 0 && base == 10 {
- is_neg = true;
- n = cast(u64) -n_;
- }
-
- c := ^(cast(^u8) buf.data)[buf.count - 1];
- len := 0;
-
- s :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
-
- while n > 0 {
- m :: n % base;
-
- *c = s[cast(u32) m];
- len += 1;
- c -= 1;
-
- n /= base;
-
- } else {
- *c = #char "0";
- len += 1;
- c -= 1;
- }
-
- if base == 16 {
- *c = #char "x";
- len += 1;
- c -= 1;
- *c = #char "0";
- len += 1;
- c -= 1;
- }
-
- if base == 2 {
- *c = #char "b";
- len += 1;
- c -= 1;
- *c = #char "0";
- len += 1;
- c -= 1;
- }
-
- if is_neg {
- *c = #char "-";
- len += 1;
- c -= 1;
- }
-
- return str.{ data = c + 1, count = len };
-}
-
-// NOTE: This is a big hack but it will work for now
-f64_to_str :: proc (f: f64, buf: [] u8) -> str {
- a := f;
- a *= 10000.0;
- v := cast(i64) a;
-
- b := Buffer.{ cast(^void) buf.data, buf.count };
- len := 0;
-
- s1 := i64_to_str(v / 10000, 10, b);
- for i: 0 .. s1.count do buf.data[i] = s1.data[i];
- buf.data[s1.count] = #char ".";
- len = s1.count + 1;
-
- if v < ~~0 do v = -v;
- s2 := i64_to_str(v % 10000, 10, b);
- for i: 0 .. s2.count do buf.data[s1.count + 1 + i] = s2.data[i];
- len += s2.count;
-
- return str.{ buf.data, len };
-}
-
-builder_add_i64 :: proc (use sb: ^StringBuilder, n: i64, base: u64 = 10) -> ^StringBuilder {
- buf : [256] u8;
- s := i64_to_str(n, base, Buffer.{ cast(^void) buf, 256 });
- return builder_add_str(sb, s);
-}
-
-builder_add_f64 :: proc (use sb: ^StringBuilder, f: f64) -> ^StringBuilder {
- buf : [256] u8;
- s := f64_to_str(f, buf[0 .. 256]);
- return builder_add_str(sb, s);
-}
-
-builder_add_bool :: proc (use sb: ^StringBuilder, b: bool) -> ^StringBuilder {
- if b {
- return builder_add_str(sb, "true");
- } else {
- return builder_add_str(sb, "false");
- }
-
- return null;
-}
-
-builder_append :: proc {
- builder_add_str,
- builder_add_cstr,
- builder_add_i64,
- builder_add_f64,
- builder_add_bool,
-}
-
-builder_to_str :: proc (use sb: ^StringBuilder) -> str {
- return str.{ data, len };
-}
-
-builder_clear :: proc (use sb: ^StringBuilder) -> ^StringBuilder {
- len = 0;
- return sb;
-}
-
read_u32 :: proc (s: ^str, out: ^u32) {
n := 0;
--- /dev/null
+package core.string.builder
+
+use package core.array as array
+use package core.string as string
+use package core.conv as conv
+
+Builder :: struct {
+ alloc : Allocator;
+ data : [..] u8;
+}
+
+make :: proc (initial_cap := 4, alloc := context.allocator) -> Builder {
+ builder : Builder;
+ builder.alloc = alloc;
+
+ #context_scope {
+ context.allocator = alloc;
+ array.init(^builder.data, initial_cap);
+ }
+
+ return builder;
+}
+
+clear :: proc (use sb: ^Builder) -> ^Builder {
+ data.count = 0;
+ return sb;
+}
+
+add_str :: proc (use sb: ^Builder, s: str) -> ^Builder {
+ len_total :: data.count + s.count;
+
+ if data.capacity < len_total do #context_scope {
+ context.allocator = alloc;
+ array.ensure_capacity(^data, len_total);
+ }
+
+ for i: 0 .. s.count do data[data.count + i] = s[i];
+ data.count += s.count;
+ return sb;
+}
+
+add_cstr :: proc (use sb: ^Builder, cstring: cstr) -> ^Builder {
+ s := string.make(cstring);
+ return add_str(sb, s);
+}
+
+add_i64 :: proc (use sb: ^Builder, n: i64, base: u64 = 10) -> ^Builder {
+ buf : [256] u8;
+ s := conv.i64_to_str(n, base, buf[0 .. 256]);
+ return add_str(sb, s);
+}
+
+add_f64 :: proc (use sb: ^Builder, f: f64) -> ^Builder {
+ buf : [256] u8;
+ s := conv.f64_to_str(f, buf[0 .. 256]);
+ return add_str(sb, s);
+}
+
+add_bool :: proc (use sb: ^Builder, b: bool) -> ^Builder {
+ if b do return add_str(sb, "true");
+ else do return add_str(sb, "false");
+
+ return sb;
+}
+
+append :: proc {
+ add_str,
+ add_cstr,
+ add_i64,
+ add_f64,
+ add_bool,
+}
+
+to_str :: proc (use sb: ^Builder) -> str {
+ return str.{ data.data, data.count };
+}
+
extern Type *builtin_range_type_type;
extern AstType *builtin_vararg_type;
extern Type *builtin_vararg_type_type;
+extern AstTyped *builtin_context_variable;
typedef struct BuiltinSymbol {
char* package;
Type *builtin_range_type_type;
AstType *builtin_vararg_type;
Type *builtin_vararg_type_type;
+AstTyped *builtin_context_variable;
const BuiltinSymbol builtin_symbols[] = {
{ NULL, "void", (AstNode *) &basic_type_void },
return;
}
+ builtin_context_variable = (AstTyped *) symbol_raw_resolve(p->scope, "context");
+ if (builtin_context_variable == NULL) {
+ onyx_report_error((OnyxFilePos) { 0 }, "'context' variable not found in builtin package.");
+ return;
+ }
bh_table_init(global_heap_allocator, intrinsic_table, 128);
static AstNumLit* parse_int_literal(OnyxParser* parser);
static AstNumLit* parse_float_literal(OnyxParser* parser);
-static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped** ret);
+static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped* left, AstTyped** ret);
static AstTyped* parse_factor(OnyxParser* parser);
static AstTyped* parse_expression(OnyxParser* parser);
static AstIfWhile* parse_if_stmt(OnyxParser* parser);
return float_node;
}
-static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped** ret) {
- if (parser->curr->type != Token_Type_Symbol) return 0;
-
- STORE_PARSER_STATE;
-
- bh_arr(OnyxToken *) syms = NULL;
- bh_arr_new(global_heap_allocator, syms, 4);
-
- b32 success = 1;
- while (parser->curr->type == Token_Type_Symbol) {
- if (parser->hit_unexpected_token) break;
-
- OnyxToken* symbol = soft_expect_token(parser, Token_Type_Symbol);
- bh_arr_push(syms, symbol);
-
- if (!soft_expect_token(parser, '.')) {
- success = 0;
- break;
- }
- }
-
- if (parser->curr->type != '{') success = 0;
-
- if (!success) {
- bh_arr_free(syms);
- RESTORE_PARSER_STATE;
- return 0;
- }
+static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped* left, AstTyped** ret) {
+ if (parser->curr->type != '.'
+ || (parser->curr + 1)->type != '{') return 0;
AstStructLiteral* sl = make_node(AstStructLiteral, Ast_Kind_Struct_Literal);
sl->token = parser->curr;
-
- sl->stnode = make_node(AstTyped, Ast_Kind_Symbol);
- sl->stnode->token = syms[0];
-
- for (i32 i = 1; i < bh_arr_length(syms); i++) {
- AstFieldAccess* fa = make_node(AstFieldAccess, Ast_Kind_Field_Access);
- fa->token = syms[i];
- fa->expr = sl->stnode;
- sl->stnode = (AstTyped *) fa;
- }
- bh_arr_free(syms);
+ sl->stnode = left;
bh_arr_new(global_heap_allocator, sl->values, 4);
bh_arr_new(global_heap_allocator, sl->named_values, 4);
sl->named_values[i] = NULL;
}
+ expect_token(parser, '.');
expect_token(parser, '{');
b32 is_named = ((parser->curr + 1)->type == '=');
}
case Token_Type_Symbol: {
- if (parse_possible_struct_literal(parser, &retval)) return retval;
-
OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
sym_node->token = sym_token;
retval = (AstTyped *) char_lit;
break;
}
+ else if (parse_possible_directive(parser, "type")) {
+ AstTypeAlias* alias = make_node(AstTypeAlias, Ast_Kind_Type_Alias);
+ alias->to = parse_type(parser);
+ retval = (AstTyped *) alias;
+ break;
+ }
onyx_report_error(parser->curr->pos, "invalid directive in expression.");
return NULL;
}
case '.': {
+ if (parse_possible_struct_literal(parser, retval, &retval)) return retval;
+
consume_token(parser);
AstFieldAccess* field = make_node(AstFieldAccess, Ast_Kind_Field_Access);
field->token = expect_token(parser, Token_Type_Symbol);
break;
}
+ case '#': {
+ if (parse_possible_directive(parser, "context_scope")) {
+ AstLocal* context_tmp = make_node(AstLocal, Ast_Kind_Local);
+ context_tmp->type_node = builtin_context_variable->type_node;
+
+ AstBinaryOp* assignment = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
+ assignment->operation = Binary_Op_Assign;
+ assignment->left = (AstTyped *) context_tmp;
+ assignment->right = builtin_context_variable;
+ context_tmp->next = (AstNode *) assignment;
+
+ AstBlock* context_block = parse_block(parser);
+ needs_semicolon = 0;
+ assignment->next = (AstNode *) context_block;
+
+ AstBinaryOp* assignment2 = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
+ assignment2->operation = Binary_Op_Assign;
+ assignment2->left = builtin_context_variable;
+ assignment2->right = (AstTyped *) context_tmp;
+ context_block->next = (AstNode *) assignment2;
+
+ retval = (AstNode *) context_tmp;
+ break;
+ }
+ }
+
default:
break;
}
bh_arr_push(bh_arr_last(semstate.block_stack)->locals, *local);
bh_arr_push(semstate.curr_function->locals, *local);
- symbol_introduce(semstate.curr_scope, (*local)->token, (AstNode *) *local);
+ if ((*local)->token != NULL)
+ symbol_introduce(semstate.curr_scope, (*local)->token, (AstNode *) *local);
}
static void symres_call(AstCall* call) {