Merge branch 'master' into tilde

This commit is contained in:
gingerBill
2023-08-03 13:14:09 +01:00
55 changed files with 1077 additions and 887 deletions
+6 -3
View File
@@ -51,7 +51,10 @@ set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -EHsc- -GR- -GF
set compiler_defines= -DODIN_VERSION_RAW=\"%odin_version_raw%\" set compiler_defines= -DODIN_VERSION_RAW=\"%odin_version_raw%\"
if not exist .git\ goto skip_git_hash if not exist .git\ goto skip_git_hash
for /f %%i in ('git rev-parse --short HEAD') do set GIT_SHA=%%i for /f "tokens=1,2" %%i IN ('git show "--pretty=%%cd %%h" "--date=format:%%Y-%%m" --no-patch --no-notes HEAD') do (
set odin_version_raw=dev-%%i
set GIT_SHA=%%j
)
if %ERRORLEVEL% equ 0 set compiler_defines=%compiler_defines% -DGIT_SHA=\"%GIT_SHA%\" if %ERRORLEVEL% equ 0 set compiler_defines=%compiler_defines% -DGIT_SHA=\"%GIT_SHA%\"
:skip_git_hash :skip_git_hash
@@ -75,8 +78,8 @@ set compiler_includes= ^
set libs= ^ set libs= ^
kernel32.lib ^ kernel32.lib ^
Synchronization.lib ^ Synchronization.lib ^
src\tilde\tb.lib ^ bin\llvm\windows\LLVM-C.lib ^
bin\llvm\windows\LLVM-C.lib src\tilde\tb.lib
set linker_flags= -incremental:no -opt:ref -subsystem:console set linker_flags= -incremental:no -opt:ref -subsystem:console
+7 -4
View File
@@ -8,17 +8,20 @@ set -eu
: ${ODIN_VERSION=dev-$(date +"%Y-%m")} : ${ODIN_VERSION=dev-$(date +"%Y-%m")}
: ${GIT_SHA=} : ${GIT_SHA=}
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\""
CXXFLAGS="$CXXFLAGS -std=c++14" CXXFLAGS="$CXXFLAGS -std=c++14"
LDFLAGS="$LDFLAGS -pthread -lm -lstdc++" LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
if [ -d ".git" ]; then if [ -d ".git" ] && [ $(which git) ]; then
GIT_SHA=$(git rev-parse --short HEAD || :) versionTag=( $(git show --pretty='%cd %h' --date=format:%Y-%m --no-patch --no-notes HEAD) )
if [ "$GIT_SHA" ]; then if [ $? -eq 0 ]; then
ODIN_VERSION="dev-${versionTag[0]}"
GIT_SHA="${versionTag[1]}"
CPPFLAGS="$CPPFLAGS -DGIT_SHA=\"$GIT_SHA\"" CPPFLAGS="$CPPFLAGS -DGIT_SHA=\"$GIT_SHA\""
fi fi
fi fi
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\""
DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value" DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value"
OS=$(uname) OS=$(uname)
+1
View File
@@ -1,3 +1,4 @@
//+vet !using-param
package zlib package zlib
/* /*
+17 -20
View File
@@ -184,28 +184,26 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
advance :: proc(t: ^Tokenizer) -> (err: Error) { advance :: proc(t: ^Tokenizer) -> (err: Error) {
if t == nil { return .Tokenizer_Is_Nil } if t == nil { return .Tokenizer_Is_Nil }
using t
#no_bounds_check { #no_bounds_check {
if read_offset < len(src) { if t.read_offset < len(t.src) {
offset = read_offset t.offset = t.read_offset
r, w = rune(src[read_offset]), 1 t.r, t.w = rune(t.src[t.read_offset]), 1
switch { switch {
case r == 0: case t.r == 0:
return .Illegal_NUL_Character return .Illegal_NUL_Character
case r >= utf8.RUNE_SELF: case t.r >= utf8.RUNE_SELF:
r, w = utf8.decode_rune_in_string(src[read_offset:]) t.r, t.w = utf8.decode_rune_in_string(t.src[t.read_offset:])
if r == utf8.RUNE_ERROR && w == 1 { if t.r == utf8.RUNE_ERROR && t.w == 1 {
return .Illegal_UTF_Encoding return .Illegal_UTF_Encoding
} else if r == utf8.RUNE_BOM && offset > 0 { } else if t.r == utf8.RUNE_BOM && t.offset > 0 {
return .Illegal_BOM return .Illegal_BOM
} }
} }
read_offset += w t.read_offset += t.w
return .None return .None
} else { } else {
offset = len(src) t.offset = len(t.src)
r = -1 t.r = -1
return return
} }
} }
@@ -273,26 +271,25 @@ _extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) {
All of these would be in the ASCII range. All of these would be in the ASCII range.
Even if one is not, it doesn't matter. All characters we need to compare to extract are. Even if one is not, it doesn't matter. All characters we need to compare to extract are.
*/ */
using t
length := len(t.src) length := len(t.src)
found := false found := false
#no_bounds_check { #no_bounds_check {
for read_offset < length { for t.read_offset < length {
if src[read_offset] == ';' { if t.src[t.read_offset] == ';' {
t.read_offset += 1
found = true found = true
read_offset += 1
break break
} }
read_offset += 1 t.read_offset += 1
} }
} }
if found { if found {
return string(src[offset + 1 : read_offset - 1]), .None return string(t.src[t.offset + 1 : t.read_offset - 1]), .None
} }
return string(src[offset : read_offset]), .Invalid_Entity_Encoding return string(t.src[t.offset : t.read_offset]), .Invalid_Entity_Encoding
} }
/* /*
+21 -23
View File
@@ -19,43 +19,39 @@ import "core:fmt"
*/ */
print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error) { print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error) {
if doc == nil { return } if doc == nil { return }
using fmt written += fmt.wprintf(writer, "[XML Prolog]\n")
written += wprintf(writer, "[XML Prolog]\n")
for attr in doc.prologue { for attr in doc.prologue {
written += wprintf(writer, "\t%v: %v\n", attr.key, attr.val) written += fmt.wprintf(writer, "\t%v: %v\n", attr.key, attr.val)
} }
written += wprintf(writer, "[Encoding] %v\n", doc.encoding) written += fmt.wprintf(writer, "[Encoding] %v\n", doc.encoding)
if len(doc.doctype.ident) > 0 { if len(doc.doctype.ident) > 0 {
written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) written += fmt.wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident)
if len(doc.doctype.rest) > 0 { if len(doc.doctype.rest) > 0 {
wprintf(writer, "\t%v\n", doc.doctype.rest) fmt.wprintf(writer, "\t%v\n", doc.doctype.rest)
} }
} }
for comment in doc.comments { for comment in doc.comments {
written += wprintf(writer, "[Pre-root comment] %v\n", comment) written += fmt.wprintf(writer, "[Pre-root comment] %v\n", comment)
} }
if len(doc.elements) > 0 { if len(doc.elements) > 0 {
wprintln(writer, " --- ") fmt.wprintln(writer, " --- ")
print_element(writer, doc, 0) print_element(writer, doc, 0)
wprintln(writer, " --- ") fmt.wprintln(writer, " --- ")
} }
return written, .None return written, .None
} }
print_element :: proc(writer: io.Writer, doc: ^Document, element_id: Element_ID, indent := 0) -> (written: int, err: io.Error) { print_element :: proc(writer: io.Writer, doc: ^Document, element_id: Element_ID, indent := 0) -> (written: int, err: io.Error) {
using fmt
tab :: proc(writer: io.Writer, indent: int) { tab :: proc(writer: io.Writer, indent: int) {
for _ in 0..=indent { for _ in 0..=indent {
wprintf(writer, "\t") fmt.wprintf(writer, "\t")
} }
} }
@@ -64,22 +60,24 @@ print_element :: proc(writer: io.Writer, doc: ^Document, element_id: Element_ID,
element := doc.elements[element_id] element := doc.elements[element_id]
if element.kind == .Element { if element.kind == .Element {
wprintf(writer, "<%v>\n", element.ident) fmt.wprintf(writer, "<%v>\n", element.ident)
if len(element.value) > 0 {
tab(writer, indent + 1) for value in element.value {
wprintf(writer, "[Value] %v\n", element.value) switch v in value {
case string:
tab(writer, indent + 1)
fmt.wprintf(writer, "[Value] %v\n", v)
case Element_ID:
print_element(writer, doc, v, indent + 1)
}
} }
for attr in element.attribs { for attr in element.attribs {
tab(writer, indent + 1) tab(writer, indent + 1)
wprintf(writer, "[Attr] %v: %v\n", attr.key, attr.val) fmt.wprintf(writer, "[Attr] %v: %v\n", attr.key, attr.val)
}
for child in element.children {
print_element(writer, doc, child, indent + 1)
} }
} else if element.kind == .Comment { } else if element.kind == .Comment {
wprintf(writer, "[COMMENT] %v\n", element.value) fmt.wprintf(writer, "[COMMENT] %v\n", element.value)
} }
return written, .None return written, .None
+3 -3
View File
@@ -72,10 +72,10 @@ example :: proc() {
return return
} }
printf("Found `<charlist>` with %v children, %v elements total\n", len(docs[0].elements[charlist].children), docs[0].element_count) printf("Found `<charlist>` with %v children, %v elements total\n", len(docs[0].elements[charlist].value), docs[0].element_count)
crc32 := doc_hash(docs[0]) crc32 := doc_hash(docs[0], false)
printf("[%v] CRC32: 0x%08x\n", "🎉" if crc32 == 0xcaa042b9 else "🤬", crc32) printf("[%v] CRC32: 0x%08x\n", "🎉" if crc32 == 0x420dbac5 else "🤬", crc32)
for round in 0..<N { for round in 0..<N {
defer xml.destroy(docs[round]) defer xml.destroy(docs[round])
+17 -12
View File
@@ -13,20 +13,25 @@ find_child_by_ident :: proc(doc: ^Document, parent_id: Element_ID, ident: string
tag := doc.elements[parent_id] tag := doc.elements[parent_id]
count := 0 count := 0
for child_id in tag.children { for v in tag.value {
child := doc.elements[child_id] switch child_id in v {
/* case string: continue
Skip commments. They have no name. case Element_ID:
*/ child := doc.elements[child_id]
if child.kind != .Element { continue } /*
Skip commments. They have no name.
*/
if child.kind != .Element { continue }
/* /*
If the ident matches and it's the nth such child, return it. If the ident matches and it's the nth such child, return it.
*/ */
if child.ident == ident { if child.ident == ident {
if count == nth { return child_id, true } if count == nth { return child_id, true }
count += 1 count += 1
}
} }
} }
return 0, false return 0, false
} }
+16 -16
View File
@@ -125,38 +125,38 @@ error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
} }
@(optimization_mode="speed") @(optimization_mode="speed")
advance_rune :: proc(using t: ^Tokenizer) { advance_rune :: proc(t: ^Tokenizer) {
#no_bounds_check { #no_bounds_check {
/* /*
Already bounds-checked here. Already bounds-checked here.
*/ */
if read_offset < len(src) { if t.read_offset < len(t.src) {
offset = read_offset t.offset = t.read_offset
if ch == '\n' { if t.ch == '\n' {
line_offset = offset t.line_offset = t.offset
line_count += 1 t.line_count += 1
} }
r, w := rune(src[read_offset]), 1 r, w := rune(t.src[t.read_offset]), 1
switch { switch {
case r == 0: case r == 0:
error(t, t.offset, "illegal character NUL") error(t, t.offset, "illegal character NUL")
case r >= utf8.RUNE_SELF: case r >= utf8.RUNE_SELF:
r, w = #force_inline utf8.decode_rune_in_string(src[read_offset:]) r, w = #force_inline utf8.decode_rune_in_string(t.src[t.read_offset:])
if r == utf8.RUNE_ERROR && w == 1 { if r == utf8.RUNE_ERROR && w == 1 {
error(t, t.offset, "illegal UTF-8 encoding") error(t, t.offset, "illegal UTF-8 encoding")
} else if r == utf8.RUNE_BOM && offset > 0 { } else if r == utf8.RUNE_BOM && t.offset > 0 {
error(t, t.offset, "illegal byte order mark") error(t, t.offset, "illegal byte order mark")
} }
} }
read_offset += w t.read_offset += w
ch = r t.ch = r
} else { } else {
offset = len(src) t.offset = len(t.src)
if ch == '\n' { if t.ch == '\n' {
line_offset = offset t.line_offset = t.offset
line_count += 1 t.line_count += 1
} }
ch = -1 t.ch = -1
} }
} }
} }
+15 -27
View File
@@ -125,16 +125,19 @@ Document :: struct {
Element :: struct { Element :: struct {
ident: string, ident: string,
value: string, value: [dynamic]Value,
attribs: Attributes, attribs: Attributes,
kind: enum { kind: enum {
Element = 0, Element = 0,
Comment, Comment,
}, },
parent: Element_ID, parent: Element_ID,
children: [dynamic]Element_ID, }
Value :: union {
string,
Element_ID,
} }
Attribute :: struct { Attribute :: struct {
@@ -247,9 +250,6 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
err = .Unexpected_Token err = .Unexpected_Token
element, parent: Element_ID element, parent: Element_ID
tag_is_open := false
first_element := true
open: Token open: Token
/* /*
@@ -275,16 +275,10 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
e.g. <odin - Start of new element. e.g. <odin - Start of new element.
*/ */
element = new_element(doc) element = new_element(doc)
tag_is_open = true if element == 0 { // First Element
parent = element
if first_element {
/*
First element.
*/
parent = element
first_element = false
} else { } else {
append(&doc.elements[parent].children, element) append(&doc.elements[parent].value, element)
} }
doc.elements[element].parent = parent doc.elements[element].parent = parent
@@ -324,7 +318,6 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
expect(t, .Gt) or_return expect(t, .Gt) or_return
parent = doc.elements[element].parent parent = doc.elements[element].parent
element = parent element = parent
tag_is_open = false
case: case:
error(t, t.offset, "Expected close tag, got: %#v\n", end_token) error(t, t.offset, "Expected close tag, got: %#v\n", end_token)
@@ -344,7 +337,6 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
} }
parent = doc.elements[element].parent parent = doc.elements[element].parent
element = parent element = parent
tag_is_open = false
} else if open.kind == .Exclaim { } else if open.kind == .Exclaim {
/* /*
@@ -392,8 +384,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
el := new_element(doc) el := new_element(doc)
doc.elements[el].parent = element doc.elements[el].parent = element
doc.elements[el].kind = .Comment doc.elements[el].kind = .Comment
doc.elements[el].value = comment append(&doc.elements[el].value, comment)
append(&doc.elements[element].children, el) append(&doc.elements[element].value, el)
} }
} }
@@ -436,9 +428,6 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
/* /*
End of file. End of file.
*/ */
if tag_is_open {
return doc, .Premature_EOF
}
break loop break loop
case: case:
@@ -450,7 +439,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
needs_processing |= .Decode_SGML_Entities in opts.flags needs_processing |= .Decode_SGML_Entities in opts.flags
if !needs_processing { if !needs_processing {
doc.elements[element].value = body_text append(&doc.elements[element].value, body_text)
continue continue
} }
@@ -472,10 +461,10 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
decoded, decode_err := entity.decode_xml(body_text, decode_opts) decoded, decode_err := entity.decode_xml(body_text, decode_opts)
if decode_err == .None { if decode_err == .None {
doc.elements[element].value = decoded append(&doc.elements[element].value, decoded)
append(&doc.strings_to_free, decoded) append(&doc.strings_to_free, decoded)
} else { } else {
doc.elements[element].value = body_text append(&doc.elements[element].value, body_text)
} }
} }
} }
@@ -518,7 +507,7 @@ destroy :: proc(doc: ^Document) {
for el in doc.elements { for el in doc.elements {
delete(el.attribs) delete(el.attribs)
delete(el.children) delete(el.value)
} }
delete(doc.elements) delete(doc.elements)
@@ -710,6 +699,5 @@ new_element :: proc(doc: ^Document) -> (id: Element_ID) {
cur := doc.element_count cur := doc.element_count
doc.element_count += 1 doc.element_count += 1
return cur return cur
} }
+11 -11
View File
@@ -835,22 +835,22 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) {
// - fi: A pointer to an Info structure // - fi: A pointer to an Info structure
// - verb: The invalid format verb // - verb: The invalid format verb
// //
fmt_bad_verb :: proc(using fi: ^Info, verb: rune) { fmt_bad_verb :: proc(fi: ^Info, verb: rune) {
prev_in_bad := fi.in_bad prev_in_bad := fi.in_bad
defer fi.in_bad = prev_in_bad defer fi.in_bad = prev_in_bad
fi.in_bad = true fi.in_bad = true
io.write_string(writer, "%!", &fi.n) io.write_string(fi.writer, "%!", &fi.n)
io.write_rune(writer, verb, &fi.n) io.write_rune(fi.writer, verb, &fi.n)
io.write_byte(writer, '(', &fi.n) io.write_byte(fi.writer, '(', &fi.n)
if arg.id != nil { if fi.arg.id != nil {
reflect.write_typeid(writer, arg.id, &fi.n) reflect.write_typeid(fi.writer, fi.arg.id, &fi.n)
io.write_byte(writer, '=', &fi.n) io.write_byte(fi.writer, '=', &fi.n)
fmt_value(fi, arg, 'v') fmt_value(fi, fi.arg, 'v')
} else { } else {
io.write_string(writer, "<nil>", &fi.n) io.write_string(fi.writer, "<nil>", &fi.n)
} }
io.write_byte(writer, ')', &fi.n) io.write_byte(fi.writer, ')', &fi.n)
} }
// Formats a boolean value according to the specified format verb // Formats a boolean value according to the specified format verb
// //
@@ -859,7 +859,7 @@ fmt_bad_verb :: proc(using fi: ^Info, verb: rune) {
// - b: The boolean value to format // - b: The boolean value to format
// - verb: The format verb // - verb: The format verb
// //
fmt_bool :: proc(using fi: ^Info, b: bool, verb: rune) { fmt_bool :: proc(fi: ^Info, b: bool, verb: rune) {
switch verb { switch verb {
case 't', 'v': case 't', 'v':
fmt_string(fi, b ? "true" : "false", 's') fmt_string(fi, b ? "true" : "false", 's')
+8 -7
View File
@@ -4,13 +4,14 @@ import "core:bytes"
import "core:image" import "core:image"
destroy :: proc(img: ^image.Image) -> bool { destroy :: proc(img: ^image.Image) -> bool {
if img == nil do return false if img == nil {
return false
}
defer free(img) defer free(img)
bytes.buffer_destroy(&img.pixels) bytes.buffer_destroy(&img.pixels)
info, ok := img.metadata.(^image.Netpbm_Info) info := img.metadata.(^image.Netpbm_Info) or_return
if !ok do return false
header_destroy(&info.header) header_destroy(&info.header)
free(info) free(info)
@@ -19,9 +20,9 @@ destroy :: proc(img: ^image.Image) -> bool {
return true return true
} }
header_destroy :: proc(using header: ^Header) { header_destroy :: proc(header: ^Header) {
if format == .P7 && tupltype != "" { if header.format == .P7 && header.tupltype != "" {
delete(tupltype) delete(header.tupltype)
tupltype = "" header.tupltype = ""
} }
} }
+1
View File
@@ -1,3 +1,4 @@
//+vet !using-stmt
package netpbm package netpbm
import "core:bytes" import "core:bytes"
+3 -4
View File
@@ -80,11 +80,10 @@ time :: proc(c: image.PNG_Chunk) -> (res: tIME, ok: bool) {
} }
core_time :: proc(c: image.PNG_Chunk) -> (t: coretime.Time, ok: bool) { core_time :: proc(c: image.PNG_Chunk) -> (t: coretime.Time, ok: bool) {
if png_time, png_ok := time(c); png_ok { if t, png_ok := time(c); png_ok {
using png_time
return coretime.datetime_to_time( return coretime.datetime_to_time(
int(year), int(month), int(day), int(t.year), int(t.month), int(t.day),
int(hour), int(minute), int(second), int(t.hour), int(t.minute), int(t.second),
) )
} else { } else {
return {}, false return {}, false
+8 -8
View File
@@ -11,6 +11,7 @@
// package png implements a PNG image reader // package png implements a PNG image reader
// //
// The PNG specification is at https://www.w3.org/TR/PNG/. // The PNG specification is at https://www.w3.org/TR/PNG/.
//+vet !using-stmt
package png package png
import "core:compress" import "core:compress"
@@ -444,15 +445,14 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
img.width = int(header.width) img.width = int(header.width)
img.height = int(header.height) img.height = int(header.height)
using header
h := image.PNG_IHDR{ h := image.PNG_IHDR{
width = width, width = header.width,
height = height, height = header.height,
bit_depth = bit_depth, bit_depth = header.bit_depth,
color_type = color_type, color_type = header.color_type,
compression_method = compression_method, compression_method = header.compression_method,
filter_method = filter_method, filter_method = header.filter_method,
interlace_method = interlace_method, interlace_method = header.interlace_method,
} }
info.header = h info.header = h
+12 -12
View File
@@ -2286,20 +2286,20 @@ F64_MASK :: 0x7ff
F64_SHIFT :: 64 - 12 F64_SHIFT :: 64 - 12
F64_BIAS :: 0x3ff F64_BIAS :: 0x3ff
INF_F16 :f16: 0h7C00 INF_F16 :: f16(0h7C00)
NEG_INF_F16 :f16: 0hFC00 NEG_INF_F16 :: f16(0hFC00)
SNAN_F16 :f16: 0h7C01 SNAN_F16 :: f16(0h7C01)
QNAN_F16 :f16: 0h7E01 QNAN_F16 :: f16(0h7E01)
INF_F32 :f32: 0h7F80_0000 INF_F32 :: f32(0h7F80_0000)
NEG_INF_F32 :f32: 0hFF80_0000 NEG_INF_F32 :: f32(0hFF80_0000)
SNAN_F32 :f32: 0hFF80_0001 SNAN_F32 :: f32(0hFF80_0001)
QNAN_F32 :f32: 0hFFC0_0001 QNAN_F32 :: f32(0hFFC0_0001)
INF_F64 :f64: 0h7FF0_0000_0000_0000 INF_F64 :: f64(0h7FF0_0000_0000_0000)
NEG_INF_F64 :f64: 0hFFF0_0000_0000_0000 NEG_INF_F64 :: f64(0hFFF0_0000_0000_0000)
SNAN_F64 :f64: 0h7FF0_0000_0000_0001 SNAN_F64 :: f64(0h7FF0_0000_0000_0001)
QNAN_F64 :f64: 0h7FF8_0000_0000_0001 QNAN_F64 :: f64(0h7FF8_0000_0000_0001)
+52 -52
View File
@@ -111,11 +111,11 @@ begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
return tmp return tmp
} }
end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) { end_arena_temp_memory :: proc(tmp: Arena_Temp_Memory) {
assert(arena.offset >= prev_offset) assert(tmp.arena.offset >= tmp.prev_offset)
assert(arena.temp_count > 0) assert(tmp.arena.temp_count > 0)
arena.offset = prev_offset tmp.arena.offset = tmp.prev_offset
arena.temp_count -= 1 tmp.arena.temp_count -= 1
} }
@@ -702,11 +702,11 @@ dynamic_pool_init :: proc(pool: ^Dynamic_Pool,
pool. used_blocks.allocator = array_allocator pool. used_blocks.allocator = array_allocator
} }
dynamic_pool_destroy :: proc(using pool: ^Dynamic_Pool) { dynamic_pool_destroy :: proc(pool: ^Dynamic_Pool) {
dynamic_pool_free_all(pool) dynamic_pool_free_all(pool)
delete(unused_blocks) delete(pool.unused_blocks)
delete(used_blocks) delete(pool.used_blocks)
delete(out_band_allocations) delete(pool.out_band_allocations)
zero(pool, size_of(pool^)) zero(pool, size_of(pool^))
} }
@@ -719,90 +719,90 @@ dynamic_pool_alloc :: proc(pool: ^Dynamic_Pool, bytes: int) -> (rawptr, Allocato
} }
@(require_results) @(require_results)
dynamic_pool_alloc_bytes :: proc(using pool: ^Dynamic_Pool, bytes: int) -> ([]byte, Allocator_Error) { dynamic_pool_alloc_bytes :: proc(p: ^Dynamic_Pool, bytes: int) -> ([]byte, Allocator_Error) {
cycle_new_block :: proc(using pool: ^Dynamic_Pool) -> (err: Allocator_Error) { cycle_new_block :: proc(p: ^Dynamic_Pool) -> (err: Allocator_Error) {
if block_allocator.procedure == nil { if p.block_allocator.procedure == nil {
panic("You must call pool_init on a Pool before using it") panic("You must call pool_init on a Pool before using it")
} }
if current_block != nil { if p.current_block != nil {
append(&used_blocks, current_block) append(&p.used_blocks, p.current_block)
} }
new_block: rawptr new_block: rawptr
if len(unused_blocks) > 0 { if len(p.unused_blocks) > 0 {
new_block = pop(&unused_blocks) new_block = pop(&p.unused_blocks)
} else { } else {
data: []byte data: []byte
data, err = block_allocator.procedure(block_allocator.data, Allocator_Mode.Alloc, data, err = p.block_allocator.procedure(p.block_allocator.data, Allocator_Mode.Alloc,
block_size, alignment, p.block_size, p.alignment,
nil, 0) nil, 0)
new_block = raw_data(data) new_block = raw_data(data)
} }
bytes_left = block_size p.bytes_left = p.block_size
current_pos = new_block p.current_pos = new_block
current_block = new_block p.current_block = new_block
return return
} }
n := bytes n := bytes
extra := alignment - (n % alignment) extra := p.alignment - (n % p.alignment)
n += extra n += extra
if n >= out_band_size { if n >= p.out_band_size {
assert(block_allocator.procedure != nil) assert(p.block_allocator.procedure != nil)
memory, err := block_allocator.procedure(block_allocator.data, Allocator_Mode.Alloc, memory, err := p.block_allocator.procedure(p.block_allocator.data, Allocator_Mode.Alloc,
block_size, alignment, p.block_size, p.alignment,
nil, 0) nil, 0)
if memory != nil { if memory != nil {
append(&out_band_allocations, raw_data(memory)) append(&p.out_band_allocations, raw_data(memory))
} }
return memory, err return memory, err
} }
if bytes_left < n { if p.bytes_left < n {
err := cycle_new_block(pool) err := cycle_new_block(p)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if current_block == nil { if p.current_block == nil {
return nil, .Out_Of_Memory return nil, .Out_Of_Memory
} }
} }
memory := current_pos memory := p.current_pos
current_pos = ptr_offset((^byte)(current_pos), n) p.current_pos = ([^]byte)(p.current_pos)[n:]
bytes_left -= n p.bytes_left -= n
return byte_slice(memory, bytes), nil return ([^]byte)(memory)[:bytes], nil
} }
dynamic_pool_reset :: proc(using pool: ^Dynamic_Pool) { dynamic_pool_reset :: proc(p: ^Dynamic_Pool) {
if current_block != nil { if p.current_block != nil {
append(&unused_blocks, current_block) append(&p.unused_blocks, p.current_block)
current_block = nil p.current_block = nil
} }
for block in used_blocks { for block in p.used_blocks {
append(&unused_blocks, block) append(&p.unused_blocks, block)
} }
clear(&used_blocks) clear(&p.used_blocks)
for a in out_band_allocations { for a in p.out_band_allocations {
free(a, block_allocator) free(a, p.block_allocator)
} }
clear(&out_band_allocations) clear(&p.out_band_allocations)
bytes_left = 0 // Make new allocations call `cycle_new_block` again. p.bytes_left = 0 // Make new allocations call `cycle_new_block` again.
} }
dynamic_pool_free_all :: proc(using pool: ^Dynamic_Pool) { dynamic_pool_free_all :: proc(p: ^Dynamic_Pool) {
dynamic_pool_reset(pool) dynamic_pool_reset(p)
for block in unused_blocks { for block in p.unused_blocks {
free(block, block_allocator) free(block, p.block_allocator)
} }
clear(&unused_blocks) clear(&p.unused_blocks)
} }
+35 -35
View File
@@ -63,100 +63,100 @@ split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host,
} }
join_url :: proc(scheme, host, path: string, queries: map[string]string, allocator := context.allocator) -> string { join_url :: proc(scheme, host, path: string, queries: map[string]string, allocator := context.allocator) -> string {
using strings b := strings.builder_make(allocator)
strings.builder_grow(&b, len(scheme) + 3 + len(host) + 1 + len(path))
b := builder_make(allocator) strings.write_string(&b, scheme)
builder_grow(&b, len(scheme) + 3 + len(host) + 1 + len(path)) strings.write_string(&b, "://")
strings.write_string(&b, strings.trim_space(host))
write_string(&b, scheme)
write_string(&b, "://")
write_string(&b, trim_space(host))
if path != "" { if path != "" {
if path[0] != '/' do write_string(&b, "/") if path[0] != '/' {
write_string(&b, trim_space(path)) strings.write_string(&b, "/")
}
strings.write_string(&b, strings.trim_space(path))
} }
query_length := len(queries) query_length := len(queries)
if query_length > 0 do write_string(&b, "?") if query_length > 0 {
strings.write_string(&b, "?")
}
i := 0 i := 0
for query_name, query_value in queries { for query_name, query_value in queries {
write_string(&b, query_name) strings.write_string(&b, query_name)
if query_value != "" { if query_value != "" {
write_string(&b, "=") strings.write_string(&b, "=")
write_string(&b, query_value) strings.write_string(&b, query_value)
} }
if i < query_length - 1 { if i < query_length - 1 {
write_string(&b, "&") strings.write_string(&b, "&")
} }
i += 1 i += 1
} }
return to_string(b) return strings.to_string(b)
} }
percent_encode :: proc(s: string, allocator := context.allocator) -> string { percent_encode :: proc(s: string, allocator := context.allocator) -> string {
using strings b := strings.builder_make(allocator)
strings.builder_grow(&b, len(s) + 16) // NOTE(tetra): A reasonable number to allow for the number of things we need to escape.
b := builder_make(allocator)
builder_grow(&b, len(s) + 16) // NOTE(tetra): A reasonable number to allow for the number of things we need to escape.
for ch in s { for ch in s {
switch ch { switch ch {
case 'A'..='Z', 'a'..='z', '0'..='9', '-', '_', '.', '~': case 'A'..='Z', 'a'..='z', '0'..='9', '-', '_', '.', '~':
write_rune(&b, ch) strings.write_rune(&b, ch)
case: case:
bytes, n := utf8.encode_rune(ch) bytes, n := utf8.encode_rune(ch)
for byte in bytes[:n] { for byte in bytes[:n] {
buf: [2]u8 = --- buf: [2]u8 = ---
t := strconv.append_int(buf[:], i64(byte), 16) t := strconv.append_int(buf[:], i64(byte), 16)
write_rune(&b, '%') strings.write_rune(&b, '%')
write_string(&b, t) strings.write_string(&b, t)
} }
} }
} }
return to_string(b) return strings.to_string(b)
} }
percent_decode :: proc(encoded_string: string, allocator := context.allocator) -> (decoded_string: string, ok: bool) { percent_decode :: proc(encoded_string: string, allocator := context.allocator) -> (decoded_string: string, ok: bool) {
using strings b := strings.builder_make(allocator)
strings.builder_grow(&b, len(encoded_string))
b := builder_make(allocator) defer if !ok do strings.builder_destroy(&b)
builder_grow(&b, len(encoded_string))
defer if !ok do builder_destroy(&b)
s := encoded_string s := encoded_string
for len(s) > 0 { for len(s) > 0 {
i := index_byte(s, '%') i := strings.index_byte(s, '%')
if i == -1 { if i == -1 {
write_string(&b, s) // no '%'s; the string is already decoded strings.write_string(&b, s) // no '%'s; the string is already decoded
break break
} }
write_string(&b, s[:i]) strings.write_string(&b, s[:i])
s = s[i:] s = s[i:]
if len(s) == 0 do return // percent without anything after it if len(s) == 0 do return // percent without anything after it
s = s[1:] s = s[1:]
if s[0] == '%' { if s[0] == '%' {
write_byte(&b, '%') strings.write_byte(&b, '%')
s = s[1:] s = s[1:]
continue continue
} }
if len(s) < 2 do return // percent without encoded value if len(s) < 2 {
return // percent without encoded value
}
val := hex.decode_sequence(s[:2]) or_return val := hex.decode_sequence(s[:2]) or_return
write_byte(&b, val) strings.write_byte(&b, val)
s = s[2:] s = s[2:]
} }
ok = true ok = true
decoded_string = to_string(b) decoded_string = strings.to_string(b)
return return
} }
+86 -92
View File
@@ -336,22 +336,20 @@ hint_current_line :: proc(p: ^Printer, hint: Line_Type) {
@(private) @(private)
visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
using ast
if decl == nil { if decl == nil {
return return
} }
#partial switch v in decl.derived_stmt { #partial switch v in decl.derived_stmt {
case ^Expr_Stmt: case ^ast.Expr_Stmt:
move_line(p, decl.pos) move_line(p, decl.pos)
visit_expr(p, v.expr) visit_expr(p, v.expr)
if p.config.semicolons { if p.config.semicolons {
push_generic_token(p, .Semicolon, 0) push_generic_token(p, .Semicolon, 0)
} }
case ^When_Stmt: case ^ast.When_Stmt:
visit_stmt(p, cast(^Stmt)decl) visit_stmt(p, cast(^ast.Stmt)decl)
case ^Foreign_Import_Decl: case ^ast.Foreign_Import_Decl:
if len(v.attributes) > 0 { if len(v.attributes) > 0 {
sort.sort(sort_attribute(&v.attributes)) sort.sort(sort_attribute(&v.attributes))
move_line(p, v.attributes[0].pos) move_line(p, v.attributes[0].pos)
@@ -370,7 +368,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
for path in v.fullpaths { for path in v.fullpaths {
push_ident_token(p, path, 0) push_ident_token(p, path, 0)
} }
case ^Foreign_Block_Decl: case ^ast.Foreign_Block_Decl:
if len(v.attributes) > 0 { if len(v.attributes) > 0 {
sort.sort(sort_attribute(&v.attributes)) sort.sort(sort_attribute(&v.attributes))
move_line(p, v.attributes[0].pos) move_line(p, v.attributes[0].pos)
@@ -383,7 +381,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
visit_expr(p, v.foreign_library) visit_expr(p, v.foreign_library)
visit_stmt(p, v.body) visit_stmt(p, v.body)
case ^Import_Decl: case ^ast.Import_Decl:
move_line(p, decl.pos) move_line(p, decl.pos)
if v.name.text != "" { if v.name.text != "" {
@@ -395,7 +393,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
push_ident_token(p, v.fullpath, 1) push_ident_token(p, v.fullpath, 1)
} }
case ^Value_Decl: case ^ast.Value_Decl:
if len(v.attributes) > 0 { if len(v.attributes) > 0 {
sort.sort(sort_attribute(&v.attributes)) sort.sort(sort_attribute(&v.attributes))
move_line(p, v.attributes[0].pos) move_line(p, v.attributes[0].pos)
@@ -447,9 +445,9 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
for value in v.values { for value in v.values {
#partial switch a in value.derived { #partial switch a in value.derived {
case ^Union_Type, ^Enum_Type, ^Struct_Type: case ^ast.Union_Type, ^ast.Enum_Type, ^ast.Struct_Type:
add_semicolon = false || called_in_stmt add_semicolon = false || called_in_stmt
case ^Proc_Lit: case ^ast.Proc_Lit:
add_semicolon = false add_semicolon = false
} }
} }
@@ -510,40 +508,38 @@ visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) {
@(private) @(private)
visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Generic, empty_block := false, block_stmt := false) { visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Generic, empty_block := false, block_stmt := false) {
using ast
if stmt == nil { if stmt == nil {
return return
} }
switch v in stmt.derived_stmt { switch v in stmt.derived_stmt {
case ^Bad_Stmt: case ^ast.Bad_Stmt:
case ^Bad_Decl: case ^ast.Bad_Decl:
case ^Package_Decl: case ^ast.Package_Decl:
case ^Empty_Stmt: case ^ast.Empty_Stmt:
push_generic_token(p, .Semicolon, 0) push_generic_token(p, .Semicolon, 0)
case ^Tag_Stmt: case ^ast.Tag_Stmt:
push_generic_token(p, .Hash, 1) push_generic_token(p, .Hash, 1)
push_generic_token(p, v.op.kind, 1, v.op.text) push_generic_token(p, v.op.kind, 1, v.op.text)
visit_stmt(p, v.stmt) visit_stmt(p, v.stmt)
case ^Import_Decl: case ^ast.Import_Decl:
visit_decl(p, cast(^Decl)stmt, true) visit_decl(p, cast(^ast.Decl)stmt, true)
return return
case ^Value_Decl: case ^ast.Value_Decl:
visit_decl(p, cast(^Decl)stmt, true) visit_decl(p, cast(^ast.Decl)stmt, true)
return return
case ^Foreign_Import_Decl: case ^ast.Foreign_Import_Decl:
visit_decl(p, cast(^Decl)stmt, true) visit_decl(p, cast(^ast.Decl)stmt, true)
return return
case ^Foreign_Block_Decl: case ^ast.Foreign_Block_Decl:
visit_decl(p, cast(^Decl)stmt, true) visit_decl(p, cast(^ast.Decl)stmt, true)
return return
case ^Using_Stmt: case ^ast.Using_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
push_generic_token(p, .Using, 1) push_generic_token(p, .Using, 1)
@@ -553,7 +549,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
if p.config.semicolons { if p.config.semicolons {
push_generic_token(p, .Semicolon, 0) push_generic_token(p, .Semicolon, 0)
} }
case ^Block_Stmt: case ^ast.Block_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
if v.pos.line == v.end.line { if v.pos.line == v.end.line {
@@ -583,7 +579,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_end_brace(p, v.end) visit_end_brace(p, v.end)
} }
} }
case ^If_Stmt: case ^ast.If_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
if v.label != nil { if v.label != nil {
@@ -606,7 +602,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
uses_do := false uses_do := false
if check_stmt, ok := v.body.derived.(^Block_Stmt); ok && check_stmt.uses_do { if check_stmt, ok := v.body.derived.(^ast.Block_Stmt); ok && check_stmt.uses_do {
uses_do = true uses_do = true
} }
@@ -637,7 +633,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_stmt(p, v.else_stmt) visit_stmt(p, v.else_stmt)
} }
case ^Switch_Stmt: case ^ast.Switch_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
if v.label != nil { if v.label != nil {
@@ -665,7 +661,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_expr(p, v.cond) visit_expr(p, v.cond)
visit_stmt(p, v.body) visit_stmt(p, v.body)
case ^Case_Clause: case ^ast.Case_Clause:
move_line(p, v.pos) move_line(p, v.pos)
if !p.config.indent_cases { if !p.config.indent_cases {
@@ -689,7 +685,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
if !p.config.indent_cases { if !p.config.indent_cases {
indent(p) indent(p)
} }
case ^Type_Switch_Stmt: case ^ast.Type_Switch_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
hint_current_line(p, {.Switch_Stmt}) hint_current_line(p, {.Switch_Stmt})
@@ -707,7 +703,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_stmt(p, v.tag) visit_stmt(p, v.tag)
visit_stmt(p, v.body) visit_stmt(p, v.body)
case ^Assign_Stmt: case ^ast.Assign_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
hint_current_line(p, {.Assign}) hint_current_line(p, {.Assign})
@@ -721,13 +717,13 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
if block_stmt && p.config.semicolons { if block_stmt && p.config.semicolons {
push_generic_token(p, .Semicolon, 0) push_generic_token(p, .Semicolon, 0)
} }
case ^Expr_Stmt: case ^ast.Expr_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
visit_expr(p, v.expr) visit_expr(p, v.expr)
if block_stmt && p.config.semicolons { if block_stmt && p.config.semicolons {
push_generic_token(p, .Semicolon, 0) push_generic_token(p, .Semicolon, 0)
} }
case ^For_Stmt: case ^ast.For_Stmt:
// this should be simplified // this should be simplified
move_line(p, v.pos) move_line(p, v.pos)
@@ -764,7 +760,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_stmt(p, v.body) visit_stmt(p, v.body)
case ^Inline_Range_Stmt: case ^ast.Inline_Range_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
if v.label != nil { if v.label != nil {
@@ -790,7 +786,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_expr(p, v.expr) visit_expr(p, v.expr)
visit_stmt(p, v.body) visit_stmt(p, v.body)
case ^Range_Stmt: case ^ast.Range_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
if v.label != nil { if v.label != nil {
@@ -816,7 +812,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_expr(p, v.expr) visit_expr(p, v.expr)
visit_stmt(p, v.body) visit_stmt(p, v.body)
case ^Return_Stmt: case ^ast.Return_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
push_generic_token(p, .Return, 1) push_generic_token(p, .Return, 1)
@@ -828,7 +824,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
if block_stmt && p.config.semicolons { if block_stmt && p.config.semicolons {
push_generic_token(p, .Semicolon, 0) push_generic_token(p, .Semicolon, 0)
} }
case ^Defer_Stmt: case ^ast.Defer_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
push_generic_token(p, .Defer, 0) push_generic_token(p, .Defer, 0)
@@ -837,7 +833,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
if p.config.semicolons { if p.config.semicolons {
push_generic_token(p, .Semicolon, 0) push_generic_token(p, .Semicolon, 0)
} }
case ^When_Stmt: case ^ast.When_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
push_generic_token(p, .When, 1) push_generic_token(p, .When, 1)
visit_expr(p, v.cond) visit_expr(p, v.cond)
@@ -857,7 +853,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_stmt(p, v.else_stmt) visit_stmt(p, v.else_stmt)
} }
case ^Branch_Stmt: case ^ast.Branch_Stmt:
move_line(p, v.pos) move_line(p, v.pos)
push_generic_token(p, v.tok.kind, 0) push_generic_token(p, v.tok.kind, 0)
@@ -921,8 +917,6 @@ push_poly_params :: proc(p: ^Printer, poly_params: ^ast.Field_List) {
@(private) @(private)
visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
using ast
if expr == nil { if expr == nil {
return return
} }
@@ -930,14 +924,14 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
set_source_position(p, expr.pos) set_source_position(p, expr.pos)
switch v in expr.derived_expr { switch v in expr.derived_expr {
case ^Bad_Expr: case ^ast.Bad_Expr:
case ^Tag_Expr: case ^ast.Tag_Expr:
push_generic_token(p, .Hash, 1) push_generic_token(p, .Hash, 1)
push_generic_token(p, v.op.kind, 1, v.op.text) push_generic_token(p, v.op.kind, 1, v.op.text)
visit_expr(p, v.expr) visit_expr(p, v.expr)
case ^Inline_Asm_Expr: case ^ast.Inline_Asm_Expr:
push_generic_token(p, v.tok.kind, 1, v.tok.text) push_generic_token(p, v.tok.kind, 1, v.tok.text)
push_generic_token(p, .Open_Paren, 1) push_generic_token(p, .Open_Paren, 1)
@@ -954,42 +948,42 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
push_generic_token(p, .Comma, 0) push_generic_token(p, .Comma, 0)
visit_expr(p, v.constraints_string) visit_expr(p, v.constraints_string)
push_generic_token(p, .Close_Brace, 0) push_generic_token(p, .Close_Brace, 0)
case ^Undef: case ^ast.Undef:
push_generic_token(p, .Undef, 1) push_generic_token(p, .Undef, 1)
case ^Auto_Cast: case ^ast.Auto_Cast:
push_generic_token(p, v.op.kind, 1) push_generic_token(p, v.op.kind, 1)
visit_expr(p, v.expr) visit_expr(p, v.expr)
case ^Ternary_If_Expr: case ^ast.Ternary_If_Expr:
visit_expr(p, v.x) visit_expr(p, v.x)
push_generic_token(p, v.op1.kind, 1) push_generic_token(p, v.op1.kind, 1)
visit_expr(p, v.cond) visit_expr(p, v.cond)
push_generic_token(p, v.op2.kind, 1) push_generic_token(p, v.op2.kind, 1)
visit_expr(p, v.y) visit_expr(p, v.y)
case ^Ternary_When_Expr: case ^ast.Ternary_When_Expr:
visit_expr(p, v.x) visit_expr(p, v.x)
push_generic_token(p, v.op1.kind, 1) push_generic_token(p, v.op1.kind, 1)
visit_expr(p, v.cond) visit_expr(p, v.cond)
push_generic_token(p, v.op2.kind, 1) push_generic_token(p, v.op2.kind, 1)
visit_expr(p, v.y) visit_expr(p, v.y)
case ^Or_Else_Expr: case ^ast.Or_Else_Expr:
visit_expr(p, v.x) visit_expr(p, v.x)
push_generic_token(p, v.token.kind, 1) push_generic_token(p, v.token.kind, 1)
visit_expr(p, v.y) visit_expr(p, v.y)
case ^Or_Return_Expr: case ^ast.Or_Return_Expr:
visit_expr(p, v.expr) visit_expr(p, v.expr)
push_generic_token(p, v.token.kind, 1) push_generic_token(p, v.token.kind, 1)
case ^Selector_Call_Expr: case ^ast.Selector_Call_Expr:
visit_expr(p, v.call.expr) visit_expr(p, v.call.expr)
push_generic_token(p, .Open_Paren, 1) push_generic_token(p, .Open_Paren, 1)
visit_exprs(p, v.call.args, {.Add_Comma}) visit_exprs(p, v.call.args, {.Add_Comma})
push_generic_token(p, .Close_Paren, 0) push_generic_token(p, .Close_Paren, 0)
case ^Ellipsis: case ^ast.Ellipsis:
push_generic_token(p, .Ellipsis, 1) push_generic_token(p, .Ellipsis, 1)
visit_expr(p, v.expr) visit_expr(p, v.expr)
case ^Relative_Type: case ^ast.Relative_Type:
visit_expr(p, v.tag) visit_expr(p, v.tag)
visit_expr(p, v.type) visit_expr(p, v.type)
case ^Slice_Expr: case ^ast.Slice_Expr:
visit_expr(p, v.expr) visit_expr(p, v.expr)
push_generic_token(p, .Open_Bracket, 0) push_generic_token(p, .Open_Bracket, 0)
visit_expr(p, v.low) visit_expr(p, v.low)
@@ -999,37 +993,37 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
visit_expr(p, v.high) visit_expr(p, v.high)
} }
push_generic_token(p, .Close_Bracket, 0) push_generic_token(p, .Close_Bracket, 0)
case ^Ident: case ^ast.Ident:
if .Enforce_Poly_Names in options { if .Enforce_Poly_Names in options {
push_generic_token(p, .Dollar, 1) push_generic_token(p, .Dollar, 1)
push_ident_token(p, v.name, 0) push_ident_token(p, v.name, 0)
} else { } else {
push_ident_token(p, v.name, 1) push_ident_token(p, v.name, 1)
} }
case ^Deref_Expr: case ^ast.Deref_Expr:
visit_expr(p, v.expr) visit_expr(p, v.expr)
push_generic_token(p, v.op.kind, 0) push_generic_token(p, v.op.kind, 0)
case ^Type_Cast: case ^ast.Type_Cast:
push_generic_token(p, v.tok.kind, 1) push_generic_token(p, v.tok.kind, 1)
push_generic_token(p, .Open_Paren, 0) push_generic_token(p, .Open_Paren, 0)
visit_expr(p, v.type) visit_expr(p, v.type)
push_generic_token(p, .Close_Paren, 0) push_generic_token(p, .Close_Paren, 0)
merge_next_token(p) merge_next_token(p)
visit_expr(p, v.expr) visit_expr(p, v.expr)
case ^Basic_Directive: case ^ast.Basic_Directive:
push_generic_token(p, v.tok.kind, 1) push_generic_token(p, v.tok.kind, 1)
push_ident_token(p, v.name, 0) push_ident_token(p, v.name, 0)
case ^Distinct_Type: case ^ast.Distinct_Type:
push_generic_token(p, .Distinct, 1) push_generic_token(p, .Distinct, 1)
visit_expr(p, v.type) visit_expr(p, v.type)
case ^Dynamic_Array_Type: case ^ast.Dynamic_Array_Type:
visit_expr(p, v.tag) visit_expr(p, v.tag)
push_generic_token(p, .Open_Bracket, 1) push_generic_token(p, .Open_Bracket, 1)
push_generic_token(p, .Dynamic, 0) push_generic_token(p, .Dynamic, 0)
push_generic_token(p, .Close_Bracket, 0) push_generic_token(p, .Close_Bracket, 0)
merge_next_token(p) merge_next_token(p)
visit_expr(p, v.elem) visit_expr(p, v.elem)
case ^Bit_Set_Type: case ^ast.Bit_Set_Type:
push_generic_token(p, .Bit_Set, 1) push_generic_token(p, .Bit_Set, 1)
push_generic_token(p, .Open_Bracket, 0) push_generic_token(p, .Open_Bracket, 0)
@@ -1041,7 +1035,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
} }
push_generic_token(p, .Close_Bracket, 0) push_generic_token(p, .Close_Bracket, 0)
case ^Union_Type: case ^ast.Union_Type:
push_generic_token(p, .Union, 1) push_generic_token(p, .Union, 1)
push_poly_params(p, v.poly_params) push_poly_params(p, v.poly_params)
@@ -1066,7 +1060,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
visit_exprs(p, v.variants, {.Add_Comma, .Trailing}) visit_exprs(p, v.variants, {.Add_Comma, .Trailing})
visit_end_brace(p, v.end) visit_end_brace(p, v.end)
} }
case ^Enum_Type: case ^ast.Enum_Type:
push_generic_token(p, .Enum, 1) push_generic_token(p, .Enum, 1)
hint_current_line(p, {.Enum}) hint_current_line(p, {.Enum})
@@ -1089,7 +1083,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
} }
set_source_position(p, v.end) set_source_position(p, v.end)
case ^Struct_Type: case ^ast.Struct_Type:
push_generic_token(p, .Struct, 1) push_generic_token(p, .Struct, 1)
hint_current_line(p, {.Struct}) hint_current_line(p, {.Struct})
@@ -1124,7 +1118,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
} }
set_source_position(p, v.end) set_source_position(p, v.end)
case ^Proc_Lit: case ^ast.Proc_Lit:
switch v.inlining { switch v.inlining {
case .None: case .None:
case .Inline: case .Inline:
@@ -1143,16 +1137,16 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
} else { } else {
push_generic_token(p, .Undef, 1) push_generic_token(p, .Undef, 1)
} }
case ^Proc_Type: case ^ast.Proc_Type:
visit_proc_type(p, v) visit_proc_type(p, v)
case ^Basic_Lit: case ^ast.Basic_Lit:
push_generic_token(p, v.tok.kind, 1, v.tok.text) push_generic_token(p, v.tok.kind, 1, v.tok.text)
case ^Binary_Expr: case ^ast.Binary_Expr:
visit_binary_expr(p, v) visit_binary_expr(p, v)
case ^Implicit_Selector_Expr: case ^ast.Implicit_Selector_Expr:
push_generic_token(p, .Period, 1) push_generic_token(p, .Period, 1)
push_ident_token(p, v.field.name, 0) push_ident_token(p, v.field.name, 0)
case ^Call_Expr: case ^ast.Call_Expr:
visit_expr(p, v.expr) visit_expr(p, v.expr)
push_format_token(p, push_format_token(p,
@@ -1167,34 +1161,34 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis) visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis)
push_generic_token(p, .Close_Paren, 0) push_generic_token(p, .Close_Paren, 0)
case ^Typeid_Type: case ^ast.Typeid_Type:
push_generic_token(p, .Typeid, 1) push_generic_token(p, .Typeid, 1)
if v.specialization != nil { if v.specialization != nil {
push_generic_token(p, .Quo, 0) push_generic_token(p, .Quo, 0)
visit_expr(p, v.specialization) visit_expr(p, v.specialization)
} }
case ^Selector_Expr: case ^ast.Selector_Expr:
visit_expr(p, v.expr) visit_expr(p, v.expr)
push_generic_token(p, v.op.kind, 0) push_generic_token(p, v.op.kind, 0)
visit_expr(p, v.field) visit_expr(p, v.field)
case ^Paren_Expr: case ^ast.Paren_Expr:
push_generic_token(p, .Open_Paren, 1) push_generic_token(p, .Open_Paren, 1)
visit_expr(p, v.expr) visit_expr(p, v.expr)
push_generic_token(p, .Close_Paren, 0) push_generic_token(p, .Close_Paren, 0)
case ^Index_Expr: case ^ast.Index_Expr:
visit_expr(p, v.expr) visit_expr(p, v.expr)
push_generic_token(p, .Open_Bracket, 0) push_generic_token(p, .Open_Bracket, 0)
visit_expr(p, v.index) visit_expr(p, v.index)
push_generic_token(p, .Close_Bracket, 0) push_generic_token(p, .Close_Bracket, 0)
case ^Matrix_Index_Expr: case ^ast.Matrix_Index_Expr:
visit_expr(p, v.expr) visit_expr(p, v.expr)
push_generic_token(p, .Open_Bracket, 0) push_generic_token(p, .Open_Bracket, 0)
visit_expr(p, v.row_index) visit_expr(p, v.row_index)
push_generic_token(p, .Comma, 0) push_generic_token(p, .Comma, 0)
visit_expr(p, v.column_index) visit_expr(p, v.column_index)
push_generic_token(p, .Close_Bracket, 0) push_generic_token(p, .Close_Bracket, 0)
case ^Proc_Group: case ^ast.Proc_Group:
push_generic_token(p, v.tok.kind, 1) push_generic_token(p, v.tok.kind, 1)
if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line { if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line {
@@ -1209,7 +1203,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
push_generic_token(p, .Close_Brace, 0) push_generic_token(p, .Close_Brace, 0)
} }
case ^Comp_Lit: case ^ast.Comp_Lit:
if v.type != nil { if v.type != nil {
visit_expr(p, v.type) visit_expr(p, v.type)
} }
@@ -1226,18 +1220,18 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
push_generic_token(p, .Close_Brace, 0) push_generic_token(p, .Close_Brace, 0)
} }
case ^Unary_Expr: case ^ast.Unary_Expr:
push_generic_token(p, v.op.kind, 1) push_generic_token(p, v.op.kind, 1)
merge_next_token(p) merge_next_token(p)
visit_expr(p, v.expr) visit_expr(p, v.expr)
case ^Field_Value: case ^ast.Field_Value:
visit_expr(p, v.field) visit_expr(p, v.field)
push_generic_token(p, .Eq, 1) push_generic_token(p, .Eq, 1)
visit_expr(p, v.value) visit_expr(p, v.value)
case ^Type_Assertion: case ^ast.Type_Assertion:
visit_expr(p, v.expr) visit_expr(p, v.expr)
if unary, ok := v.type.derived.(^Unary_Expr); ok && unary.op.text == "?" { if unary, ok := v.type.derived.(^ast.Unary_Expr); ok && unary.op.text == "?" {
push_generic_token(p, .Period, 0) push_generic_token(p, .Period, 0)
visit_expr(p, v.type) visit_expr(p, v.type)
} else { } else {
@@ -1247,13 +1241,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
push_generic_token(p, .Close_Paren, 0) push_generic_token(p, .Close_Paren, 0)
} }
case ^Pointer_Type: case ^ast.Pointer_Type:
push_generic_token(p, .Pointer, 1) push_generic_token(p, .Pointer, 1)
merge_next_token(p) merge_next_token(p)
visit_expr(p, v.elem) visit_expr(p, v.elem)
case ^Implicit: case ^ast.Implicit:
push_generic_token(p, v.tok.kind, 1) push_generic_token(p, v.tok.kind, 1)
case ^Poly_Type: case ^ast.Poly_Type:
push_generic_token(p, .Dollar, 1) push_generic_token(p, .Dollar, 1)
merge_next_token(p) merge_next_token(p)
visit_expr(p, v.type) visit_expr(p, v.type)
@@ -1263,28 +1257,28 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
merge_next_token(p) merge_next_token(p)
visit_expr(p, v.specialization) visit_expr(p, v.specialization)
} }
case ^Array_Type: case ^ast.Array_Type:
visit_expr(p, v.tag) visit_expr(p, v.tag)
push_generic_token(p, .Open_Bracket, 1) push_generic_token(p, .Open_Bracket, 1)
visit_expr(p, v.len) visit_expr(p, v.len)
push_generic_token(p, .Close_Bracket, 0) push_generic_token(p, .Close_Bracket, 0)
merge_next_token(p) merge_next_token(p)
visit_expr(p, v.elem) visit_expr(p, v.elem)
case ^Map_Type: case ^ast.Map_Type:
push_generic_token(p, .Map, 1) push_generic_token(p, .Map, 1)
push_generic_token(p, .Open_Bracket, 0) push_generic_token(p, .Open_Bracket, 0)
visit_expr(p, v.key) visit_expr(p, v.key)
push_generic_token(p, .Close_Bracket, 0) push_generic_token(p, .Close_Bracket, 0)
merge_next_token(p) merge_next_token(p)
visit_expr(p, v.value) visit_expr(p, v.value)
case ^Helper_Type: case ^ast.Helper_Type:
visit_expr(p, v.type) visit_expr(p, v.type)
case ^Multi_Pointer_Type: case ^ast.Multi_Pointer_Type:
push_generic_token(p, .Open_Bracket, 1) push_generic_token(p, .Open_Bracket, 1)
push_generic_token(p, .Pointer, 0) push_generic_token(p, .Pointer, 0)
push_generic_token(p, .Close_Bracket, 0) push_generic_token(p, .Close_Bracket, 0)
visit_expr(p, v.elem) visit_expr(p, v.elem)
case ^Matrix_Type: case ^ast.Matrix_Type:
push_generic_token(p, .Matrix, 1) push_generic_token(p, .Matrix, 1)
push_generic_token(p, .Open_Bracket, 0) push_generic_token(p, .Open_Bracket, 0)
visit_expr(p, v.row_count) visit_expr(p, v.row_count)
+16 -16
View File
@@ -75,34 +75,34 @@ error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
t.error_count += 1 t.error_count += 1
} }
advance_rune :: proc(using t: ^Tokenizer) { advance_rune :: proc(t: ^Tokenizer) {
if read_offset < len(src) { if t.read_offset < len(t.src) {
offset = read_offset t.offset = t.read_offset
if ch == '\n' { if t.ch == '\n' {
line_offset = offset t.line_offset = t.offset
line_count += 1 t.line_count += 1
} }
r, w := rune(src[read_offset]), 1 r, w := rune(t.src[t.read_offset]), 1
switch { switch {
case r == 0: case r == 0:
error(t, t.offset, "illegal character NUL") error(t, t.offset, "illegal character NUL")
case r >= utf8.RUNE_SELF: case r >= utf8.RUNE_SELF:
r, w = utf8.decode_rune_in_string(src[read_offset:]) r, w = utf8.decode_rune_in_string(t.src[t.read_offset:])
if r == utf8.RUNE_ERROR && w == 1 { if r == utf8.RUNE_ERROR && w == 1 {
error(t, t.offset, "illegal UTF-8 encoding") error(t, t.offset, "illegal UTF-8 encoding")
} else if r == utf8.RUNE_BOM && offset > 0 { } else if r == utf8.RUNE_BOM && t.offset > 0 {
error(t, t.offset, "illegal byte order mark") error(t, t.offset, "illegal byte order mark")
} }
} }
read_offset += w t.read_offset += w
ch = r t.ch = r
} else { } else {
offset = len(src) t.offset = len(t.src)
if ch == '\n' { if t.ch == '\n' {
line_offset = offset t.line_offset = t.offset
line_count += 1 t.line_count += 1
} }
ch = -1 t.ch = -1
} }
} }
+118 -98
View File
@@ -414,68 +414,21 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
tk := map_cell_index_dynamic(sk, info.ks, 1) tk := map_cell_index_dynamic(sk, info.ks, 1)
tv := map_cell_index_dynamic(sv, info.vs, 1) tv := map_cell_index_dynamic(sv, info.vs, 1)
for { swap_loop: for {
hp := &hs[pos] element_hash := hs[pos]
element_hash := hp^
if map_hash_is_empty(element_hash) { if map_hash_is_empty(element_hash) {
kp := map_cell_index_dynamic(ks, info.ks, pos) k_dst := map_cell_index_dynamic(ks, info.ks, pos)
vp := map_cell_index_dynamic(vs, info.vs, pos) v_dst := map_cell_index_dynamic(vs, info.vs, pos)
intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k) intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v) intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
hp^ = h hs[pos] = h
return result if result != 0 else vp return result if result != 0 else v_dst
} }
if map_hash_is_deleted(element_hash) { if map_hash_is_deleted(element_hash) {
next_pos := (pos + 1) & mask break swap_loop
// backward shift
for !map_hash_is_empty(hs[next_pos]) {
probe_distance := map_probe_distance(m^, hs[next_pos], next_pos)
if probe_distance == 0 {
break
}
probe_distance -= 1
kp := map_cell_index_dynamic(ks, info.ks, pos)
vp := map_cell_index_dynamic(vs, info.vs, pos)
kn := map_cell_index_dynamic(ks, info.ks, next_pos)
vn := map_cell_index_dynamic(vs, info.vs, next_pos)
if distance > probe_distance {
if result == 0 {
result = vp
}
// move stored into pos; store next
intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v)
hs[pos] = h
intrinsics.mem_copy_non_overlapping(rawptr(k), rawptr(kn), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(v), rawptr(vn), size_of_v)
h = hs[next_pos]
} else {
// move next back 1
intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(kn), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(vn), size_of_v)
hs[pos] = hs[next_pos]
distance = probe_distance
}
hs[next_pos] = 0
pos = (pos + 1) & mask
next_pos = (next_pos + 1) & mask
distance += 1
}
kp := map_cell_index_dynamic(ks, info.ks, pos)
vp := map_cell_index_dynamic(vs, info.vs, pos)
intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v)
hs[pos] = h
return result if result != 0 else vp
} }
if probe_distance := map_probe_distance(m^, element_hash, pos); distance > probe_distance { if probe_distance := map_probe_distance(m^, element_hash, pos); distance > probe_distance {
@@ -495,8 +448,8 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(tv), size_of_v) intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(tv), size_of_v)
th := h th := h
h = hp^ h = hs[pos]
hp^ = th hs[pos] = th
distance = probe_distance distance = probe_distance
} }
@@ -504,6 +457,103 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
pos = (pos + 1) & mask pos = (pos + 1) & mask
distance += 1 distance += 1
} }
// backward shift loop
hs[pos] = 0
look_ahead: uintptr = 1
for {
la_pos := (pos + look_ahead) & mask
element_hash := hs[la_pos]
if map_hash_is_deleted(element_hash) {
look_ahead += 1
hs[la_pos] = 0
continue
}
k_dst := map_cell_index_dynamic(ks, info.ks, pos)
v_dst := map_cell_index_dynamic(vs, info.vs, pos)
if map_hash_is_empty(element_hash) {
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
hs[pos] = h
return result if result != 0 else v_dst
}
k_src := map_cell_index_dynamic(ks, info.ks, la_pos)
v_src := map_cell_index_dynamic(vs, info.vs, la_pos)
probe_distance := map_probe_distance(m^, element_hash, la_pos)
if probe_distance < look_ahead {
// probed can be made ideal while placing saved (ending condition)
if result == 0 {
result = v_dst
}
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
hs[pos] = h
// This will be an ideal move
pos = (la_pos - probe_distance) & mask
look_ahead -= probe_distance
// shift until we hit ideal/empty
for probe_distance != 0 {
k_dst = map_cell_index_dynamic(ks, info.ks, pos)
v_dst = map_cell_index_dynamic(vs, info.vs, pos)
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k_src), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v_src), size_of_v)
hs[pos] = element_hash
hs[la_pos] = 0
pos = (pos + 1) & mask
la_pos = (la_pos + 1) & mask
look_ahead = (la_pos - pos) & mask
element_hash = hs[la_pos]
if map_hash_is_empty(element_hash) {
return
}
probe_distance = map_probe_distance(m^, element_hash, la_pos)
if probe_distance == 0 {
return
}
// can be ideal?
if probe_distance < look_ahead {
pos = (la_pos - probe_distance) & mask
}
k_src = map_cell_index_dynamic(ks, info.ks, la_pos)
v_src = map_cell_index_dynamic(vs, info.vs, la_pos)
}
return
} else if distance < probe_distance - look_ahead {
// shift back probed
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k_src), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v_src), size_of_v)
hs[pos] = element_hash
hs[la_pos] = 0
} else {
// place saved, save probed
if result == 0 {
result = v_dst
}
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
hs[pos] = h
intrinsics.mem_copy_non_overlapping(rawptr(k), rawptr(k_src), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(v), rawptr(v_src), size_of_v)
h = hs[la_pos]
hs[la_pos] = 0
distance = probe_distance - look_ahead
}
pos = (pos + 1) & mask
distance += 1
}
} }
@(require_results) @(require_results)
@@ -696,49 +746,19 @@ map_erase_dynamic :: #force_inline proc "contextless" (#no_alias m: ^Raw_Map, #n
m.len -= 1 m.len -= 1
ok = true ok = true
{ // coalesce tombstones mask := (uintptr(1)<<map_log2_cap(m^)) - 1
// HACK NOTE(bill): This is an ugly bodge but it is coalescing the tombstone slots curr_index := uintptr(index)
mask := (uintptr(1)<<map_log2_cap(m^)) - 1 next_index := (curr_index + 1) & mask
curr_index := uintptr(index)
// TODO(bill): determine a good value for this empirically
// if we do not implement backward shift deletion
PROBE_COUNT :: 8
for _ in 0..<PROBE_COUNT {
next_index := (curr_index + 1) & mask
if next_index == index {
// looped around
break
}
// if the next element is empty or has zero probe distance, then any lookup
// will always fail on the next, so we can clear both of them
hash := hs[next_index]
if map_hash_is_empty(hash) || map_probe_distance(m^, hash, next_index) == 0 {
hs[curr_index] = 0
return
}
// now the next element will have a probe count of at least one,
// so it can use the delete slot instead
hs[curr_index] = hs[next_index]
mem_copy_non_overlapping(
rawptr(map_cell_index_dynamic(ks, info.ks, curr_index)),
rawptr(map_cell_index_dynamic(ks, info.ks, next_index)),
int(info.ks.size_of_type),
)
mem_copy_non_overlapping(
rawptr(map_cell_index_dynamic(vs, info.vs, curr_index)),
rawptr(map_cell_index_dynamic(vs, info.vs, next_index)),
int(info.vs.size_of_type),
)
curr_index = next_index
}
// if the next element is empty or has zero probe distance, then any lookup
// will always fail on the next, so we can clear both of them
hash := hs[next_index]
if map_hash_is_empty(hash) || map_probe_distance(m^, hash, next_index) == 0 {
hs[curr_index] = 0
} else {
hs[curr_index] |= TOMBSTONE_MASK hs[curr_index] |= TOMBSTONE_MASK
} }
return return
} }
+2
View File
@@ -71,6 +71,8 @@ Error :: enum {
TS_File_Expected_Source, TS_File_Expected_Source,
TS_File_Expected_Translation, TS_File_Expected_Translation,
TS_File_Expected_NumerusForm, TS_File_Expected_NumerusForm,
Bad_Str,
Bad_Id,
} }
+34 -8
View File
@@ -30,10 +30,26 @@ TS_XML_Options := xml.Options{
parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) {
context.allocator = allocator context.allocator = allocator
get_str :: proc(val: xml.Value) -> (str: string, err: Error) {
v, ok := val.(string)
if ok {
return v, .None
}
return "", .Bad_Str
}
get_id :: proc(val: xml.Value) -> (str: xml.Element_ID, err: Error) {
v, ok := val.(xml.Element_ID)
if ok {
return v, .None
}
return 0, .Bad_Id
}
ts, xml_err := xml.parse(data, TS_XML_Options) ts, xml_err := xml.parse(data, TS_XML_Options)
defer xml.destroy(ts) defer xml.destroy(ts)
if xml_err != .None || ts.element_count < 1 || ts.elements[0].ident != "TS" || len(ts.elements[0].children) == 0 { if xml_err != .None || ts.element_count < 1 || ts.elements[0].ident != "TS" || len(ts.elements[0].value) == 0 {
return nil, .TS_File_Parse_Error return nil, .TS_File_Parse_Error
} }
@@ -46,10 +62,12 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
section: ^Section section: ^Section
for child_id in ts.elements[0].children { for value in ts.elements[0].value {
child_id := get_id(value) or_return
// These should be <context>s. // These should be <context>s.
child := ts.elements[child_id]
if child.ident != "context" { if ts.elements[child_id].ident != "context" {
return translation, .TS_File_Expected_Context return translation, .TS_File_Expected_Context
} }
@@ -61,7 +79,8 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
section_name, _ := strings.intern_get(&translation.intern, "") section_name, _ := strings.intern_get(&translation.intern, "")
if !options.merge_sections { if !options.merge_sections {
section_name, _ = strings.intern_get(&translation.intern, ts.elements[section_name_id].value) value_text := get_str(ts.elements[section_name_id].value[0]) or_return
section_name, _ = strings.intern_get(&translation.intern, value_text)
} }
if section_name not_in translation.k_v { if section_name not_in translation.k_v {
@@ -92,8 +111,14 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
return translation, .TS_File_Expected_Translation return translation, .TS_File_Expected_Translation
} }
source, _ := strings.intern_get(&translation.intern, ts.elements[source_id].value) source := get_str(ts.elements[source_id].value[0]) or_return
xlat, _ := strings.intern_get(&translation.intern, ts.elements[translation_id].value) source, _ = strings.intern_get(&translation.intern, source)
xlat := ""
if !has_plurals {
xlat = get_str(ts.elements[translation_id].value[0]) or_return
xlat, _ = strings.intern_get(&translation.intern, xlat)
}
if source in section { if source in section {
return translation, .Duplicate_Key return translation, .Duplicate_Key
@@ -124,7 +149,8 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
if !numerus_found { if !numerus_found {
break break
} }
numerus, _ := strings.intern_get(&translation.intern, ts.elements[numerus_id].value) numerus := get_str(ts.elements[numerus_id].value[0]) or_return
numerus, _ = strings.intern_get(&translation.intern, numerus)
section[source][num_plurals] = numerus section[source][num_plurals] = numerus
num_plurals += 1 num_plurals += 1
+2 -2
View File
@@ -129,8 +129,8 @@ _destroy :: proc(thread: ^Thread) {
free(thread, thread.creation_allocator) free(thread, thread.creation_allocator)
} }
_terminate :: proc(using thread : ^Thread, exit_code: int) { _terminate :: proc(thread: ^Thread, exit_code: int) {
win32.TerminateThread(win32_thread, u32(exit_code)) win32.TerminateThread(thread.win32_thread, u32(exit_code))
} }
_yield :: proc() { _yield :: proc() {
+19 -17
View File
@@ -59,28 +59,30 @@ sleep :: proc "contextless" (d: Duration) {
_sleep(d) _sleep(d)
} }
stopwatch_start :: proc "contextless" (using stopwatch: ^Stopwatch) { stopwatch_start :: proc "contextless" (stopwatch: ^Stopwatch) {
if !running { if !stopwatch.running {
_start_time = tick_now() stopwatch._start_time = tick_now()
running = true stopwatch.running = true
} }
} }
stopwatch_stop :: proc "contextless" (using stopwatch: ^Stopwatch) { stopwatch_stop :: proc "contextless" (stopwatch: ^Stopwatch) {
if running { if stopwatch.running {
_accumulation += tick_diff(_start_time, tick_now()) stopwatch._accumulation += tick_diff(stopwatch._start_time, tick_now())
running = false stopwatch.running = false
} }
} }
stopwatch_reset :: proc "contextless" (using stopwatch: ^Stopwatch) { stopwatch_reset :: proc "contextless" (stopwatch: ^Stopwatch) {
_accumulation = {} stopwatch._accumulation = {}
running = false stopwatch.running = false
} }
stopwatch_duration :: proc "contextless" (using stopwatch: Stopwatch) -> Duration { stopwatch_duration :: proc "contextless" (stopwatch: Stopwatch) -> Duration {
if !running { return _accumulation } if !stopwatch.running {
return _accumulation + tick_diff(_start_time, tick_now()) return stopwatch._accumulation
}
return stopwatch._accumulation + tick_diff(stopwatch._start_time, tick_now())
} }
diff :: proc "contextless" (start, end: Time) -> Duration { diff :: proc "contextless" (start, end: Time) -> Duration {
@@ -171,9 +173,9 @@ day :: proc "contextless" (t: Time) -> (day: int) {
} }
weekday :: proc "contextless" (t: Time) -> (weekday: Weekday) { weekday :: proc "contextless" (t: Time) -> (weekday: Weekday) {
abs := _time_abs(t) abs := _time_abs(t)
sec := (abs + u64(Weekday.Monday) * SECONDS_PER_DAY) % SECONDS_PER_WEEK sec := (abs + u64(Weekday.Monday) * SECONDS_PER_DAY) % SECONDS_PER_WEEK
return Weekday(int(sec) / SECONDS_PER_DAY) return Weekday(int(sec) / SECONDS_PER_DAY)
} }
clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch } clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch }
+1
View File
@@ -1,3 +1,4 @@
//+vet !using-stmt !using-param
package main package main
import "core:fmt" import "core:fmt"
+39 -3
View File
@@ -216,6 +216,43 @@ enum BuildPath : u8 {
BuildPathCOUNT, BuildPathCOUNT,
}; };
enum VetFlags : u64 {
VetFlag_NONE = 0,
VetFlag_Unused = 1u<<0, // 1
VetFlag_Shadowing = 1u<<1, // 2
VetFlag_UsingStmt = 1u<<2, // 4
VetFlag_UsingParam = 1u<<3, // 8
VetFlag_Style = 1u<<4, // 16
VetFlag_Semicolon = 1u<<5, // 32
VetFlag_Extra = 1u<<16,
VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt, // excluding extra
VetFlag_Using = VetFlag_UsingStmt|VetFlag_UsingParam,
};
u64 get_vet_flag_from_name(String const &name) {
if (name == "unused") {
return VetFlag_Unused;
} else if (name == "shadowing") {
return VetFlag_Shadowing;
} else if (name == "using-stmt") {
return VetFlag_UsingStmt;
} else if (name == "using-param") {
return VetFlag_UsingParam;
} else if (name == "style") {
return VetFlag_Style;
} else if (name == "semicolon") {
return VetFlag_Semicolon;
} else if (name == "extra") {
return VetFlag_Extra;
}
return VetFlag_NONE;
}
// This stores the information for the specify architecture of this build // This stores the information for the specify architecture of this build
struct BuildContext { struct BuildContext {
// Constants // Constants
@@ -255,6 +292,8 @@ struct BuildContext {
String resource_filepath; String resource_filepath;
String pdb_filepath; String pdb_filepath;
u64 vet_flags;
bool has_resource; bool has_resource;
String link_flags; String link_flags;
String extra_linker_flags; String extra_linker_flags;
@@ -280,15 +319,12 @@ struct BuildContext {
bool no_entry_point; bool no_entry_point;
bool no_thread_local; bool no_thread_local;
bool use_lld; bool use_lld;
bool vet;
bool vet_extra;
bool cross_compiling; bool cross_compiling;
bool different_os; bool different_os;
bool keep_object_files; bool keep_object_files;
bool disallow_do; bool disallow_do;
bool strict_style; bool strict_style;
bool strict_style_init_only;
bool ignore_warnings; bool ignore_warnings;
bool warnings_as_errors; bool warnings_as_errors;
+1 -1
View File
@@ -1406,7 +1406,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
} }
return false; return false;
} else if (name == "load_or") { } else if (name == "load_or") {
warning(call, "'#load_or' is deprecated in favour of '#load(path) or_else default'"); error(call, "'#load_or' has now been removed in favour of '#load(path) or_else default'");
if (ce->args.count != 2) { if (ce->args.count != 2) {
if (ce->args.count == 0) { if (ce->args.count == 0) {
+10 -33
View File
@@ -7,13 +7,15 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
e->type == t_invalid) { e->type == t_invalid) {
if (operand->mode == Addressing_Builtin) { if (operand->mode == Addressing_Builtin) {
ERROR_BLOCK();
gbString expr_str = expr_to_string(operand->expr); gbString expr_str = expr_to_string(operand->expr);
// TODO(bill): is this a good enough error message?
error(operand->expr, error(operand->expr,
"Cannot assign built-in procedure '%s' in %.*s", "Cannot assign built-in procedure '%s' in %.*s",
expr_str, expr_str,
LIT(context_name)); LIT(context_name));
error_line("\tBuilt-in procedures are implemented by the compiler and might not be actually instantiated procedure\n");
operand->mode = Addressing_Invalid; operand->mode = Addressing_Invalid;
@@ -159,9 +161,8 @@ gb_internal void check_init_constant(CheckerContext *ctx, Entity *e, Operand *op
} }
if (operand->mode != Addressing_Constant) { if (operand->mode != Addressing_Constant) {
// TODO(bill): better error
gbString str = expr_to_string(operand->expr); gbString str = expr_to_string(operand->expr);
error(operand->expr, "'%s' is not a constant", str); error(operand->expr, "'%s' is not a compile-time known constant", str);
gb_string_free(str); gb_string_free(str);
if (e->type == nullptr) { if (e->type == nullptr) {
e->type = t_invalid; e->type = t_invalid;
@@ -354,31 +355,7 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr,
// using decl // using decl
if (decl->is_using) { if (decl->is_using) {
warning(init_expr, "'using' an enum declaration is not allowed, prefer using implicit selector expressions e.g. '.A'"); error(init_expr, "'using' an enum declaration is not allowed, prefer using implicit selector expressions e.g. '.A'");
#if 1
// NOTE(bill): Must be an enum declaration
if (te->kind == Ast_EnumType) {
Scope *parent = e->scope;
if (parent->flags&ScopeFlag_File) {
// NOTE(bill): Use package scope
parent = parent->parent;
}
Type *t = base_type(e->type);
if (t->kind == Type_Enum) {
for (Entity *f : t->Enum.fields) {
if (f->kind != Entity_Constant) {
continue;
}
String name = f->token.string;
if (is_blank_ident(name)) {
continue;
}
add_entity(ctx, parent, nullptr, f);
}
}
}
#endif
} }
} }
@@ -1064,7 +1041,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
auto *fp = &ctx->info->foreigns; auto *fp = &ctx->info->foreigns;
StringHashKey key = string_hash_string(name); StringHashKey key = string_hash_string(name);
Entity **found = string_map_get(fp, key); Entity **found = string_map_get(fp, key);
if (found) { if (found && e != *found) {
Entity *f = *found; Entity *f = *found;
TokenPos pos = f->token.pos; TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type); Type *this_type = base_type(e->type);
@@ -1636,7 +1613,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
} }
check_close_scope(ctx); check_close_scope(ctx);
check_scope_usage(ctx->checker, ctx->scope); check_scope_usage(ctx->checker, ctx->scope, check_vet_flags(body));
add_deps_from_child_to_parent(decl); add_deps_from_child_to_parent(decl);
+14 -34
View File
@@ -349,6 +349,10 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
return false; return false;
} }
if (base_entity->flags & EntityFlag_Disabled) {
return false;
}
String name = base_entity->token.string; String name = base_entity->token.string;
Type *src = base_type(base_entity->type); Type *src = base_type(base_entity->type);
@@ -462,7 +466,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
{ {
// LEAK TODO(bill): This is technically a memory leak as it has to generate the type twice // LEAK NOTE(bill): This is technically a memory leak as it has to generate the type twice
bool prev_no_polymorphic_errors = nctx.no_polymorphic_errors; bool prev_no_polymorphic_errors = nctx.no_polymorphic_errors;
defer (nctx.no_polymorphic_errors = prev_no_polymorphic_errors); defer (nctx.no_polymorphic_errors = prev_no_polymorphic_errors);
nctx.no_polymorphic_errors = false; nctx.no_polymorphic_errors = false;
@@ -470,7 +474,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
// NOTE(bill): Reset scope from the failed procedure type // NOTE(bill): Reset scope from the failed procedure type
scope_reset(scope); scope_reset(scope);
// LEAK TODO(bill): Cloning this AST may be leaky // LEAK NOTE(bill): Cloning this AST may be leaky but this is not really an issue due to arena-based allocation
Ast *cloned_proc_type_node = clone_ast(pt->node); Ast *cloned_proc_type_node = clone_ast(pt->node);
success = check_procedure_type(&nctx, final_proc_type, cloned_proc_type_node, &operands); success = check_procedure_type(&nctx, final_proc_type, cloned_proc_type_node, &operands);
if (!success) { if (!success) {
@@ -778,16 +782,6 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
} }
} }
// ^T <- rawptr
#if 0
// TODO(bill): Should C-style (not C++) pointer cast be allowed?
if (is_type_pointer(dst) && is_type_rawptr(src)) {
return true;
}
#endif
#if 1
// rawptr <- ^T // rawptr <- ^T
if (are_types_identical(type, t_rawptr) && is_type_pointer(src)) { if (are_types_identical(type, t_rawptr) && is_type_pointer(src)) {
return 5; return 5;
@@ -808,7 +802,6 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
return 4; return 4;
} }
} }
#endif
if (is_type_polymorphic(dst) && !is_type_polymorphic(src)) { if (is_type_polymorphic(dst) && !is_type_polymorphic(src)) {
bool modify_type = !c->no_polymorphic_errors; bool modify_type = !c->no_polymorphic_errors;
@@ -824,7 +817,6 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
} }
} }
// TODO(bill): Determine which rule is a better on in practice
if (dst->Union.variants.count == 1) { if (dst->Union.variants.count == 1) {
Type *vt = dst->Union.variants[0]; Type *vt = dst->Union.variants[0];
i64 score = check_distance_between_types(c, operand, vt); i64 score = check_distance_between_types(c, operand, vt);
@@ -1093,7 +1085,7 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
// TODO(bill): is this a good enough error message? // TODO(bill): is this a good enough error message?
error(operand->expr, error(operand->expr,
"Cannot assign overloaded procedure '%s' to '%s' in %.*s", "Cannot assign overloaded procedure group '%s' to '%s' in %.*s",
expr_str, expr_str,
op_type_str, op_type_str,
LIT(context_name)); LIT(context_name));
@@ -1120,7 +1112,6 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
switch (operand->mode) { switch (operand->mode) {
case Addressing_Builtin: case Addressing_Builtin:
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
error(operand->expr, error(operand->expr,
"Cannot assign built-in procedure '%s' in %.*s", "Cannot assign built-in procedure '%s' in %.*s",
expr_str, expr_str,
@@ -1412,9 +1403,6 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T
return false; return false;
case Type_Proc: case Type_Proc:
if (source->kind == Type_Proc) { if (source->kind == Type_Proc) {
// return check_is_assignable_to(c, &o, poly);
// TODO(bill): Polymorphic type assignment
#if 1
TypeProc *x = &poly->Proc; TypeProc *x = &poly->Proc;
TypeProc *y = &source->Proc; TypeProc *y = &source->Proc;
if (x->calling_convention != y->calling_convention) { if (x->calling_convention != y->calling_convention) {
@@ -1447,7 +1435,6 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T
} }
return true; return true;
#endif
} }
return false; return false;
case Type_Map: case Type_Map:
@@ -1699,7 +1686,6 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
gb_string_free(str); gb_string_free(str);
return false; return false;
} }
// TODO(bill): Handle errors correctly
Type *type = base_type(core_array_type(o->type)); Type *type = base_type(core_array_type(o->type));
gbString str = nullptr; gbString str = nullptr;
switch (op.kind) { switch (op.kind) {
@@ -1743,7 +1729,6 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
gb_internal bool check_binary_op(CheckerContext *c, Operand *o, Token op) { gb_internal bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
Type *main_type = o->type; Type *main_type = o->type;
// TODO(bill): Handle errors correctly
Type *type = base_type(core_array_type(main_type)); Type *type = base_type(core_array_type(main_type));
Type *ct = core_type(type); Type *ct = core_type(type);
@@ -2261,7 +2246,7 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) {
} }
gb_internal void check_old_for_or_switch_value_usage(Ast *expr) { gb_internal void check_old_for_or_switch_value_usage(Ast *expr) {
if (!build_context.strict_style) { if (!(build_context.strict_style || (check_vet_flags(expr) & VetFlag_Style))) {
return; return;
} }
@@ -2351,7 +2336,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
o->type = alloc_type_pointer(o->type); o->type = alloc_type_pointer(o->type);
} }
} else { } else {
if (build_context.strict_style && ast_node_expect(node, Ast_UnaryExpr)) { if (ast_node_expect(node, Ast_UnaryExpr)) {
ast_node(ue, UnaryExpr, node); ast_node(ue, UnaryExpr, node);
check_old_for_or_switch_value_usage(ue->expr); check_old_for_or_switch_value_usage(ue->expr);
} }
@@ -2775,8 +2760,6 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod
gb_string_free(err_str); gb_string_free(err_str);
} }
// TODO(bill): Should we support shifts for fixed arrays and #simd vectors?
if (!is_type_integer(x->type)) { if (!is_type_integer(x->type)) {
gbString err_str = expr_to_string(x->expr); gbString err_str = expr_to_string(x->expr);
error(node, "Shift operand '%s' must be an integer", err_str); error(node, "Shift operand '%s' must be an integer", err_str);
@@ -3099,7 +3082,7 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
update_untyped_expr_type(c, x->expr, final_type, true); update_untyped_expr_type(c, x->expr, final_type, true);
} }
if (build_context.vet_extra) { if (check_vet_flags(x->expr) & VetFlag_Extra) {
if (are_types_identical(x->type, type)) { if (are_types_identical(x->type, type)) {
gbString str = type_to_string(type); gbString str = type_to_string(type);
warning(x->expr, "Unneeded cast to the same type '%s'", str); warning(x->expr, "Unneeded cast to the same type '%s'", str);
@@ -3171,7 +3154,7 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
return false; return false;
} }
if (build_context.vet_extra) { if (check_vet_flags(node) & VetFlag_Extra) {
if (are_types_identical(o->type, dst_t)) { if (are_types_identical(o->type, dst_t)) {
gbString str = type_to_string(dst_t); gbString str = type_to_string(dst_t);
warning(o->expr, "Unneeded transmute to the same type '%s'", str); warning(o->expr, "Unneeded transmute to the same type '%s'", str);
@@ -4437,7 +4420,6 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
case_end; case_end;
default: default:
// TODO(bill): Should this be a general fallback?
if (success_) *success_ = true; if (success_) *success_ = true;
if (finish_) *finish_ = true; if (finish_) *finish_ = true;
return empty_exact_value; return empty_exact_value;
@@ -4793,8 +4775,6 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
} }
if (entity == nullptr && selector->kind == Ast_Ident && is_type_array(type_deref(operand->type))) { if (entity == nullptr && selector->kind == Ast_Ident && is_type_array(type_deref(operand->type))) {
// TODO(bill): Simd_Vector swizzling
String field_name = selector->Ident.token.string; String field_name = selector->Ident.token.string;
if (1 < field_name.len && field_name.len <= 4) { if (1 < field_name.len && field_name.len <= 4) {
u8 swizzles_xyzw[4] = {'x', 'y', 'z', 'w'}; u8 swizzles_xyzw[4] = {'x', 'y', 'z', 'w'};
@@ -5989,8 +5969,8 @@ gb_internal bool check_call_arguments_single(CheckerContext *c, Ast *call, Opera
} }
Entity *entity_to_use = data->gen_entity != nullptr ? data->gen_entity : e; Entity *entity_to_use = data->gen_entity != nullptr ? data->gen_entity : e;
add_entity_use(c, ident, entity_to_use);
if (!return_on_failure && entity_to_use != nullptr) { if (!return_on_failure && entity_to_use != nullptr) {
add_entity_use(c, ident, entity_to_use);
update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); update_untyped_expr_type(c, operand->expr, entity_to_use->type, true);
add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value); add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value);
} }
@@ -7157,7 +7137,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
i32 id = operand->builtin_id; i32 id = operand->builtin_id;
Entity *e = entity_of_node(operand->expr); Entity *e = entity_of_node(operand->expr);
if (e != nullptr && e->token.string == "expand_to_tuple") { if (e != nullptr && e->token.string == "expand_to_tuple") {
warning(operand->expr, "'expand_to_tuple' has been replaced with 'expand_values'"); error(operand->expr, "'expand_to_tuple' has been replaced with 'expand_values'");
} }
if (!check_builtin_procedure(c, operand, call, id, type_hint)) { if (!check_builtin_procedure(c, operand, call, id, type_hint)) {
operand->mode = Addressing_Invalid; operand->mode = Addressing_Invalid;
@@ -10033,7 +10013,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
Type *type = type_of_expr(ac->expr); Type *type = type_of_expr(ac->expr);
check_cast(c, o, type_hint); check_cast(c, o, type_hint);
if (is_type_typed(type) && are_types_identical(type, type_hint)) { if (is_type_typed(type) && are_types_identical(type, type_hint)) {
if (build_context.vet_extra) { if (check_vet_flags(node) & VetFlag_Extra) {
error(node, "Redundant 'auto_cast' applied to expression"); error(node, "Redundant 'auto_cast' applied to expression");
} }
} }
+11 -6
View File
@@ -384,7 +384,6 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
} }
if (e != nullptr) { if (e != nullptr) {
// HACK TODO(bill): Should the entities be freed as it's technically a leak
rhs->mode = Addressing_Value; rhs->mode = Addressing_Value;
rhs->type = e->type; rhs->type = e->type;
rhs->proc_group = nullptr; rhs->proc_group = nullptr;
@@ -394,7 +393,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
ast_node(i, Ident, node); ast_node(i, Ident, node);
e = scope_lookup(ctx->scope, i->token.string); e = scope_lookup(ctx->scope, i->token.string);
if (e != nullptr && e->kind == Entity_Variable) { if (e != nullptr && e->kind == Entity_Variable) {
used = (e->flags & EntityFlag_Used) != 0; // TODO(bill): Make backup just in case used = (e->flags & EntityFlag_Used) != 0; // NOTE(bill): Make backup just in case
} }
} }
@@ -888,7 +887,7 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags
check_open_scope(ctx, node); check_open_scope(ctx, node);
defer (check_close_scope(ctx)); defer (check_close_scope(ctx));
check_label(ctx, ss->label, node); // TODO(bill): What should the label's "scope" be? check_label(ctx, ss->label, node);
if (ss->init != nullptr) { if (ss->init != nullptr) {
check_stmt(ctx, ss->init, 0); check_stmt(ctx, ss->init, 0);
@@ -1125,7 +1124,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
check_open_scope(ctx, node); check_open_scope(ctx, node);
defer (check_close_scope(ctx)); defer (check_close_scope(ctx));
check_label(ctx, ss->label, node); // TODO(bill): What should the label's "scope" be? check_label(ctx, ss->label, node);
if (ss->tag->kind != Ast_AssignStmt) { if (ss->tag->kind != Ast_AssignStmt) {
error(ss->tag, "Expected an 'in' assignment for this type switch statement"); error(ss->tag, "Expected an 'in' assignment for this type switch statement");
@@ -1960,7 +1959,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
Token token = ast_token(node); Token token = ast_token(node);
if (vd->type != nullptr && entity_count > 1) { if (vd->type != nullptr && entity_count > 1) {
error(token, "'using' can only be applied to one variable of the same type"); error(token, "'using' can only be applied to one variable of the same type");
// TODO(bill): Should a 'continue' happen here? // NOTE(bill): `using` will only be applied to a single declaration
} }
for (isize entity_index = 0; entity_index < 1; entity_index++) { for (isize entity_index = 0; entity_index < 1; entity_index++) {
@@ -2294,7 +2293,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
mod_flags |= Stmt_BreakAllowed | Stmt_ContinueAllowed; mod_flags |= Stmt_BreakAllowed | Stmt_ContinueAllowed;
check_open_scope(ctx, node); check_open_scope(ctx, node);
check_label(ctx, fs->label, node); // TODO(bill): What should the label's "scope" be? check_label(ctx, fs->label, node);
if (fs->init != nullptr) { if (fs->init != nullptr) {
check_stmt(ctx, fs->init, 0); check_stmt(ctx, fs->init, 0);
@@ -2464,6 +2463,12 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
error(us->token, "Empty 'using' list"); error(us->token, "Empty 'using' list");
return; return;
} }
if (check_vet_flags(node) & VetFlag_UsingStmt) {
ERROR_BLOCK();
error(node, "'using' as a statement is not allowed when '-vet' or '-vet-using' is applied");
error_line("\t'using' is considered bad practice to use as a statement outside of immediate refactoring\n");
}
for (Ast *expr : us->list) { for (Ast *expr : us->list) {
expr = unparen_expr(expr); expr = unparen_expr(expr);
Entity *e = nullptr; Entity *e = nullptr;
+6
View File
@@ -1474,6 +1474,12 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
Type *specialization = nullptr; Type *specialization = nullptr;
bool is_using = (p->flags&FieldFlag_using) != 0; bool is_using = (p->flags&FieldFlag_using) != 0;
if ((check_vet_flags(param) & VetFlag_UsingParam) && is_using) {
ERROR_BLOCK();
error(param, "'using' on a procedure parameter is now allowed when '-vet' or '-vet-using-param' is applied");
error_line("\t'using' is considered bad practice to use as a statement/procedure parameter outside of immediate refactoring\n");
}
if (type_expr == nullptr) { if (type_expr == nullptr) {
param_value = handle_parameter_value(ctx, nullptr, &type, default_value, true); param_value = handle_parameter_value(ctx, nullptr, &type, default_value, true);
+63 -36
View File
@@ -521,6 +521,28 @@ GB_COMPARE_PROC(entity_variable_pos_cmp) {
} }
gb_internal u64 check_vet_flags(CheckerContext *c) {
AstFile *file = c->file;
if (file == nullptr &&
c->curr_proc_decl &&
c->curr_proc_decl->proc_lit) {
file = c->curr_proc_decl->proc_lit->file();
}
if (file && file->vet_flags_set) {
return file->vet_flags;
}
return build_context.vet_flags;
}
gb_internal u64 check_vet_flags(Ast *node) {
AstFile *file = node->file();
if (file && file->vet_flags_set) {
return file->vet_flags;
}
return build_context.vet_flags;
}
enum VettedEntityKind { enum VettedEntityKind {
VettedEntity_Invalid, VettedEntity_Invalid,
@@ -655,9 +677,9 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) {
return false; return false;
} }
gb_internal void check_scope_usage(Checker *c, Scope *scope) { gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
bool vet_unused = true; bool vet_unused = (vet_flags & VetFlag_Unused) != 0;
bool vet_shadowing = true; bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0;
Array<VettedEntity> vetted_entities = {}; Array<VettedEntity> vetted_entities = {};
array_init(&vetted_entities, heap_allocator()); array_init(&vetted_entities, heap_allocator());
@@ -691,15 +713,17 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope) {
if (ve.kind == VettedEntity_Shadowed_And_Unused) { if (ve.kind == VettedEntity_Shadowed_And_Unused) {
error(e->token, "'%.*s' declared but not used, possibly shadows declaration at line %d", LIT(name), other->token.pos.line); error(e->token, "'%.*s' declared but not used, possibly shadows declaration at line %d", LIT(name), other->token.pos.line);
} else if (build_context.vet) { } else if (vet_flags) {
switch (ve.kind) { switch (ve.kind) {
case VettedEntity_Unused: case VettedEntity_Unused:
error(e->token, "'%.*s' declared but not used", LIT(name)); if (vet_flags & VetFlag_Unused) {
error(e->token, "'%.*s' declared but not used", LIT(name));
}
break; break;
case VettedEntity_Shadowed: case VettedEntity_Shadowed:
if (e->flags&EntityFlag_Using) { if ((vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0 && e->flags&EntityFlag_Using) {
error(e->token, "Declaration of '%.*s' from 'using' shadows declaration at line %d", LIT(name), other->token.pos.line); error(e->token, "Declaration of '%.*s' from 'using' shadows declaration at line %d", LIT(name), other->token.pos.line);
} else { } else if ((vet_flags & (VetFlag_Shadowing)) != 0) {
error(e->token, "Declaration of '%.*s' shadows declaration at line %d", LIT(name), other->token.pos.line); error(e->token, "Declaration of '%.*s' shadows declaration at line %d", LIT(name), other->token.pos.line);
} }
break; break;
@@ -726,7 +750,7 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope) {
if (child->flags & (ScopeFlag_Proc|ScopeFlag_Type|ScopeFlag_File)) { if (child->flags & (ScopeFlag_Proc|ScopeFlag_Type|ScopeFlag_File)) {
// Ignore these // Ignore these
} else { } else {
check_scope_usage(c, child); check_scope_usage(c, child, vet_flags);
} }
} }
} }
@@ -943,7 +967,6 @@ gb_internal void init_universal(void) {
add_global_bool_constant("true", true); add_global_bool_constant("true", true);
add_global_bool_constant("false", false); add_global_bool_constant("false", false);
// TODO(bill): Set through flags in the compiler
add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR); add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION); add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT); add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
@@ -1455,7 +1478,6 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo
if (ctx->decl) { if (ctx->decl) {
mutex = &ctx->decl->type_and_value_mutex; mutex = &ctx->decl->type_and_value_mutex;
} else if (ctx->pkg) { } else if (ctx->pkg) {
// TODO(bill): is a per package mutex is a good idea here?
mutex = &ctx->pkg->type_and_value_mutex; mutex = &ctx->pkg->type_and_value_mutex;
} }
@@ -1583,30 +1605,28 @@ gb_internal void add_entity_use(CheckerContext *c, Ast *identifier, Entity *enti
if (entity == nullptr) { if (entity == nullptr) {
return; return;
} }
if (identifier != nullptr) {
if (identifier->kind != Ast_Ident) {
return;
}
Ast *empty_ident = nullptr;
entity->identifier.compare_exchange_strong(empty_ident, identifier);
identifier->Ident.entity = entity;
String dmsg = entity->deprecated_message;
if (dmsg.len > 0) {
warning(identifier, "%.*s is deprecated: %.*s", LIT(entity->token.string), LIT(dmsg));
}
String wmsg = entity->warning_message;
if (wmsg.len > 0) {
warning(identifier, "%.*s: %.*s", LIT(entity->token.string), LIT(wmsg));
}
}
entity->flags |= EntityFlag_Used;
add_declaration_dependency(c, entity); add_declaration_dependency(c, entity);
entity->flags |= EntityFlag_Used;
if (entity_has_deferred_procedure(entity)) { if (entity_has_deferred_procedure(entity)) {
Entity *deferred = entity->Procedure.deferred_procedure.entity; Entity *deferred = entity->Procedure.deferred_procedure.entity;
add_entity_use(c, nullptr, deferred); add_entity_use(c, nullptr, deferred);
} }
if (identifier == nullptr || identifier->kind != Ast_Ident) {
return;
}
Ast *empty_ident = nullptr;
entity->identifier.compare_exchange_strong(empty_ident, identifier);
identifier->Ident.entity = entity;
String dmsg = entity->deprecated_message;
if (dmsg.len > 0) {
warning(identifier, "%.*s is deprecated: %.*s", LIT(entity->token.string), LIT(dmsg));
}
String wmsg = entity->warning_message;
if (wmsg.len > 0) {
warning(identifier, "%.*s: %.*s", LIT(entity->token.string), LIT(wmsg));
}
} }
@@ -2560,9 +2580,6 @@ gb_internal Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInf
} }
} }
// TODO(bill): This could be multithreaded to improve performance
// This means that the entity graph node set will have to be thread safe
TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2"); TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2");
auto G = array_make<EntityGraphNode *>(allocator, 0, M.count); auto G = array_make<EntityGraphNode *>(allocator, 0, M.count);
@@ -2982,6 +2999,12 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_group_attribute) {
} }
} }
return true; return true;
} else if (name == "require_results") {
if (value != nullptr) {
error(elem, "Expected no value for '%.*s'", LIT(name));
}
ac->require_results = true;
return true;
} }
return false; return false;
} }
@@ -3059,7 +3082,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
check_expr(c, &o, value); check_expr(c, &o, value);
Entity *e = entity_of_node(o.expr); Entity *e = entity_of_node(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) { if (e != nullptr && e->kind == Entity_Procedure) {
warning(elem, "'%.*s' is deprecated, please use one of the following instead: 'deferred_none', 'deferred_in', 'deferred_out'", LIT(name)); error(elem, "'%.*s' is not allowed any more, please use one of the following instead: 'deferred_none', 'deferred_in', 'deferred_out'", LIT(name));
if (ac->deferred_procedure.entity != nullptr) { if (ac->deferred_procedure.entity != nullptr) {
error(elem, "Previous usage of a 'deferred_*' attribute"); error(elem, "Previous usage of a 'deferred_*' attribute");
} }
@@ -4558,7 +4581,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
if (value != nullptr) { if (value != nullptr) {
error(elem, "Expected no parameter for '%.*s'", LIT(name)); error(elem, "Expected no parameter for '%.*s'", LIT(name));
} else if (name == "force") { } else if (name == "force") {
warning(elem, "'force' is deprecated and is identical to 'require'"); error(elem, "'force' was replaced with 'require'");
} }
ac->require_declaration = true; ac->require_declaration = true;
return true; return true;
@@ -5956,7 +5979,11 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("check scope usage"); TIME_SECTION("check scope usage");
for (auto const &entry : c->info.files) { for (auto const &entry : c->info.files) {
AstFile *f = entry.value; AstFile *f = entry.value;
check_scope_usage(c, f->scope); u64 vet_flags = build_context.vet_flags;
if (f->vet_flags_set) {
vet_flags = f->vet_flags;
}
check_scope_usage(c, f->scope, vet_flags);
} }
TIME_SECTION("add basic type information"); TIME_SECTION("add basic type information");
@@ -6074,7 +6101,7 @@ gb_internal void check_parsed_files(Checker *c) {
while (mpsc_dequeue(&c->info.intrinsics_entry_point_usage, &node)) { while (mpsc_dequeue(&c->info.intrinsics_entry_point_usage, &node)) {
if (c->info.entry_point == nullptr && node != nullptr) { if (c->info.entry_point == nullptr && node != nullptr) {
if (node->file()->pkg->kind != Package_Runtime) { if (node->file()->pkg->kind != Package_Runtime) {
warning(node, "usage of intrinsics.__entry_point will be a no-op"); error(node, "usage of intrinsics.__entry_point will be a no-op");
} }
} }
} }
+3 -2
View File
@@ -387,8 +387,6 @@ struct CheckerInfo {
BlockingMutex foreign_mutex; // NOT recursive BlockingMutex foreign_mutex; // NOT recursive
StringMap<Entity *> foreigns; StringMap<Entity *> foreigns;
// NOTE(bill): These are actually MPSC queues
// TODO(bill): Convert them to be MPSC queues
MPSCQueue<Entity *> definition_queue; MPSCQueue<Entity *> definition_queue;
MPSCQueue<Entity *> entity_queue; MPSCQueue<Entity *> entity_queue;
MPSCQueue<Entity *> required_global_variable_queue; MPSCQueue<Entity *> required_global_variable_queue;
@@ -449,6 +447,9 @@ struct CheckerContext {
Ast *assignment_lhs_hint; Ast *assignment_lhs_hint;
}; };
gb_internal u64 check_vet_flags(CheckerContext *c);
gb_internal u64 check_vet_flags(Ast *node);
struct Checker { struct Checker {
Parser * parser; Parser * parser;
+3 -4
View File
@@ -291,7 +291,6 @@ gb_internal bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = f
} }
gb_internal bool is_entity_exported(Entity *e, bool allow_builtin = false) { gb_internal bool is_entity_exported(Entity *e, bool allow_builtin = false) {
// TODO(bill): Determine the actual exportation rules for imports of entities
GB_ASSERT(e != nullptr); GB_ASSERT(e != nullptr);
if (!is_entity_kind_exported(e->kind, allow_builtin)) { if (!is_entity_kind_exported(e->kind, allow_builtin)) {
return false; return false;
@@ -405,7 +404,7 @@ gb_internal Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *typ
return entity; return entity;
} }
gb_internal Entity *alloc_entity_procedure(Scope *scope, Token token, Type *signature_type, u64 tags) { gb_internal Entity *alloc_entity_procedure(Scope *scope, Token token, Type *signature_type, u64 tags=0) {
Entity *entity = alloc_entity(Entity_Procedure, scope, token, signature_type); Entity *entity = alloc_entity(Entity_Procedure, scope, token, signature_type);
entity->Procedure.tags = tags; entity->Procedure.tags = tags;
return entity; return entity;
@@ -422,7 +421,7 @@ gb_internal Entity *alloc_entity_import_name(Scope *scope, Token token, Type *ty
entity->ImportName.path = path; entity->ImportName.path = path;
entity->ImportName.name = name; entity->ImportName.name = name;
entity->ImportName.scope = import_scope; entity->ImportName.scope = import_scope;
entity->state = EntityState_Resolved; // TODO(bill): Is this correct? entity->state = EntityState_Resolved;
return entity; return entity;
} }
@@ -431,7 +430,7 @@ gb_internal Entity *alloc_entity_library_name(Scope *scope, Token token, Type *t
Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type); Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type);
entity->LibraryName.paths = paths; entity->LibraryName.paths = paths;
entity->LibraryName.name = name; entity->LibraryName.name = name;
entity->state = EntityState_Resolved; // TODO(bill): Is this correct? entity->state = EntityState_Resolved;
return entity; return entity;
} }
+2 -5
View File
@@ -26,8 +26,8 @@ enum ExactValueKind {
ExactValue_Complex = 5, ExactValue_Complex = 5,
ExactValue_Quaternion = 6, ExactValue_Quaternion = 6,
ExactValue_Pointer = 7, ExactValue_Pointer = 7,
ExactValue_Compound = 8, // TODO(bill): Is this good enough? ExactValue_Compound = 8,
ExactValue_Procedure = 9, // TODO(bill): Is this good enough? ExactValue_Procedure = 9,
ExactValue_Typeid = 10, ExactValue_Typeid = 10,
ExactValue_Count, ExactValue_Count,
@@ -101,7 +101,6 @@ gb_internal ExactValue exact_value_bool(bool b) {
} }
gb_internal ExactValue exact_value_string(String string) { gb_internal ExactValue exact_value_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
ExactValue result = {ExactValue_String}; ExactValue result = {ExactValue_String};
result.value_string = string; result.value_string = string;
return result; return result;
@@ -702,7 +701,6 @@ gb_internal void match_exact_values(ExactValue *x, ExactValue *y) {
compiler_error("match_exact_values: How'd you get here? Invalid ExactValueKind %d", x->kind); compiler_error("match_exact_values: How'd you get here? Invalid ExactValueKind %d", x->kind);
} }
// TODO(bill): Allow for pointer arithmetic? Or are pointer slices good enough?
gb_internal ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) { gb_internal ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) {
match_exact_values(&x, &y); match_exact_values(&x, &y);
@@ -943,7 +941,6 @@ gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y)
case ExactValue_String: { case ExactValue_String: {
String a = x.value_string; String a = x.value_string;
String b = y.value_string; String b = y.value_string;
// TODO(bill): gb_memcompare is used because the strings are UTF-8
switch (op) { switch (op) {
case Token_CmpEq: return a == b; case Token_CmpEq: return a == b;
case Token_NotEq: return a != b; case Token_NotEq: return a != b;
+1 -2
View File
@@ -1861,8 +1861,8 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
case Type_SimdVector: case Type_SimdVector:
return lb_type_internal(m, base); return lb_type_internal(m, base);
// TODO(bill): Deal with this correctly. Can this be named?
case Type_Proc: case Type_Proc:
// TODO(bill): Deal with this correctly. Can this be named?
return lb_type_internal(m, base); return lb_type_internal(m, base);
case Type_Tuple: case Type_Tuple:
@@ -2835,7 +2835,6 @@ gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e) {
if (USE_SEPARATE_MODULES) { if (USE_SEPARATE_MODULES) {
lbModule *other_module = lb_module_of_entity(m->gen, e); lbModule *other_module = lb_module_of_entity(m->gen, e);
// TODO(bill): correct this logic
bool is_external = other_module != m; bool is_external = other_module != m;
if (!is_external) { if (!is_external) {
if (e->code_gen_module != nullptr) { if (e->code_gen_module != nullptr) {
+1 -4
View File
@@ -362,7 +362,6 @@ gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name
Type *pt = p->type; Type *pt = p->type;
lbCallingConventionKind cc_kind = lbCallingConvention_C; lbCallingConventionKind cc_kind = lbCallingConvention_C;
// TODO(bill): Clean up this logic
if (!is_arch_wasm()) { if (!is_arch_wasm()) {
cc_kind = lb_calling_convention_map[pt->Proc.calling_convention]; cc_kind = lb_calling_convention_map[pt->Proc.calling_convention];
} }
@@ -1702,7 +1701,6 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
lbValue v = lb_build_expr(p, ce->args[0]); lbValue v = lb_build_expr(p, ce->args[0]);
Type *t = base_type(v.type); Type *t = base_type(v.type);
if (is_type_pointer(t)) { if (is_type_pointer(t)) {
// IMPORTANT TODO(bill): Should there be a nil pointer check?
v = lb_emit_load(p, v); v = lb_emit_load(p, v);
t = type_deref(t); t = type_deref(t);
} }
@@ -1730,7 +1728,6 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
lbValue v = lb_build_expr(p, ce->args[0]); lbValue v = lb_build_expr(p, ce->args[0]);
Type *t = base_type(v.type); Type *t = base_type(v.type);
if (is_type_pointer(t)) { if (is_type_pointer(t)) {
// IMPORTANT TODO(bill): Should there be a nil pointer check?
v = lb_emit_load(p, v); v = lb_emit_load(p, v);
t = type_deref(t); t = type_deref(t);
} }
@@ -3144,7 +3141,7 @@ gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
lbValue res = lb_build_call_expr_internal(p, expr); lbValue res = lb_build_call_expr_internal(p, expr);
if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures if (ce->optional_ok_one) {
GB_ASSERT(is_type_tuple(res.type)); GB_ASSERT(is_type_tuple(res.type));
GB_ASSERT(res.type->Tuple.variables.count == 2); GB_ASSERT(res.type->Tuple.variables.count == 2);
return lb_emit_struct_ev(p, res, 0); return lb_emit_struct_ev(p, res, 0);
+1 -4
View File
@@ -1688,7 +1688,6 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss
lb_add_entity(p->module, case_entity, ptr); lb_add_entity(p->module, case_entity, ptr);
lb_add_debug_local_variable(p, ptr.value, case_entity->type, case_entity->token); lb_add_debug_local_variable(p, ptr.value, case_entity->type, case_entity->token);
} else { } else {
// TODO(bill): is the correct expected behaviour?
lb_store_type_case_implicit(p, clause, parent_value); lb_store_type_case_implicit(p, clause, parent_value);
} }
@@ -2014,12 +2013,10 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
defer (lb_close_scope(p, lbDeferExit_Default, nullptr)); defer (lb_close_scope(p, lbDeferExit_Default, nullptr));
if (is->init != nullptr) { if (is->init != nullptr) {
// TODO(bill): Should this have a separate block to begin with?
#if 1
lbBlock *init = lb_create_block(p, "if.init"); lbBlock *init = lb_create_block(p, "if.init");
lb_emit_jump(p, init); lb_emit_jump(p, init);
lb_start_block(p, init); lb_start_block(p, init);
#endif
lb_build_stmt(p, is->init); lb_build_stmt(p, is->init);
} }
lbBlock *then = lb_create_block(p, "if.then"); lbBlock *then = lb_create_block(p, "if.then");
-1
View File
@@ -731,7 +731,6 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup
type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet
for (isize source_index = 0; source_index < count; source_index++) { for (isize source_index = 0; source_index < count; source_index++) {
// TODO(bill): Order fields in source order not layout order
Entity *f = t->Struct.fields[source_index]; Entity *f = t->Struct.fields[source_index];
lbValue tip = lb_type_info(m, f->type); lbValue tip = lb_type_info(m, f->type);
i64 foffset = 0; i64 foffset = 0;
+89 -39
View File
@@ -1,5 +1,4 @@
// #define NO_ARRAY_BOUNDS_CHECK // #define NO_ARRAY_BOUNDS_CHECK
#include "common.cpp" #include "common.cpp"
#include "timings.cpp" #include "timings.cpp"
#include "tokenizer.cpp" #include "tokenizer.cpp"
@@ -74,6 +73,12 @@ gb_global Timings global_timings = {0};
#include "linker.cpp" #include "linker.cpp"
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
#define ALLOW_TILDE 1
#else
#define ALLOW_TILDE 0
#endif
#if ALLOW_TILDE
#include "tilde.cpp" #include "tilde.cpp"
#endif #endif
@@ -243,8 +248,16 @@ enum BuildFlagKind {
BuildFlag_UseSeparateModules, BuildFlag_UseSeparateModules,
BuildFlag_NoThreadedChecker, BuildFlag_NoThreadedChecker,
BuildFlag_ShowDebugMessages, BuildFlag_ShowDebugMessages,
BuildFlag_Vet, BuildFlag_Vet,
BuildFlag_VetShadowing,
BuildFlag_VetUnused,
BuildFlag_VetUsingStmt,
BuildFlag_VetUsingParam,
BuildFlag_VetStyle,
BuildFlag_VetSemicolon,
BuildFlag_VetExtra, BuildFlag_VetExtra,
BuildFlag_IgnoreUnknownAttributes, BuildFlag_IgnoreUnknownAttributes,
BuildFlag_ExtraLinkerFlags, BuildFlag_ExtraLinkerFlags,
BuildFlag_ExtraAssemblerFlags, BuildFlag_ExtraAssemblerFlags,
@@ -261,7 +274,6 @@ enum BuildFlagKind {
BuildFlag_DisallowDo, BuildFlag_DisallowDo,
BuildFlag_DefaultToNilAllocator, BuildFlag_DefaultToNilAllocator,
BuildFlag_StrictStyle, BuildFlag_StrictStyle,
BuildFlag_StrictStyleInitOnly,
BuildFlag_ForeignErrorProcedures, BuildFlag_ForeignErrorProcedures,
BuildFlag_NoRTTI, BuildFlag_NoRTTI,
BuildFlag_DynamicMapCalls, BuildFlag_DynamicMapCalls,
@@ -285,9 +297,9 @@ enum BuildFlagKind {
BuildFlag_InternalIgnoreLazy, BuildFlag_InternalIgnoreLazy,
BuildFlag_InternalIgnoreLLVMBuild, BuildFlag_InternalIgnoreLLVMBuild,
#if defined(GB_SYSTEM_WINDOWS)
BuildFlag_Tilde, BuildFlag_Tilde,
#if defined(GB_SYSTEM_WINDOWS)
BuildFlag_IgnoreVsSearch, BuildFlag_IgnoreVsSearch,
BuildFlag_ResourceFile, BuildFlag_ResourceFile,
BuildFlag_WindowsPdbName, BuildFlag_WindowsPdbName,
@@ -422,8 +434,16 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUnused, str_lit("vet-unused"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetShadowing, str_lit("vet-shadowing"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUsingStmt, str_lit("vet-using-stmt"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUsingParam, str_lit("vet-using-param"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetStyle, str_lit("vet-style"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetSemicolon, str_lit("vet-semicolon"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetExtra, str_lit("vet-extra"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetExtra, str_lit("vet-extra"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build);
@@ -439,7 +459,6 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_StrictStyle, str_lit("strict-style"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_StrictStyle, str_lit("strict-style"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_StrictStyleInitOnly, str_lit("strict-style-init-only"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoRTTI, str_lit("no-rtti"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoRTTI, str_lit("no-rtti"), BuildFlagParam_None, Command__does_check);
@@ -461,9 +480,11 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all);
#if defined(GB_SYSTEM_WINDOWS) #if ALLOW_TILDE
add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build);
#endif
#if defined(GB_SYSTEM_WINDOWS)
add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"), BuildFlagParam_String, Command__does_build);
@@ -956,13 +977,25 @@ gb_internal bool parse_build_flags(Array<String> args) {
build_context.show_debug_messages = true; build_context.show_debug_messages = true;
break; break;
case BuildFlag_Vet: case BuildFlag_Vet:
build_context.vet = true; if (build_context.vet_flags & VetFlag_Extra) {
build_context.vet_flags |= VetFlag_All;
} else {
build_context.vet_flags &= ~VetFlag_Extra;
build_context.vet_flags |= VetFlag_All;
}
break; break;
case BuildFlag_VetExtra: {
build_context.vet = true; case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break;
build_context.vet_extra = true; case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break;
case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break;
case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break;
case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break;
case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break;
case BuildFlag_VetExtra:
build_context.vet_flags = VetFlag_All | VetFlag_Extra;
break; break;
}
case BuildFlag_IgnoreUnknownAttributes: case BuildFlag_IgnoreUnknownAttributes:
build_context.ignore_unknown_attributes = true; build_context.ignore_unknown_attributes = true;
break; break;
@@ -1050,20 +1083,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_ForeignErrorProcedures: case BuildFlag_ForeignErrorProcedures:
build_context.ODIN_FOREIGN_ERROR_PROCEDURES = true; build_context.ODIN_FOREIGN_ERROR_PROCEDURES = true;
break; break;
case BuildFlag_StrictStyle: { case BuildFlag_StrictStyle:
if (build_context.strict_style_init_only) {
gb_printf_err("-strict-style and -strict-style-init-only cannot be used together\n");
}
build_context.strict_style = true; build_context.strict_style = true;
break; break;
}
case BuildFlag_StrictStyleInitOnly: {
if (build_context.strict_style) {
gb_printf_err("-strict-style and -strict-style-init-only cannot be used together\n");
}
build_context.strict_style_init_only = true;
break;
}
case BuildFlag_Short: case BuildFlag_Short:
build_context.cmd_doc_flags |= CmdDocFlag_Short; build_context.cmd_doc_flags |= CmdDocFlag_Short;
break; break;
@@ -1130,11 +1152,11 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_InternalIgnoreLLVMBuild: case BuildFlag_InternalIgnoreLLVMBuild:
build_context.ignore_llvm_build = true; build_context.ignore_llvm_build = true;
break; break;
#if defined(GB_SYSTEM_WINDOWS)
case BuildFlag_Tilde: case BuildFlag_Tilde:
build_context.tilde_backend = true; build_context.tilde_backend = true;
break; break;
#if defined(GB_SYSTEM_WINDOWS)
case BuildFlag_IgnoreVsSearch: { case BuildFlag_IgnoreVsSearch: {
GB_ASSERT(value.kind == ExactValue_Invalid); GB_ASSERT(value.kind == ExactValue_Invalid);
build_context.ignore_microsoft_magic = true; build_context.ignore_microsoft_magic = true;
@@ -1170,7 +1192,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
if (path_is_directory(path)) { if (path_is_directory(path)) {
gb_printf_err("Invalid -pdb-name path. %.*s, is a directory.\n", LIT(path)); gb_printf_err("Invalid -pdb-name path. %.*s, is a directory.\n", LIT(path));
bad_flags = true; bad_flags = true;
break; break;
} }
// #if defined(GB_SYSTEM_WINDOWS) // #if defined(GB_SYSTEM_WINDOWS)
// String ext = path_extension(path); // String ext = path_extension(path);
@@ -1603,6 +1625,10 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds"); print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-show-system-calls");
print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler");
print_usage_line(0, "");
print_usage_line(1, "-export-timings:<format>"); print_usage_line(1, "-export-timings:<format>");
print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`"); print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`");
print_usage_line(2, "Available options:"); print_usage_line(2, "Available options:");
@@ -1712,29 +1738,55 @@ gb_internal void print_show_help(String const arg0, String const &command) {
} }
if (check) { if (check) {
#if defined(GB_SYSTEM_WINDOWS)
print_usage_line(1, "-no-threaded-checker"); print_usage_line(1, "-no-threaded-checker");
print_usage_line(2, "Disabled multithreading in the semantic checker stage"); print_usage_line(2, "Disabled multithreading in the semantic checker stage");
print_usage_line(0, ""); print_usage_line(0, "");
#else }
print_usage_line(1, "-threaded-checker");
print_usage_line(1, "[EXPERIMENTAL]");
print_usage_line(2, "Multithread the semantic checker stage");
print_usage_line(0, "");
#endif
if (check) {
print_usage_line(1, "-vet"); print_usage_line(1, "-vet");
print_usage_line(2, "Do extra checks on the code"); print_usage_line(2, "Do extra checks on the code");
print_usage_line(2, "Extra checks include:"); print_usage_line(2, "Extra checks include:");
print_usage_line(3, "Variable shadowing within procedures"); print_usage_line(2, "-vet-unused");
print_usage_line(3, "Unused declarations"); print_usage_line(2, "-vet-shadowing");
print_usage_line(2, "-vet-using-stmt");
print_usage_line(0, "");
print_usage_line(1, "-vet-unused");
print_usage_line(2, "Checks for unused declarations");
print_usage_line(0, "");
print_usage_line(1, "-vet-shadowing");
print_usage_line(2, "Checks for variable shadowing within procedures");
print_usage_line(0, "");
print_usage_line(1, "-vet-using-stmt");
print_usage_line(2, "Checks for the use of 'using' as a statement");
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring");
print_usage_line(0, "");
print_usage_line(1, "-vet-using-param");
print_usage_line(2, "Checks for the use of 'using' on procedure parameters");
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring");
print_usage_line(0, "");
print_usage_line(1, "-vet-style");
print_usage_line(2, "Errs on missing trailing commas followed by a newline");
print_usage_line(2, "Errs on deprecated syntax");
print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style)");
print_usage_line(0, "");
print_usage_line(1, "-vet-semicolon");
print_usage_line(2, "Errs on unneeded semicolons");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-extra"); print_usage_line(1, "-vet-extra");
print_usage_line(2, "Do even more checks than standard vet on the code"); print_usage_line(2, "Do even more checks than standard vet on the code");
print_usage_line(2, "To treat the extra warnings as errors, use -warnings-as-errors"); print_usage_line(2, "To treat the extra warnings as errors, use -warnings-as-errors");
print_usage_line(0, ""); print_usage_line(0, "");
}
if (check) {
print_usage_line(1, "-ignore-unknown-attributes"); print_usage_line(1, "-ignore-unknown-attributes");
print_usage_line(2, "Ignores unknown attributes"); print_usage_line(2, "Ignores unknown attributes");
print_usage_line(2, "This can be used with metaprogramming tools"); print_usage_line(2, "This can be used with metaprogramming tools");
@@ -1804,10 +1856,8 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(1, "-strict-style"); print_usage_line(1, "-strict-style");
print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons"); print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons");
print_usage_line(0, ""); print_usage_line(2, "Errs on missing trailing commas followed by a newline");
print_usage_line(2, "Errs on deprecated syntax");
print_usage_line(1, "-strict-style-init-only");
print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons, only on the initial project");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-ignore-warnings"); print_usage_line(1, "-ignore-warnings");
@@ -2417,7 +2467,7 @@ int main(int arg_count, char const **arg_ptr) {
for_array(i, build_context.build_paths) { for_array(i, build_context.build_paths) {
String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]); String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]);
debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path)); debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path));
} }
} }
TIME_SECTION("init thread pool"); TIME_SECTION("init thread pool");
@@ -2487,7 +2537,7 @@ int main(int arg_count, char const **arg_ptr) {
return 0; return 0;
} }
#if defined(GB_SYSTEM_WINDOWS) #if ALLOW_TILDE
if (build_context.tilde_backend) { if (build_context.tilde_backend) {
LinkerData linker_data = {}; LinkerData linker_data = {};
MAIN_TIME_SECTION("Tilde Code Gen"); MAIN_TIME_SECTION("Tilde Code Gen");
+127 -33
View File
@@ -1,7 +1,21 @@
#include "parser_pos.cpp" #include "parser_pos.cpp"
// #undef at the bottom of this file gb_internal u64 ast_file_vet_flags(AstFile *f) {
#define ALLOW_NEWLINE (!build_context.strict_style) if (f->vet_flags_set) {
return f->vet_flags;
}
return build_context.vet_flags;
}
gb_internal bool ast_file_vet_style(AstFile *f) {
return (ast_file_vet_flags(f) & VetFlag_Style) != 0;
}
gb_internal bool file_allow_newline(AstFile *f) {
bool is_strict = build_context.strict_style || ast_file_vet_style(f);
return !is_strict;
}
gb_internal Token token_end_of_line(AstFile *f, Token tok) { gb_internal Token token_end_of_line(AstFile *f, Token tok) {
u8 const *start = f->tokenizer.start + tok.pos.offset; u8 const *start = f->tokenizer.start + tok.pos.offset;
@@ -1567,29 +1581,29 @@ gb_internal void assign_removal_flag_to_semicolon(AstFile *f) {
Token *prev_token = &f->tokens[f->prev_token_index]; Token *prev_token = &f->tokens[f->prev_token_index];
Token *curr_token = &f->tokens[f->curr_token_index]; Token *curr_token = &f->tokens[f->curr_token_index];
GB_ASSERT(prev_token->kind == Token_Semicolon); GB_ASSERT(prev_token->kind == Token_Semicolon);
if (prev_token->string == ";") { if (prev_token->string != ";") {
bool ok = false; return;
if (curr_token->pos.line > prev_token->pos.line) { }
bool ok = false;
if (curr_token->pos.line > prev_token->pos.line) {
ok = true;
} else if (curr_token->pos.line == prev_token->pos.line) {
switch (curr_token->kind) {
case Token_CloseBrace:
case Token_CloseParen:
case Token_EOF:
ok = true; ok = true;
} else if (curr_token->pos.line == prev_token->pos.line) { break;
switch (curr_token->kind) {
case Token_CloseBrace:
case Token_CloseParen:
case Token_EOF:
ok = true;
break;
}
}
if (ok) {
if (build_context.strict_style) {
syntax_error(*prev_token, "Found unneeded semicolon");
} else if (build_context.strict_style_init_only && f->pkg->kind == Package_Init) {
syntax_error(*prev_token, "Found unneeded semicolon");
}
prev_token->flags |= TokenFlag_Remove;
} }
} }
if (!ok) {
return;
}
if (build_context.strict_style || (ast_file_vet_flags(f) & VetFlag_Semicolon)) {
syntax_error(*prev_token, "Found unneeded semicolon");
}
prev_token->flags |= TokenFlag_Remove;
} }
gb_internal void expect_semicolon(AstFile *f) { gb_internal void expect_semicolon(AstFile *f) {
@@ -2748,7 +2762,7 @@ gb_internal Ast *parse_call_expr(AstFile *f, Ast *operand) {
isize prev_expr_level = f->expr_level; isize prev_expr_level = f->expr_level;
bool prev_allow_newline = f->allow_newline; bool prev_allow_newline = f->allow_newline;
f->expr_level = 0; f->expr_level = 0;
f->allow_newline = ALLOW_NEWLINE; f->allow_newline = file_allow_newline(f);
open_paren = expect_token(f, Token_OpenParen); open_paren = expect_token(f, Token_OpenParen);
@@ -3147,7 +3161,7 @@ gb_internal Ast *parse_expr(AstFile *f, bool lhs) {
gb_internal Array<Ast *> parse_expr_list(AstFile *f, bool lhs) { gb_internal Array<Ast *> parse_expr_list(AstFile *f, bool lhs) {
bool allow_newline = f->allow_newline; bool allow_newline = f->allow_newline;
f->allow_newline = ALLOW_NEWLINE; f->allow_newline = file_allow_newline(f);
auto list = array_make<Ast *>(heap_allocator()); auto list = array_make<Ast *>(heap_allocator());
for (;;) { for (;;) {
@@ -3472,7 +3486,7 @@ gb_internal Ast *parse_results(AstFile *f, bool *diverging) {
Ast *list = nullptr; Ast *list = nullptr;
expect_token(f, Token_OpenParen); expect_token(f, Token_OpenParen);
list = parse_field_list(f, nullptr, FieldFlag_Results, Token_CloseParen, true, false); list = parse_field_list(f, nullptr, FieldFlag_Results, Token_CloseParen, true, false);
if (ALLOW_NEWLINE) { if (file_allow_newline(f)) {
skip_possible_newline(f); skip_possible_newline(f);
} }
expect_token_after(f, Token_CloseParen, "parameter list"); expect_token_after(f, Token_CloseParen, "parameter list");
@@ -3532,7 +3546,7 @@ gb_internal Ast *parse_proc_type(AstFile *f, Token proc_token) {
expect_token(f, Token_OpenParen); expect_token(f, Token_OpenParen);
params = parse_field_list(f, nullptr, FieldFlag_Signature, Token_CloseParen, true, true); params = parse_field_list(f, nullptr, FieldFlag_Signature, Token_CloseParen, true, true);
if (ALLOW_NEWLINE) { if (file_allow_newline(f)) {
skip_possible_newline(f); skip_possible_newline(f);
} }
expect_token_after(f, Token_CloseParen, "parameter list"); expect_token_after(f, Token_CloseParen, "parameter list");
@@ -3754,7 +3768,7 @@ gb_internal bool allow_field_separator(AstFile *f) {
} }
if (token.kind == Token_Semicolon) { if (token.kind == Token_Semicolon) {
bool ok = false; bool ok = false;
if (ALLOW_NEWLINE && token_is_newline(token)) { if (file_allow_newline(f) && token_is_newline(token)) {
TokenKind next = peek_token(f).kind; TokenKind next = peek_token(f).kind;
switch (next) { switch (next) {
case Token_CloseBrace: case Token_CloseBrace:
@@ -3818,7 +3832,7 @@ gb_internal bool check_procedure_name_list(Array<Ast *> const &names) {
gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters, bool allow_typeid_token) { gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters, bool allow_typeid_token) {
bool prev_allow_newline = f->allow_newline; bool prev_allow_newline = f->allow_newline;
defer (f->allow_newline = prev_allow_newline); defer (f->allow_newline = prev_allow_newline);
f->allow_newline = ALLOW_NEWLINE; f->allow_newline = file_allow_newline(f);
Token start_token = f->curr_token; Token start_token = f->curr_token;
@@ -4954,7 +4968,6 @@ gb_internal bool init_parser(Parser *p) {
gb_internal void destroy_parser(Parser *p) { gb_internal void destroy_parser(Parser *p) {
GB_ASSERT(p != nullptr); GB_ASSERT(p != nullptr);
// TODO(bill): Fix memory leak
for (AstPackage *pkg : p->packages) { for (AstPackage *pkg : p->packages) {
for (AstFile *file : pkg->files) { for (AstFile *file : pkg->files) {
destroy_ast_file(file); destroy_ast_file(file);
@@ -4998,7 +5011,6 @@ gb_internal WORKER_TASK_PROC(parser_worker_proc) {
gb_internal void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) { gb_internal void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) {
// TODO(bill): Use a better allocator
ImportedFile f = {pkg, fi, pos, p->file_to_process_count++}; ImportedFile f = {pkg, fi, pos, p->file_to_process_count++};
auto wd = gb_alloc_item(permanent_allocator(), ParserWorkerData); auto wd = gb_alloc_item(permanent_allocator(), ParserWorkerData);
wd->parser = p; wd->parser = p;
@@ -5528,6 +5540,88 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
return any_correct; return any_correct;
} }
gb_internal String vet_tag_get_token(String s, String *out) {
s = string_trim_whitespace(s);
isize n = 0;
while (n < s.len) {
Rune rune = 0;
isize width = utf8_decode(&s[n], s.len-n, &rune);
if (n == 0 && rune == '!') {
} else if (!rune_is_letter(rune) && !rune_is_digit(rune) && rune != '-') {
isize k = gb_max(gb_max(n, width), 1);
*out = substring(s, k, s.len);
return substring(s, 0, k);
}
n += width;
}
out->len = 0;
return s;
}
gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
String const prefix = str_lit("+vet");
GB_ASSERT(string_starts_with(s, prefix));
s = string_trim_whitespace(substring(s, prefix.len, s.len));
if (s.len == 0) {
return VetFlag_All;
}
u64 vet_flags = 0;
u64 vet_not_flags = 0;
while (s.len > 0) {
String p = string_trim_whitespace(vet_tag_get_token(s, &s));
if (p.len == 0) {
break;
}
bool is_notted = false;
if (p[0] == '!') {
is_notted = true;
p = substring(p, 1, p.len);
if (p.len == 0) {
syntax_error(token_for_pos, "Expected a vet flag name after '!'");
return build_context.vet_flags;
}
}
u64 flag = get_vet_flag_from_name(p);
if (flag != VetFlag_NONE) {
if (is_notted) {
vet_not_flags |= flag;
} else {
vet_flags |= flag;
}
} else {
ERROR_BLOCK();
syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p));
error_line("\tExpected one of the following\n");
error_line("\tunused\n");
error_line("\tshadowing\n");
error_line("\tusing-stmt\n");
error_line("\tusing-param\n");
error_line("\textra\n");
return build_context.vet_flags;
}
}
if (vet_flags == 0 && vet_not_flags == 0) {
return build_context.vet_flags;
}
if (vet_flags == 0 && vet_not_flags != 0) {
return build_context.vet_flags &~ vet_not_flags;
}
if (vet_flags != 0 && vet_not_flags == 0) {
return vet_flags;
}
GB_ASSERT(vet_flags != 0 && vet_not_flags != 0);
return vet_flags &~ vet_not_flags;
}
gb_internal String dir_from_path(String path) { gb_internal String dir_from_path(String path) {
String base_dir = path; String base_dir = path;
for (isize i = path.len-1; i >= 0; i--) { for (isize i = path.len-1; i >= 0; i--) {
@@ -5679,6 +5773,9 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
if (!parse_build_tag(tok, lc)) { if (!parse_build_tag(tok, lc)) {
return false; return false;
} }
} else if (string_starts_with(lc, str_lit("+vet"))) {
f->vet_flags = parse_vet_tag(tok, lc);
f->vet_flags_set = true;
} else if (string_starts_with(lc, str_lit("+ignore"))) { } else if (string_starts_with(lc, str_lit("+ignore"))) {
return false; return false;
} else if (string_starts_with(lc, str_lit("+private"))) { } else if (string_starts_with(lc, str_lit("+private"))) {
@@ -5920,6 +6017,3 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) {
return ParseFile_None; return ParseFile_None;
} }
#undef ALLOW_NEWLINE
+2
View File
@@ -104,6 +104,8 @@ struct AstFile {
Token package_token; Token package_token;
String package_name; String package_name;
u64 vet_flags;
bool vet_flags_set;
// >= 0: In Expression // >= 0: In Expression
// < 0: In Control Clause // < 0: In Control Clause
+2 -2
View File
@@ -696,8 +696,8 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) {
if (entry->kind != Token_Invalid && entry->hash == hash) { if (entry->kind != Token_Invalid && entry->hash == hash) {
if (str_eq(entry->text, token->string)) { if (str_eq(entry->text, token->string)) {
token->kind = entry->kind; token->kind = entry->kind;
if (token->kind == Token_not_in && entry->text == "notin") { if (token->kind == Token_not_in && entry->text.len == 5) {
syntax_warning(*token, "'notin' is deprecated in favour of 'not_in'"); syntax_error(*token, "Did you mean 'not_in'?");
} }
} }
} }
+14 -10
View File
@@ -143,6 +143,7 @@ struct TypeStruct {
Type * soa_elem; Type * soa_elem;
i32 soa_count; i32 soa_count;
StructSoaKind soa_kind; StructSoaKind soa_kind;
BlockingMutex mutex; // for settings offsets
bool is_polymorphic; bool is_polymorphic;
bool are_offsets_set : 1; bool are_offsets_set : 1;
@@ -244,6 +245,7 @@ struct TypeProc {
TYPE_KIND(Tuple, struct { \ TYPE_KIND(Tuple, struct { \
Slice<Entity *> variables; /* Entity_Variable */ \ Slice<Entity *> variables; /* Entity_Variable */ \
i64 * offsets; \ i64 * offsets; \
BlockingMutex mutex; /* for settings offsets */ \
bool are_offsets_being_processed; \ bool are_offsets_being_processed; \
bool are_offsets_set; \ bool are_offsets_set; \
bool is_packed; \ bool is_packed; \
@@ -822,6 +824,9 @@ gb_internal void type_path_pop(TypePath *tp) {
#define FAILURE_ALIGNMENT 0 #define FAILURE_ALIGNMENT 0
gb_internal bool type_ptr_set_update(PtrSet<Type *> *s, Type *t) { gb_internal bool type_ptr_set_update(PtrSet<Type *> *s, Type *t) {
if (t == nullptr) {
return true;
}
if (ptr_set_exists(s, t)) { if (ptr_set_exists(s, t)) {
return true; return true;
} }
@@ -830,13 +835,17 @@ gb_internal bool type_ptr_set_update(PtrSet<Type *> *s, Type *t) {
} }
gb_internal bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t) { gb_internal bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t) {
if (t == nullptr) {
return true;
}
if (ptr_set_exists(s, t)) { if (ptr_set_exists(s, t)) {
return true; return true;
} }
// TODO(bill, 2019-10-05): This is very slow and it's probably a lot // TODO(bill, 2019-10-05): This is very slow and it's probably a lot
// faster to cache types correctly // faster to cache types correctly
for (Type *f : *s) { for (Type *f : *s) if (f->kind == t->kind) {
if (are_types_identical(t, f)) { if (are_types_identical(t, f)) {
ptr_set_add(s, t); ptr_set_add(s, t);
return true; return true;
@@ -989,7 +998,7 @@ gb_internal Type *alloc_type_enumerated_array(Type *elem, Type *index, ExactValu
gb_internal Type *alloc_type_slice(Type *elem) { gb_internal Type *alloc_type_slice(Type *elem) {
Type *t = alloc_type(Type_Slice); Type *t = alloc_type(Type_Slice);
t->Array.elem = elem; t->Slice.elem = elem;
return t; return t;
} }
@@ -2667,7 +2676,6 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
x->Struct.soa_kind == y->Struct.soa_kind && x->Struct.soa_kind == y->Struct.soa_kind &&
x->Struct.soa_count == y->Struct.soa_count && x->Struct.soa_count == y->Struct.soa_count &&
are_types_identical(x->Struct.soa_elem, y->Struct.soa_elem)) { are_types_identical(x->Struct.soa_elem, y->Struct.soa_elem)) {
// TODO(bill); Fix the custom alignment rule
for_array(i, x->Struct.fields) { for_array(i, x->Struct.fields) {
Entity *xf = x->Struct.fields[i]; Entity *xf = x->Struct.fields[i];
Entity *yf = y->Struct.fields[i]; Entity *yf = y->Struct.fields[i];
@@ -2808,7 +2816,6 @@ gb_internal i64 union_tag_size(Type *u) {
return 0; return 0;
} }
// TODO(bill): Is this an okay approach?
i64 max_align = 1; i64 max_align = 1;
if (u->Union.variants.count < 1ull<<8) { if (u->Union.variants.count < 1ull<<8) {
@@ -2818,7 +2825,7 @@ gb_internal i64 union_tag_size(Type *u) {
} else if (u->Union.variants.count < 1ull<<32) { } else if (u->Union.variants.count < 1ull<<32) {
max_align = 4; max_align = 4;
} else { } else {
GB_PANIC("how many variants do you have?!"); compiler_error("how many variants do you have?! %lld", cast(long long)u->Union.variants.count);
} }
for_array(i, u->Union.variants) { for_array(i, u->Union.variants) {
@@ -3137,8 +3144,6 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
switch (type->Basic.kind) { switch (type->Basic.kind) {
case Basic_any: { case Basic_any: {
#if 1 #if 1
// IMPORTANT TODO(bill): Should these members be available to should I only allow them with
// `Raw_Any` type?
String data_str = str_lit("data"); String data_str = str_lit("data");
String id_str = str_lit("id"); String id_str = str_lit("id");
gb_local_persist Entity *entity__any_data = alloc_entity_field(nullptr, make_token_ident(data_str), t_rawptr, false, 0); gb_local_persist Entity *entity__any_data = alloc_entity_field(nullptr, make_token_ident(data_str), t_rawptr, false, 0);
@@ -3672,10 +3677,9 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
} }
gb_internal bool type_set_offsets(Type *t) { gb_internal bool type_set_offsets(Type *t) {
MUTEX_GUARD(&g_type_mutex); // TODO(bill): only per struct
t = base_type(t); t = base_type(t);
if (t->kind == Type_Struct) { if (t->kind == Type_Struct) {
MUTEX_GUARD(&t->Struct.mutex);
if (!t->Struct.are_offsets_set) { if (!t->Struct.are_offsets_set) {
t->Struct.are_offsets_being_processed = true; t->Struct.are_offsets_being_processed = true;
t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union); t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union);
@@ -3684,6 +3688,7 @@ gb_internal bool type_set_offsets(Type *t) {
return true; return true;
} }
} else if (is_type_tuple(t)) { } else if (is_type_tuple(t)) {
MUTEX_GUARD(&t->Tuple.mutex);
if (!t->Tuple.are_offsets_set) { if (!t->Tuple.are_offsets_set) {
t->Tuple.are_offsets_being_processed = true; t->Tuple.are_offsets_being_processed = true;
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false); t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false);
@@ -3858,7 +3863,6 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
max = size; max = size;
} }
} }
// TODO(bill): Is this how it should work?
return align_formula(max, align); return align_formula(max, align);
} else { } else {
i64 count = 0, size = 0, align = 0; i64 count = 0, size = 0, align = 0;
+14 -20
View File
@@ -21,16 +21,13 @@ main :: proc() {
@test @test
test_read :: proc(t: ^testing.T) { test_read :: proc(t: ^testing.T) {
using hxa
filename := tc.get_data_path(t, TEAPOT_PATH) filename := tc.get_data_path(t, TEAPOT_PATH)
defer delete(filename) defer delete(filename)
file, err := read_from_file(filename) file, err := hxa.read_from_file(filename)
e :: hxa.Read_Error.None e :: hxa.Read_Error.None
tc.expect(t, err == e, fmt.tprintf("%v: read_from_file(%v) -> %v != %v", #procedure, filename, err, e)) tc.expect(t, err == e, fmt.tprintf("%v: read_from_file(%v) -> %v != %v", #procedure, filename, err, e))
defer file_destroy(file) defer hxa.file_destroy(file)
/* Header */ /* Header */
tc.expect(t, file.magic_number == 0x417848, fmt.tprintf("%v: file.magic_number %v != %v", tc.expect(t, file.magic_number == 0x417848, fmt.tprintf("%v: file.magic_number %v != %v",
@@ -134,38 +131,35 @@ test_read :: proc(t: ^testing.T) {
@test @test
test_write :: proc(t: ^testing.T) { test_write :: proc(t: ^testing.T) {
n1: hxa.Node
using hxa
n1 :Node
n1_m1_value := []f64le{0.4, -1.23, 2341.6, -333.333} n1_m1_value := []f64le{0.4, -1.23, 2341.6, -333.333}
n1_m1 := Meta{"m1", n1_m1_value} n1_m1 := hxa.Meta{"m1", n1_m1_value}
n1.meta_data = []Meta{n1_m1} n1.meta_data = []hxa.Meta{n1_m1}
n1_l1 := Layer{"l1", 2, []f32le{32.1, -41.3}} n1_l1 := hxa.Layer{"l1", 2, []f32le{32.1, -41.3}}
n1_l2 := Layer{"l2", 3, []f64le{0.64, 1.64, -2.64}} n1_l2 := hxa.Layer{"l2", 3, []f64le{0.64, 1.64, -2.64}}
n1_content := Node_Image{Image_Type.Image_1D, [3]u32le{1, 1, 2}, Layer_Stack{n1_l1, n1_l2}} n1_content := hxa.Node_Image{.Image_1D, [3]u32le{1, 1, 2}, hxa.Layer_Stack{n1_l1, n1_l2}}
n1.content = n1_content n1.content = n1_content
w_file :File w_file: hxa.File
w_file.nodes = []Node{n1} w_file.nodes = []hxa.Node{n1}
required_size := required_write_size(w_file) required_size := hxa.required_write_size(w_file)
buf := make([]u8, required_size) buf := make([]u8, required_size)
n, write_err := write(buf, w_file) n, write_err := hxa.write(buf, w_file)
write_e :: hxa.Write_Error.None write_e :: hxa.Write_Error.None
tc.expect(t, write_err == write_e, fmt.tprintf("%v: write_err %v != %v", #procedure, write_err, write_e)) tc.expect(t, write_err == write_e, fmt.tprintf("%v: write_err %v != %v", #procedure, write_err, write_e))
tc.expect(t, n == required_size, fmt.tprintf("%v: n %v != %v", #procedure, n, required_size)) tc.expect(t, n == required_size, fmt.tprintf("%v: n %v != %v", #procedure, n, required_size))
file, read_err := read(buf) file, read_err := hxa.read(buf)
read_e :: hxa.Read_Error.None read_e :: hxa.Read_Error.None
tc.expect(t, read_err == read_e, fmt.tprintf("%v: read_err %v != %v", #procedure, read_err, read_e)) tc.expect(t, read_err == read_e, fmt.tprintf("%v: read_err %v != %v", #procedure, read_err, read_e))
defer file_destroy(file) defer hxa.file_destroy(file)
delete(buf) delete(buf)
+33 -36
View File
@@ -47,7 +47,7 @@ TESTS :: []TEST{
}, },
expected_doctype = "恥ずべきフクロウ", expected_doctype = "恥ずべきフクロウ",
}, },
crc32 = 0x30d82264, crc32 = 0xe9b62f03,
}, },
{ {
@@ -62,7 +62,7 @@ TESTS :: []TEST{
}, },
expected_doctype = "恥ずべきフクロウ", expected_doctype = "恥ずべきフクロウ",
}, },
crc32 = 0xad31d8e8, crc32 = 0x9c2643ed,
}, },
{ {
@@ -77,7 +77,7 @@ TESTS :: []TEST{
}, },
expected_doctype = "TS", expected_doctype = "TS",
}, },
crc32 = 0x7bce2630, crc32 = 0x859b7443,
}, },
{ {
@@ -92,7 +92,7 @@ TESTS :: []TEST{
}, },
expected_doctype = "xliff", expected_doctype = "xliff",
}, },
crc32 = 0x43f19d61, crc32 = 0x3deaf329,
}, },
{ {
@@ -107,7 +107,7 @@ TESTS :: []TEST{
}, },
expected_doctype = "xliff", expected_doctype = "xliff",
}, },
crc32 = 0x961e7635, crc32 = 0x0c55e287,
}, },
{ {
@@ -118,7 +118,7 @@ TESTS :: []TEST{
}, },
expected_doctype = "html", expected_doctype = "html",
}, },
crc32 = 0x573c1033, crc32 = 0x05373317,
}, },
{ {
@@ -129,7 +129,7 @@ TESTS :: []TEST{
}, },
expected_doctype = "html", expected_doctype = "html",
}, },
crc32 = 0x82588917, crc32 = 0x3b6d4a90,
}, },
{ {
@@ -140,7 +140,7 @@ TESTS :: []TEST{
}, },
expected_doctype = "html", expected_doctype = "html",
}, },
crc32 = 0x5e74d8a6, crc32 = 0x5be2ffdc,
}, },
/* /*
@@ -170,7 +170,7 @@ TESTS :: []TEST{
expected_doctype = "", expected_doctype = "",
}, },
err = .None, err = .None,
crc32 = 0xcaa042b9, crc32 = 0x420dbac5,
}, },
} }
@@ -214,43 +214,40 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) {
*/ */
print :: proc(writer: io.Writer, doc: ^xml.Document) -> (written: int, err: io.Error) { print :: proc(writer: io.Writer, doc: ^xml.Document) -> (written: int, err: io.Error) {
if doc == nil { return } if doc == nil { return }
using fmt
written += wprintf(writer, "[XML Prolog]\n") written += fmt.wprintf(writer, "[XML Prolog]\n")
for attr in doc.prologue { for attr in doc.prologue {
written += wprintf(writer, "\t%v: %v\n", attr.key, attr.val) written += fmt.wprintf(writer, "\t%v: %v\n", attr.key, attr.val)
} }
written += wprintf(writer, "[Encoding] %v\n", doc.encoding) written += fmt.wprintf(writer, "[Encoding] %v\n", doc.encoding)
if len(doc.doctype.ident) > 0 { if len(doc.doctype.ident) > 0 {
written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) written += fmt.wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident)
if len(doc.doctype.rest) > 0 { if len(doc.doctype.rest) > 0 {
wprintf(writer, "\t%v\n", doc.doctype.rest) fmt.wprintf(writer, "\t%v\n", doc.doctype.rest)
} }
} }
for comment in doc.comments { for comment in doc.comments {
written += wprintf(writer, "[Pre-root comment] %v\n", comment) written += fmt.wprintf(writer, "[Pre-root comment] %v\n", comment)
} }
if doc.element_count > 0 { if doc.element_count > 0 {
wprintln(writer, " --- ") fmt.wprintln(writer, " --- ")
print_element(writer, doc, 0) print_element(writer, doc, 0)
wprintln(writer, " --- ") fmt.wprintln(writer, " --- ")
} }
return written, .None return written, .None
} }
print_element :: proc(writer: io.Writer, doc: ^xml.Document, element_id: xml.Element_ID, indent := 0) -> (written: int, err: io.Error) { print_element :: proc(writer: io.Writer, doc: ^xml.Document, element_id: xml.Element_ID, indent := 0) -> (written: int, err: io.Error) {
using fmt
tab :: proc(writer: io.Writer, indent: int) { tab :: proc(writer: io.Writer, indent: int) {
for _ in 0..=indent { for _ in 0..=indent {
wprintf(writer, "\t") fmt.wprintf(writer, "\t")
} }
} }
@@ -259,22 +256,24 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) {
element := doc.elements[element_id] element := doc.elements[element_id]
if element.kind == .Element { if element.kind == .Element {
wprintf(writer, "<%v>\n", element.ident) fmt.wprintf(writer, "<%v>\n", element.ident)
if len(element.value) > 0 {
tab(writer, indent + 1) for value in element.value {
wprintf(writer, "[Value] %v\n", element.value) switch v in value {
case string:
tab(writer, indent + 1)
fmt.wprintf(writer, "[Value] %v\n", v)
case xml.Element_ID:
print_element(writer, doc, v, indent + 1)
}
} }
for attr in element.attribs { for attr in element.attribs {
tab(writer, indent + 1) tab(writer, indent + 1)
wprintf(writer, "[Attr] %v: %v\n", attr.key, attr.val) fmt.wprintf(writer, "[Attr] %v: %v\n", attr.key, attr.val)
}
for child in element.children {
print_element(writer, doc, child, indent + 1)
} }
} else if element.kind == .Comment { } else if element.kind == .Comment {
wprintf(writer, "[COMMENT] %v\n", element.value) fmt.wprintf(writer, "[COMMENT] %v\n", element.value)
} }
return written, .None return written, .None
@@ -289,8 +288,6 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) {
@test @test
run_tests :: proc(t: ^testing.T) { run_tests :: proc(t: ^testing.T) {
using fmt
for test in TESTS { for test in TESTS {
path := test_file_path(test.filename) path := test_file_path(test.filename)
log(t, fmt.tprintf("Trying to parse %v", path)) log(t, fmt.tprintf("Trying to parse %v", path))
@@ -305,11 +302,11 @@ run_tests :: proc(t: ^testing.T) {
crc32 := hash.crc32(tree_bytes) crc32 := hash.crc32(tree_bytes)
failed := err != test.err failed := err != test.err
err_msg := tprintf("Expected return value %v, got %v", test.err, err) err_msg := fmt.tprintf("Expected return value %v, got %v", test.err, err)
expect(t, err == test.err, err_msg) expect(t, err == test.err, err_msg)
failed |= crc32 != test.crc32 failed |= crc32 != test.crc32
err_msg = tprintf("Expected CRC 0x%08x, got 0x%08x, with options %v", test.crc32, crc32, test.options) err_msg = fmt.tprintf("Expected CRC 0x%08x, got 0x%08x, with options %v", test.crc32, crc32, test.options)
expect(t, crc32 == test.crc32, err_msg) expect(t, crc32 == test.crc32, err_msg)
if failed { if failed {
@@ -317,7 +314,7 @@ run_tests :: proc(t: ^testing.T) {
Don't fully print big trees. Don't fully print big trees.
*/ */
tree_string = tree_string[:min(2_048, len(tree_string))] tree_string = tree_string[:min(2_048, len(tree_string))]
println(tree_string) fmt.println(tree_string)
} }
} }
} }
@@ -22,9 +22,6 @@ main :: proc() {
@test @test
test_fract_f32 :: proc(t: ^testing.T) { test_fract_f32 :: proc(t: ^testing.T) {
using math
r: f32 r: f32
Datum :: struct { Datum :: struct {
@@ -35,8 +32,8 @@ test_fract_f32 :: proc(t: ^testing.T) {
@static data := []Datum{ @static data := []Datum{
{ 0, 10.5, 0.5 }, // Issue #1574 fract in linalg/glm is broken { 0, 10.5, 0.5 }, // Issue #1574 fract in linalg/glm is broken
{ 1, -10.5, -0.5 }, { 1, -10.5, -0.5 },
{ 2, F32_MIN, F32_MIN }, // 0x1p-126 { 2, math.F32_MIN, math.F32_MIN }, // 0x1p-126
{ 3, -F32_MIN, -F32_MIN }, { 3, -math.F32_MIN, -math.F32_MIN },
{ 4, 0.0, 0.0 }, { 4, 0.0, 0.0 },
{ 5, -0.0, -0.0 }, { 5, -0.0, -0.0 },
{ 6, 1, 0.0 }, { 6, 1, 0.0 },
@@ -54,9 +51,6 @@ test_fract_f32 :: proc(t: ^testing.T) {
@test @test
test_fract_f64 :: proc(t: ^testing.T) { test_fract_f64 :: proc(t: ^testing.T) {
using math
r: f64 r: f64
Datum :: struct { Datum :: struct {
@@ -67,8 +61,8 @@ test_fract_f64 :: proc(t: ^testing.T) {
@static data := []Datum{ @static data := []Datum{
{ 0, 10.5, 0.5 }, // Issue #1574 fract in linalg/glm is broken { 0, 10.5, 0.5 }, // Issue #1574 fract in linalg/glm is broken
{ 1, -10.5, -0.5 }, { 1, -10.5, -0.5 },
{ 2, F64_MIN, F64_MIN }, // 0x1p-1022 { 2, math.F64_MIN, math.F64_MIN }, // 0x1p-1022
{ 3, -F64_MIN, -F64_MIN }, { 3, -math.F64_MIN, -math.F64_MIN },
{ 4, 0.0, 0.0 }, { 4, 0.0, 0.0 },
{ 5, -0.0, -0.0 }, { 5, -0.0, -0.0 },
{ 6, 1, 0.0 }, { 6, 1, 0.0 },
+73 -94
View File
@@ -43,11 +43,7 @@ main :: proc() {
@test @test
test_classify_f16 :: proc(t: ^testing.T) { test_classify_f16 :: proc(t: ^testing.T) {
r: math.Float_Class
using math
using Float_Class
r: Float_Class
Datum :: struct { Datum :: struct {
i: int, i: int,
@@ -55,38 +51,34 @@ test_classify_f16 :: proc(t: ^testing.T) {
e: math.Float_Class, e: math.Float_Class,
} }
@static data := []Datum{ @static data := []Datum{
{ 0, 1.2, Normal }, { 0, 1.2, .Normal },
{ 1, 0h0001, Subnormal }, { 1, 0h0001, .Subnormal },
{ 2, 0.0, Zero }, { 2, 0.0, .Zero },
{ 3, -0.0, Neg_Zero }, { 3, -0.0, .Neg_Zero },
{ 4, SNAN_F16, NaN }, { 4, math.SNAN_F16, .NaN },
{ 5, QNAN_F16, NaN }, { 5, math.QNAN_F16, .NaN },
{ 6, INF_F16, Inf }, { 6, math.INF_F16, .Inf },
{ 7, NEG_INF_F16, Neg_Inf }, { 7, math.NEG_INF_F16, .Neg_Inf },
} }
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r = classify_f16(d.v) r = math.classify_f16(d.v)
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e))
} }
/* Check all subnormals (exponent 0, 10-bit significand non-zero) */ /* Check all subnormals (exponent 0, 10-bit significand non-zero) */
for i :u16 = 1; i < 0x400; i += 1 { for i in u16(1)..<0x400 {
v :f16 = transmute(f16)i v := transmute(f16)i
r = classify_f16(v) r = math.classify_f16(v)
e :Float_Class: Subnormal e :: math.Float_Class.Subnormal
tc.expect(t, r == e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, v, r, e)) tc.expect(t, r == e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, v, r, e))
} }
} }
@test @test
test_classify_f32 :: proc(t: ^testing.T) { test_classify_f32 :: proc(t: ^testing.T) {
r: math.Float_Class
using math
using Float_Class
r: Float_Class
Datum :: struct { Datum :: struct {
i: int, i: int,
@@ -94,30 +86,26 @@ test_classify_f32 :: proc(t: ^testing.T) {
e: math.Float_Class, e: math.Float_Class,
} }
@static data := []Datum{ @static data := []Datum{
{ 0, 1.2, Normal }, { 0, 1.2, .Normal },
{ 1, 0h0000_0001, Subnormal }, { 1, 0h0000_0001, .Subnormal },
{ 2, 0.0, Zero }, { 2, 0.0, .Zero },
{ 3, -0.0, Neg_Zero }, { 3, -0.0, .Neg_Zero },
{ 4, SNAN_F32, NaN }, { 4, math.SNAN_F32, .NaN },
{ 5, QNAN_F32, NaN }, { 5, math.QNAN_F32, .NaN },
{ 6, INF_F32, Inf }, { 6, math.INF_F32, .Inf },
{ 7, NEG_INF_F32, Neg_Inf }, { 7, math.NEG_INF_F32, .Neg_Inf },
} }
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r = classify_f32(d.v) r = math.classify_f32(d.v)
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e))
} }
} }
@test @test
test_classify_f64 :: proc(t: ^testing.T) { test_classify_f64 :: proc(t: ^testing.T) {
r: math.Float_Class
using math
using Float_Class
r: Float_Class
Datum :: struct { Datum :: struct {
i: int, i: int,
@@ -125,28 +113,25 @@ test_classify_f64 :: proc(t: ^testing.T) {
e: math.Float_Class, e: math.Float_Class,
} }
@static data := []Datum{ @static data := []Datum{
{ 0, 1.2, Normal }, { 0, 1.2, .Normal },
{ 1, 0h0000_0000_0000_0001, Subnormal }, { 1, 0h0000_0000_0000_0001, .Subnormal },
{ 2, 0.0, Zero }, { 2, 0.0, .Zero },
{ 3, -0.0, Neg_Zero }, { 3, -0.0, .Neg_Zero },
{ 4, SNAN_F64, NaN }, { 4, math.SNAN_F64, .NaN },
{ 5, QNAN_F64, NaN }, { 5, math.QNAN_F64, .NaN },
{ 6, INF_F64, Inf }, { 6, math.INF_F64, .Inf },
{ 7, NEG_INF_F64, Neg_Inf }, { 7, math.NEG_INF_F64, .Neg_Inf },
} }
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r = classify_f64(d.v) r = math.classify_f64(d.v)
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e))
} }
} }
@test @test
test_trunc_f16 :: proc(t: ^testing.T) { test_trunc_f16 :: proc(t: ^testing.T) {
using math
r, v: f16 r, v: f16
Datum :: struct { Datum :: struct {
@@ -158,16 +143,16 @@ test_trunc_f16 :: proc(t: ^testing.T) {
{ 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken { 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken
{ 1, -10.5, -10 }, { 1, -10.5, -10 },
{ 2, F16_MAX, F16_MAX }, { 2, math.F16_MAX, math.F16_MAX },
{ 3, -F16_MAX, -F16_MAX }, { 3, -math.F16_MAX, -math.F16_MAX },
{ 4, F16_MIN, 0.0 }, { 4, math.F16_MIN, 0.0 },
{ 5, -F16_MIN, -0.0 }, { 5, -math.F16_MIN, -0.0 },
{ 6, 0.0, 0.0 }, { 6, 0.0, 0.0 },
{ 7, -0.0, -0.0 }, { 7, -0.0, -0.0 },
{ 8, 1, 1 }, { 8, 1, 1 },
{ 9, -1, -1 }, { 9, -1, -1 },
{ 10, INF_F16, INF_F16 }, { 10, math.INF_F16, math.INF_F16 },
{ 11, NEG_INF_F16, NEG_INF_F16 }, { 11, math.NEG_INF_F16, math.NEG_INF_F16 },
/* From https://en.wikipedia.org/wiki/Half-precision_floating-point_format */ /* From https://en.wikipedia.org/wiki/Half-precision_floating-point_format */
{ 12, 0h3C01, 1 }, // 0x1.004p+0 (smallest > 1) { 12, 0h3C01, 1 }, // 0x1.004p+0 (smallest > 1)
@@ -185,24 +170,21 @@ test_trunc_f16 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r = trunc_f16(d.v) r = math.trunc_f16(d.v)
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e))
} }
v = SNAN_F16 v = math.SNAN_F16
r = trunc_f16(v) r = math.trunc_f16(v)
tc.expect(t, is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) tc.expect(t, math.is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
v = QNAN_F16 v = math.QNAN_F16
r = trunc_f16(v) r = math.trunc_f16(v)
tc.expect(t, is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) tc.expect(t, math.is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
} }
@test @test
test_trunc_f32 :: proc(t: ^testing.T) { test_trunc_f32 :: proc(t: ^testing.T) {
using math
r, v: f32 r, v: f32
Datum :: struct { Datum :: struct {
@@ -214,16 +196,16 @@ test_trunc_f32 :: proc(t: ^testing.T) {
{ 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken { 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken
{ 1, -10.5, -10 }, { 1, -10.5, -10 },
{ 2, F32_MAX, F32_MAX }, { 2, math.F32_MAX, math.F32_MAX },
{ 3, -F32_MAX, -F32_MAX }, { 3, -math.F32_MAX, -math.F32_MAX },
{ 4, F32_MIN, 0.0 }, { 4, math.F32_MIN, 0.0 },
{ 5, -F32_MIN, -0.0 }, { 5, -math.F32_MIN, -0.0 },
{ 6, 0.0, 0.0 }, { 6, 0.0, 0.0 },
{ 7, -0.0, -0.0 }, { 7, -0.0, -0.0 },
{ 8, 1, 1 }, { 8, 1, 1 },
{ 9, -1, -1 }, { 9, -1, -1 },
{ 10, INF_F32, INF_F32 }, { 10, math.INF_F32, math.INF_F32 },
{ 11, NEG_INF_F32, NEG_INF_F32 }, { 11, math.NEG_INF_F32, math.NEG_INF_F32 },
/* From https://en.wikipedia.org/wiki/Single-precision_floating-point_format */ /* From https://en.wikipedia.org/wiki/Single-precision_floating-point_format */
{ 12, 0h3F80_0001, 1 }, // 0x1.000002p+0 (smallest > 1) { 12, 0h3F80_0001, 1 }, // 0x1.000002p+0 (smallest > 1)
@@ -250,24 +232,21 @@ test_trunc_f32 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r = trunc_f32(d.v) r = math.trunc_f32(d.v)
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e))
} }
v = SNAN_F32 v = math.SNAN_F32
r = trunc_f32(v) r = math.trunc_f32(v)
tc.expect(t, is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) tc.expect(t, math.is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
v = QNAN_F32 v = math.QNAN_F32
r = trunc_f32(v) r = math.trunc_f32(v)
tc.expect(t, is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) tc.expect(t, math.is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
} }
@test @test
test_trunc_f64 :: proc(t: ^testing.T) { test_trunc_f64 :: proc(t: ^testing.T) {
using math
r, v: f64 r, v: f64
Datum :: struct { Datum :: struct {
@@ -279,16 +258,16 @@ test_trunc_f64 :: proc(t: ^testing.T) {
{ 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken { 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken
{ 1, -10.5, -10 }, { 1, -10.5, -10 },
{ 2, F64_MAX, F64_MAX }, { 2, math.F64_MAX, math.F64_MAX },
{ 3, -F64_MAX, -F64_MAX }, { 3, -math.F64_MAX, -math.F64_MAX },
{ 4, F64_MIN, 0.0 }, { 4, math.F64_MIN, 0.0 },
{ 5, -F64_MIN, -0.0 }, { 5, -math.F64_MIN, -0.0 },
{ 6, 0.0, 0.0 }, { 6, 0.0, 0.0 },
{ 7, -0.0, -0.0 }, { 7, -0.0, -0.0 },
{ 8, 1, 1 }, { 8, 1, 1 },
{ 9, -1, -1 }, { 9, -1, -1 },
{ 10, INF_F64, INF_F64 }, { 10, math.INF_F64, math.INF_F64 },
{ 11, NEG_INF_F64, NEG_INF_F64 }, { 11, math.NEG_INF_F64, math.NEG_INF_F64 },
/* From https://en.wikipedia.org/wiki/Double-precision_floating-point_format */ /* From https://en.wikipedia.org/wiki/Double-precision_floating-point_format */
{ 12, 0h3FF0_0000_0000_0001, 1 }, // 0x1.0000000000001p+0 (smallest > 1) { 12, 0h3FF0_0000_0000_0001, 1 }, // 0x1.0000000000001p+0 (smallest > 1)
@@ -315,17 +294,17 @@ test_trunc_f64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r = trunc_f64(d.v) r = math.trunc_f64(d.v)
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e))
} }
v = SNAN_F64 v = math.SNAN_F64
r = trunc_f64(v) r = math.trunc_f64(v)
tc.expect(t, is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) tc.expect(t, math.is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
v = QNAN_F64 v = math.QNAN_F64
r = trunc_f64(v) r = math.trunc_f64(v)
tc.expect(t, is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) tc.expect(t, math.is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
} }
@@ -22,9 +22,6 @@ main :: proc() {
@test @test
test_split_list_windows :: proc(t: ^testing.T) { test_split_list_windows :: proc(t: ^testing.T) {
using filepath
Datum :: struct { Datum :: struct {
i: int, i: int,
v: string, v: string,
@@ -43,7 +40,7 @@ test_split_list_windows :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i)) assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i))
r := split_list(d.v) r := filepath.split_list(d.v)
defer delete(r) defer delete(r)
tc.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", tc.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d",
i, #procedure, d.v, len(r), len(d.e))) i, #procedure, d.v, len(r), len(d.e)))
@@ -57,12 +54,12 @@ test_split_list_windows :: proc(t: ^testing.T) {
{ {
v := "" v := ""
r := split_list(v) r := filepath.split_list(v)
tc.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r)) tc.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r))
} }
{ {
v := "a" v := "a"
r := split_list(v) r := filepath.split_list(v)
defer delete(r) defer delete(r)
tc.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r))) tc.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r)))
if len(r) == 1 { if len(r) == 1 {
@@ -73,9 +70,6 @@ test_split_list_windows :: proc(t: ^testing.T) {
@test @test
test_split_list_unix :: proc(t: ^testing.T) { test_split_list_unix :: proc(t: ^testing.T) {
using filepath
Datum :: struct { Datum :: struct {
i: int, i: int,
v: string, v: string,
@@ -94,7 +88,7 @@ test_split_list_unix :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i)) assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i))
r := split_list(d.v) r := filepath.split_list(d.v)
defer delete(r) defer delete(r)
tc.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", tc.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d",
i, #procedure, d.v, len(r), len(d.e))) i, #procedure, d.v, len(r), len(d.e)))
@@ -108,12 +102,12 @@ test_split_list_unix :: proc(t: ^testing.T) {
{ {
v := "" v := ""
r := split_list(v) r := filepath.split_list(v)
tc.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r)) tc.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r))
} }
{ {
v := "a" v := "a"
r := split_list(v) r := filepath.split_list(v)
defer delete(r) defer delete(r)
tc.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r))) tc.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r)))
if len(r) == 1 { if len(r) == 1 {
+16 -20
View File
@@ -19,8 +19,6 @@ main :: proc() {
@test @test
test_as_u64 :: proc(t: ^testing.T) { test_as_u64 :: proc(t: ^testing.T) {
using reflect
{ {
/* i8 */ /* i8 */
Datum :: struct { i: int, v: i8, e: u64 } Datum :: struct { i: int, v: i8, e: u64 }
@@ -32,7 +30,7 @@ test_as_u64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_u64(d.v) r, valid := reflect.as_u64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(i8 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(i8 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i8 %v) -> %v (0x%X) != %v (0x%X)\n", tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i8 %v) -> %v (0x%X) != %v (0x%X)\n",
i, #procedure, d.v, r, r, d.e, d.e)) i, #procedure, d.v, r, r, d.e, d.e))
@@ -49,7 +47,7 @@ test_as_u64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_u64(d.v) r, valid := reflect.as_u64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(i16 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(i16 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i16 %v) -> %v (0x%X) != %v (0x%X)\n", tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i16 %v) -> %v (0x%X) != %v (0x%X)\n",
i, #procedure, d.v, r, r, d.e, d.e)) i, #procedure, d.v, r, r, d.e, d.e))
@@ -66,7 +64,7 @@ test_as_u64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_u64(d.v) r, valid := reflect.as_u64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(i32 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(i32 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i32 %v) -> %v (0x%X) != %v (0x%X)\n", tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i32 %v) -> %v (0x%X) != %v (0x%X)\n",
i, #procedure, d.v, r, r, d.e, d.e)) i, #procedure, d.v, r, r, d.e, d.e))
@@ -83,7 +81,7 @@ test_as_u64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_u64(d.v) r, valid := reflect.as_u64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(i64 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(i64 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i64 %v) -> %v (0x%X) != %v (0x%X)\n", tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i64 %v) -> %v (0x%X) != %v (0x%X)\n",
i, #procedure, d.v, r, r, d.e, d.e)) i, #procedure, d.v, r, r, d.e, d.e))
@@ -103,7 +101,7 @@ test_as_u64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_u64(d.v) r, valid := reflect.as_u64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(i128 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(i128 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i128 %v) -> %v (0x%X) != %v (0x%X)\n", tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i128 %v) -> %v (0x%X) != %v (0x%X)\n",
i, #procedure, d.v, r, r, d.e, d.e)) i, #procedure, d.v, r, r, d.e, d.e))
@@ -119,7 +117,7 @@ test_as_u64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_u64(d.v) r, valid := reflect.as_u64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(f16 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(f16 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f16 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f16 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e))
} }
@@ -133,7 +131,7 @@ test_as_u64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_u64(d.v) r, valid := reflect.as_u64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(f32 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(f32 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f32 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f32 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e))
} }
@@ -147,7 +145,7 @@ test_as_u64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_u64(d.v) r, valid := reflect.as_u64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(f64 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(f64 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e))
} }
@@ -156,8 +154,6 @@ test_as_u64 :: proc(t: ^testing.T) {
@test @test
test_as_f64 :: proc(t: ^testing.T) { test_as_f64 :: proc(t: ^testing.T) {
using reflect
{ {
/* i8 */ /* i8 */
Datum :: struct { i: int, v: i8, e: f64 } Datum :: struct { i: int, v: i8, e: f64 }
@@ -169,7 +165,7 @@ test_as_f64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_f64(d.v) r, valid := reflect.as_f64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(i8 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(i8 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i8 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i8 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e))
} }
@@ -185,7 +181,7 @@ test_as_f64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_f64(d.v) r, valid := reflect.as_f64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(i16 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(i16 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i16 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i16 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e))
} }
@@ -201,7 +197,7 @@ test_as_f64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_f64(d.v) r, valid := reflect.as_f64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(i32 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(i32 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i32 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i32 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e))
} }
@@ -217,7 +213,7 @@ test_as_f64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_f64(d.v) r, valid := reflect.as_f64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(i64 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(i64 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e))
} }
@@ -234,7 +230,7 @@ test_as_f64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_f64(d.v) r, valid := reflect.as_f64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(i128 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(i128 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i128 %v) -> %v (%H) != %v (%H)\n", tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i128 %v) -> %v (%H) != %v (%H)\n",
i, #procedure, d.v, r, r, d.e, d.e)) i, #procedure, d.v, r, r, d.e, d.e))
@@ -250,7 +246,7 @@ test_as_f64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_f64(d.v) r, valid := reflect.as_f64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(f16 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(f16 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f16 %v (%H)) -> %v (%H) != %v (%H)\n", tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f16 %v (%H)) -> %v (%H) != %v (%H)\n",
i, #procedure, d.v, d.v, r, r, d.e, d.e)) i, #procedure, d.v, d.v, r, r, d.e, d.e))
@@ -265,7 +261,7 @@ test_as_f64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_f64(d.v) r, valid := reflect.as_f64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(f32 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(f32 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f32 %v (%H)) -> %v (%H) != %v (%H)\n", tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f32 %v (%H)) -> %v (%H) != %v (%H)\n",
i, #procedure, d.v, d.v, r, r, d.e, d.e)) i, #procedure, d.v, d.v, r, r, d.e, d.e))
@@ -280,7 +276,7 @@ test_as_f64 :: proc(t: ^testing.T) {
for d, i in data { for d, i in data {
assert(i == d.i) assert(i == d.i)
r, valid := as_f64(d.v) r, valid := reflect.as_f64(d.v)
tc.expect(t, valid, fmt.tprintf("i:%d %s(f64 %v) !valid\n", i, #procedure, d.v)) tc.expect(t, valid, fmt.tprintf("i:%d %s(f64 %v) !valid\n", i, #procedure, d.v))
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e))
} }
@@ -118,8 +118,6 @@ TESTS := []Test_Suite{
@test @test
tests :: proc(t: ^testing.T) { tests :: proc(t: ^testing.T) {
using fmt
cat: ^i18n.Translation cat: ^i18n.Translation
err: i18n.Error err: i18n.Error
@@ -142,8 +140,6 @@ tests :: proc(t: ^testing.T) {
} }
main :: proc() { main :: proc() {
using fmt
track: mem.Tracking_Allocator track: mem.Tracking_Allocator
mem.tracking_allocator_init(&track, context.allocator) mem.tracking_allocator_init(&track, context.allocator)
context.allocator = mem.tracking_allocator(&track) context.allocator = mem.tracking_allocator(&track)
@@ -157,9 +153,9 @@ main :: proc() {
} }
if len(track.allocation_map) > 0 { if len(track.allocation_map) > 0 {
println() fmt.println()
for _, v in track.allocation_map { for _, v in track.allocation_map {
printf("%v Leaked %v bytes.\n", v.location, v.size) fmt.printf("%v Leaked %v bytes.\n", v.location, v.size)
} }
} }
} }
+1
View File
@@ -15,6 +15,7 @@ set COMMON=-collection:tests=..\..
..\..\..\odin test ..\test_issue_2466.odin %COMMON% -file || exit /b ..\..\..\odin test ..\test_issue_2466.odin %COMMON% -file || exit /b
..\..\..\odin test ..\test_issue_2615.odin %COMMON% -file || exit /b ..\..\..\odin test ..\test_issue_2615.odin %COMMON% -file || exit /b
..\..\..\odin test ..\test_issue_2637.odin %COMMON% -file || exit /b ..\..\..\odin test ..\test_issue_2637.odin %COMMON% -file || exit /b
..\..\..\odin test ..\test_issue_2666.odin %COMMON% -file || exit /b
@echo off @echo off
+1
View File
@@ -18,6 +18,7 @@ $ODIN build ../test_issue_2113.odin $COMMON -file -debug
$ODIN test ../test_issue_2466.odin $COMMON -file $ODIN test ../test_issue_2466.odin $COMMON -file
$ODIN test ../test_issue_2615.odin $COMMON -file $ODIN test ../test_issue_2615.odin $COMMON -file
$ODIN test ../test_issue_2637.odin $COMMON -file $ODIN test ../test_issue_2637.odin $COMMON -file
$ODIN test ../test_issue_2666.odin $COMMON -file
if [[ $($ODIN build ../test_issue_2395.odin $COMMON -file 2>&1 >/dev/null | grep -c "$NO_NIL_ERR") -eq 2 ]] ; then if [[ $($ODIN build ../test_issue_2395.odin $COMMON -file 2>&1 >/dev/null | grep -c "$NO_NIL_ERR") -eq 2 ]] ; then
echo "SUCCESSFUL 1/1" echo "SUCCESSFUL 1/1"
else else
+26
View File
@@ -0,0 +1,26 @@
// Tests issue https://github.com/odin-lang/Odin/issues/2666
// @(disabled=<boolean>) does not work with polymorphic procs
package test_issues
import "core:testing"
@(test)
test_disabled_parapoly :: proc(t: ^testing.T) {
disabled_parapoly(t, 1)
disabled_parapoly_constant(t, 1)
}
@(private="file")
@(disabled = true)
disabled_parapoly :: proc(t: ^testing.T, num: $T) {
testing.error(t, "disabled_parapoly should be disabled")
}
@(private="file")
DISABLE :: true
@(disabled = DISABLE)
@(private = "file")
disabled_parapoly_constant :: proc(t: ^testing.T, num: $T) {
testing.error(t, "disabled_parapoly_constant should be disabled")
}
+1
View File
@@ -1,4 +1,5 @@
//+build windows, linux, darwin //+build windows, linux, darwin
//+vet !using-param
package fontstash package fontstash
import "core:runtime" import "core:runtime"