From ba15f2fce77de48fa1c001dace1ee65792a05d07 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Fri, 11 Dec 2020 08:19:49 -0600 Subject: [PATCH] swapped usage of 'str' and 'string'; broke many things --- core/builtin.onyx | 5 +- core/file.onyx | 10 +- core/js/webgl.onyx | 26 ++--- core/stdio.onyx | 58 +++++----- core/string.onyx | 234 +++++++++++++++++++-------------------- core/string/reader.onyx | 49 +++++--- core/strmap.onyx | 18 +-- core/sys/js.onyx | 4 +- core/sys/wasi.onyx | 6 +- core/wasi.onyx | 22 ++-- docs/todo | 24 ++-- misc/onyx.sublime-syntax | 2 +- misc/onyx.vim | 1 + onyx | Bin 502220 -> 502684 bytes progs/wasi_test.onyx | 2 +- src/onyxbuiltins.c | 4 +- src/onyxsymres.c | 8 ++ src/onyxwasm.c | 6 +- tests/general1.onyx | 8 +- tests/hello_world.onyx | 2 +- tests/i32map.onyx | 4 +- tests/vararg_test.onyx | 6 +- 22 files changed, 271 insertions(+), 228 deletions(-) diff --git a/core/builtin.onyx b/core/builtin.onyx index 9e4e5fdd..6ac95cb6 100644 --- a/core/builtin.onyx +++ b/core/builtin.onyx @@ -1,8 +1,9 @@ package builtin -string :: #type []u8; -cstring :: #type ^u8; +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 diff --git a/core/file.onyx b/core/file.onyx index 0305ba7c..da9381ff 100644 --- a/core/file.onyx +++ b/core/file.onyx @@ -17,7 +17,7 @@ File :: struct { fd : FileDescriptor; } -open :: proc (file: ^File, path: string, mode := OpenMode.Read, flags := FDFlags.Sync) -> bool { +open :: proc (file: ^File, path: str, mode := OpenMode.Read, flags := FDFlags.Sync) -> bool { // Currently the directory's file descriptor appears to always be 3 DIR_FD :: 3; @@ -105,7 +105,7 @@ close :: proc (file: File) -> bool { return true; } -write :: proc (file: File, data: string) { +write :: proc (file: File, data: str) { vec := IOVec.{ buf = data.data, len = data.count }; tmp : Size; fd_write(file.fd, IOVecArray.{ ^vec, 1 }, ^tmp); @@ -119,7 +119,7 @@ get_size :: proc (file: File) -> u64 { return fs.size; } -get_contents_from_file :: proc (file: File) -> string { +get_contents_from_file :: proc (file: File) -> str { size := cast(u32) get_size(file); data := cast(^u8) alloc(context.allocator, size); @@ -142,10 +142,10 @@ get_contents_from_file :: proc (file: File) -> string { get_contents :: proc { get_contents_from_file, - proc (path: string) -> string { + proc (path: str) -> str { tmp_file: File; - if !open(^tmp_file, path, OpenMode.Read) do return string.{ null, 0 }; + if !open(^tmp_file, path, OpenMode.Read) do return str.{ null, 0 }; defer close(tmp_file); return get_contents(tmp_file); diff --git a/core/js/webgl.onyx b/core/js/webgl.onyx index 428a1263..e89a9761 100644 --- a/core/js/webgl.onyx +++ b/core/js/webgl.onyx @@ -724,7 +724,7 @@ GLMat4 :: #type [16] GLfloat activeTexture :: proc (texture: GLenum) #foreign "gl" "activeTexture" --- attachShader :: proc (program: GLProgram, shader: GLShader) -> GLProgram #foreign "gl" "attachShader" --- -bindAttribLocation :: proc (program: GLProgram, index: GLuint, name: string) #foreign "gl" "bindAttribLocation" --- +bindAttribLocation :: proc (program: GLProgram, index: GLuint, name: str) #foreign "gl" "bindAttribLocation" --- bindBuffer :: proc (target: GLenum, buffer: GLBuffer) #foreign "gl" "bindBuffer" --- bindFramebuffer :: proc (target: GLenum, framebuffer: GLFramebuffer) #foreign "gl" "bindFramebuffer" --- bindRenderbuffer :: proc (target: GLenum, renderbuffer: GLRenderbuffer) #foreign "gl" "bindRenderbuffer" --- @@ -748,8 +748,8 @@ clearDepth :: proc (depth: GLclampf) #foreign "gl" "clearDep clearStencil :: proc (s: GLint) #foreign "gl" "clearStencil" --- colorMask :: proc (red: GLboolean, green: GLboolean, blue: GLboolean, alpha: GLboolean) #foreign "gl" "colorMask" --- compileShader :: proc (shader: GLShader) #foreign "gl" "compileShader" --- -compressedTexImage2D :: proc (target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, border: GLint, data: string) #foreign "gl" "compressedTexImage2D" --- -compressedTexSubImage2D :: proc (target: GLenum, level: GLint, internalformat: GLenum, xoff: GLint, yoff: GLint, width: GLsizei, height: GLsizei, format: GLenum, data: string) #foreign "gl" "compressedTexSubImage2D" --- +compressedTexImage2D :: proc (target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, border: GLint, data: str) #foreign "gl" "compressedTexImage2D" --- +compressedTexSubImage2D :: proc (target: GLenum, level: GLint, internalformat: GLenum, xoff: GLint, yoff: GLint, width: GLsizei, height: GLsizei, format: GLenum, data: str) #foreign "gl" "compressedTexSubImage2D" --- copyBufferSubData :: proc (readTarget: GLenum, writeTarget: GLenum, readOffset: GLintptr, writeOffset: GLintptr, size: GLsizeiptr) #foreign "gl" "copyBufferSubData" --- copyTexImage2D :: proc (target: GLenum, level: GLint, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, height: GLsizei, border: GLint) #foreign "gl" "copyTexImage2D" --- copyTexSubImage2D :: proc (target: GLenum, level: GLint, xoff: GLint, yoff: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) #foreign "gl" "copyTexSubImage2D" --- @@ -790,20 +790,20 @@ generateMipmap :: proc (target: GLenum) #foreign "gl" "generateM getActiveAttrib :: proc (program: GLProgram, index: GLuint, out: ^GLActiveInfo) #foreign "gl" "getActiveAttrib" --- getActiveUniform :: proc (program: GLProgram, index: GLuint, out: ^GLActiveInfo) #foreign "gl" "getActiveUniform" --- // getAttachedShaders does not work yet because we can't return a list of things -getAttribLocation :: proc (program: GLProgram, name: string) -> GLint #foreign "gl" "getAttribLocation" --- -getBufferSubData :: proc (target: GLenum, srcByteOffset: GLintptr, dstBuffer: string, dstOffset: GLuint, length: GLuint) #foreign "gl" "getBufferSubData" --- +getAttribLocation :: proc (program: GLProgram, name: str) -> GLint #foreign "gl" "getAttribLocation" --- +getBufferSubData :: proc (target: GLenum, srcByteOffset: GLintptr, dstBuffer: str, dstOffset: GLuint, length: GLuint) #foreign "gl" "getBufferSubData" --- // getBufferParameter and getParameter do not work getError :: proc () -> GLenum #foreign "gl" "getError" --- getInternalformatParameter :: proc (target: GLenum, internalFormat: GLenum, pname: GLenum) -> GLenum #foreign "gl" "getInternalformatParameter" --- // many of the 'gets' don't work yet because they return very javascripty things getProgramParameter :: proc (program: GLProgram, pname: GLenum) -> GLenum #foreign "gl" "getProgramParameter" --- getShaderParameter :: proc (shader: GLShader, pname: GLenum) -> GLenum #foreign "gl" "getShaderParameter" --- -getUniformLocation :: proc (program: GLProgram, name: string) -> GLUniformLocation #foreign "gl" "getUniformLocation" --- +getUniformLocation :: proc (program: GLProgram, name: str) -> GLUniformLocation #foreign "gl" "getUniformLocation" --- getVertexAttribOffset :: proc (index: GLuint, pname: GLenum) #foreign "gl" "getVertexAttribOffset" --- hint :: proc (target: GLenum, mode: GLenum) #foreign "gl" "hint" --- -init :: proc (canvasname: string) -> GLboolean #foreign "gl" "init" --- -invalidateFramebuffer :: proc (target: GLenum, attachments: string) #foreign "gl" "invalidateFramebuffer" --- -invalidateSubFramebuffer :: proc (target: GLenum, attachments: string, x: GLint, y: GLint, width: GLsizei, height: GLsizei) #foreign "gl" "invalidateSubFramebuffer" --- +init :: proc (canvasname: str) -> GLboolean #foreign "gl" "init" --- +invalidateFramebuffer :: proc (target: GLenum, attachments: str) #foreign "gl" "invalidateFramebuffer" --- +invalidateSubFramebuffer :: proc (target: GLenum, attachments: str, x: GLint, y: GLint, width: GLsizei, height: GLsizei) #foreign "gl" "invalidateSubFramebuffer" --- isEnabled :: proc (cap: GLenum) -> GLboolean #foreign "gl" "isEnabled" --- lineWidth :: proc (width: GLfloat) #foreign "gl" "lineWidth" --- linkProgram :: proc (program: GLProgram) #foreign "gl" "linkProgram" --- @@ -812,21 +812,21 @@ polygonOffset :: proc (factor: GLfloat, units: GLfloat) #foreig printProgramInfoLog :: proc (program: GLProgram) #foreign "gl" "printProgramInfoLog" --- printShaderInfoLog :: proc (shader: GLShader) #foreign "gl" "printShaderInfoLog" --- readBuffer :: proc (src: GLenum) #foreign "gl" "readBuffer" --- -readPixels :: proc (x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, type: GLenum, pixels: string) #foreign "gl" "readPixels" --- +readPixels :: proc (x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, type: GLenum, pixels: str) #foreign "gl" "readPixels" --- renderbufferStorageMultisample :: proc (target: GLenum, samples: GLsizei, internalforamt: GLenum, width: GLsizei, height: GLsizei) #foreign "gl" "renderbufferStorageMultisample" --- sampleCoverage :: proc (value: GLclampf, invert: GLboolean) #foreign "gl" "sampleCoverage" --- scissor :: proc (x: GLint, y: GLint, width: GLsizei, height: GLsizei) #foreign "gl" "scissor" --- -shaderSource :: proc (shader: GLShader, source: string) #foreign "gl" "shaderSource" --- +shaderSource :: proc (shader: GLShader, source: str) #foreign "gl" "shaderSource" --- stencilFunc :: proc (func: GLenum, ref: GLint, mask: GLuint) #foreign "gl" "stencilFunc" --- stencilFuncSeparate :: proc (face: GLenum, func: GLenum, ref: GLint, mask: GLuint) #foreign "gl" "stencilFuncSeparate" --- stencilMask :: proc (mask: GLuint) #foreign "gl" "stencilMask" --- stencilMaskSeparate :: proc (face: GLenum, mask: GLenum) #foreign "gl" "stencilMaskSeparate" --- stencilOp :: proc (fail: GLenum, zfail: GLenum, zpass: GLenum) #foreign "gl" "stencilOp" --- stencilOpSeparate :: proc (face: GLenum, fail: GLenum, zfail: GLenum, zpass: GLenum) #foreign "gl" "stencilOpSeparate" --- -texImage2D :: proc (target: GLenum, level: GLint, internalFormat: GLenum, width: GLsizei, height: GLsizei, border: GLint, format: GLenum, type: GLenum, pixels: string) #foreign "gl" "texImage2D" --- +texImage2D :: proc (target: GLenum, level: GLint, internalFormat: GLenum, width: GLsizei, height: GLsizei, border: GLint, format: GLenum, type: GLenum, pixels: str) #foreign "gl" "texImage2D" --- texParameterf :: proc (target: GLenum, pname: GLenum, param: GLfloat) #foreign "gl" "texParameterf" --- texParameteri :: proc (target: GLenum, pname: GLenum, param: GLint) #foreign "gl" "texParameteri" --- -texSubImage2D :: proc (target: GLenum, level: GLint, xoff: GLint, yoff: GLint, width: GLsizei, height: GLsizei, format: GLenum, type: GLenum, pixels: string) #foreign "gl" "texSubImage2D" --- +texSubImage2D :: proc (target: GLenum, level: GLint, xoff: GLint, yoff: GLint, width: GLsizei, height: GLsizei, format: GLenum, type: GLenum, pixels: str) #foreign "gl" "texSubImage2D" --- uniform1f :: proc (loc: GLUniformLocation, x: GLfloat) #foreign "gl" "uniform1f" --- uniform1i :: proc (loc: GLUniformLocation, x: GLint) #foreign "gl" "uniform1i" --- uniform2f :: proc (loc: GLUniformLocation, x: GLfloat, y: GLfloat) #foreign "gl" "uniform2f" --- diff --git a/core/stdio.onyx b/core/stdio.onyx index bf11b7c8..54d7863a 100644 --- a/core/stdio.onyx +++ b/core/stdio.onyx @@ -4,24 +4,24 @@ package core // of the system package use package system as system -#private_file print_buffer : str.StringBuilder; +#private_file print_buffer : string.StringBuilder; stdio_init :: proc () { - print_buffer = str.builder_make(2048); + print_buffer = string.builder_make(2048); } -print_string :: proc (s: string) { - str.builder_append(^print_buffer, s); +print_str :: proc (s: str) { + string.builder_append(^print_buffer, s); if s.data[s.count - 1] == #char "\n" do print_buffer_flush(); } -print_cstring :: proc (s: cstring) do str.builder_append(^print_buffer, s); -print_i64 :: proc (n: i64, base: u64 = 10) do str.builder_append(^print_buffer, n, base); -print_i32 :: proc (n: i32, base: u32 = 10) do str.builder_append(^print_buffer, cast(i64) n, cast(u64) base); -print_f64 :: proc (n: f64) do str.builder_append(^print_buffer, n); -print_f32 :: proc (n: f32) do str.builder_append(^print_buffer, cast(f64) n); -print_bool :: proc (b: bool) do str.builder_append(^print_buffer, b); -print_ptr :: proc (p: ^void) do str.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 { @@ -32,7 +32,7 @@ print_range :: proc (r: range, sep := " ") { } print :: proc { - print_string, print_cstring, + print_str, print_cstr, print_i64, print_i32, print_f64, print_f32, print_bool, print_ptr, @@ -44,7 +44,7 @@ println :: proc (x: $T) { print("\n"); } -printf :: proc (format: string, va: ...) { +printf :: proc (format: str, va: ...) { buffer: [2048] u8; len := 0; @@ -67,7 +67,7 @@ printf :: proc (format: string, va: ...) { if !vararg_get(va, ^n) do return; ibuf : [128] u8; - istr := str.i64_to_string(~~n, 10, Buffer.{ ~~ibuf, 128 }); + istr := string.i64_to_str(~~n, 10, Buffer.{ ~~ibuf, 128 }); for a: istr { buffer[len] = a; @@ -80,7 +80,7 @@ printf :: proc (format: string, va: ...) { if !vararg_get(va, ^n) do return; ibuf : [128] u8; - istr := str.i64_to_string(n, 10, Buffer.{ ~~ibuf, 128 }); + istr := string.i64_to_str(n, 10, Buffer.{ ~~ibuf, 128 }); for a: istr { buffer[len] = a; @@ -93,7 +93,7 @@ printf :: proc (format: string, va: ...) { if !vararg_get(va, ^n) do return; fbuf : [128] u8; - fstr := str.f64_to_string(~~n, fbuf[0 .. 128]); + fstr := string.f64_to_str(~~n, fbuf[0 .. 128]); for a: fstr { buffer[len] = a; @@ -106,7 +106,7 @@ printf :: proc (format: string, va: ...) { if !vararg_get(va, ^n) do return; fbuf : [128] u8; - fstr := str.f64_to_string(n, fbuf[0 .. 128]); + fstr := string.f64_to_str(n, fbuf[0 .. 128]); for a: fstr { buffer[len] = a; @@ -115,10 +115,10 @@ printf :: proc (format: string, va: ...) { } case #char "s" { - str : string; - if !vararg_get(va, ^str) do return; + s : str; + if !vararg_get(va, ^s) do return; - for a: str { + for a: s { buffer[len] = a; len += 1; } @@ -129,20 +129,28 @@ printf :: proc (format: string, va: ...) { if !vararg_get(va, ^n) do return; ibuf : [128] u8; - istr := str.i64_to_string(~~n, 16, Buffer.{ ~~ibuf, 128 }); + 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(string.{ ~~buffer, len }); + print(str.{ ~~buffer, len }); } // This works on both slices and arrays @@ -159,9 +167,9 @@ print_buffer_flush :: proc () { if print_buffer.len == 0 do return; ^print_buffer - |> str.builder_to_string() - |> system.output_string(); + |> string.builder_to_str() + |> system.output_str(); - ^print_buffer |> str.builder_clear(); + ^print_buffer |> string.builder_clear(); } diff --git a/core/string.onyx b/core/string.onyx index 814ee00f..571725f9 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -1,13 +1,13 @@ -package core.str +package core.string -make :: proc (s: cstring) -> string { +make :: proc (s: cstr) -> str { len :: length(s); - return string.{ count = len, data = s }; + return str.{ count = len, data = s }; } length :: proc { - proc (s: cstring) -> u32 { + proc (s: cstr) -> u32 { len := 0; c := s; while *c != #char "\0" { @@ -18,27 +18,27 @@ length :: proc { return len; }, - proc (s: string) -> u32 { + proc (s: str) -> u32 { return s.count; }, } -alloc_copy :: proc (orig: string) -> string { - new_str : string; +alloc_copy :: proc (orig: str) -> str { + new_str : str; new_str.data = calloc(sizeof u8 * orig.count); new_str.count = orig.count; copy(orig, new_str); return new_str; } -copy :: proc (orig: string, dest: string) { +copy :: proc (orig: str, dest: str) { len := orig.count; if dest.count < len do len = dest.count; for i: 0 .. len do dest.data[i] = orig.data[i]; } -concat :: proc (s1: string, s2: string) -> string { +concat :: proc (s1: str, s2: str) -> str { len1 :: length(s1); len2 :: length(s2); @@ -46,54 +46,54 @@ concat :: proc (s1: string, s2: string) -> string { for i: 0 .. len1 do data[i] = s1[i]; for i: 0 .. len2 do data[i + len1] = s2[i]; - return string.{ data, len1 + len2 }; + return str.{ data, len1 + len2 }; } -free :: proc (s: string) do cfree(s.data); +free :: proc (s: str) do cfree(s.data); -// This is an example doc string +// This is an example doc str // You can have as many comments as you want // It documents the split function -split :: proc (str: string, delim: u8) -> []string { +split :: proc (s: str, delim: u8) -> []str { delim_count := 0; - for i: 0 .. str.count do if str[i] == delim do delim_count += 1; + for i: 0 .. s.count do if s[i] == delim do delim_count += 1; - strarr := cast(^string) calloc(sizeof string * (delim_count + 1)); + strarr := cast(^str) calloc(sizeof str * (delim_count + 1)); curr_str := 0; begin := 0; - for i: 0 .. str.count { - if str[i] == delim { - strarr[curr_str] = str.data[begin .. i]; + for i: 0 .. s.count { + if s[i] == delim { + strarr[curr_str] = s.data[begin .. i]; begin = i + 1; curr_str += 1; } } - strarr[curr_str] = str.data[begin .. str.count]; + strarr[curr_str] = s.data[begin .. s.count]; return strarr[0 .. delim_count + 1]; } -substr :: proc (str: string, sub: string) -> string { - for i: 0 .. str.count { - while j := 0; j < sub.count && str[i + j] == sub[j] { - j += 1; - - if j == sub.count do return str.data[i .. i + j]; - } - } - - return str.data[0 .. 0]; -} +// substr :: proc (s: str, sub: str) -> str { +// for i: 0 .. str.count { +// while j := 0; j < sub.count && str[i + j] == sub[j] { +// j += 1; +// +// if j == sub.count do return str.data[i .. i + j]; +// } +// } +// +// return str.data[0 .. 0]; +// } -contains :: proc (str: string, c: u8) -> bool { - for ch: str do if ch == c do return true; +contains :: proc (s: str, c: u8) -> bool { + for ch: s do if ch == c do return true; return false; } -// compare :: proc (str1: string, str2: string) -> i32 { +// compare :: proc (str1: str, str2: str) -> i32 { // if str1.count != str2.count do return str1.count - str2.count; // // i := 0; @@ -103,7 +103,7 @@ contains :: proc (str: string, c: u8) -> bool { // return ~~(str1[i] - str2[i]); // } -equal :: proc (str1: string, str2: string) -> bool { +equal :: proc (str1: str, str2: str) -> bool { if str1.count != str2.count do return false; while i := 0; i < str1.count { if str1[i] != str2[i] do return false; @@ -112,7 +112,7 @@ equal :: proc (str1: string, str2: string) -> bool { return true; } -starts_with :: proc (str1: string, str2: string) -> bool { +starts_with :: proc (str1: str, str2: str) -> bool { if str1.count < str2.count do return false; while i := 0; i < str2.count { if str1[i] != str2[i] do return false; @@ -121,21 +121,21 @@ starts_with :: proc (str1: string, str2: string) -> bool { return true; } -strip_leading_whitespace :: proc (str: ^string) { - while true do switch str.data[0] { +strip_leading_whitespace :: proc (s: ^str) { + while true do switch s.data[0] { case #char " ", #char "\t", #char "\n", #char "\r" { - str.data += 1; - str.count -= 1; + s.data += 1; + s.count -= 1; } case #default do return; } } -strip_trailing_whitespace :: proc (str: ^string) { - while true do switch str.data[str.count - 1] { +strip_trailing_whitespace :: proc (s: ^str) { + while true do switch s.data[s.count - 1] { case #char " ", #char "\t", #char "\n", #char "\r" { - str.count -= 1; + s.count -= 1; } case #default do return; @@ -170,12 +170,12 @@ builder_make :: proc (initial_cap: u32) -> StringBuilder { }; } -builder_add_string :: proc (use sb: ^StringBuilder, str: string) -> ^StringBuilder { - len_total :: len + str.count; +builder_add_str :: proc (use sb: ^StringBuilder, s: str) -> ^StringBuilder { + len_total :: len + s.count; if cap >= len_total { - for i: 0 .. str.count do data[len + i] = str[i]; - len += str.count; + for i: 0 .. s.count do data[len + i] = s[i]; + len += s.count; return sb; } @@ -188,17 +188,17 @@ builder_add_string :: proc (use sb: ^StringBuilder, str: string) -> ^StringBuild data = new_data; cap = new_cap; - for i: 0 .. str.count do data[len + i] = str[i]; - len += str.count; + for i: 0 .. s.count do data[len + i] = s[i]; + len += s.count; return sb; } -builder_add_cstring :: proc (use sb: ^StringBuilder, cstr: cstring) -> ^StringBuilder { - s := make(cstr); - return builder_add_string(sb, s); +builder_add_cstr :: proc (use sb: ^StringBuilder, cstring: cstr) -> ^StringBuilder { + s := make(cstring); + return builder_add_str(sb, s); } -i64_to_string :: proc (n_: i64, base: u64, buf: Buffer) -> string { +i64_to_str :: proc (n_: i64, base: u64, buf: Buffer) -> str { n := cast(u64) n_; is_neg := false; @@ -251,11 +251,11 @@ i64_to_string :: proc (n_: i64, base: u64, buf: Buffer) -> string { c -= 1; } - return string.{ data = c + 1, count = len }; + return str.{ data = c + 1, count = len }; } // NOTE: This is a big hack but it will work for now -f64_to_string :: proc (f: f64, buf: [] u8) -> string { +f64_to_str :: proc (f: f64, buf: [] u8) -> str { a := f; a *= 10000.0; v := cast(i64) a; @@ -263,51 +263,51 @@ f64_to_string :: proc (f: f64, buf: [] u8) -> string { b := Buffer.{ cast(^void) buf.data, buf.count }; len := 0; - s1 := i64_to_string(v / 10000, 10, b); + 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_string(v % 10000, 10, b); + 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 string.{ buf.data, len }; + return str.{ buf.data, len }; } builder_add_i64 :: proc (use sb: ^StringBuilder, n: i64, base: u64 = 10) -> ^StringBuilder { buf : [256] u8; - s := i64_to_string(n, base, Buffer.{ cast(^void) buf, 256 }); - return builder_add_string(sb, s); + 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_string(f, buf[0 .. 256]); - return builder_add_string(sb, s); + 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_string(sb, "true"); + return builder_add_str(sb, "true"); } else { - return builder_add_string(sb, "false"); + return builder_add_str(sb, "false"); } return null; } builder_append :: proc { - builder_add_string, - builder_add_cstring, + builder_add_str, + builder_add_cstr, builder_add_i64, builder_add_f64, builder_add_bool, } -builder_to_string :: proc (use sb: ^StringBuilder) -> string { - return string.{ data, len }; +builder_to_str :: proc (use sb: ^StringBuilder) -> str { + return str.{ data, len }; } builder_clear :: proc (use sb: ^StringBuilder) -> ^StringBuilder { @@ -315,114 +315,114 @@ builder_clear :: proc (use sb: ^StringBuilder) -> ^StringBuilder { return sb; } -read_u32 :: proc (str: ^string, out: ^u32) { +read_u32 :: proc (s: ^str, out: ^u32) { n := 0; - strip_leading_whitespace(str); - while str.data[0] >= #char "0" && str.data[0] <= #char "9" { + strip_leading_whitespace(s); + while s.data[0] >= #char "0" && s.data[0] <= #char "9" { n *= 10; - n += cast(u32) (str.data[0] - #char "0"); + n += cast(u32) (s.data[0] - #char "0"); - str.data += 1; - str.count -= 1; + s.data += 1; + s.count -= 1; } *out = n; } -read_char :: proc (str: ^string, out: ^u8) { - *out = str.data[0]; - str.data += 1; - str.count -= 1; +read_char :: proc (s: ^str, out: ^u8) { + *out = s.data[0]; + s.data += 1; + s.count -= 1; } -read_chars :: proc (str: ^string, out: ^string, char_count := 1) { - out.data = str.data; +read_chars :: proc (s: ^str, out: ^str, char_count := 1) { + out.data = s.data; out.count = char_count; - str.data += char_count; - str.count -= char_count; + s.data += char_count; + s.count -= char_count; } -discard_chars :: proc (str: ^string, char_count := 1) { - str.data += char_count; - str.count -= char_count; +discard_chars :: proc (s: ^str, char_count := 1) { + s.data += char_count; + s.count -= char_count; } // Goes up to but not including the closest newline or EOF -read_line :: proc (str: ^string, out: ^string) { - out.data = str.data; +read_line :: proc (s: ^str, out: ^str) { + out.data = s.data; out.count = 0; - for ch: *str { + for ch: *s { if ch == #char "\n" do break; out.count += 1; } - str.data += out.count; - str.count -= out.count; + s.data += out.count; + s.count -= out.count; - if str.count > 0 { - str.data += 1; - str.count -= 1; + if s.count > 0 { + s.data += 1; + s.count -= 1; } } -read_until :: proc (str: ^string, upto: u8, skip := 0) -> string { - if str.count == 0 do return ""; +read_until :: proc (s: ^str, upto: u8, skip := 0) -> str { + if s.count == 0 do return ""; - out : string; - out.data = str.data; + out : str; + out.data = s.data; out.count = 0; - s := skip; - for ch: *str { + rem := skip; + for ch: *s { if ch == upto { - if s <= 0 do break; - else do s -= 1; + if rem <= 0 do break; + else do rem -= 1; } out.count += 1; } - str.data += out.count; - str.count -= out.count; + s.data += out.count; + s.count -= out.count; return out; } -read_until_either :: proc (str: ^string, skip: u32, uptos: ..u8) -> string { - if str.count == 0 do return ""; +read_until_either :: proc (s: ^str, skip: u32, uptos: ..u8) -> str { + if s.count == 0 do return ""; - out : string; - out.data = str.data; + out : str; + out.data = s.data; out.count = 0; - s := skip; - for ch: *str { + rem := skip; + for ch: *s { for upto: uptos { if ch == upto { - if s <= 0 do break break; - else do s -= 1; + if rem <= 0 do break break; + else do rem -= 1; } } out.count += 1; } - str.data += out.count; - str.count -= out.count; + s.data += out.count; + s.count -= out.count; return out; } -advance_line :: proc (str: ^string) { - if str.count == 0 do return; +advance_line :: proc (s: ^str) { + if s.count == 0 do return; adv := 0; - while str.data[adv] != #char "\n" do adv += 1; + while s.data[adv] != #char "\n" do adv += 1; - str.data += adv + 1; - str.count -= adv + 1; + s.data += adv + 1; + s.count -= adv + 1; } read :: proc { diff --git a/core/string/reader.onyx b/core/string/reader.onyx index 5cf797a4..b60a34b2 100644 --- a/core/string/reader.onyx +++ b/core/string/reader.onyx @@ -1,21 +1,23 @@ -package core.str.reader +package core.string.reader + +use package core { printf } StringReader :: struct { data : ^u8; count : u32; // The original string. - original_str : string; + original_str : str; } -make :: proc (str: string) -> StringReader { +make :: proc (s: str) -> StringReader { reader : StringReader; - init(^reader, str); + init(^reader, s); return reader; } -init :: proc (use reader: ^StringReader, str: string) { - original_str = str; +init :: proc (use reader: ^StringReader, orig_str: str) { + original_str = orig_str; data = original_str.data; count = original_str.count; } @@ -70,7 +72,7 @@ read_byte :: proc (use reader: ^StringReader) -> u8 { return data[0]; } -read_bytes :: proc (use reader: ^StringReader, byte_count := 1) -> string { +read_bytes :: proc (use reader: ^StringReader, byte_count := 1) -> str { bc := byte_count; if count < bc do bc = count; @@ -79,16 +81,16 @@ read_bytes :: proc (use reader: ^StringReader, byte_count := 1) -> string { count -= bc; } - return string.{ data, bc }; + return str.{ data, bc }; } -read_line :: proc (use reader: ^StringReader) -> string { - out : string; +read_line :: proc (use reader: ^StringReader) -> str { + out : str; out.data = data; out.count = 0; // HACK(Brendan): I want to use a for loop, but I don't know why. - for ch: *(cast(^string) reader) { + for ch: *(cast(^str) reader) { if ch == #char "\n" do break; out.count += 1; } @@ -104,20 +106,22 @@ read_line :: proc (use reader: ^StringReader) -> string { return out; } -read_until :: proc (use reader: ^StringReader, skip: u32, uptos: ..u8) -> string { - if count == 0 do return string.{ null, 0 }; +read_until :: proc (use reader: ^StringReader, skip: u32, uptos: ..u8) -> str { + if count == 0 do return str.{ null, 0 }; - out : string; + out : str; out.data = data; out.count = 0; s := skip; // HACK(Brendan): See above. - for ch: *(cast(^string) reader) { + for ch: *(cast(^str) reader) { for upto: uptos do if ch == upto { - if s <= 0 do break; + if s == 0 do break break; else do s -= 1; + + break; } out.count += 1; @@ -141,7 +145,7 @@ advance_line :: proc (use reader: ^StringReader) { skip_whitespace :: proc (use reader: ^StringReader) { - while count > 0 do switch *data { + while count > 0 do switch data[0] { case #char " ", #char "\t", #char "\n", #char "\r" { data += 1; count -= 1; @@ -158,3 +162,14 @@ skip_bytes :: proc (use reader: ^StringReader, byte_count := 1) { data += bc; count -= bc; } + + + +starts_with :: proc (use reader: ^StringReader, s: str) -> bool { + if count < s.count do return false; + while i := 0; i < s.count { + if data[i] != s[i] do return false; + i += 1; + } + return true; +} diff --git a/core/strmap.onyx b/core/strmap.onyx index f5a3be55..f248f052 100644 --- a/core/strmap.onyx +++ b/core/strmap.onyx @@ -1,7 +1,7 @@ package core.strmap use package core.array as array -use package core.str as str +use package core.string as string use package core { print } StrMap :: struct ($T) { @@ -13,7 +13,7 @@ StrMap :: struct ($T) { StrMapEntry :: struct ($T) { next : i32; - key : string; + key : str; value : T; } @@ -31,7 +31,7 @@ free :: proc (use smap: ^StrMap($T)) { array.free(^key_store); } -put :: proc (use smap: ^StrMap($T), key: string, value: T, copy_key := false) { +put :: proc (use smap: ^StrMap($T), key: str, value: T, copy_key := false) { lr := lookup(smap, key); if lr.entry_index >= 0 { @@ -49,7 +49,7 @@ put :: proc (use smap: ^StrMap($T), key: string, value: T, copy_key := false) { // array.ensure_capacity(^key_store, key_store.count + key.count); // key_store.count += key.count; - // str.copy(key, new_key); + // string.copy(key, new_key); // } entry : StrMapEntry(T); @@ -62,19 +62,19 @@ put :: proc (use smap: ^StrMap($T), key: string, value: T, copy_key := false) { hashes[lr.hash_index] = entries.count - 1; } -has :: proc (use smap: ^StrMap($T), key: string) -> bool { +has :: proc (use smap: ^StrMap($T), key: str) -> bool { lr := lookup(smap, key); return lr.entry_index >= 0; } -get :: proc (use smap: ^StrMap($T), key: string, default := cast(T) 0) -> T { +get :: proc (use smap: ^StrMap($T), key: str, default := cast(T) 0) -> T { lr := lookup(smap, key); if lr.entry_index >= 0 do return entries[lr.entry_index].value; return default; } -delete :: proc (use smap: ^StrMap($T), key: string) { +delete :: proc (use smap: ^StrMap($T), key: str) { lr := lookup(smap, key); if lr.entry_index < 0 do return; @@ -111,7 +111,7 @@ StrMapLookupResult :: struct { } #private_file -lookup :: proc (use smap: ^StrMap($T), key: string) -> StrMapLookupResult { +lookup :: proc (use smap: ^StrMap($T), key: str) -> StrMapLookupResult { lr := StrMapLookupResult.{}; hash: u32 = 5381; @@ -121,7 +121,7 @@ lookup :: proc (use smap: ^StrMap($T), key: string) -> StrMapLookupResult { lr.entry_index = hashes[lr.hash_index]; while lr.entry_index >= 0 { - if str.equal(entries[lr.entry_index].key, key) do return lr; + if string.equal(entries[lr.entry_index].key, key) do return lr; lr.entry_prev = lr.entry_index; lr.entry_index = entries[lr.entry_index].next; diff --git a/core/sys/js.onyx b/core/sys/js.onyx index e09f55cb..e1635677 100644 --- a/core/sys/js.onyx +++ b/core/sys/js.onyx @@ -3,7 +3,7 @@ package system use package core use package main as main -output_string :: proc (s: string) -> u32 #foreign "host" "print_str" --- +output_str :: proc (s: str) -> u32 #foreign "host" "print_str" --- // The builtin _start proc. // Sets up everything needed for execution. @@ -13,7 +13,7 @@ proc () #export "_start" { context.allocator = allocator.heap_allocator; context.temp_allocator = allocator.heap_allocator; - args : [] cstring; + args : [] cstr; args.data = null; args.count = 0; diff --git a/core/sys/wasi.onyx b/core/sys/wasi.onyx index cc782153..0dbd2c7c 100644 --- a/core/sys/wasi.onyx +++ b/core/sys/wasi.onyx @@ -8,7 +8,7 @@ use package main as main STDOUT_FILENO :: 1 -output_string :: proc (s: string) -> u32 { +output_str :: proc (s: str) -> u32 { vec := IOVec.{ buf = s.data, len = s.count }; tmp : Size; fd_write(STDOUT_FILENO, IOVecArray.{ ^vec, 1 }, ^tmp); @@ -29,8 +29,8 @@ proc () #export "_start" { args_sizes_get(^argc, ^argv_buf_size); - argv := cast(^cstring) calloc(sizeof cstring * argc); - argv_buf := cast(cstring) calloc(argv_buf_size); + argv := cast(^cstr) calloc(sizeof cstr * argc); + argv_buf := cast(cstr) calloc(argv_buf_size); args_get(argv, argv_buf); diff --git a/core/wasi.onyx b/core/wasi.onyx index 2821cd10..f5600f9b 100644 --- a/core/wasi.onyx +++ b/core/wasi.onyx @@ -385,7 +385,7 @@ fd_filestat_set_size :: proc (fd: FileDescriptor, size: Filesize) -> Errno #for fd_filestat_set_times :: proc (fd: FileDescriptor, atim: Timestamp, mtim: Timestamp, fst_flags: FSTFlags) -> Errno #foreign "wasi_unstable" "fd_filestat_set_times" --- fd_pread :: proc (fd: FileDescriptor, iovs: IOVecArray, offset: Filesize, nread: ^Size) -> Errno #foreign "wasi_unstable" "fd_pread" --- fd_prestat_get :: proc (fd: FileDescriptor, buf: ^PrestatTagged) -> Errno #foreign "wasi_unstable" "fd_prestat_get" --- -fd_prestat_dir_name :: proc (fd: FileDescriptor, path: string) -> Errno #foreign "wasi_unstable" "fd_prestat_dir_name" --- +fd_prestat_dir_name :: proc (fd: FileDescriptor, path: str) -> Errno #foreign "wasi_unstable" "fd_prestat_dir_name" --- fd_pwrite :: proc (fd: FileDescriptor, iovs: IOVecArray, offset: Filesize, nwritten: ^Size) -> Errno #foreign "wasi_unstable" "fd_pwrite" --- fd_read :: proc (fd: FileDescriptor, iovs: IOVecArray, nread: ^Size) -> Errno #foreign "wasi_unstable" "fd_read" --- fd_readdir :: proc (fd: FileDescriptor, buf: ^u8, buf_len: Size, cookie: DirCookie, bufused: ^Size) -> Errno #foreign "wasi_unstable" "fd_readdir" --- @@ -395,15 +395,15 @@ fd_sync :: proc (fd: FileDescriptor) -> Errno #foreign "wasi_unsta fd_tell :: proc (fd: FileDescriptor, offset: ^Filesize) -> Errno #foreign "wasi_unstable" "fd_tell" --- fd_write :: proc (fd: FileDescriptor, iovs: IOVecArray, nwritten: ^Size) -> Errno #foreign "wasi_unstable" "fd_write" --- -path_create_directory :: proc (fd: FileDescriptor, path: string) -> Errno #foreign "wasi_unstable" "path_create_directory" --- -path_filestat_get :: proc (fd: FileDescriptor, flags: LookupFlags, path: string, buf: ^FileStat) -> Errno #foreign "wasi_unstable" "path_filestat_get" --- -path_filestat_set_times :: proc (fd: FileDescriptor, flags: LookupFlags, path: string, atim: Timestamp, mtim: Timestamp, fst_flags: FSTFlags) -> Errno #foreign "wasi_unstable" "path_filestat_set_times" --- +path_create_directory :: proc (fd: FileDescriptor, path: str) -> Errno #foreign "wasi_unstable" "path_create_directory" --- +path_filestat_get :: proc (fd: FileDescriptor, flags: LookupFlags, path: str, buf: ^FileStat) -> Errno #foreign "wasi_unstable" "path_filestat_get" --- +path_filestat_set_times :: proc (fd: FileDescriptor, flags: LookupFlags, path: str, atim: Timestamp, mtim: Timestamp, fst_flags: FSTFlags) -> Errno #foreign "wasi_unstable" "path_filestat_set_times" --- -path_link :: proc (fd: FileDescriptor, old_flags: LookupFlags, old_path: string, new_fd: FileDescriptor, new_path: string) -> Errno #foreign "wasi_unstable" "path_link" --- +path_link :: proc (fd: FileDescriptor, old_flags: LookupFlags, old_path: str, new_fd: FileDescriptor, new_path: str) -> Errno #foreign "wasi_unstable" "path_link" --- path_open :: proc ( fd: FileDescriptor , dirflags: LookupFlags - , path: string + , path: str , oflags: OFlags , fs_rights_base: Rights , fs_rights_inherting: Rights @@ -412,11 +412,11 @@ path_open :: proc ) -> Errno #foreign "wasi_unstable" "path_open" --- -path_readlink :: proc (fd: FileDescriptor, path: string, buf: ^u8, buf_len: Size, bufused: ^Size) -> Errno #foreign "wasi_unstable" "path_readlink" --- -path_remove_directory :: proc (fd: FileDescriptor, path: string) -> Errno #foreign "wasi_unstable" "path_remove_directory" --- -path_rename :: proc (fd: FileDescriptor, old_path: string, new_fd: FileDescriptor, new_path: string) -> Errno #foreign "wasi_unstable" "path_rename" --- -path_symlink :: proc (old_path: ^u8, old_path_len: Size, fd: FileDescriptor, new_path: string) -> Errno #foreign "wasi_unstable" "path_symlink" --- -path_unlink_file :: proc (fd: FileDescriptor, path: string) -> Errno #foreign "wasi_unstable" "path_unlink_file" --- +path_readlink :: proc (fd: FileDescriptor, path: str, buf: ^u8, buf_len: Size, bufused: ^Size) -> Errno #foreign "wasi_unstable" "path_readlink" --- +path_remove_directory :: proc (fd: FileDescriptor, path: str) -> Errno #foreign "wasi_unstable" "path_remove_directory" --- +path_rename :: proc (fd: FileDescriptor, old_path: str, new_fd: FileDescriptor, new_path: str) -> Errno #foreign "wasi_unstable" "path_rename" --- +path_symlink :: proc (old_path: ^u8, old_path_len: Size, fd: FileDescriptor, new_path: str) -> Errno #foreign "wasi_unstable" "path_symlink" --- +path_unlink_file :: proc (fd: FileDescriptor, path: str) -> Errno #foreign "wasi_unstable" "path_unlink_file" --- poll_oneoff :: proc (in: ^Subscription, out: ^Event, nsubscriptions: Size, nevents: ^Size) -> Errno #foreign "wasi_unstable" "poll_oneoff" --- diff --git a/docs/todo b/docs/todo index d3498299..9a7dea09 100644 --- a/docs/todo +++ b/docs/todo @@ -50,16 +50,13 @@ Language Cohesion: The following should work when this is patched: var := some.packages.nested.here.StructName.{ value1, value2, ... }; - - [ ] Rearrange APIs. There is a lot of functionality in the standard libraries, - but it isn't organized in a usable way. - - 'core.array' contains a lot of functionality that would also apply to - slices. 'core.slice' should contain this functionality and 'core.array' - can provide wrappers that convert the array to a slice. - - 'core.str' is a bad name, it should be 'core.string'. The issue is that - it conflicts with 'builtin.string'. These two should be switched. Type - name should be 'str' and package name should be 'string' + [ ] 'use' statements have two different variations and should be unified. + They can be used to include a package, 'use package', and they can + be used to add names from a namespace to the current scope. The problem + is that 'use package' can only be at the top level, and 'use' can only + be used at the block level. + [ ] :: should not declare a local variable, just bind a name to an expression. They can still be lexically scoped. @@ -71,6 +68,15 @@ API Expansion: There are many differeny places where the standard API for WASI and JS backends could be improved. Here are some of the target areas. + [ ] Rearrange APIs. There is a lot of functionality in the standard libraries, + but it isn't organized in a usable way. + - 'core.array' contains a lot of functionality that would also apply to + slices. 'core.slice' should contain this functionality and 'core.array' + can provide wrappers that convert the array to a slice. + - 'core.str' is a bad name, it should be 'core.string'. The issue is that + it conflicts with 'builtin.string'. These two should be switched. Type + name should be 'str' and package name should be 'string' + [ ] Expand capabilities of file api on WASI. [ ] Add clock / time api for both backends [ ] Better random number api diff --git a/misc/onyx.sublime-syntax b/misc/onyx.sublime-syntax index 20fe6be3..ed980ee6 100644 --- a/misc/onyx.sublime-syntax +++ b/misc/onyx.sublime-syntax @@ -29,7 +29,7 @@ contexts: - match: '\b(package|struct|proc|use|global|enum|if|elseif|else|for|while|do|break|continue|fallthrough|return|as|cast|sizeof|alignof|defer|switch|case)\b' scope: keyword.control.onyx - - match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr|string|cstring|range)\b' + - match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr|str|cstr|range)\b' scope: storage.type - match: '\b(i8x16|i16x8|i32x4|i64x2|f32x4|f64x2|v128)\b' diff --git a/misc/onyx.vim b/misc/onyx.vim index 261049fb..98b95e87 100644 --- a/misc/onyx.vim +++ b/misc/onyx.vim @@ -23,6 +23,7 @@ syn keyword onyxType i64 u64 syn keyword onyxType f32 syn keyword onyxType f64 syn keyword onyxType rawptr +syn keyword onyxType str cstr syn keyword onyxType i8x16 i16x8 i32x4 i64x2 f32x4 f64x2 v128 syn keyword onyxConstant true false null diff --git a/onyx b/onyx index 8e4bcab871bf9f407a516924ea2a40292d93b85b..be7fee5fe0d7b92d25f8655bd21302f261b227fa 100755 GIT binary patch delta 74602 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