Merge branch 'master' into master

This commit is contained in:
Brendan Punsky
2019-03-18 17:22:57 -04:00
committed by GitHub
19 changed files with 691 additions and 244 deletions
+17 -8
View File
@@ -130,10 +130,15 @@ shift_right :: proc(a: ^Decimal, k: uint) {
}
shift_left :: proc(a: ^Decimal, k: uint) {
delta := int(k/4);
// NOTE(bill): used to determine buffer size required for the decimal from the binary shift
// 'k' means `1<<k` == `2^k` which equates to roundup(k*log10(2)) digits required
log10_2 :: 0.301029995663981195213738894724493026768189881462108541310;
capacity := int(f64(k)*log10_2 + 1);
r := a.count; // read index
w := a.count+delta; // write index
r := a.count; // read index
w := a.count+capacity; // write index
d := len(a.digits);
n: uint;
for r -= 1; r >= 0; r -= 1 {
@@ -141,7 +146,7 @@ shift_left :: proc(a: ^Decimal, k: uint) {
quo := n/10;
rem := n - 10*quo;
w -= 1;
if w < len(a.digits) {
if w < d {
a.digits[w] = byte('0' + rem);
} else if rem != 0 {
a.trunc = true;
@@ -153,7 +158,7 @@ shift_left :: proc(a: ^Decimal, k: uint) {
quo := n/10;
rem := n - 10*quo;
w -= 1;
if 0 <= w && w < len(a.digits) {
if w < d {
a.digits[w] = byte('0' + rem);
} else if rem != 0 {
a.trunc = true;
@@ -161,9 +166,12 @@ shift_left :: proc(a: ^Decimal, k: uint) {
n = quo;
}
a.count += delta;
a.count = min(a.count, len(a.digits));
a.decimal_point += delta;
// NOTE(bill): Remove unused buffer size
assert(w >= 0);
capacity -= w;
a.count = min(a.count+capacity, d);
a.decimal_point += capacity;
trim(a);
}
@@ -253,3 +261,4 @@ rounded_integer :: proc(a: ^Decimal) -> u64 {
}
return n;
}
+18 -20
View File
@@ -2,8 +2,6 @@ package cel;
import "core:fmt"
import "core:strconv"
import "core:os"
import "core:mem"
import "core:unicode/utf8"
import "core:strings"
@@ -34,7 +32,7 @@ Parser :: struct {
print_value :: proc(value: Value, pretty := true, indent := 0) {
print_indent :: proc(indent: int) {
for i in 0..indent-1 do fmt.print("\t");
for _ in 0..indent-1 do fmt.print("\t");
}
switch v in value {
@@ -62,16 +60,16 @@ print_value :: proc(value: Value, pretty := true, indent := 0) {
if pretty do fmt.println();
i := 0;
for name, value in v {
for name, val in v {
if pretty {
print_indent(indent+1);
fmt.printf("%s = ", name);
print_value(value, pretty, indent+1);
print_value(val, pretty, indent+1);
fmt.println(",");
} else {
if i > 0 do fmt.print(", ");
fmt.printf("%s = ", name);
print_value(value, pretty, indent+1);
print_value(val, pretty, indent+1);
i += 1;
}
}
@@ -155,7 +153,7 @@ destroy :: proc(p: ^Parser) {
delete(v);
case Dict:
for key, value in v do destroy_value(value);
for _, dv in v do destroy_value(dv);
delete(v);
}
}
@@ -201,11 +199,12 @@ unquote_char :: proc(s: string, quote: byte) -> (r: rune, multiple_bytes: bool,
}
return -1;
}
w: int;
if s[0] == quote && quote == '"' {
return;
} else if s[0] >= 0x80 {
r, w := utf8.decode_rune_in_string(s);
r, w = utf8.decode_rune_in_string(s);
return r, true, s[w:], true;
} else if s[0] != '\\' {
return rune(s[0]), false, s[1:], true;
@@ -291,7 +290,6 @@ unquote_string :: proc(p: ^Parser, t: Token) -> (string, bool) {
return t.lit, true;
}
s := t.lit;
n := len(s);
quote := '"';
if s == `""` {
@@ -442,7 +440,7 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) {
case Kind.Open_Paren:
expect_token(p, Kind.Open_Paren);
expr, pos := parse_expr(p);
expr, _ := parse_expr(p);
expect_token(p, Kind.Close_Paren);
return expr, tok.pos;
@@ -451,7 +449,7 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) {
elems := make([dynamic]Value, 0, 4);
for p.curr_token.kind != Kind.Close_Bracket &&
p.curr_token.kind != Kind.EOF {
elem, pos := parse_expr(p);
elem, _ := parse_expr(p);
append(&elems, elem);
if p.curr_token.kind == Kind.Semicolon && p.curr_token.lit == "\n" {
@@ -481,9 +479,9 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) {
name, ok := unquote_string(p, name_tok);
if !ok do error(p, tok.pos, "Unable to unquote string");
expect_token(p, Kind.Assign);
elem, pos := parse_expr(p);
elem, _ := parse_expr(p);
if _, ok := dict[name]; ok {
if _, ok2 := dict[name]; ok2 {
error(p, name_tok.pos, "Previous declaration of %s in this scope", name);
} else {
dict[name] = elem;
@@ -533,9 +531,9 @@ parse_atom_expr :: proc(p: ^Parser, operand: Value, pos: Pos) -> (Value, Pos) {
}
case Kind.Open_Bracket:
open := expect_token(p, Kind.Open_Bracket);
expect_token(p, Kind.Open_Bracket);
index, index_pos := parse_expr(p);
close := expect_token(p, Kind.Close_Bracket);
expect_token(p, Kind.Close_Bracket);
switch a in operand {
@@ -613,7 +611,7 @@ parse_unary_expr :: proc(p: ^Parser) -> (Value, Pos) {
case Kind.Not:
next_token(p);
expr, pos := parse_unary_expr(p);
expr, _ := parse_unary_expr(p);
if v, ok := expr.(bool); ok {
return !v, op.pos;
}
@@ -757,9 +755,9 @@ parse_binary_expr :: proc(p: ^Parser, prec_in: int) -> (Value, Pos) {
if op.kind == Kind.Question {
cond := expr;
x, x_pos := parse_expr(p);
x, _ := parse_expr(p);
expect_token(p, Kind.Colon);
y, y_pos := parse_expr(p);
y, _ := parse_expr(p);
if t, ok := cond.(bool); ok {
expr = t ? x : y;
@@ -824,9 +822,9 @@ parse_assignment :: proc(p: ^Parser) -> bool {
expect_token(p, Kind.Assign);
name, ok := unquote_string(p, tok);
if !ok do error(p, tok.pos, "Unable to unquote string");
expr, pos := parse_expr(p);
expr, _ := parse_expr(p);
d := top_dict(p);
if _, ok := d[name]; ok {
if _, ok2 := d[name]; ok2 {
error(p, tok.pos, "Previous declaration of %s", name);
} else {
d[name] = expr;
+5 -5
View File
@@ -322,7 +322,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
}
if t.curr_rune == '0' {
offset := t.offset;
offset = t.offset;
advance_to_next_rune(t);
switch t.curr_rune {
case 'b', 'B':
@@ -403,17 +403,17 @@ scan :: proc(t: ^Tokenizer) -> Token {
quote := r;
tok = String;
for {
r := t.curr_rune;
if r == '\n' || r < 0 {
this_r := t.curr_rune;
if this_r == '\n' || r < 0 {
token_error(t, "String literal not terminated");
break;
}
advance_to_next_rune(t);
if r == quote {
if this_r == quote {
break;
}
// TODO(bill); Handle properly
if r == '\\' && t.curr_rune == quote {
if this_r == '\\' && t.curr_rune == quote {
advance_to_next_rune(t);
}
}
+125 -21
View File
@@ -10,7 +10,7 @@ import "core:strconv"
import "core:strings"
@(private)
@private
DEFAULT_BUFFER_SIZE :: 1<<12;
Info :: struct {
@@ -31,6 +31,7 @@ Info :: struct {
buf: ^strings.Builder,
arg: any, // Temporary
record_level: int,
}
fprint :: proc(fd: os.Handle, args: ..any) -> int {
@@ -551,9 +552,6 @@ _pad :: proc(fi: ^Info, s: string) {
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
switch verb {
// case 'e', 'E', 'f', 'F', 'g', 'G', 'v':
// case 'f', 'F', 'v':
case 'f', 'F', 'v':
prec: int = 3;
if fi.prec_set do prec = fi.prec;
@@ -588,6 +586,59 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
_pad(fi, str[1:]);
}
case 'e', 'E':
prec: int = 3;
if fi.prec_set do prec = fi.prec;
buf: [386]byte;
str := strconv.append_float(buf[1:], v, 'e', prec, bit_size);
str = string(buf[:len(str)+1]);
if str[1] == '+' || str[1] == '-' {
str = str[1:];
} else {
str[0] = '+';
}
if fi.space && !fi.plus && str[0] == '+' {
str[0] = ' ';
}
if len(str) > 1 && (str[1] == 'N' || str[1] == 'I') {
strings.write_string(fi.buf, str);
return;
}
if fi.plus || str[0] != '+' {
if fi.zero && fi.width_set && fi.width > len(str) {
strings.write_byte(fi.buf, str[0]);
fmt_write_padding(fi, fi.width - len(str));
strings.write_string(fi.buf, str[1:]);
} else {
_pad(fi, str);
}
} else {
_pad(fi, str[1:]);
}
case 'h', 'H':
prev_fi := fi^;
defer fi^ = prev_fi;
fi.hash = false;
fi.width = bit_size;
fi.zero = true;
fi.plus = false;
u: u64;
switch bit_size {
case 32: u = u64(transmute(u32)f32(v));
case 64: u = transmute(u64)v;
case: panic("Unhandled float size");
}
strings.write_string(fi.buf, "0h");
_fmt_int(fi, u, 16, false, bit_size, verb == 'h' ? __DIGITS_LOWER : __DIGITS_UPPER);
case:
fmt_bad_verb(fi, verb);
}
@@ -623,13 +674,20 @@ fmt_cstring :: proc(fi: ^Info, s: cstring, verb: rune) {
}
fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) {
u := u64(uintptr(p));
switch verb {
case 'p', 'v':
u := u64(uintptr(p));
if !fi.hash || verb == 'v' {
strings.write_string(fi.buf, "0x");
}
_fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
case 'b': _fmt_int(fi, u, 2, false, 8*size_of(rawptr), __DIGITS_UPPER);
case 'o': _fmt_int(fi, u, 8, false, 8*size_of(rawptr), __DIGITS_UPPER);
case 'd': _fmt_int(fi, u, 10, false, 8*size_of(rawptr), __DIGITS_UPPER);
case 'x': _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
case 'X': _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
case:
fmt_bad_verb(fi, verb);
}
@@ -982,6 +1040,43 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
if v.id == typeid_of(^runtime.Type_Info) {
write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
} else {
if verb != 'p' {
ptr := (^rawptr)(v.data)^;
a := any{ptr, info.elem.id};
elem := runtime.type_info_base(info.elem);
if elem != nil do switch e in elem.variant {
case runtime.Type_Info_Array,
runtime.Type_Info_Slice,
runtime.Type_Info_Dynamic_Array,
runtime.Type_Info_Map:
if ptr == nil {
strings.write_string(fi.buf, "<nil>");
return;
}
if fi.record_level < 1 {
fi.record_level += 1;
defer fi.record_level -= 1;
strings.write_byte(fi.buf, '&');
fmt_value(fi, a, verb);
return;
}
case runtime.Type_Info_Struct,
runtime.Type_Info_Union:
if ptr == nil {
strings.write_string(fi.buf, "<nil>");
return;
}
if fi.record_level < 1 {
fi.record_level += 1;
defer fi.record_level -= 1;
strings.write_byte(fi.buf, '&');
fmt_value(fi, a, verb);
return;
}
}
}
fmt_pointer(fi, (^rawptr)(v.data)^, verb);
}
@@ -996,14 +1091,19 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
}
case runtime.Type_Info_Dynamic_Array:
strings.write_byte(fi.buf, '[');
defer strings.write_byte(fi.buf, ']');
array := cast(^mem.Raw_Dynamic_Array)v.data;
for i in 0..array.len-1 {
if i > 0 do strings.write_string(fi.buf, ", ");
if verb == 'p' {
slice := cast(^mem.Raw_Dynamic_Array)v.data;
fmt_pointer(fi, slice.data, 'p');
} else {
strings.write_byte(fi.buf, '[');
defer strings.write_byte(fi.buf, ']');
array := cast(^mem.Raw_Dynamic_Array)v.data;
for i in 0..array.len-1 {
if i > 0 do strings.write_string(fi.buf, ", ");
data := uintptr(array.data) + uintptr(i*info.elem_size);
fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
data := uintptr(array.data) + uintptr(i*info.elem_size);
fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
}
}
case runtime.Type_Info_Simd_Vector:
@@ -1021,16 +1121,20 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
case runtime.Type_Info_Slice:
strings.write_byte(fi.buf, '[');
defer strings.write_byte(fi.buf, ']');
slice := cast(^mem.Raw_Slice)v.data;
for i in 0..slice.len-1 {
if i > 0 do strings.write_string(fi.buf, ", ");
if verb == 'p' {
slice := cast(^mem.Raw_Slice)v.data;
fmt_pointer(fi, slice.data, 'p');
} else {
strings.write_byte(fi.buf, '[');
defer strings.write_byte(fi.buf, ']');
slice := cast(^mem.Raw_Slice)v.data;
for i in 0..slice.len-1 {
if i > 0 do strings.write_string(fi.buf, ", ");
data := uintptr(slice.data) + uintptr(i*info.elem_size);
fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
data := uintptr(slice.data) + uintptr(i*info.elem_size);
fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
}
}
case runtime.Type_Info_Map:
if verb != 'v' {
fmt_bad_verb(fi, verb);
@@ -1161,7 +1265,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) {
switch verb {
case 'f', 'F', 'v':
case 'f', 'F', 'v', 'h', 'H':
r, i := real(c), imag(c);
fmt_float(fi, r, bits/2, verb);
if !fi.plus && i >= 0 {
+6 -6
View File
@@ -212,7 +212,7 @@ get_last_error :: proc() -> int {
}
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
cstr := strings.new_cstring(path);
cstr := strings.clone_to_cstring(path);
handle := _unix_open(cstr, flags, mode);
delete(cstr);
if handle == -1 {
@@ -289,7 +289,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
}
stat :: inline proc(path: string) -> (Stat, Errno) {
cstr := strings.new_cstring(path);
cstr := strings.clone_to_cstring(path);
defer delete(cstr);
s: Stat;
@@ -310,7 +310,7 @@ fstat :: inline proc(fd: Handle) -> (Stat, Errno) {
}
access :: inline proc(path: string, mask: int) -> (bool, Errno) {
cstr := strings.new_cstring(path);
cstr := strings.clone_to_cstring(path);
defer delete(cstr);
result := _unix_access(cstr, mask);
if result == -1 {
@@ -333,7 +333,7 @@ heap_free :: proc(ptr: rawptr) {
}
getenv :: proc(name: string) -> (string, bool) {
path_str := strings.new_cstring(name);
path_str := strings.clone_to_cstring(name);
defer delete(path_str);
cstr := _unix_getenv(path_str);
if cstr == nil {
@@ -370,14 +370,14 @@ current_thread_id :: proc "contextless" () -> int {
}
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
cstr := strings.new_cstring(filename);
cstr := strings.clone_to_cstring(filename);
defer delete(cstr);
handle := _unix_dlopen(cstr, flags);
return handle;
}
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
assert(handle != nil);
cstr := strings.new_cstring(symbol);
cstr := strings.clone_to_cstring(symbol);
defer delete(cstr);
proc_handle := _unix_dlsym(handle, cstr);
return proc_handle;
+75 -15
View File
@@ -213,28 +213,28 @@ append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> str
DecimalSlice :: struct {
Decimal_Slice :: struct {
digits: []byte,
count: int,
decimal_point: int,
neg: bool,
}
FloatInfo :: struct {
Float_Info :: struct {
mantbits: uint,
expbits: uint,
bias: int,
}
_f16_info := FloatInfo{10, 5, -15};
_f32_info := FloatInfo{23, 8, -127};
_f64_info := FloatInfo{52, 11, -1023};
_f16_info := Float_Info{10, 5, -15};
_f32_info := Float_Info{23, 8, -127};
_f64_info := Float_Info{52, 11, -1023};
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
bits: u64;
flt: ^FloatInfo;
flt: ^Float_Info;
switch bit_size {
case 32:
bits = u64(transmute(u32)f32(val));
@@ -276,11 +276,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
d := &d_;
assign(d, mant);
shift(d, exp - int(flt.mantbits));
digs: DecimalSlice;
digs: Decimal_Slice;
shortest := prec < 0;
if shortest {
round_shortest(d, mant, exp, flt);
digs = DecimalSlice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
switch fmt {
case 'e', 'E': prec = digs.count-1;
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
@@ -297,14 +297,14 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
round(d, prec);
}
digs = DecimalSlice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
}
return format_digits(buf, shortest, neg, digs, prec, fmt);
}
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: byte) -> []byte {
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
Buffer :: struct {
b: []byte,
n: int,
@@ -347,12 +347,72 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice
return to_bytes(b);
case 'e', 'E':
panic("strconv: e/E float printing is not yet supported");
return to_bytes(b); // TODO
add_bytes(&b, neg ? '-' : '+');
ch := byte('0');
if digs.count != 0 {
ch = digs.digits[0];
}
add_bytes(&b, ch);
if prec > 0 {
add_bytes(&b, '.');
i := 1;
m := min(digs.count, prec+1);
if i < m {
add_bytes(&b, ..digs.digits[i:m]);
i = m;
}
for ; i <= prec; i += 1 {
add_bytes(&b, '0');
}
}
add_bytes(&b, fmt);
exp := digs.decimal_point-1;
if digs.count == 0 {
// Zero has exponent of 0
exp = 0;
}
ch = '+';
if exp < 0 {
ch = '-';
exp = -exp;
}
add_bytes(&b, ch);
switch {
case exp < 10: add_bytes(&b, '0', byte(exp)+'0'); // add prefix 0
case exp < 100: add_bytes(&b, byte(exp/10)+'0', byte(exp%10)+'0');
case: add_bytes(&b, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0');
}
return to_bytes(b);
case 'g', 'G':
panic("strconv: g/G float printing is not yet supported");
return to_bytes(b); // TODO
eprec := prec;
if eprec > digs.count && digs.count >= digs.decimal_point {
eprec = digs.count;
}
if shortest {
eprec = 6;
}
exp := digs.decimal_point - 1;
if exp < -4 || exp >= eprec {
if prec > digs.count {
prec = digs.count;
}
return format_digits(buf, shortest, neg, digs, prec-1, fmt+'e'-'g'); // keep the same case
}
if prec > digs.decimal_point {
prec = digs.count;
}
return format_digits(buf, shortest, neg, digs, max(prec-digs.decimal_point, 0), 'f');
case:
add_bytes(&b, '%', fmt);
@@ -362,7 +422,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice
}
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
if mant == 0 { // If mantissa is zero, the number is zero
d.count = 0;
return;
+4
View File
@@ -17,6 +17,10 @@ destroy_builder :: proc(b: ^Builder) {
clear(&b.buf);
}
grow_builder :: proc(b: ^Builder, cap: int) {
reserve(&b.buf, cap);
}
builder_from_slice :: proc(backing: []byte) -> Builder {
s := transmute(mem.Raw_Slice)backing;
d := mem.Raw_Dynamic_Array{
+200 -1
View File
@@ -3,6 +3,21 @@ package strings
import "core:mem"
import "core:unicode/utf8"
clone :: proc(s: string, allocator := context.allocator) -> string {
c := make([]byte, len(s)+1, allocator);
copy(c, cast([]byte)s);
c[len(s)] = 0;
return string(c[:len(s)]);
}
clone_to_cstring :: proc(s: string, allocator := context.allocator) -> cstring {
c := make([]byte, len(s)+1, allocator);
copy(c, cast([]byte)s);
c[len(s)] = 0;
return cstring(&c[0]);
}
@(deprecated="Please use 'strings.clone'")
new_string :: proc(s: string, allocator := context.allocator) -> string {
c := make([]byte, len(s)+1, allocator);
copy(c, cast([]byte)s);
@@ -10,6 +25,7 @@ new_string :: proc(s: string, allocator := context.allocator) -> string {
return string(c[:len(s)]);
}
@(deprecated="Please use 'strings.clone_to_cstring'")
new_cstring :: proc(s: string, allocator := context.allocator) -> cstring {
c := make([]byte, len(s)+1, allocator);
copy(c, cast([]byte)s);
@@ -46,6 +62,10 @@ contains_any :: proc(s, chars: string) -> bool {
}
rune_count :: proc(s: string) -> int {
return utf8.rune_count_in_string(s);
}
equal_fold :: proc(s, t: string) -> bool {
loop: for s != "" && t != "" {
@@ -209,7 +229,7 @@ last_index_any :: proc(s, chars: string) -> int {
count :: proc(s, substr: string) -> int {
if len(substr) == 0 { // special case
return utf8.rune_count_in_string(s) + 1;
return rune_count(s) + 1;
}
if len(substr) == 1 {
c := substr[0];
@@ -642,3 +662,182 @@ split_multi :: proc(s: string, substrs: []string, skip_empty := false, allocator
return buf;
}
// scrub scruvs invalid utf-8 characters and replaces them with the replacement string
// Adjacent invalid bytes are only replaced once
scrub :: proc(str: string, replacement: string, allocator := context.allocator) -> string {
b := make_builder(allocator);;
grow_builder(&b, len(str));
has_error := false;
cursor := 0;
origin := str;
for len(str) > 0 {
r, w := utf8.decode_rune_in_string(str);
if r == utf8.RUNE_ERROR {
if !has_error {
has_error = true;
write_string(&b, origin[:cursor]);
}
} else if has_error {
has_error = false;
write_string(&b, replacement);
origin = origin[cursor:];
cursor = 0;
}
cursor += w;
str = str[w:];
}
return to_string(b);
}
reverse :: proc(str: string, allocator := context.allocator) -> string {
n := len(str);
buf := make([]byte, n);
i := 0;
for len(str) > 0 {
_, w := utf8.decode_rune_in_string(str);
copy(buf[i:], cast([]byte)str[:w]);
str = str[w:];
}
return string(buf);
}
expand_tabs :: proc(str: string, tab_size: int, allocator := context.allocator) -> string {
if tab_size <= 0 {
panic("tab size must be positive");
}
if str == "" {
return "";
}
b := make_builder(allocator);
column: int;
for len(str) > 0 {
r, w := utf8.decode_rune_in_string(str);
if r == '\t' {
expand := tab_size - column%tab_size;
for i := 0; i < expand; i += 1 {
write_byte(&b, ' ');
}
column += expand;
} else {
if r == '\n' {
column = 0;
} else {
column += w;
}
write_rune(&b, r);
}
str = str[w:];
}
return to_string(b);
}
partition :: proc(str, sep: string) -> (head, match, tail: string) {
i := index(str, sep);
if i == -1 {
head = str;
return;
}
head = str[:i];
match = str[i:i+len(sep)];
tail = str[i+len(sep):];
return;
}
center_justify :: centre_justify; // NOTE(bill): Because Americans exist
// centre_justify returns a string with a pad string at boths sides if the str's rune length is smaller than length
centre_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
n := rune_count(str);
if n >= length || pad == "" {
return clone(str, allocator);
}
remains := length-1;
pad_len := rune_count(pad);
b := make_builder(allocator);
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
write_pad_string(&b, pad, pad_len, remains/2);
write_string(&b, str);
write_pad_string(&b, pad, pad_len, (remains+1)/2);
return to_string(b);
}
// left_justify returns a string with a pad string at left side if the str's rune length is smaller than length
left_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
n := rune_count(str);
if n >= length || pad == "" {
return clone(str, allocator);
}
remains := length-1;
pad_len := rune_count(pad);
b := make_builder(allocator);
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
write_string(&b, str);
write_pad_string(&b, pad, pad_len, remains);
return to_string(b);
}
// right_justify returns a string with a pad string at right side if the str's rune length is smaller than length
right_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
n := rune_count(str);
if n >= length || pad == "" {
return clone(str, allocator);
}
remains := length-1;
pad_len := rune_count(pad);
b := make_builder(allocator);
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
write_pad_string(&b, pad, pad_len, remains);
write_string(&b, str);
return to_string(b);
}
@private
write_pad_string :: proc(b: ^Builder, pad: string, pad_len, remains: int) {
repeats := remains / pad_len;
for i := 0; i < repeats; i += 1 {
write_string(b, pad);
}
remains = remains % pad_len;
if remains != 0 do for i := 0; i < remains; i += 1 {
r, w := utf8.decode_rune_in_string(pad);
write_rune(b, r);
pad = pad[w:];
}
}
+67 -79
View File
@@ -11,92 +11,86 @@ Ordering :: enum {
}
strongest_failure_ordering :: inline proc "contextless" (order: Ordering) -> Ordering {
using Ordering;
#complete switch order {
case Relaxed: return Relaxed;
case Release: return Relaxed;
case Acquire: return Acquire;
case Acquire_Release: return Acquire;
case Sequentially_Consistent: return Sequentially_Consistent;
case .Relaxed: return .Relaxed;
case .Release: return .Relaxed;
case .Acquire: return .Acquire;
case .Acquire_Release: return .Acquire;
case .Sequentially_Consistent: return .Sequentially_Consistent;
}
return Relaxed;
return .Relaxed;
}
fence :: inline proc "contextless" (order: Ordering) {
using Ordering;
#complete switch order {
case Relaxed: panic("there is no such thing as a relaxed fence");
case Release: intrinsics.atomic_fence_rel();
case Acquire: intrinsics.atomic_fence_acq();
case Acquire_Release: intrinsics.atomic_fence_acqrel();
case Sequentially_Consistent: intrinsics.atomic_fence();
case .Relaxed: panic("there is no such thing as a relaxed fence");
case .Release: intrinsics.atomic_fence_rel();
case .Acquire: intrinsics.atomic_fence_acq();
case .Acquire_Release: intrinsics.atomic_fence_acqrel();
case .Sequentially_Consistent: intrinsics.atomic_fence();
case: panic("unknown order");
}
}
atomic_store :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) {
using Ordering;
#complete switch order {
case Relaxed: intrinsics.atomic_store_relaxed(dst, val);
case Release: intrinsics.atomic_store_rel(dst, val);
case Sequentially_Consistent: intrinsics.atomic_store(dst, val);
case Acquire: panic("there is not such thing as an acquire store");
case Acquire_Release: panic("there is not such thing as an acquire/release store");
case .Relaxed: intrinsics.atomic_store_relaxed(dst, val);
case .Release: intrinsics.atomic_store_rel(dst, val);
case .Sequentially_Consistent: intrinsics.atomic_store(dst, val);
case .Acquire: panic("there is not such thing as an acquire store");
case .Acquire_Release: panic("there is not such thing as an acquire/release store");
case: panic("unknown order");
}
}
atomic_load :: inline proc "contextless" (dst: ^$T, order: Ordering) -> T {
using Ordering;
#complete switch order {
case Relaxed: return intrinsics.atomic_load_relaxed(dst);
case Acquire: return intrinsics.atomic_load_acq(dst);
case Sequentially_Consistent: return intrinsics.atomic_load(dst);
case Release: panic("there is no such thing as a release load");
case Acquire_Release: panic("there is no such thing as an acquire/release load");
case .Relaxed: return intrinsics.atomic_load_relaxed(dst);
case .Acquire: return intrinsics.atomic_load_acq(dst);
case .Sequentially_Consistent: return intrinsics.atomic_load(dst);
case .Release: panic("there is no such thing as a release load");
case .Acquire_Release: panic("there is no such thing as an acquire/release load");
}
panic("unknown order");
return T{};
}
atomic_swap :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
using Ordering;
#complete switch order {
case Relaxed: return intrinsics.atomic_xchg_relaxed(dst, val);
case Release: return intrinsics.atomic_xchg_rel(dst, val);
case Acquire: return intrinsics.atomic_xchg_acq(dst, val);
case Acquire_Release: return intrinsics.atomic_xchg_acqrel(dst, val);
case Sequentially_Consistent: return intrinsics.atomic_xchg(dst, val);
case .Relaxed: return intrinsics.atomic_xchg_relaxed(dst, val);
case .Release: return intrinsics.atomic_xchg_rel(dst, val);
case .Acquire: return intrinsics.atomic_xchg_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_xchg_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_xchg(dst, val);
}
panic("unknown order");
return T{};
}
atomic_compare_exchange :: inline proc "contextless" (dst: ^$T, old, new: T, success, failure: Ordering) -> (val: T, ok: bool) {
using Ordering;
switch failure {
case Relaxed:
case .Relaxed:
switch success {
case Relaxed: return intrinsics.atomic_cxchg_relaxed(dst, old, new);
case Acquire: return intrinsics.atomic_cxchg_acq_failrelaxed(dst, old, new);
case Acquire_Release: return intrinsics.atomic_cxchg_acqrel_failrelaxed(dst, old, new);
case Sequentially_Consistent: return intrinsics.atomic_cxchg_failrelaxed(dst, old, new);
case .Relaxed: return intrinsics.atomic_cxchg_relaxed(dst, old, new);
case .Acquire: return intrinsics.atomic_cxchg_acq_failrelaxed(dst, old, new);
case .Acquire_Release: return intrinsics.atomic_cxchg_acqrel_failrelaxed(dst, old, new);
case .Sequentially_Consistent: return intrinsics.atomic_cxchg_failrelaxed(dst, old, new);
case: panic("an unknown ordering combination");
}
case Acquire:
case .Acquire:
switch success {
case Acquire: return intrinsics.atomic_cxchg_acq(dst, old, new);
case .Acquire: return intrinsics.atomic_cxchg_acq(dst, old, new);
case: panic("an unknown ordering combination");
}
case Sequentially_Consistent:
case .Sequentially_Consistent:
switch success {
case Sequentially_Consistent: return intrinsics.atomic_cxchg(dst, old, new);
case .Sequentially_Consistent: return intrinsics.atomic_cxchg(dst, old, new);
case: panic("an unknown ordering combination");
}
case Acquire_Release:
case .Acquire_Release:
panic("there is not such thing as an acquire/release failure ordering");
case Release:
case .Release:
panic("there is not such thing as an release failure ordering");
}
return T{}, false;
@@ -105,78 +99,72 @@ atomic_compare_exchange :: inline proc "contextless" (dst: ^$T, old, new: T, suc
atomic_add :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
using Ordering;
#complete switch order {
case Relaxed: return intrinsics.atomic_add_relaxed(dst, val);
case Release: return intrinsics.atomic_add_rel(dst, val);
case Acquire: return intrinsics.atomic_add_acq(dst, val);
case Acquire_Release: return intrinsics.atomic_add_acqrel(dst, val);
case Sequentially_Consistent: return intrinsics.atomic_add(dst, val);
case .Relaxed: return intrinsics.atomic_add_relaxed(dst, val);
case .Release: return intrinsics.atomic_add_rel(dst, val);
case .Acquire: return intrinsics.atomic_add_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_add_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_add(dst, val);
}
panic("unknown order");
return T{};
}
atomic_sub :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
using Ordering;
#complete switch order {
case Relaxed: return intrinsics.atomic_sub_relaxed(dst, val);
case Release: return intrinsics.atomic_sub_rel(dst, val);
case Acquire: return intrinsics.atomic_sub_acq(dst, val);
case Acquire_Release: return intrinsics.atomic_sub_acqrel(dst, val);
case Sequentially_Consistent: return intrinsics.atomic_sub(dst, val);
case .Relaxed: return intrinsics.atomic_sub_relaxed(dst, val);
case .Release: return intrinsics.atomic_sub_rel(dst, val);
case .Acquire: return intrinsics.atomic_sub_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_sub_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_sub(dst, val);
}
panic("unknown order");
return T{};
}
atomic_and :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
using Ordering;
#complete switch order {
case Relaxed: return intrinsics.atomic_and_relaxed(dst, val);
case Release: return intrinsics.atomic_and_rel(dst, val);
case Acquire: return intrinsics.atomic_and_acq(dst, val);
case Acquire_Release: return intrinsics.atomic_and_acqrel(dst, val);
case Sequentially_Consistent: return intrinsics.atomic_and(dst, val);
case .Relaxed: return intrinsics.atomic_and_relaxed(dst, val);
case .Release: return intrinsics.atomic_and_rel(dst, val);
case .Acquire: return intrinsics.atomic_and_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_and_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_and(dst, val);
}
panic("unknown order");
return T{};
}
atomic_nand :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
using Ordering;
#complete switch order {
case Relaxed: return intrinsics.atomic_nand_relaxed(dst, val);
case Release: return intrinsics.atomic_nand_rel(dst, val);
case Acquire: return intrinsics.atomic_nand_acq(dst, val);
case Acquire_Release: return intrinsics.atomic_nand_acqrel(dst, val);
case Sequentially_Consistent: return intrinsics.atomic_nand(dst, val);
case .Relaxed: return intrinsics.atomic_nand_relaxed(dst, val);
case .Release: return intrinsics.atomic_nand_rel(dst, val);
case .Acquire: return intrinsics.atomic_nand_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_nand_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_nand(dst, val);
}
panic("unknown order");
return T{};
}
atomic_or :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
using Ordering;
#complete switch order {
case Relaxed: return intrinsics.atomic_or_relaxed(dst, val);
case Release: return intrinsics.atomic_or_rel(dst, val);
case Acquire: return intrinsics.atomic_or_acq(dst, val);
case Acquire_Release: return intrinsics.atomic_or_acqrel(dst, val);
case Sequentially_Consistent: return intrinsics.atomic_or(dst, val);
case .Relaxed: return intrinsics.atomic_or_relaxed(dst, val);
case .Release: return intrinsics.atomic_or_rel(dst, val);
case .Acquire: return intrinsics.atomic_or_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_or_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_or(dst, val);
}
panic("unknown order");
return T{};
}
atomic_xor :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
using Ordering;
#complete switch order {
case Relaxed: return intrinsics.atomic_xor_relaxed(dst, val);
case Release: return intrinsics.atomic_xor_rel(dst, val);
case Acquire: return intrinsics.atomic_xor_acq(dst, val);
case Acquire_Release: return intrinsics.atomic_xor_acqrel(dst, val);
case Sequentially_Consistent: return intrinsics.atomic_xor(dst, val);
case .Relaxed: return intrinsics.atomic_xor_relaxed(dst, val);
case .Release: return intrinsics.atomic_xor_rel(dst, val);
case .Acquire: return intrinsics.atomic_xor_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_xor_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_xor(dst, val);
}
panic("unknown order");
return T{};
+17 -7
View File
@@ -5,7 +5,6 @@ foreign import "system:kernel32.lib"
@(default_calling_convention = "std")
foreign kernel32 {
@(link_name="GetLastError") get_last_error :: proc() -> i32 ---;
@(link_name="CreateProcessA") create_process_a :: proc(application_name, command_line: cstring,
process_attributes, thread_attributes: ^Security_Attributes,
inherit_handle: Bool, creation_flags: u32, environment: rawptr,
@@ -18,8 +17,12 @@ foreign kernel32 {
process_information: ^Process_Information) -> Bool ---;
@(link_name="GetExitCodeProcess") get_exit_code_process :: proc(process: Handle, exit: ^u32) -> Bool ---;
@(link_name="ExitProcess") exit_process :: proc(exit_code: u32) ---;
@(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: cstring) -> Hinstance ---;
@(link_name="GetModuleHandleW") get_module_handle_w :: proc(module_name: Wstring) -> Hinstance ---;
@(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: cstring) -> Hmodule ---;
@(link_name="GetModuleHandleW") get_module_handle_w :: proc(module_name: Wstring) -> Hmodule ---;
@(link_name="GetModuleFileNameA") get_module_file_name_a :: proc(module: Hmodule, filename: cstring, size: u32) -> u32 ---;
@(link_name="GetModuleFileNameW") get_module_file_name_w :: proc(module: Hmodule, filename: Wstring, size: u32) -> u32 ---;
@(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---;
@(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---;
@(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---;
@@ -54,10 +57,6 @@ foreign kernel32 {
@(link_name="WriteFile") write_file :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool ---;
@(link_name="GetFileSizeEx") get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool ---;
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---;
@(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---;
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
@(link_name="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
@(link_name="GetFileInformationByHandle") get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool ---;
@(link_name="CreateDirectoryA") create_directory_a :: proc(path: cstring, security_attributes: ^Security_Attributes) -> Bool ---;
@@ -117,6 +116,17 @@ foreign kernel32 {
@(link_name="WaitForSingleObject") wait_for_single_object :: proc(handle: Handle, milliseconds: u32) -> u32 ---;
}
@(default_calling_convention = "c")
foreign kernel32 {
@(link_name="GetLastError") get_last_error :: proc() -> i32 ---;
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---;
@(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---;
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
@(link_name="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
@(link_name="CompareFileTime") compare_file_time :: proc(a, b: ^Filetime) -> i32 ---;
}
@(default_calling_convention = "c")
foreign kernel32 {
@(link_name="InterlockedCompareExchange") interlocked_compare_exchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 ---;
+1
View File
@@ -92,6 +92,7 @@ struct BuildContext {
String out_filepath;
String resource_filepath;
String pdb_filepath;
bool has_resource;
String opt_flags;
String llc_flags;
+12 -2
View File
@@ -391,8 +391,18 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
case Entity_Procedure:
case Entity_LibraryName:
case Entity_ImportName:
override_entity_in_scope(e, entity);
return;
{
override_entity_in_scope(e, entity);
DeclInfo *decl = decl_info_of_entity(e);
if (decl != nullptr) {
if (decl->attributes.count > 0) {
error(decl->attributes[0], "Constant alias declarations cannot have attributes");
}
}
return;
}
}
}
}
+2 -1
View File
@@ -474,10 +474,11 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b
case Entity_ImportName: {
Scope *scope = e->ImportName.scope;
for_array(i, scope->elements.entries) {
String name = scope->elements.entries[i].key.string;
Entity *decl = scope->elements.entries[i].value;
if (!is_entity_exported(decl)) continue;
Entity *found = scope_insert(ctx->scope, decl);
Entity *found = scope_insert_with_name(ctx->scope, name, decl);
if (found != nullptr) {
gbString expr_str = expr_to_string(expr);
error(us->token,
+2
View File
@@ -2507,7 +2507,9 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
case_ast_node(et, BitFieldType, e);
*type = alloc_type_bit_field();
set_base_type(named_type, *type);
check_open_scope(ctx, e);
check_bit_field_type(ctx, *type, e);
check_close_scope(ctx);
return true;
case_end;
+53 -35
View File
@@ -388,8 +388,7 @@ Entity *scope_lookup(Scope *s, String name) {
Entity *scope_insert(Scope *s, Entity *entity) {
String name = entity->token.string;
Entity *scope_insert_with_name(Scope *s, String name, Entity *entity) {
if (name == "") {
return nullptr;
}
@@ -406,6 +405,11 @@ Entity *scope_insert(Scope *s, Entity *entity) {
return nullptr;
}
Entity *scope_insert(Scope *s, Entity *entity) {
String name = entity->token.string;
return scope_insert_with_name(s, name, entity);
}
GB_COMPARE_PROC(entity_variable_pos_cmp) {
Entity *x = *cast(Entity **)a;
@@ -1023,39 +1027,41 @@ void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) {
array_add(&i->definitions, entity);
}
bool add_entity(Checker *c, Scope *scope, Ast *identifier, Entity *entity) {
bool redeclaration_error(String name, Entity *prev, Entity *found) {
TokenPos pos = found->token.pos;
Entity *up = found->using_parent;
if (up != nullptr) {
if (pos == up->token.pos) {
// NOTE(bill): Error should have been handled already
return false;
}
error(prev->token,
"Redeclaration of '%.*s' in this scope through 'using'\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
} else {
if (pos == prev->token.pos) {
// NOTE(bill): Error should have been handled already
return false;
}
error(prev->token,
"Redeclaration of '%.*s' in this scope\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(pos.file), pos.line, pos.column);
}
return false;
}
bool add_entity_with_name(Checker *c, Scope *scope, Ast *identifier, Entity *entity, String name) {
if (scope == nullptr) {
return false;
}
String name = entity->token.string;
if (!is_blank_ident(name)) {
Entity *ie = scope_insert(scope, entity);
if (ie != nullptr) {
TokenPos pos = ie->token.pos;
Entity *up = ie->using_parent;
if (up != nullptr) {
if (pos == up->token.pos) {
// NOTE(bill): Error should have been handled already
return false;
}
error(entity->token,
"Redeclaration of '%.*s' in this scope through 'using'\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
return false;
} else {
if (pos == entity->token.pos) {
// NOTE(bill): Error should have been handled already
return false;
}
error(entity->token,
"Redeclaration of '%.*s' in this scope\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(pos.file), pos.line, pos.column);
return false;
}
return redeclaration_error(name, entity, ie);
}
}
if (identifier != nullptr) {
@@ -1063,6 +1069,9 @@ bool add_entity(Checker *c, Scope *scope, Ast *identifier, Entity *entity) {
}
return true;
}
bool add_entity(Checker *c, Scope *scope, Ast *identifier, Entity *entity) {
return add_entity_with_name(c, scope, identifier, entity, entity->token.string);
}
void add_entity_use(CheckerContext *c, Ast *identifier, Entity *entity) {
if (entity == nullptr) {
@@ -2005,7 +2014,7 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
if (value != nullptr) {
Operand o = {};
check_expr(c, &o, value);
Entity *e = entity_of_ident(o.expr);
Entity *e = entity_of_node(o.expr);
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));
if (ac->deferred_procedure.entity != nullptr) {
@@ -2022,7 +2031,7 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
if (value != nullptr) {
Operand o = {};
check_expr(c, &o, value);
Entity *e = entity_of_ident(o.expr);
Entity *e = entity_of_node(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) {
ac->deferred_procedure.kind = DeferredProcedure_none;
ac->deferred_procedure.entity = e;
@@ -2035,7 +2044,7 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
if (value != nullptr) {
Operand o = {};
check_expr(c, &o, value);
Entity *e = entity_of_ident(o.expr);
Entity *e = entity_of_node(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) {
if (ac->deferred_procedure.entity != nullptr) {
error(elem, "Previous usage of a 'deferred_*' attribute");
@@ -2051,7 +2060,7 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
if (value != nullptr) {
Operand o = {};
check_expr(c, &o, value);
Entity *e = entity_of_ident(o.expr);
Entity *e = entity_of_node(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) {
if (ac->deferred_procedure.entity != nullptr) {
error(elem, "Previous usage of a 'deferred_*' attribute");
@@ -3050,12 +3059,21 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
// NOTE(bill): Add imported entities to this file's scope
for_array(elem_index, scope->elements.entries) {
String name = scope->elements.entries[elem_index].key.string;
Entity *e = scope->elements.entries[elem_index].value;
if (e->scope == parent_scope) continue;
if (is_entity_exported(e)) {
Entity *prev = scope_lookup(parent_scope, e->token.string);
add_entity(ctx->checker, parent_scope, e->identifier, e);
Entity *found = scope_lookup_current(parent_scope, name);
if (found != nullptr) {
// NOTE(bill):
// Date: 2019-03-17
// The order has to be the other way around as `using` adds the entity into the that
// file scope otherwise the error would be the wrong way around
redeclaration_error(name, found, e);
} else {
add_entity_with_name(ctx->checker, parent_scope, e->identifier, e, name);
}
}
}
}
+9 -5
View File
@@ -2875,12 +2875,12 @@ irValue *ir_copy_value_to_ptr(irProcedure *proc, irValue *val, Type *new_type, i
if (alignment < type_alignment) {
alignment = type_alignment;
}
GB_ASSERT_MSG(are_types_identical(new_type, ir_type(val)), "%s %s", type_to_string(new_type), type_to_string(ir_type(val)));
irValue *ptr = ir_add_local_generated(proc, new_type, false);
ptr->Instr.Local.alignment = alignment;
ir_emit_store(proc, ptr, val);
if (val) val->uses += 1;
return ptr;
}
@@ -2972,11 +2972,15 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
Type *original_type = e->type;
Type *new_type = pt->Proc.abi_compat_params[i];
if (original_type != new_type) {
if (is_type_pointer(new_type)) {
Type *arg_type = ir_type(args[i]);
if (are_types_identical(arg_type, new_type)) {
// NOTE(bill): Done
} else if (!are_types_identical(original_type, new_type)) {
if (is_type_pointer(new_type) && !is_type_pointer(original_type)) {
if (e->flags&EntityFlag_Value) {
args[i] = ir_address_from_load_or_generate_local(p, args[i]);
} else {
} else if (!is_type_pointer(arg_type)) {
args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16);
}
} else if (is_type_integer(new_type)) {
+1 -1
View File
@@ -471,7 +471,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
i64 align_of_union = type_align_of(t);
ir_write_byte(f, '{');
ir_print_alignment_prefix_hack(f, align_of_union);
ir_fprintf(f, ", [%lld x i8]}", align_of_union, size_of_union);
ir_fprintf(f, ", [%lld x i8]}", size_of_union);
return;
} else {
if (t->Struct.is_packed) {
+72 -35
View File
@@ -18,7 +18,7 @@
#include "ir_print.cpp"
// NOTE(bill): 'name' is used in debugging and profiling modes
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
i32 system_exec_command_line_app(char *name, char *fmt, ...) {
#if defined(GB_SYSTEM_WINDOWS)
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
PROCESS_INFORMATION pi = {0};
@@ -201,7 +201,6 @@ enum BuildFlagKind {
BuildFlag_Invalid,
BuildFlag_OutFile,
BuildFlag_ResourceFile,
BuildFlag_OptimizationLevel,
BuildFlag_ShowTimings,
BuildFlag_ThreadCount,
@@ -218,6 +217,11 @@ enum BuildFlagKind {
BuildFlag_Vet,
BuildFlag_IgnoreUnknownAttributes,
#if defined(GB_SYSTEM_WINDOWS)
BuildFlag_ResourceFile,
BuildFlag_WindowsPdbName,
#endif
BuildFlag_COUNT,
};
@@ -281,7 +285,6 @@ ExactValue build_param_to_exact_value(String name, String param) {
bool parse_build_flags(Array<String> args) {
auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer);
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
@@ -296,7 +299,12 @@ bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("-ignore-unknown-attributes"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None);
#if defined(GB_SYSTEM_WINDOWS)
add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"), BuildFlagParam_String);
#endif
GB_ASSERT(args.count >= 3);
Array<String> flag_args = array_slice(args, 3, args.count);
@@ -436,24 +444,6 @@ bool parse_build_flags(Array<String> args) {
}
break;
}
case BuildFlag_ResourceFile: {
GB_ASSERT(value.kind == ExactValue_String);
String path = value.value_string;
path = string_trim_whitespace(path);
if (is_import_path_valid(path)) {
if(!string_ends_with(path, str_lit(".rc"))) {
gb_printf_err("Invalid -resource path %.*s, missing .rc\n", LIT(path));
bad_flags = true;
break;
}
build_context.resource_filepath = substring(path, 0, string_extension_position(path));
build_context.has_resource = true;
} else {
gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path));
bad_flags = true;
}
break;
}
case BuildFlag_OptimizationLevel:
GB_ASSERT(value.kind == ExactValue_Integer);
build_context.optimization_level = cast(i32)big_int_to_i64(&value.value_integer);
@@ -671,6 +661,48 @@ bool parse_build_flags(Array<String> args) {
case BuildFlag_IgnoreUnknownAttributes:
build_context.ignore_unknown_attributes = true;
break;
#if defined(GB_SYSTEM_WINDOWS)
case BuildFlag_ResourceFile: {
GB_ASSERT(value.kind == ExactValue_String);
String path = value.value_string;
path = string_trim_whitespace(path);
if (is_import_path_valid(path)) {
if(!string_ends_with(path, str_lit(".rc"))) {
gb_printf_err("Invalid -resource path %.*s, missing .rc\n", LIT(path));
bad_flags = true;
break;
}
build_context.resource_filepath = substring(path, 0, string_extension_position(path));
build_context.has_resource = true;
} else {
gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path));
bad_flags = true;
}
break;
}
case BuildFlag_WindowsPdbName: {
GB_ASSERT(value.kind == ExactValue_String);
String path = value.value_string;
path = string_trim_whitespace(path);
if (is_import_path_valid(path)) {
// #if defined(GB_SYSTEM_WINDOWS)
// String ext = path_extension(path);
// if (ext != ".pdb") {
// path = substring(path, 0, string_extension_position(path));
// }
// #endif
build_context.pdb_filepath = path;
} else {
gb_printf_err("Invalid -pdb-name path, got %.*s\n", LIT(path));
bad_flags = true;
}
break;
break;
}
#endif
}
}
@@ -784,7 +816,7 @@ void remove_temp_files(String output_base) {
i32 exec_llvm_opt(String output_base) {
#if defined(GB_SYSTEM_WINDOWS)
// For more passes arguments: http://llvm.org/docs/Passes.html
return system_exec_command_line_app("llvm-opt", false,
return system_exec_command_line_app("llvm-opt",
"\"%.*sbin/opt\" \"%.*s.ll\" -o \"%.*s.bc\" %.*s "
"",
LIT(build_context.ODIN_ROOT),
@@ -793,7 +825,7 @@ i32 exec_llvm_opt(String output_base) {
#else
// NOTE(zangent): This is separate because it seems that LLVM tools are packaged
// with the Windows version, while they will be system-provided on MacOS and GNU/Linux
return system_exec_command_line_app("llvm-opt", false,
return system_exec_command_line_app("llvm-opt",
"opt \"%.*s.ll\" -o \"%.*s.bc\" %.*s "
"",
LIT(output_base), LIT(output_base),
@@ -804,10 +836,10 @@ i32 exec_llvm_opt(String output_base) {
i32 exec_llvm_llc(String output_base) {
#if defined(GB_SYSTEM_WINDOWS)
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
return system_exec_command_line_app("llvm-llc", false,
return system_exec_command_line_app("llvm-llc",
"\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d "
"-o \"%.*s.obj\" "
"%.*s "
"%.*s"
"",
LIT(build_context.ODIN_ROOT),
LIT(output_base),
@@ -817,7 +849,7 @@ i32 exec_llvm_llc(String output_base) {
#else
// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
return system_exec_command_line_app("llc", false,
return system_exec_command_line_app("llc",
"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
"%.*s "
"%s"
@@ -1041,6 +1073,11 @@ int main(int arg_count, char **arg_ptr) {
} else {
link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup");
}
if (build_context.pdb_filepath != "") {
link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath));
}
if (build_context.no_crt) {
link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib");
} else {
@@ -1052,7 +1089,7 @@ int main(int arg_count, char **arg_ptr) {
}
if (!build_context.use_lld) { // msvc
if (build_context.has_resource) {
exit_code = system_exec_command_line_app("msvc-link", true,
exit_code = system_exec_command_line_app("msvc-link",
"rc /nologo /fo \"%.*s.res\" \"%.*s.rc\"",
LIT(output_base),
LIT(build_context.resource_filepath)
@@ -1062,7 +1099,7 @@ int main(int arg_count, char **arg_ptr) {
return exit_code;
}
exit_code = system_exec_command_line_app("msvc-link", true,
exit_code = system_exec_command_line_app("msvc-link",
"link \"%.*s.obj\" \"%.*s.res\" -OUT:\"%.*s.%s\" %s "
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
" %.*s "
@@ -1073,7 +1110,7 @@ int main(int arg_count, char **arg_ptr) {
link_settings
);
} else {
exit_code = system_exec_command_line_app("msvc-link", true,
exit_code = system_exec_command_line_app("msvc-link",
"link \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
" %.*s "
@@ -1085,7 +1122,7 @@ int main(int arg_count, char **arg_ptr) {
);
}
} else { // lld
exit_code = system_exec_command_line_app("msvc-link", true,
exit_code = system_exec_command_line_app("msvc-link",
"\"%.*s\\bin\\lld-link\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
" %.*s "
@@ -1109,7 +1146,7 @@ int main(int arg_count, char **arg_ptr) {
remove_temp_files(output_base);
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
}
#else
timings_start_section(&timings, str_lit("ld-link"));
@@ -1206,7 +1243,7 @@ int main(int arg_count, char **arg_ptr) {
}
#endif
exit_code = system_exec_command_line_app("ld-link", true,
exit_code = system_exec_command_line_app("ld-link",
"%s \"%.*s.o\" -o \"%.*s%.*s\" %s "
" %s "
" %.*s "
@@ -1235,7 +1272,7 @@ int main(int arg_count, char **arg_ptr) {
if (build_context.ODIN_DEBUG) {
// NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe
// to the symbols in the object file
exit_code = system_exec_command_line_app("dsymutil", true,
exit_code = system_exec_command_line_app("dsymutil",
"dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext)
);
@@ -1256,7 +1293,7 @@ int main(int arg_count, char **arg_ptr) {
//NOTE(thebirk): This whole thing is a little leaky
String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
complete_path = path_to_full_path(heap_allocator(), complete_path);
system_exec_command_line_app("odin run", false, "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
}
#endif
#endif
+5 -3
View File
@@ -212,6 +212,8 @@ void warning_va(Token token, char *fmt, va_list va) {
gb_mutex_unlock(&global_error_collector.mutex);
}
#define MAX_ERROR_COLLECTOR_COUNT (36)
void error_va(Token token, char *fmt, va_list va) {
gb_mutex_lock(&global_error_collector.mutex);
global_error_collector.count++;
@@ -225,7 +227,7 @@ void error_va(Token token, char *fmt, va_list va) {
gb_bprintf_va(fmt, va));
}
gb_mutex_unlock(&global_error_collector.mutex);
if (global_error_collector.count > 20) {
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) {
gb_exit(1);
}
}
@@ -243,7 +245,7 @@ void error_no_newline_va(Token token, char *fmt, va_list va) {
gb_bprintf_va(fmt, va));
}
gb_mutex_unlock(&global_error_collector.mutex);
if (global_error_collector.count > 20) {
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) {
gb_exit(1);
}
}
@@ -263,7 +265,7 @@ void syntax_error_va(Token token, char *fmt, va_list va) {
}
gb_mutex_unlock(&global_error_collector.mutex);
if (global_error_collector.count > 20) {
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) {
gb_exit(1);
}
}