mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Merge pull request #1082 from odin-lang/or_else-or_return-operator
`or_else` and `or_return` operators
This commit is contained in:
@@ -183,9 +183,7 @@ writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
if writer_available(b) == 0 {
|
if writer_available(b) == 0 {
|
||||||
if ferr := writer_flush(b); ferr != nil {
|
writer_flush(b) or_return;
|
||||||
return n, ferr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if b.max_consecutive_empty_writes <= 0 {
|
if b.max_consecutive_empty_writes <= 0 {
|
||||||
b.max_consecutive_empty_writes = DEFAULT_MAX_CONSECUTIVE_EMPTY_READS;
|
b.max_consecutive_empty_writes = DEFAULT_MAX_CONSECUTIVE_EMPTY_READS;
|
||||||
|
|||||||
@@ -442,24 +442,22 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
|||||||
return E_General.Unknown_Compression_Method;
|
return E_General.Unknown_Compression_Method;
|
||||||
}
|
}
|
||||||
|
|
||||||
cinfo := (cmf >> 4) & 0xf;
|
if cinfo := (cmf >> 4) & 0xf; cinfo > 7 {
|
||||||
if cinfo > 7 {
|
|
||||||
return E_ZLIB.Unsupported_Window_Size;
|
return E_ZLIB.Unsupported_Window_Size;
|
||||||
}
|
}
|
||||||
flg, _ := compress.read_u8(ctx);
|
flg, _ := compress.read_u8(ctx);
|
||||||
|
|
||||||
fcheck := flg & 0x1f;
|
fcheck := flg & 0x1f;
|
||||||
fcheck_computed := (cmf << 8 | flg) & 0x1f;
|
fcheck_computed := (cmf << 8 | flg) & 0x1f;
|
||||||
if fcheck != fcheck_computed {
|
if fcheck != fcheck_computed {
|
||||||
return E_General.Checksum_Failed;
|
return E_General.Checksum_Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fdict := (flg >> 5) & 1;
|
|
||||||
/*
|
/*
|
||||||
We don't handle built-in dictionaries for now.
|
We don't handle built-in dictionaries for now.
|
||||||
They're application specific and PNG doesn't use them.
|
They're application specific and PNG doesn't use them.
|
||||||
*/
|
*/
|
||||||
if fdict != 0 {
|
if fdict := (flg >> 5) & 1; fdict != 0 {
|
||||||
return E_ZLIB.FDICT_Unsupported;
|
return E_ZLIB.FDICT_Unsupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,10 +471,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse ZLIB stream without header.
|
// Parse ZLIB stream without header.
|
||||||
err = inflate_raw(z=ctx, expected_output_size=expected_output_size);
|
inflate_raw(z=ctx, expected_output_size=expected_output_size) or_return;
|
||||||
if err != nil {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !raw {
|
if !raw {
|
||||||
compress.discard_to_next_byte_lsb(ctx);
|
compress.discard_to_next_byte_lsb(ctx);
|
||||||
@@ -527,23 +522,14 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
z_repeat: ^Huffman_Table;
|
z_repeat: ^Huffman_Table;
|
||||||
z_offset: ^Huffman_Table;
|
z_offset: ^Huffman_Table;
|
||||||
codelength_ht: ^Huffman_Table;
|
codelength_ht: ^Huffman_Table;
|
||||||
|
|
||||||
z_repeat, err = allocate_huffman_table(allocator=context.allocator);
|
|
||||||
if err != nil {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
z_offset, err = allocate_huffman_table(allocator=context.allocator);
|
|
||||||
if err != nil {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
codelength_ht, err = allocate_huffman_table(allocator=context.allocator);
|
|
||||||
if err != nil {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
defer free(z_repeat);
|
defer free(z_repeat);
|
||||||
defer free(z_offset);
|
defer free(z_offset);
|
||||||
defer free(codelength_ht);
|
defer free(codelength_ht);
|
||||||
|
|
||||||
|
z_repeat = allocate_huffman_table(allocator=context.allocator) or_return;
|
||||||
|
z_offset = allocate_huffman_table(allocator=context.allocator) or_return;
|
||||||
|
codelength_ht = allocate_huffman_table(allocator=context.allocator) or_return;
|
||||||
|
|
||||||
final := u32(0);
|
final := u32(0);
|
||||||
type := u32(0);
|
type := u32(0);
|
||||||
|
|
||||||
@@ -560,8 +546,8 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
// Discard bits until next byte boundary
|
// Discard bits until next byte boundary
|
||||||
compress.discard_to_next_byte_lsb(z);
|
compress.discard_to_next_byte_lsb(z);
|
||||||
|
|
||||||
uncompressed_len := i16(compress.read_bits_lsb(z, 16));
|
uncompressed_len := i16(compress.read_bits_lsb(z, 16));
|
||||||
length_check := i16(compress.read_bits_lsb(z, 16));
|
length_check := i16(compress.read_bits_lsb(z, 16));
|
||||||
|
|
||||||
// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check);
|
// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check);
|
||||||
|
|
||||||
@@ -586,14 +572,8 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
|
// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
|
||||||
if type == 1 {
|
if type == 1 {
|
||||||
// Use fixed code lengths.
|
// Use fixed code lengths.
|
||||||
err = build_huffman(z_repeat, Z_FIXED_LENGTH[:]);
|
build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return;
|
||||||
if err != nil {
|
build_huffman(z_offset, Z_FIXED_DIST[:]) or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
err = build_huffman(z_offset, Z_FIXED_DIST[:]);
|
|
||||||
if err != nil {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
lencodes: [286+32+137]u8;
|
lencodes: [286+32+137]u8;
|
||||||
codelength_sizes: [19]u8;
|
codelength_sizes: [19]u8;
|
||||||
@@ -611,19 +591,13 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
s := compress.read_bits_lsb(z, 3);
|
s := compress.read_bits_lsb(z, 3);
|
||||||
codelength_sizes[Z_LENGTH_DEZIGZAG[i]] = u8(s);
|
codelength_sizes[Z_LENGTH_DEZIGZAG[i]] = u8(s);
|
||||||
}
|
}
|
||||||
err = build_huffman(codelength_ht, codelength_sizes[:]);
|
build_huffman(codelength_ht, codelength_sizes[:]) or_return;
|
||||||
if err != nil {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
c: u16;
|
c: u16;
|
||||||
|
|
||||||
for n < ntot {
|
for n < ntot {
|
||||||
c, err = decode_huffman(z, codelength_ht);
|
c = decode_huffman(z, codelength_ht) or_return;
|
||||||
if err != nil {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if c < 0 || c >= 19 {
|
if c < 0 || c >= 19 {
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths;
|
return E_Deflate.Huffman_Bad_Code_Lengths;
|
||||||
@@ -664,21 +638,10 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
return E_Deflate.Huffman_Bad_Code_Lengths;
|
return E_Deflate.Huffman_Bad_Code_Lengths;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = build_huffman(z_repeat, lencodes[:hlit]);
|
build_huffman(z_repeat, lencodes[:hlit]) or_return;
|
||||||
if err != nil {
|
build_huffman(z_offset, lencodes[hlit:ntot]) or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = build_huffman(z_offset, lencodes[hlit:ntot]);
|
|
||||||
if err != nil {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = parse_huffman_block(z, z_repeat, z_offset);
|
|
||||||
// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
|
|
||||||
if err != nil {
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
parse_huffman_block(z, z_repeat, z_offset) or_return;
|
||||||
}
|
}
|
||||||
if final == 1 {
|
if final == 1 {
|
||||||
break;
|
break;
|
||||||
@@ -698,9 +661,7 @@ inflate_from_byte_array :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, e
|
|||||||
ctx.input_data = input;
|
ctx.input_data = input;
|
||||||
ctx.output = buf;
|
ctx.output = buf;
|
||||||
|
|
||||||
err = inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size);
|
return inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size);
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) {
|
inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) {
|
||||||
@@ -712,4 +673,4 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals
|
|||||||
return inflate_raw(z=&ctx, expected_output_size=expected_output_size);
|
return inflate_raw(z=&ctx, expected_output_size=expected_output_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
inflate :: proc{inflate_from_context, inflate_from_byte_array};
|
inflate :: proc{inflate_from_context, inflate_from_byte_array};
|
||||||
@@ -64,21 +64,15 @@ write :: proc(w: ^Writer, record: []string) -> io.Error {
|
|||||||
field := record[field_idx];
|
field := record[field_idx];
|
||||||
|
|
||||||
if field_idx > 0 {
|
if field_idx > 0 {
|
||||||
if _, err := io.write_rune(w.w, w.comma); err != nil {
|
io.write_rune(w.w, w.comma) or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !field_needs_quoting(w, field) {
|
if !field_needs_quoting(w, field) {
|
||||||
if _, err := io.write_string(w.w, field); err != nil {
|
io.write_string(w.w, field) or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := io.write_byte(w.w, '"'); err != nil {
|
io.write_byte(w.w, '"') or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
for len(field) > 0 {
|
for len(field) > 0 {
|
||||||
i := strings.index_any(field, CHAR_SET);
|
i := strings.index_any(field, CHAR_SET);
|
||||||
@@ -86,40 +80,28 @@ write :: proc(w: ^Writer, record: []string) -> io.Error {
|
|||||||
i = len(field);
|
i = len(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := io.write_string(w.w, field[:i]); err != nil {
|
io.write_string(w.w, field[:i]) or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
field = field[i:];
|
field = field[i:];
|
||||||
|
|
||||||
if len(field) > 0 {
|
if len(field) > 0 {
|
||||||
switch field[0] {
|
switch field[0] {
|
||||||
case '\r':
|
case '\r':
|
||||||
if !w.use_crlf {
|
if !w.use_crlf {
|
||||||
if err := io.write_byte(w.w, '\r'); err != nil {
|
io.write_byte(w.w, '\r') or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case '\n':
|
case '\n':
|
||||||
if w.use_crlf {
|
if w.use_crlf {
|
||||||
if _, err := io.write_string(w.w, "\r\n"); err != nil {
|
io.write_string(w.w, "\r\n") or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if err := io.write_byte(w.w, '\n'); err != nil {
|
io.write_byte(w.w, '\n') or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case '"':
|
case '"':
|
||||||
if _, err := io.write_string(w.w, `""`); err != nil {
|
io.write_string(w.w, `""`) or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
field = field[1:];
|
field = field[1:];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := io.write_byte(w.w, '"'); err != nil {
|
io.write_byte(w.w, '"') or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.use_crlf {
|
if w.use_crlf {
|
||||||
@@ -132,10 +114,7 @@ write :: proc(w: ^Writer, record: []string) -> io.Error {
|
|||||||
// write_all writes multiple CSV records to w using write, and then flushes (if necessary).
|
// write_all writes multiple CSV records to w using write, and then flushes (if necessary).
|
||||||
write_all :: proc(w: ^Writer, records: [][]string) -> io.Error {
|
write_all :: proc(w: ^Writer, records: [][]string) -> io.Error {
|
||||||
for record in records {
|
for record in records {
|
||||||
err := write(w, record);
|
write(w, record) or_return;
|
||||||
if err != nil {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return writer_flush(w);
|
return writer_flush(w);
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-53
@@ -67,17 +67,9 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
}
|
}
|
||||||
|
|
||||||
read_name :: proc(r: ^Reader) -> (value: string, err: Read_Error) {
|
read_name :: proc(r: ^Reader) -> (value: string, err: Read_Error) {
|
||||||
len: u8;
|
len := read_value(r, u8) or_return;
|
||||||
data: []byte;
|
data := read_array(r, byte, int(len)) or_return;
|
||||||
len, err = read_value(r, u8);
|
return string(data[:len]), nil;
|
||||||
if err != nil {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data, err = read_array(r, byte, int(len));
|
|
||||||
if err == nil {
|
|
||||||
value = string(data[:len]);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
read_meta :: proc(r: ^Reader, capacity: u32le) -> (meta_data: []Meta, err: Read_Error) {
|
read_meta :: proc(r: ^Reader, capacity: u32le) -> (meta_data: []Meta, err: Read_Error) {
|
||||||
@@ -85,10 +77,9 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
count := 0;
|
count := 0;
|
||||||
defer meta_data = meta_data[:count];
|
defer meta_data = meta_data[:count];
|
||||||
for m in &meta_data {
|
for m in &meta_data {
|
||||||
if m.name, err = read_name(r); err != nil { return };
|
m.name = read_name(r) or_return;
|
||||||
|
|
||||||
type: Meta_Value_Type;
|
type := read_value(r, Meta_Value_Type) or_return;
|
||||||
if type, err = read_value(r, Meta_Value_Type); err != nil { return }
|
|
||||||
if type > max(Meta_Value_Type) {
|
if type > max(Meta_Value_Type) {
|
||||||
if r.print_error {
|
if r.print_error {
|
||||||
fmt.eprintf("HxA Error: file '%s' has meta value type %d. Maximum value is ", r.filename, u8(type), u8(max(Meta_Value_Type)));
|
fmt.eprintf("HxA Error: file '%s' has meta value type %d. Maximum value is ", r.filename, u8(type), u8(max(Meta_Value_Type)));
|
||||||
@@ -96,22 +87,15 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
err = .Invalid_Data;
|
err = .Invalid_Data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
array_length: u32le;
|
array_length := read_value(r, u32le) or_return;
|
||||||
if array_length, err = read_value(r, u32le); err != nil { return }
|
|
||||||
|
|
||||||
switch type {
|
switch type {
|
||||||
case .Int64:
|
case .Int64: m.value = read_array(r, i64le, int(array_length)) or_return;
|
||||||
if m.value, err = read_array(r, i64le, int(array_length)); err != nil { return }
|
case .Double: m.value = read_array(r, f64le, int(array_length)) or_return;
|
||||||
case .Double:
|
case .Node: m.value = read_array(r, Node_Index, int(array_length)) or_return;
|
||||||
if m.value, err = read_array(r, f64le, int(array_length)); err != nil { return }
|
case .Text: m.value = read_string(r, int(array_length)) or_return;
|
||||||
case .Node:
|
case .Binary: m.value = read_array(r, byte, int(array_length)) or_return;
|
||||||
if m.value, err = read_array(r, Node_Index, int(array_length)); err != nil { return }
|
case .Meta: m.value = read_meta(r, array_length) or_return;
|
||||||
case .Text:
|
|
||||||
if m.value, err = read_string(r, int(array_length)); err != nil { return }
|
|
||||||
case .Binary:
|
|
||||||
if m.value, err = read_array(r, byte, int(array_length)); err != nil { return }
|
|
||||||
case .Meta:
|
|
||||||
if m.value, err = read_meta(r, array_length); err != nil { return }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
count += 1;
|
count += 1;
|
||||||
@@ -120,16 +104,14 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
}
|
}
|
||||||
|
|
||||||
read_layer_stack :: proc(r: ^Reader, capacity: u32le) -> (layers: Layer_Stack, err: Read_Error) {
|
read_layer_stack :: proc(r: ^Reader, capacity: u32le) -> (layers: Layer_Stack, err: Read_Error) {
|
||||||
stack_count: u32le;
|
stack_count := read_value(r, u32le) or_return;
|
||||||
if stack_count, err = read_value(r, u32le); err != nil { return }
|
|
||||||
layer_count := 0;
|
layer_count := 0;
|
||||||
layers = make(Layer_Stack, stack_count);
|
layers = make(Layer_Stack, stack_count);
|
||||||
defer layers = layers[:layer_count];
|
defer layers = layers[:layer_count];
|
||||||
for layer in &layers {
|
for layer in &layers {
|
||||||
type: Layer_Data_Type;
|
layer.name = read_name(r) or_return;
|
||||||
if layer.name, err = read_name(r); err != nil { return }
|
layer.components = read_value(r, u8) or_return;
|
||||||
if layer.components, err = read_value(r, u8); err != nil { return }
|
type := read_value(r, Layer_Data_Type) or_return;
|
||||||
if type, err = read_value(r, Layer_Data_Type); err != nil { return }
|
|
||||||
if type > max(type) {
|
if type > max(type) {
|
||||||
if r.print_error {
|
if r.print_error {
|
||||||
fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is ", r.filename, u8(type), u8(max(Layer_Data_Type)));
|
fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is ", r.filename, u8(type), u8(max(Layer_Data_Type)));
|
||||||
@@ -140,10 +122,10 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
data_len := int(layer.components) * int(capacity);
|
data_len := int(layer.components) * int(capacity);
|
||||||
|
|
||||||
switch type {
|
switch type {
|
||||||
case .Uint8: if layer.data, err = read_array(r, u8, data_len); err != nil { return }
|
case .Uint8: layer.data = read_array(r, u8, data_len) or_return;
|
||||||
case .Int32: if layer.data, err = read_array(r, i32le, data_len); err != nil { return }
|
case .Int32: layer.data = read_array(r, i32le, data_len) or_return;
|
||||||
case .Float: if layer.data, err = read_array(r, f32le, data_len); err != nil { return }
|
case .Float: layer.data = read_array(r, f32le, data_len) or_return;
|
||||||
case .Double: if layer.data, err = read_array(r, f64le, data_len); err != nil { return }
|
case .Double: layer.data = read_array(r, f64le, data_len) or_return;
|
||||||
}
|
}
|
||||||
layer_count += 1;
|
layer_count += 1;
|
||||||
}
|
}
|
||||||
@@ -177,8 +159,7 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
|
|
||||||
for node_idx in 0..<header.internal_node_count {
|
for node_idx in 0..<header.internal_node_count {
|
||||||
node := &file.nodes[node_count];
|
node := &file.nodes[node_count];
|
||||||
type: Node_Type;
|
type := read_value(r, Node_Type) or_return;
|
||||||
if type, err = read_value(r, Node_Type); err != nil { return }
|
|
||||||
if type > max(Node_Type) {
|
if type > max(Node_Type) {
|
||||||
if r.print_error {
|
if r.print_error {
|
||||||
fmt.eprintf("HxA Error: file '%s' has node type %d. Maximum value is ", r.filename, u8(type), u8(max(Node_Type)));
|
fmt.eprintf("HxA Error: file '%s' has node type %d. Maximum value is ", r.filename, u8(type), u8(max(Node_Type)));
|
||||||
@@ -188,9 +169,7 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
}
|
}
|
||||||
node_count += 1;
|
node_count += 1;
|
||||||
|
|
||||||
meta_data_count: u32le;
|
node.meta_data = read_meta(r, read_value(r, u32le) or_return) or_return;
|
||||||
if meta_data_count, err = read_value(r, u32le); err != nil { return }
|
|
||||||
if node.meta_data, err = read_meta(r, meta_data_count); err != nil { return }
|
|
||||||
|
|
||||||
switch type {
|
switch type {
|
||||||
case .Meta_Only:
|
case .Meta_Only:
|
||||||
@@ -198,35 +177,35 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
case .Geometry:
|
case .Geometry:
|
||||||
g: Node_Geometry;
|
g: Node_Geometry;
|
||||||
|
|
||||||
if g.vertex_count, err = read_value(r, u32le); err != nil { return }
|
g.vertex_count = read_value(r, u32le) or_return;
|
||||||
if g.vertex_stack, err = read_layer_stack(r, g.vertex_count); err != nil { return }
|
g.vertex_stack = read_layer_stack(r, g.vertex_count) or_return;
|
||||||
if g.edge_corner_count, err = read_value(r, u32le); err != nil { return }
|
g.edge_corner_count = read_value(r, u32le) or_return;
|
||||||
if g.corner_stack, err = read_layer_stack(r, g.edge_corner_count); err != nil { return }
|
g.corner_stack = read_layer_stack(r, g.edge_corner_count) or_return;
|
||||||
if header.version > 2 {
|
if header.version > 2 {
|
||||||
if g.edge_stack, err = read_layer_stack(r, g.edge_corner_count); err != nil { return }
|
g.edge_stack = read_layer_stack(r, g.edge_corner_count) or_return;
|
||||||
}
|
}
|
||||||
if g.face_count, err = read_value(r, u32le); err != nil { return }
|
g.face_count = read_value(r, u32le) or_return;
|
||||||
if g.face_stack, err = read_layer_stack(r, g.face_count); err != nil { return }
|
g.face_stack = read_layer_stack(r, g.face_count) or_return;
|
||||||
|
|
||||||
node.content = g;
|
node.content = g;
|
||||||
|
|
||||||
case .Image:
|
case .Image:
|
||||||
img: Node_Image;
|
img: Node_Image;
|
||||||
|
|
||||||
if img.type, err = read_value(r, Image_Type); err != nil { return }
|
img.type = read_value(r, Image_Type) or_return;
|
||||||
dimensions := int(img.type);
|
dimensions := int(img.type);
|
||||||
if img.type == .Image_Cube {
|
if img.type == .Image_Cube {
|
||||||
dimensions = 2;
|
dimensions = 2;
|
||||||
}
|
}
|
||||||
img.resolution = {1, 1, 1};
|
img.resolution = {1, 1, 1};
|
||||||
for d in 0..<dimensions {
|
for d in 0..<dimensions {
|
||||||
if img.resolution[d], err = read_value(r, u32le); err != nil { return }
|
img.resolution[d] = read_value(r, u32le) or_return;
|
||||||
}
|
}
|
||||||
size := img.resolution[0]*img.resolution[1]*img.resolution[2];
|
size := img.resolution[0]*img.resolution[1]*img.resolution[2];
|
||||||
if img.type == .Image_Cube {
|
if img.type == .Image_Cube {
|
||||||
size *= 6;
|
size *= 6;
|
||||||
}
|
}
|
||||||
if img.image_stack, err = read_layer_stack(r, size); err != nil { return }
|
img.image_stack = read_layer_stack(r, size) or_return;
|
||||||
|
|
||||||
node.content = img;
|
node.content = img;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,9 +133,7 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
|
parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
|
||||||
if err = expect_token(p, .Open_Bracket); err != .None {
|
expect_token(p, .Open_Bracket) or_return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
array: Array;
|
array: Array;
|
||||||
array.allocator = p.allocator;
|
array.allocator = p.allocator;
|
||||||
@@ -147,11 +145,7 @@ parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for p.curr_token.kind != .Close_Bracket {
|
for p.curr_token.kind != .Close_Bracket {
|
||||||
elem, elem_err := parse_value(p);
|
elem := parse_value(p) or_return;
|
||||||
if elem_err != .None {
|
|
||||||
err = elem_err;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
append(&array, elem);
|
append(&array, elem);
|
||||||
|
|
||||||
// Disallow trailing commas for the time being
|
// Disallow trailing commas for the time being
|
||||||
@@ -162,10 +156,7 @@ parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = expect_token(p, .Close_Bracket); err != .None {
|
expect_token(p, .Close_Bracket) or_return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = array;
|
value = array;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -200,9 +191,7 @@ parse_object_key :: proc(p: ^Parser) -> (key: string, err: Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
|
parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
|
||||||
if err = expect_token(p, .Open_Brace); err != .None {
|
expect_token(p, .Open_Brace) or_return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj: Object;
|
obj: Object;
|
||||||
obj.allocator = p.allocator;
|
obj.allocator = p.allocator;
|
||||||
@@ -227,11 +216,7 @@ parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
elem, elem_err := parse_value(p);
|
elem := parse_value(p) or_return;
|
||||||
if elem_err != .None {
|
|
||||||
err = elem_err;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if key in obj {
|
if key in obj {
|
||||||
err = .Duplicate_Object_Key;
|
err = .Duplicate_Object_Key;
|
||||||
@@ -256,10 +241,7 @@ parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = expect_token(p, .Close_Brace); err != .None {
|
expect_token(p, .Close_Brace) or_return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = obj;
|
value = obj;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-30
@@ -372,8 +372,7 @@ load_from_file :: proc(filename: string, options := Options{}, allocator := cont
|
|||||||
defer delete(data);
|
defer delete(data);
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
img, err = load_from_slice(data, options, allocator);
|
return load_from_slice(data, options, allocator);
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
img = new(Image);
|
img = new(Image);
|
||||||
return img, E_General.File_Not_Found;
|
return img, E_General.File_Not_Found;
|
||||||
@@ -453,10 +452,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
|||||||
}
|
}
|
||||||
seen_ihdr = true;
|
seen_ihdr = true;
|
||||||
|
|
||||||
header, err = read_header(ctx);
|
header = read_header(ctx) or_return;
|
||||||
if err != nil {
|
|
||||||
return img, err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if .Paletted in header.color_type {
|
if .Paletted in header.color_type {
|
||||||
// Color type 3
|
// Color type 3
|
||||||
@@ -506,10 +502,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
|||||||
return img, E_PNG.PLTE_Encountered_Unexpectedly;
|
return img, E_PNG.PLTE_Encountered_Unexpectedly;
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err = read_chunk(ctx);
|
c = read_chunk(ctx) or_return;
|
||||||
if err != nil {
|
|
||||||
return img, err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.header.length % 3 != 0 || c.header.length > 768 {
|
if c.header.length % 3 != 0 || c.header.length > 768 {
|
||||||
return img, E_PNG.PLTE_Invalid_Length;
|
return img, E_PNG.PLTE_Invalid_Length;
|
||||||
@@ -540,10 +533,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
|||||||
|
|
||||||
next := ch.type;
|
next := ch.type;
|
||||||
for next == .IDAT {
|
for next == .IDAT {
|
||||||
c, err = read_chunk(ctx);
|
c = read_chunk(ctx) or_return;
|
||||||
if err != nil {
|
|
||||||
return img, err;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes.buffer_write(&idat_b, c.data);
|
bytes.buffer_write(&idat_b, c.data);
|
||||||
idat_length += c.header.length;
|
idat_length += c.header.length;
|
||||||
@@ -560,19 +550,13 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
|||||||
}
|
}
|
||||||
seen_idat = true;
|
seen_idat = true;
|
||||||
case .IEND:
|
case .IEND:
|
||||||
c, err = read_chunk(ctx);
|
c = read_chunk(ctx) or_return;
|
||||||
if err != nil {
|
|
||||||
return img, err;
|
|
||||||
}
|
|
||||||
seen_iend = true;
|
seen_iend = true;
|
||||||
case .bKGD:
|
case .bKGD:
|
||||||
|
|
||||||
// TODO: Make sure that 16-bit bKGD + tRNS chunks return u16 instead of u16be
|
// TODO: Make sure that 16-bit bKGD + tRNS chunks return u16 instead of u16be
|
||||||
|
|
||||||
c, err = read_chunk(ctx);
|
c = read_chunk(ctx) or_return;
|
||||||
if err != nil {
|
|
||||||
return img, err;
|
|
||||||
}
|
|
||||||
seen_bkgd = true;
|
seen_bkgd = true;
|
||||||
if .return_metadata in options {
|
if .return_metadata in options {
|
||||||
append(&info.chunks, c);
|
append(&info.chunks, c);
|
||||||
@@ -604,10 +588,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
|||||||
img.background = [3]u16{u16(col[0]), u16(col[1]), u16(col[2])};
|
img.background = [3]u16{u16(col[0]), u16(col[1]), u16(col[2])};
|
||||||
}
|
}
|
||||||
case .tRNS:
|
case .tRNS:
|
||||||
c, err = read_chunk(ctx);
|
c = read_chunk(ctx) or_return;
|
||||||
if err != nil {
|
|
||||||
return img, err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if .Alpha in info.header.color_type {
|
if .Alpha in info.header.color_type {
|
||||||
return img, E_PNG.TRNS_Encountered_Unexpectedly;
|
return img, E_PNG.TRNS_Encountered_Unexpectedly;
|
||||||
@@ -646,10 +627,8 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
|||||||
return img, E_PNG.PNG_Does_Not_Adhere_to_Spec;
|
return img, E_PNG.PNG_Does_Not_Adhere_to_Spec;
|
||||||
case:
|
case:
|
||||||
// Unhandled type
|
// Unhandled type
|
||||||
c, err = read_chunk(ctx);
|
c = read_chunk(ctx) or_return;
|
||||||
if err != nil {
|
|
||||||
return img, err;
|
|
||||||
}
|
|
||||||
if .return_metadata in options {
|
if .return_metadata in options {
|
||||||
// NOTE: Chunk cata is currently allocated on the temp allocator.
|
// NOTE: Chunk cata is currently allocated on the temp allocator.
|
||||||
append(&info.chunks, c);
|
append(&info.chunks, c);
|
||||||
|
|||||||
+46
-50
@@ -42,7 +42,7 @@ int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator :
|
|||||||
Check that `src` is usable and `dest` isn't immutable.
|
Check that `src` is usable and `dest` isn't immutable.
|
||||||
*/
|
*/
|
||||||
assert_if_nil(dest);
|
assert_if_nil(dest);
|
||||||
if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; }
|
#force_inline internal_error_if_immutable(dest) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_set_from_integer(dest, src, minimize);
|
return #force_inline internal_int_set_from_integer(dest, src, minimize);
|
||||||
}
|
}
|
||||||
@@ -64,8 +64,8 @@ int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.alloca
|
|||||||
assert_if_nil(dest, src);
|
assert_if_nil(dest, src);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; }
|
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||||
if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; }
|
#force_inline internal_error_if_immutable(dest) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_copy(dest, src, minimize);
|
return #force_inline internal_int_copy(dest, src, minimize);
|
||||||
}
|
}
|
||||||
@@ -92,8 +92,8 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
|
|||||||
assert_if_nil(dest, src);
|
assert_if_nil(dest, src);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; }
|
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||||
if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; }
|
#force_inline internal_error_if_immutable(dest) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_abs(dest, src);
|
return #force_inline internal_int_abs(dest, src);
|
||||||
}
|
}
|
||||||
@@ -113,8 +113,8 @@ int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
|
|||||||
assert_if_nil(dest, src);
|
assert_if_nil(dest, src);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; }
|
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||||
if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; }
|
#force_inline internal_error_if_immutable(dest) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_neg(dest, src);
|
return #force_inline internal_int_neg(dest, src);
|
||||||
}
|
}
|
||||||
@@ -134,8 +134,8 @@ int_bitfield_extract :: proc(a: ^Int, offset, count: int, allocator := context.a
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = #force_inline internal_clear_if_uninitialized(a); err != nil { return {}, err; }
|
#force_inline internal_clear_if_uninitialized(a) or_return;
|
||||||
return #force_inline internal_int_bitfield_extract(a, offset, count);
|
return #force_inline internal_int_bitfield_extract(a, offset, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -148,8 +148,8 @@ shrink :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = #force_inline internal_clear_if_uninitialized(a); err != nil { return err; }
|
#force_inline internal_clear_if_uninitialized(a) or_return;
|
||||||
return #force_inline internal_shrink(a);
|
return #force_inline internal_shrink(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
|
int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
|
||||||
@@ -305,8 +305,8 @@ int_get :: proc(a: ^Int, $T: typeid, allocator := context.allocator) -> (res: T,
|
|||||||
Check that `a` is usable.
|
Check that `a` is usable.
|
||||||
*/
|
*/
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return T{}, err; }
|
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||||
return #force_inline internal_int_get(a, T);
|
return #force_inline internal_int_get(a, T);
|
||||||
}
|
}
|
||||||
get :: proc { int_get, };
|
get :: proc { int_get, };
|
||||||
|
|
||||||
@@ -315,8 +315,8 @@ int_get_float :: proc(a: ^Int, allocator := context.allocator) -> (res: f64, err
|
|||||||
Check that `a` is usable.
|
Check that `a` is usable.
|
||||||
*/
|
*/
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return 0, err; }
|
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||||
return #force_inline internal_int_get_float(a);
|
return #force_inline internal_int_get_float(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -327,8 +327,8 @@ count_bits :: proc(a: ^Int, allocator := context.allocator) -> (count: int, err:
|
|||||||
Check that `a` is usable.
|
Check that `a` is usable.
|
||||||
*/
|
*/
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return 0, err; }
|
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||||
return #force_inline internal_count_bits(a), nil;
|
return #force_inline internal_count_bits(a), nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -340,8 +340,8 @@ int_count_lsb :: proc(a: ^Int, allocator := context.allocator) -> (count: int, e
|
|||||||
Check that `a` is usable.
|
Check that `a` is usable.
|
||||||
*/
|
*/
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return 0, err; }
|
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||||
return #force_inline internal_int_count_lsb(a);
|
return #force_inline internal_int_count_lsb(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_count_lsb :: #force_inline proc(a: $T) -> (count: int)
|
platform_count_lsb :: #force_inline proc(a: $T) -> (count: int)
|
||||||
@@ -398,7 +398,7 @@ clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocato
|
|||||||
assert_if_nil(..args);
|
assert_if_nil(..args);
|
||||||
|
|
||||||
for i in &args {
|
for i in &args {
|
||||||
if err = #force_inline internal_clear_if_uninitialized_single(i, allocator); err != nil { return nil; }
|
#force_inline internal_clear_if_uninitialized_single(i, allocator) or_return;
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -425,7 +425,7 @@ int_init_multi :: proc(integers: ..^Int, allocator := context.allocator) -> (err
|
|||||||
|
|
||||||
integers := integers;
|
integers := integers;
|
||||||
for a in &integers {
|
for a in &integers {
|
||||||
if err = #force_inline internal_clear(a, true, allocator); err != nil { return err; }
|
#force_inline internal_clear(a, true, allocator) or_return;
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
@@ -440,7 +440,7 @@ copy_digits :: proc(dest, src: ^Int, digits: int, allocator := context.allocator
|
|||||||
Check that `src` is usable and `dest` isn't immutable.
|
Check that `src` is usable and `dest` isn't immutable.
|
||||||
*/
|
*/
|
||||||
assert_if_nil(dest, src);
|
assert_if_nil(dest, src);
|
||||||
if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; }
|
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||||
|
|
||||||
digits = min(digits, len(src.digit), len(dest.digit));
|
digits = min(digits, len(src.digit), len(dest.digit));
|
||||||
return #force_inline internal_copy_digits(dest, src, digits);
|
return #force_inline internal_copy_digits(dest, src, digits);
|
||||||
@@ -454,7 +454,7 @@ copy_digits :: proc(dest, src: ^Int, digits: int, allocator := context.allocator
|
|||||||
*/
|
*/
|
||||||
clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
|
clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return err; }
|
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||||
|
|
||||||
for a.used > 0 && a.digit[a.used - 1] == 0 {
|
for a.used > 0 && a.digit[a.used - 1] == 0 {
|
||||||
a.used -= 1;
|
a.used -= 1;
|
||||||
@@ -472,7 +472,7 @@ clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
|
|||||||
*/
|
*/
|
||||||
int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocator) -> (size_in_bytes: int, err: Error) {
|
int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocator) -> (size_in_bytes: int, err: Error) {
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return {}, err; }
|
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||||
|
|
||||||
size_in_bits := internal_count_bits(a);
|
size_in_bits := internal_count_bits(a);
|
||||||
|
|
||||||
@@ -488,9 +488,8 @@ int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocat
|
|||||||
*/
|
*/
|
||||||
int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
size_in_bytes: int;
|
|
||||||
|
|
||||||
if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
|
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||||
l := len(buf);
|
l := len(buf);
|
||||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||||
|
|
||||||
@@ -512,9 +511,8 @@ int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := co
|
|||||||
*/
|
*/
|
||||||
int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
size_in_bytes: int;
|
|
||||||
|
|
||||||
if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
|
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||||
l := len(buf);
|
l := len(buf);
|
||||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||||
|
|
||||||
@@ -537,18 +535,17 @@ int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := conte
|
|||||||
*/
|
*/
|
||||||
int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
size_in_bytes: int;
|
|
||||||
|
|
||||||
if !signed && a.sign == .Negative { return .Invalid_Argument; }
|
if !signed && a.sign == .Negative { return .Invalid_Argument; }
|
||||||
|
|
||||||
l := len(buf);
|
l := len(buf);
|
||||||
if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
|
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||||
|
|
||||||
if a.sign == .Negative {
|
if a.sign == .Negative {
|
||||||
t := &Int{};
|
t := &Int{};
|
||||||
defer destroy(t);
|
defer destroy(t);
|
||||||
if err = internal_complement(t, a, allocator); err != nil { return err; }
|
internal_complement(t, a, allocator) or_return;
|
||||||
|
|
||||||
size_in_bits := internal_count_bits(t);
|
size_in_bits := internal_count_bits(t);
|
||||||
i := 0;
|
i := 0;
|
||||||
@@ -574,19 +571,18 @@ int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocato
|
|||||||
*/
|
*/
|
||||||
int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
size_in_bytes: int;
|
|
||||||
|
|
||||||
if !signed && a.sign == .Negative { return .Invalid_Argument; }
|
if !signed && a.sign == .Negative { return .Invalid_Argument; }
|
||||||
if a.sign == .Zero_or_Positive { return int_to_bytes_big(a, buf, signed, allocator); }
|
if a.sign == .Zero_or_Positive { return int_to_bytes_big(a, buf, signed, allocator); }
|
||||||
|
|
||||||
l := len(buf);
|
l := len(buf);
|
||||||
if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
|
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||||
|
|
||||||
t := &Int{};
|
t := &Int{};
|
||||||
defer destroy(t);
|
defer destroy(t);
|
||||||
|
|
||||||
if err = internal_complement(t, a, allocator); err != nil { return err; }
|
internal_complement(t, a, allocator) or_return;
|
||||||
|
|
||||||
size_in_bits := internal_count_bits(t);
|
size_in_bits := internal_count_bits(t);
|
||||||
i := l - 1;
|
i := l - 1;
|
||||||
@@ -619,8 +615,8 @@ int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := con
|
|||||||
}
|
}
|
||||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
||||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
||||||
if err = internal_zero(a, false, allocator); err != nil { return err; }
|
internal_zero(a, false, allocator) or_return;
|
||||||
if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; }
|
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||||
|
|
||||||
if signed {
|
if signed {
|
||||||
sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
|
sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
|
||||||
@@ -628,7 +624,7 @@ int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := con
|
|||||||
}
|
}
|
||||||
|
|
||||||
for v in buf {
|
for v in buf {
|
||||||
if err = internal_shl(a, a, 8); err != nil { return err; }
|
internal_shl(a, a, 8) or_return;
|
||||||
a.digit[0] |= DIGIT(v);
|
a.digit[0] |= DIGIT(v);
|
||||||
}
|
}
|
||||||
a.sign = sign;
|
a.sign = sign;
|
||||||
@@ -656,8 +652,8 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator
|
|||||||
}
|
}
|
||||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
||||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
||||||
if err = internal_zero(a, false, allocator); err != nil { return err; }
|
internal_zero(a, false, allocator) or_return;
|
||||||
if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; }
|
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||||
|
|
||||||
if signed {
|
if signed {
|
||||||
sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
|
sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
|
||||||
@@ -665,7 +661,7 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator
|
|||||||
}
|
}
|
||||||
|
|
||||||
for v in buf {
|
for v in buf {
|
||||||
if err = internal_shl(a, a, 8); err != nil { return err; }
|
internal_shl(a, a, 8) or_return;
|
||||||
if signed && sign == .Negative {
|
if signed && sign == .Negative {
|
||||||
a.digit[0] |= DIGIT(255 - v);
|
a.digit[0] |= DIGIT(255 - v);
|
||||||
} else {
|
} else {
|
||||||
@@ -674,7 +670,7 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator
|
|||||||
}
|
}
|
||||||
a.sign = sign;
|
a.sign = sign;
|
||||||
a.used = size_in_digits;
|
a.used = size_in_digits;
|
||||||
if err = internal_clamp(a); err != nil { return err; }
|
internal_clamp(a) or_return;
|
||||||
|
|
||||||
if signed && sign == .Negative {
|
if signed && sign == .Negative {
|
||||||
return internal_sub(a, a, 1);
|
return internal_sub(a, a, 1);
|
||||||
@@ -702,8 +698,8 @@ int_from_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator :=
|
|||||||
}
|
}
|
||||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
||||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
||||||
if err = internal_zero(a, false, allocator); err != nil { return err; }
|
internal_zero(a, false, allocator) or_return;
|
||||||
if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; }
|
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||||
|
|
||||||
if signed {
|
if signed {
|
||||||
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
|
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
|
||||||
@@ -712,7 +708,7 @@ int_from_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator :=
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, i in buf {
|
for _, i in buf {
|
||||||
if err = internal_shl(a, a, 8); err != nil { return err; }
|
internal_shl(a, a, 8) or_return;
|
||||||
a.digit[0] |= DIGIT(buf[l-i-1]);
|
a.digit[0] |= DIGIT(buf[l-i-1]);
|
||||||
}
|
}
|
||||||
a.sign = sign;
|
a.sign = sign;
|
||||||
@@ -740,8 +736,8 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca
|
|||||||
}
|
}
|
||||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
||||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
||||||
if err = internal_zero(a, false, allocator); err != nil { return err; }
|
internal_zero(a, false, allocator) or_return;
|
||||||
if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; }
|
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||||
|
|
||||||
if signed {
|
if signed {
|
||||||
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
|
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
|
||||||
@@ -750,7 +746,7 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, i in buf {
|
for _, i in buf {
|
||||||
if err = internal_shl(a, a, 8); err != nil { return err; }
|
internal_shl(a, a, 8) or_return;
|
||||||
if signed && sign == .Negative {
|
if signed && sign == .Negative {
|
||||||
a.digit[0] |= DIGIT(255 - buf[l-i-1]);
|
a.digit[0] |= DIGIT(255 - buf[l-i-1]);
|
||||||
} else {
|
} else {
|
||||||
@@ -759,7 +755,7 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca
|
|||||||
}
|
}
|
||||||
a.sign = sign;
|
a.sign = sign;
|
||||||
a.used = size_in_digits;
|
a.used = size_in_digits;
|
||||||
if err = internal_clamp(a); err != nil { return err; }
|
internal_clamp(a) or_return;
|
||||||
|
|
||||||
if signed && sign == .Negative {
|
if signed && sign == .Negative {
|
||||||
return internal_sub(a, a, 1);
|
return internal_sub(a, a, 1);
|
||||||
|
|||||||
+72
-75
@@ -58,7 +58,7 @@ internal_int_add_unsigned :: proc(dest, a, b: ^Int, allocator := context.allocat
|
|||||||
max_used = x.used;
|
max_used = x.used;
|
||||||
old_used = dest.used;
|
old_used = dest.used;
|
||||||
|
|
||||||
if err = internal_grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)); err != nil { return err; }
|
internal_grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)) or_return;
|
||||||
dest.used = max_used + 1;
|
dest.used = max_used + 1;
|
||||||
/*
|
/*
|
||||||
All parameters have been initialized.
|
All parameters have been initialized.
|
||||||
@@ -158,7 +158,7 @@ internal_add_signed :: proc { internal_int_add_signed, };
|
|||||||
internal_int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
|
internal_int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_grow(dest, a.used + 1); err != nil { return err; }
|
internal_grow(dest, a.used + 1) or_return;
|
||||||
/*
|
/*
|
||||||
Fast paths for destination and input Int being the same.
|
Fast paths for destination and input Int being the same.
|
||||||
*/
|
*/
|
||||||
@@ -284,7 +284,7 @@ internal_int_sub_unsigned :: proc(dest, number, decrease: ^Int, allocator := con
|
|||||||
max_used := x.used;
|
max_used := x.used;
|
||||||
i: int;
|
i: int;
|
||||||
|
|
||||||
if err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); err != nil { return err; }
|
grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)) or_return;
|
||||||
dest.used = max_used;
|
dest.used = max_used;
|
||||||
/*
|
/*
|
||||||
All parameters have been initialized.
|
All parameters have been initialized.
|
||||||
@@ -389,7 +389,7 @@ internal_int_sub_signed :: proc(dest, number, decrease: ^Int, allocator := conte
|
|||||||
internal_int_sub_digit :: proc(dest, number: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
|
internal_int_sub_digit :: proc(dest, number: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_grow(dest, number.used + 1); err != nil { return err; }
|
internal_grow(dest, number.used + 1) or_return;
|
||||||
|
|
||||||
dest := dest; digit := digit;
|
dest := dest; digit := digit;
|
||||||
/*
|
/*
|
||||||
@@ -520,12 +520,12 @@ internal_int_shr1 :: proc(dest, src: ^Int) -> (err: Error) {
|
|||||||
internal_int_shl1 :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
internal_int_shl1 :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_copy(dest, src); err != nil { return err; }
|
internal_copy(dest, src) or_return;
|
||||||
/*
|
/*
|
||||||
Grow `dest` to accommodate the additional bits.
|
Grow `dest` to accommodate the additional bits.
|
||||||
*/
|
*/
|
||||||
digits_needed := dest.used + 1;
|
digits_needed := dest.used + 1;
|
||||||
if err = internal_grow(dest, digits_needed); err != nil { return err; }
|
internal_grow(dest, digits_needed) or_return;
|
||||||
dest.used = digits_needed;
|
dest.used = digits_needed;
|
||||||
|
|
||||||
mask := (DIGIT(1) << uint(1)) - DIGIT(1);
|
mask := (DIGIT(1) << uint(1)) - DIGIT(1);
|
||||||
@@ -568,15 +568,14 @@ internal_int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator :=
|
|||||||
return #force_inline internal_int_shl1(dest, src);
|
return #force_inline internal_int_shl1(dest, src);
|
||||||
}
|
}
|
||||||
if #force_inline platform_int_is_power_of_two(int(multiplier)) {
|
if #force_inline platform_int_is_power_of_two(int(multiplier)) {
|
||||||
ix: int;
|
ix := internal_log(multiplier, 2) or_return;
|
||||||
if ix, err = internal_log(multiplier, 2); err != nil { return err; }
|
|
||||||
return internal_shl(dest, src, ix);
|
return internal_shl(dest, src, ix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Ensure `dest` is big enough to hold `src` * `multiplier`.
|
Ensure `dest` is big enough to hold `src` * `multiplier`.
|
||||||
*/
|
*/
|
||||||
if err = grow(dest, max(src.used + 1, _DEFAULT_DIGIT_COUNT)); err != nil { return err; }
|
grow(dest, max(src.used + 1, _DEFAULT_DIGIT_COUNT)) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Save the original used count.
|
Save the original used count.
|
||||||
@@ -722,7 +721,7 @@ internal_int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, a
|
|||||||
*/
|
*/
|
||||||
if #force_inline internal_cmp_mag(numerator, denominator) == -1 {
|
if #force_inline internal_cmp_mag(numerator, denominator) == -1 {
|
||||||
if remainder != nil {
|
if remainder != nil {
|
||||||
if err = internal_copy(remainder, numerator); err != nil { return err; }
|
internal_copy(remainder, numerator) or_return;
|
||||||
}
|
}
|
||||||
if quotient != nil {
|
if quotient != nil {
|
||||||
internal_zero(quotient);
|
internal_zero(quotient);
|
||||||
@@ -809,7 +808,7 @@ internal_int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT,
|
|||||||
*/
|
*/
|
||||||
q := &Int{};
|
q := &Int{};
|
||||||
|
|
||||||
if err = internal_grow(q, numerator.used); err != nil { return 0, err; }
|
internal_grow(q, numerator.used) or_return;
|
||||||
|
|
||||||
q.used = numerator.used;
|
q.used = numerator.used;
|
||||||
q.sign = numerator.sign;
|
q.sign = numerator.sign;
|
||||||
@@ -853,7 +852,7 @@ internal_div :: proc { internal_int_div, };
|
|||||||
Asssumes quotient, numerator and denominator to have been initialized and not to be nil.
|
Asssumes quotient, numerator and denominator to have been initialized and not to be nil.
|
||||||
*/
|
*/
|
||||||
internal_int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
|
internal_int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
if err = #force_inline internal_int_divmod(nil, remainder, numerator, denominator, allocator); err != nil { return err; }
|
#force_inline internal_int_divmod(nil, remainder, numerator, denominator, allocator) or_return;
|
||||||
|
|
||||||
if remainder.used == 0 || denominator.sign == remainder.sign { return nil; }
|
if remainder.used == 0 || denominator.sign == remainder.sign { return nil; }
|
||||||
|
|
||||||
@@ -865,7 +864,7 @@ internal_mod :: proc{ internal_int_mod, };
|
|||||||
remainder = (number + addend) % modulus.
|
remainder = (number + addend) % modulus.
|
||||||
*/
|
*/
|
||||||
internal_int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
internal_int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
if err = #force_inline internal_add(remainder, number, addend, allocator); err != nil { return err; }
|
#force_inline internal_add(remainder, number, addend, allocator) or_return;
|
||||||
return #force_inline internal_mod(remainder, remainder, modulus, allocator);
|
return #force_inline internal_mod(remainder, remainder, modulus, allocator);
|
||||||
}
|
}
|
||||||
internal_addmod :: proc { internal_int_addmod, };
|
internal_addmod :: proc { internal_int_addmod, };
|
||||||
@@ -874,7 +873,7 @@ internal_addmod :: proc { internal_int_addmod, };
|
|||||||
remainder = (number - decrease) % modulus.
|
remainder = (number - decrease) % modulus.
|
||||||
*/
|
*/
|
||||||
internal_int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
internal_int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
if err = #force_inline internal_sub(remainder, number, decrease, allocator); err != nil { return err; }
|
#force_inline internal_sub(remainder, number, decrease, allocator) or_return;
|
||||||
return #force_inline internal_mod(remainder, remainder, modulus, allocator);
|
return #force_inline internal_mod(remainder, remainder, modulus, allocator);
|
||||||
}
|
}
|
||||||
internal_submod :: proc { internal_int_submod, };
|
internal_submod :: proc { internal_int_submod, };
|
||||||
@@ -883,7 +882,7 @@ internal_submod :: proc { internal_int_submod, };
|
|||||||
remainder = (number * multiplicand) % modulus.
|
remainder = (number * multiplicand) % modulus.
|
||||||
*/
|
*/
|
||||||
internal_int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
internal_int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
if err = #force_inline internal_mul(remainder, number, multiplicand, allocator); err != nil { return err; }
|
#force_inline internal_mul(remainder, number, multiplicand, allocator) or_return;
|
||||||
return #force_inline internal_mod(remainder, remainder, modulus, allocator);
|
return #force_inline internal_mod(remainder, remainder, modulus, allocator);
|
||||||
}
|
}
|
||||||
internal_mulmod :: proc { internal_int_mulmod, };
|
internal_mulmod :: proc { internal_int_mulmod, };
|
||||||
@@ -892,7 +891,7 @@ internal_mulmod :: proc { internal_int_mulmod, };
|
|||||||
remainder = (number * number) % modulus.
|
remainder = (number * number) % modulus.
|
||||||
*/
|
*/
|
||||||
internal_int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
internal_int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
if err = #force_inline internal_sqr(remainder, number, allocator); err != nil { return err; }
|
#force_inline internal_sqr(remainder, number, allocator) or_return;
|
||||||
return #force_inline internal_mod(remainder, remainder, modulus, allocator);
|
return #force_inline internal_mod(remainder, remainder, modulus, allocator);
|
||||||
}
|
}
|
||||||
internal_sqrmod :: proc { internal_int_sqrmod, };
|
internal_sqrmod :: proc { internal_int_sqrmod, };
|
||||||
@@ -915,9 +914,11 @@ internal_int_factorial :: proc(res: ^Int, n: int, allocator := context.allocator
|
|||||||
return #force_inline internal_set(res, _factorial_table[n]);
|
return #force_inline internal_set(res, _factorial_table[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = #force_inline internal_set(res, _factorial_table[i - 1]); err != nil { return err; }
|
#force_inline internal_set(res, _factorial_table[i - 1]) or_return;
|
||||||
for {
|
for {
|
||||||
if err = #force_inline internal_mul(res, res, DIGIT(i)); err != nil || i == n { return err; }
|
if err = #force_inline internal_mul(res, res, DIGIT(i)); err != nil || i == n {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,8 +951,8 @@ internal_int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator :
|
|||||||
/*
|
/*
|
||||||
If the modulus is larger than the value, return the value.
|
If the modulus is larger than the value, return the value.
|
||||||
*/
|
*/
|
||||||
err = internal_copy(remainder, numerator);
|
internal_copy(remainder, numerator) or_return;
|
||||||
if bits >= (numerator.used * _DIGIT_BITS) || err != nil {
|
if bits >= (numerator.used * _DIGIT_BITS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1264,7 +1265,7 @@ internal_int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allo
|
|||||||
A zero base is a special case.
|
A zero base is a special case.
|
||||||
*/
|
*/
|
||||||
if power < 0 {
|
if power < 0 {
|
||||||
if err = internal_zero(dest); err != nil { return err; }
|
internal_zero(dest) or_return;
|
||||||
return .Math_Domain_Error;
|
return .Math_Domain_Error;
|
||||||
}
|
}
|
||||||
if power == 0 { return internal_one(dest); }
|
if power == 0 { return internal_one(dest); }
|
||||||
@@ -1293,37 +1294,34 @@ internal_int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allo
|
|||||||
}
|
}
|
||||||
|
|
||||||
g := &Int{};
|
g := &Int{};
|
||||||
if err = internal_copy(g, base); err != nil { return err; }
|
internal_copy(g, base) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set initial result.
|
Set initial result.
|
||||||
*/
|
*/
|
||||||
if err = internal_one(dest); err != nil { return err; }
|
internal_one(dest) or_return;
|
||||||
|
|
||||||
loop: for power > 0 {
|
defer internal_destroy(g);
|
||||||
|
|
||||||
|
for power > 0 {
|
||||||
/*
|
/*
|
||||||
If the bit is set, multiply.
|
If the bit is set, multiply.
|
||||||
*/
|
*/
|
||||||
if power & 1 != 0 {
|
if power & 1 != 0 {
|
||||||
if err = internal_mul(dest, g, dest); err != nil {
|
internal_mul(dest, g, dest) or_return;
|
||||||
break loop;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Square.
|
Square.
|
||||||
*/
|
*/
|
||||||
if power > 1 {
|
if power > 1 {
|
||||||
if err = #force_inline internal_sqr(g, g); err != nil {
|
internal_sqr(g, g) or_return;
|
||||||
break loop;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shift to next bit */
|
/* shift to next bit */
|
||||||
power >>= 1;
|
power >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal_destroy(g);
|
return;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1336,7 +1334,7 @@ internal_int_pow_int :: proc(dest: ^Int, base, power: int, allocator := context.
|
|||||||
base_t := &Int{};
|
base_t := &Int{};
|
||||||
defer internal_destroy(base_t);
|
defer internal_destroy(base_t);
|
||||||
|
|
||||||
if err = internal_set(base_t, base); err != nil { return err; }
|
internal_set(base_t, base) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_pow(dest, base_t, power);
|
return #force_inline internal_int_pow(dest, base_t, power);
|
||||||
}
|
}
|
||||||
@@ -1387,15 +1385,15 @@ internal_int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (e
|
|||||||
count := #force_inline internal_count_bits(src);
|
count := #force_inline internal_count_bits(src);
|
||||||
|
|
||||||
a, b := count >> 1, count & 1;
|
a, b := count >> 1, count & 1;
|
||||||
if err = internal_int_power_of_two(x, a+b, allocator); err != nil { return err; }
|
internal_int_power_of_two(x, a+b, allocator) or_return;
|
||||||
|
|
||||||
for {
|
for {
|
||||||
/*
|
/*
|
||||||
y = (x + n // x) // 2
|
y = (x + n // x) // 2
|
||||||
*/
|
*/
|
||||||
if err = internal_div(t1, src, x); err != nil { return err; }
|
internal_div(t1, src, x) or_return;
|
||||||
if err = internal_add(t2, t1, x); err != nil { return err; }
|
internal_add(t2, t1, x) or_return;
|
||||||
if err = internal_shr(y, t2, 1); err != nil { return err; }
|
internal_shr(y, t2, 1) or_return;
|
||||||
|
|
||||||
if c := internal_cmp(y, x); c == 0 || c == 1 {
|
if c := internal_cmp(y, x); c == 0 || c == 1 {
|
||||||
internal_swap(dest, x);
|
internal_swap(dest, x);
|
||||||
@@ -1480,33 +1478,33 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca
|
|||||||
Start value must be larger than root.
|
Start value must be larger than root.
|
||||||
*/
|
*/
|
||||||
ilog2 += 2;
|
ilog2 += 2;
|
||||||
if err = internal_int_power_of_two(t2, ilog2); err != nil { return err; }
|
internal_int_power_of_two(t2, ilog2) or_return;
|
||||||
|
|
||||||
c: int;
|
c: int;
|
||||||
iterations := 0;
|
iterations := 0;
|
||||||
for {
|
for {
|
||||||
/* t1 = t2 */
|
/* t1 = t2 */
|
||||||
if err = internal_copy(t1, t2); err != nil { return err; }
|
internal_copy(t1, t2) or_return;
|
||||||
|
|
||||||
/* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */
|
/* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */
|
||||||
|
|
||||||
/* t3 = t1**(b-1) */
|
/* t3 = t1**(b-1) */
|
||||||
if err = internal_pow(t3, t1, n-1); err != nil { return err; }
|
internal_pow(t3, t1, n-1) or_return;
|
||||||
|
|
||||||
/* numerator */
|
/* numerator */
|
||||||
/* t2 = t1**b */
|
/* t2 = t1**b */
|
||||||
if err = internal_mul(t2, t1, t3); err != nil { return err; }
|
internal_mul(t2, t1, t3) or_return;
|
||||||
|
|
||||||
/* t2 = t1**b - a */
|
/* t2 = t1**b - a */
|
||||||
if err = internal_sub(t2, t2, a); err != nil { return err; }
|
internal_sub(t2, t2, a) or_return;
|
||||||
|
|
||||||
/* denominator */
|
/* denominator */
|
||||||
/* t3 = t1**(b-1) * b */
|
/* t3 = t1**(b-1) * b */
|
||||||
if err = internal_mul(t3, t3, DIGIT(n)); err != nil { return err; }
|
internal_mul(t3, t3, DIGIT(n)) or_return;
|
||||||
|
|
||||||
/* t3 = (t1**b - a)/(b * t1**(b-1)) */
|
/* t3 = (t1**b - a)/(b * t1**(b-1)) */
|
||||||
if err = internal_div(t3, t2, t3); err != nil { return err; }
|
internal_div(t3, t2, t3) or_return;
|
||||||
if err = internal_sub(t2, t1, t3); err != nil { return err; }
|
internal_sub(t2, t1, t3) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Number of rounds is at most log_2(root). If it is more it
|
Number of rounds is at most log_2(root). If it is more it
|
||||||
@@ -1526,14 +1524,14 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca
|
|||||||
|
|
||||||
iterations = 0;
|
iterations = 0;
|
||||||
for {
|
for {
|
||||||
if err = internal_pow(t2, t1, n); err != nil { return err; }
|
internal_pow(t2, t1, n) or_return;
|
||||||
|
|
||||||
c = internal_cmp(t2, a);
|
c = internal_cmp(t2, a);
|
||||||
if c == 0 {
|
if c == 0 {
|
||||||
swap(dest, t1);
|
swap(dest, t1);
|
||||||
return nil;
|
return nil;
|
||||||
} else if c == -1 {
|
} else if c == -1 {
|
||||||
if err = internal_add(t1, t1, DIGIT(1)); err != nil { return err; }
|
internal_add(t1, t1, DIGIT(1)) or_return;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1549,11 +1547,11 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca
|
|||||||
Correct overshoot from above or from recurrence.
|
Correct overshoot from above or from recurrence.
|
||||||
*/
|
*/
|
||||||
for {
|
for {
|
||||||
if err = internal_pow(t2, t1, n); err != nil { return err; }
|
internal_pow(t2, t1, n) or_return;
|
||||||
|
|
||||||
if internal_cmp(t2, a) != 1 { break; }
|
if internal_cmp(t2, a) != 1 { break; }
|
||||||
|
|
||||||
if err = internal_sub(t1, t1, DIGIT(1)); err != nil { return err; }
|
internal_sub(t1, t1, DIGIT(1)) or_return;
|
||||||
|
|
||||||
iterations += 1;
|
iterations += 1;
|
||||||
if iterations == MAX_ITERATIONS_ROOT_N {
|
if iterations == MAX_ITERATIONS_ROOT_N {
|
||||||
@@ -1606,12 +1604,12 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al
|
|||||||
|
|
||||||
src := src;
|
src := src;
|
||||||
|
|
||||||
if err = internal_error_if_immutable(dest); err != nil { return err; }
|
internal_error_if_immutable(dest) or_return;
|
||||||
/*
|
/*
|
||||||
Most internal procs asssume an Int to have already been initialize,
|
Most internal procs asssume an Int to have already been initialize,
|
||||||
but as this is one of the procs that initializes, we have to check the following.
|
but as this is one of the procs that initializes, we have to check the following.
|
||||||
*/
|
*/
|
||||||
if err = internal_clear_if_uninitialized_single(dest); err != nil { return err; }
|
internal_clear_if_uninitialized_single(dest) or_return;
|
||||||
|
|
||||||
dest.flags = {}; // We're not -Inf, Inf, NaN or Immutable.
|
dest.flags = {}; // We're not -Inf, Inf, NaN or Immutable.
|
||||||
|
|
||||||
@@ -1631,7 +1629,7 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al
|
|||||||
internal_set :: proc { internal_int_set_from_integer, internal_int_copy };
|
internal_set :: proc { internal_int_set_from_integer, internal_int_copy };
|
||||||
|
|
||||||
internal_copy_digits :: #force_inline proc(dest, src: ^Int, digits: int) -> (err: Error) {
|
internal_copy_digits :: #force_inline proc(dest, src: ^Int, digits: int) -> (err: Error) {
|
||||||
if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; }
|
#force_inline internal_error_if_immutable(dest) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If dest == src, do nothing
|
If dest == src, do nothing
|
||||||
@@ -1653,7 +1651,7 @@ internal_int_copy :: proc(dest, src: ^Int, minimize := false, allocator := conte
|
|||||||
*/
|
*/
|
||||||
if (dest == src) { return nil; }
|
if (dest == src) { return nil; }
|
||||||
|
|
||||||
if err = internal_error_if_immutable(dest); err != nil { return err; }
|
internal_error_if_immutable(dest) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grow `dest` to fit `src`.
|
Grow `dest` to fit `src`.
|
||||||
@@ -1661,7 +1659,7 @@ internal_int_copy :: proc(dest, src: ^Int, minimize := false, allocator := conte
|
|||||||
*/
|
*/
|
||||||
needed := src.used if minimize else max(src.used, _DEFAULT_DIGIT_COUNT);
|
needed := src.used if minimize else max(src.used, _DEFAULT_DIGIT_COUNT);
|
||||||
|
|
||||||
if err = internal_grow(dest, needed, minimize); err != nil { return err; }
|
internal_grow(dest, needed, minimize) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copy everything over and zero high digits.
|
Copy everything over and zero high digits.
|
||||||
@@ -1708,9 +1706,7 @@ internal_int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (er
|
|||||||
/*
|
/*
|
||||||
Copy `src` to `dest`
|
Copy `src` to `dest`
|
||||||
*/
|
*/
|
||||||
if err = internal_copy(dest, src); err != nil {
|
internal_copy(dest, src) or_return;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fix sign.
|
Fix sign.
|
||||||
@@ -1744,7 +1740,7 @@ internal_int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (er
|
|||||||
/*
|
/*
|
||||||
Copy `src` to `dest`
|
Copy `src` to `dest`
|
||||||
*/
|
*/
|
||||||
if err = internal_copy(dest, src); err != nil { return err; }
|
internal_copy(dest, src) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fix sign.
|
Fix sign.
|
||||||
@@ -1953,7 +1949,7 @@ internal_int_power_of_two :: proc(a: ^Int, power: int, allocator := context.allo
|
|||||||
Grow to accomodate the single bit.
|
Grow to accomodate the single bit.
|
||||||
*/
|
*/
|
||||||
a.used = (power / _DIGIT_BITS) + 1;
|
a.used = (power / _DIGIT_BITS) + 1;
|
||||||
if err = internal_grow(a, a.used); err != nil { return err; }
|
internal_grow(a, a.used) or_return;
|
||||||
/*
|
/*
|
||||||
Zero the entirety.
|
Zero the entirety.
|
||||||
*/
|
*/
|
||||||
@@ -2061,7 +2057,7 @@ internal_int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (e
|
|||||||
/*
|
/*
|
||||||
Grow the destination to accomodate the result.
|
Grow the destination to accomodate the result.
|
||||||
*/
|
*/
|
||||||
if err = internal_grow(dest, used); err != nil { return err; }
|
internal_grow(dest, used) or_return;
|
||||||
|
|
||||||
neg_a := #force_inline internal_is_negative(a);
|
neg_a := #force_inline internal_is_negative(a);
|
||||||
neg_b := #force_inline internal_is_negative(b);
|
neg_b := #force_inline internal_is_negative(b);
|
||||||
@@ -2122,7 +2118,7 @@ internal_int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (er
|
|||||||
/*
|
/*
|
||||||
Grow the destination to accomodate the result.
|
Grow the destination to accomodate the result.
|
||||||
*/
|
*/
|
||||||
if err = internal_grow(dest, used); err != nil { return err; }
|
internal_grow(dest, used) or_return;
|
||||||
|
|
||||||
neg_a := #force_inline internal_is_negative(a);
|
neg_a := #force_inline internal_is_negative(a);
|
||||||
neg_b := #force_inline internal_is_negative(b);
|
neg_b := #force_inline internal_is_negative(b);
|
||||||
@@ -2183,7 +2179,7 @@ internal_int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (e
|
|||||||
/*
|
/*
|
||||||
Grow the destination to accomodate the result.
|
Grow the destination to accomodate the result.
|
||||||
*/
|
*/
|
||||||
if err = internal_grow(dest, used); err != nil { return err; }
|
internal_grow(dest, used) or_return;
|
||||||
|
|
||||||
neg_a := #force_inline internal_is_negative(a);
|
neg_a := #force_inline internal_is_negative(a);
|
||||||
neg_b := #force_inline internal_is_negative(b);
|
neg_b := #force_inline internal_is_negative(b);
|
||||||
@@ -2269,21 +2265,21 @@ internal_int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, all
|
|||||||
bits := bits;
|
bits := bits;
|
||||||
if bits < 0 { return .Invalid_Argument; }
|
if bits < 0 { return .Invalid_Argument; }
|
||||||
|
|
||||||
if err = internal_copy(quotient, numerator); err != nil { return err; }
|
internal_copy(quotient, numerator) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Shift right by a certain bit count (store quotient and optional remainder.)
|
Shift right by a certain bit count (store quotient and optional remainder.)
|
||||||
`numerator` should not be used after this.
|
`numerator` should not be used after this.
|
||||||
*/
|
*/
|
||||||
if remainder != nil {
|
if remainder != nil {
|
||||||
if err = internal_int_mod_bits(remainder, numerator, bits); err != nil { return err; }
|
internal_int_mod_bits(remainder, numerator, bits) or_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Shift by as many digits in the bit count.
|
Shift by as many digits in the bit count.
|
||||||
*/
|
*/
|
||||||
if bits >= _DIGIT_BITS {
|
if bits >= _DIGIT_BITS {
|
||||||
if err = internal_shr_digit(quotient, bits / _DIGIT_BITS); err != nil { return err; }
|
internal_shr_digit(quotient, bits / _DIGIT_BITS) or_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2362,9 +2358,8 @@ internal_int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context
|
|||||||
if src.sign == .Zero_or_Positive {
|
if src.sign == .Zero_or_Positive {
|
||||||
return internal_shr(dest, src, bits);
|
return internal_shr(dest, src, bits);
|
||||||
}
|
}
|
||||||
if err = internal_int_add_digit(dest, src, DIGIT(1)); err != nil { return err; }
|
internal_int_add_digit(dest, src, DIGIT(1)) or_return;
|
||||||
|
internal_shr(dest, dest, bits) or_return;
|
||||||
if err = internal_shr(dest, dest, bits); err != nil { return err; }
|
|
||||||
return internal_sub(dest, src, DIGIT(1));
|
return internal_sub(dest, src, DIGIT(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2380,19 +2375,19 @@ internal_int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.alloca
|
|||||||
|
|
||||||
if bits < 0 { return .Invalid_Argument; }
|
if bits < 0 { return .Invalid_Argument; }
|
||||||
|
|
||||||
if err = internal_copy(dest, src); err != nil { return err; }
|
internal_copy(dest, src) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grow `dest` to accommodate the additional bits.
|
Grow `dest` to accommodate the additional bits.
|
||||||
*/
|
*/
|
||||||
digits_needed := dest.used + (bits / _DIGIT_BITS) + 1;
|
digits_needed := dest.used + (bits / _DIGIT_BITS) + 1;
|
||||||
if err = internal_grow(dest, digits_needed); err != nil { return err; }
|
internal_grow(dest, digits_needed) or_return;
|
||||||
dest.used = digits_needed;
|
dest.used = digits_needed;
|
||||||
/*
|
/*
|
||||||
Shift by as many digits in the bit count as we have.
|
Shift by as many digits in the bit count as we have.
|
||||||
*/
|
*/
|
||||||
if bits >= _DIGIT_BITS {
|
if bits >= _DIGIT_BITS {
|
||||||
if err = internal_shl_digit(dest, bits / _DIGIT_BITS); err != nil { return err; }
|
internal_shl_digit(dest, bits / _DIGIT_BITS) or_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2434,12 +2429,14 @@ internal_int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context
|
|||||||
/*
|
/*
|
||||||
No need to shift a zero.
|
No need to shift a zero.
|
||||||
*/
|
*/
|
||||||
if #force_inline internal_is_zero(quotient) { return {}; }
|
if #force_inline internal_is_zero(quotient) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Resize `quotient` to accomodate extra digits.
|
Resize `quotient` to accomodate extra digits.
|
||||||
*/
|
*/
|
||||||
if err = #force_inline internal_grow(quotient, quotient.used + digits); err != nil { return err; }
|
#force_inline internal_grow(quotient, quotient.used + digits) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Increment the used by the shift amount then copy upwards.
|
Increment the used by the shift amount then copy upwards.
|
||||||
@@ -2537,7 +2534,7 @@ internal_int_rand :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator :
|
|||||||
digits += 1;
|
digits += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = #force_inline internal_grow(dest, digits); err != nil { return err; }
|
#force_inline internal_grow(dest, digits) or_return;
|
||||||
|
|
||||||
for i := 0; i < digits; i += 1 {
|
for i := 0; i < digits; i += 1 {
|
||||||
dest.digit[i] = int_random_digit(r) & _MASK;
|
dest.digit[i] = int_random_digit(r) & _MASK;
|
||||||
@@ -2600,7 +2597,7 @@ internal_int_init_multi :: proc(integers: ..^Int, allocator := context.allocator
|
|||||||
|
|
||||||
integers := integers;
|
integers := integers;
|
||||||
for a in &integers {
|
for a in &integers {
|
||||||
if err = internal_clear(a); err != nil { return err; }
|
internal_clear(a) or_return;
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error
|
|||||||
assert_if_nil(dest, a, b);
|
assert_if_nil(dest, a, b);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
|
internal_clear_if_uninitialized(a, b) or_return;
|
||||||
return #force_inline internal_int_and(dest, a, b);
|
return #force_inline internal_int_and(dest, a, b);
|
||||||
}
|
}
|
||||||
and :: proc { int_and, };
|
and :: proc { int_and, };
|
||||||
@@ -37,7 +37,7 @@ int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error)
|
|||||||
assert_if_nil(dest, a, b);
|
assert_if_nil(dest, a, b);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
|
internal_clear_if_uninitialized(a, b) or_return;
|
||||||
return #force_inline internal_int_or(dest, a, b);
|
return #force_inline internal_int_or(dest, a, b);
|
||||||
}
|
}
|
||||||
or :: proc { int_or, };
|
or :: proc { int_or, };
|
||||||
@@ -49,7 +49,7 @@ int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error
|
|||||||
assert_if_nil(dest, a, b);
|
assert_if_nil(dest, a, b);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
|
internal_clear_if_uninitialized(a, b) or_return;
|
||||||
return #force_inline internal_int_xor(dest, a, b);
|
return #force_inline internal_int_xor(dest, a, b);
|
||||||
}
|
}
|
||||||
xor :: proc { int_xor, };
|
xor :: proc { int_xor, };
|
||||||
@@ -64,7 +64,7 @@ int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err:
|
|||||||
assert_if_nil(dest, src);
|
assert_if_nil(dest, src);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
|
internal_clear_if_uninitialized(dest, src) or_return;
|
||||||
return #force_inline internal_int_complement(dest, src);
|
return #force_inline internal_int_complement(dest, src);
|
||||||
}
|
}
|
||||||
complement :: proc { int_complement, };
|
complement :: proc { int_complement, };
|
||||||
@@ -97,7 +97,7 @@ int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato
|
|||||||
assert_if_nil(quotient);
|
assert_if_nil(quotient);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(quotient); err != nil { return err; }
|
internal_clear_if_uninitialized(quotient) or_return;
|
||||||
return #force_inline internal_int_shr_digit(quotient, digits);
|
return #force_inline internal_int_shr_digit(quotient, digits);
|
||||||
}
|
}
|
||||||
shr_digit :: proc { int_shr_digit, };
|
shr_digit :: proc { int_shr_digit, };
|
||||||
@@ -109,7 +109,7 @@ int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context.allocato
|
|||||||
assert_if_nil(dest, src);
|
assert_if_nil(dest, src);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
|
internal_clear_if_uninitialized(dest, src) or_return;
|
||||||
return #force_inline internal_int_shr_signed(dest, src, bits);
|
return #force_inline internal_int_shr_signed(dest, src, bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (
|
|||||||
assert_if_nil(dest, src);
|
assert_if_nil(dest, src);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
|
internal_clear_if_uninitialized(dest, src) or_return;
|
||||||
return #force_inline internal_int_shl(dest, src, bits);
|
return #force_inline internal_int_shl(dest, src, bits);
|
||||||
}
|
}
|
||||||
shl :: proc { int_shl, };
|
shl :: proc { int_shl, };
|
||||||
@@ -138,7 +138,7 @@ int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato
|
|||||||
assert_if_nil(quotient);
|
assert_if_nil(quotient);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(quotient); err != nil { return err; }
|
internal_clear_if_uninitialized(quotient) or_return;
|
||||||
return #force_inline internal_int_shl_digit(quotient, digits);
|
return #force_inline internal_int_shl_digit(quotient, digits);
|
||||||
}
|
}
|
||||||
shl_digit :: proc { int_shl_digit, };
|
shl_digit :: proc { int_shl_digit, };
|
||||||
@@ -19,12 +19,13 @@ int_prime_is_divisible :: proc(a: ^Int, allocator := context.allocator) -> (res:
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a); err != nil { return {}, err; }
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
|
|
||||||
rem: DIGIT;
|
|
||||||
for prime in _private_prime_table {
|
for prime in _private_prime_table {
|
||||||
if rem, err = #force_inline int_mod_digit(a, prime); err != nil { return false, err; }
|
rem := #force_inline int_mod_digit(a, prime) or_return;
|
||||||
if rem == 0 { return true, nil; }
|
if rem == 0 {
|
||||||
|
return true, nil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Default to not divisible.
|
Default to not divisible.
|
||||||
|
|||||||
+241
-206
File diff suppressed because it is too large
Load Diff
+45
-46
@@ -24,7 +24,7 @@ int_add :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error
|
|||||||
assert_if_nil(dest, a, b);
|
assert_if_nil(dest, a, b);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(dest, a, b); err != nil { return err; }
|
internal_clear_if_uninitialized(dest, a, b) or_return;
|
||||||
/*
|
/*
|
||||||
All parameters have been initialized.
|
All parameters have been initialized.
|
||||||
*/
|
*/
|
||||||
@@ -41,11 +41,11 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato
|
|||||||
assert_if_nil(dest, a);
|
assert_if_nil(dest, a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a); err != nil { return err; }
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
/*
|
/*
|
||||||
Grow destination as required.
|
Grow destination as required.
|
||||||
*/
|
*/
|
||||||
if err = grow(dest, a.used + 1); err != nil { return err; }
|
grow(dest, a.used + 1) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
All parameters have been initialized.
|
All parameters have been initialized.
|
||||||
@@ -60,7 +60,7 @@ int_sub :: proc(dest, number, decrease: ^Int, allocator := context.allocator) ->
|
|||||||
assert_if_nil(dest, number, decrease);
|
assert_if_nil(dest, number, decrease);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(dest, number, decrease); err != nil { return err; }
|
internal_clear_if_uninitialized(dest, number, decrease) or_return;
|
||||||
/*
|
/*
|
||||||
All parameters have been initialized.
|
All parameters have been initialized.
|
||||||
*/
|
*/
|
||||||
@@ -77,11 +77,11 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato
|
|||||||
assert_if_nil(dest, a);
|
assert_if_nil(dest, a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a); err != nil { return err; }
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
/*
|
/*
|
||||||
Grow destination as required.
|
Grow destination as required.
|
||||||
*/
|
*/
|
||||||
if err = grow(dest, a.used + 1); err != nil { return err; }
|
grow(dest, a.used + 1) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
All parameters have been initialized.
|
All parameters have been initialized.
|
||||||
@@ -97,11 +97,11 @@ int_halve :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Erro
|
|||||||
assert_if_nil(dest, src);
|
assert_if_nil(dest, src);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
|
internal_clear_if_uninitialized(dest, src) or_return;
|
||||||
/*
|
/*
|
||||||
Grow destination as required.
|
Grow destination as required.
|
||||||
*/
|
*/
|
||||||
if dest != src { if err = grow(dest, src.used + 1); err != nil { return err; } }
|
if dest != src { grow(dest, src.used + 1) or_return }
|
||||||
|
|
||||||
return #force_inline internal_int_shr1(dest, src);
|
return #force_inline internal_int_shr1(dest, src);
|
||||||
}
|
}
|
||||||
@@ -116,11 +116,11 @@ int_double :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Err
|
|||||||
assert_if_nil(dest, src);
|
assert_if_nil(dest, src);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
|
internal_clear_if_uninitialized(dest, src) or_return;
|
||||||
/*
|
/*
|
||||||
Grow destination as required.
|
Grow destination as required.
|
||||||
*/
|
*/
|
||||||
if dest != src { if err = grow(dest, src.used + 1); err != nil { return err; } }
|
if dest != src { grow(dest, src.used + 1) or_return; }
|
||||||
|
|
||||||
return #force_inline internal_int_shl1(dest, src);
|
return #force_inline internal_int_shl1(dest, src);
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := context.a
|
|||||||
assert_if_nil(dest, src);
|
assert_if_nil(dest, src);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(src, dest); err != nil { return err; }
|
internal_clear_if_uninitialized(src, dest) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_mul_digit(dest, src, multiplier);
|
return #force_inline internal_int_mul_digit(dest, src, multiplier);
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.allocator) ->
|
|||||||
assert_if_nil(dest, src, multiplier);
|
assert_if_nil(dest, src, multiplier);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(dest, src, multiplier); err != nil { return err; }
|
internal_clear_if_uninitialized(dest, src, multiplier) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_mul(dest, src, multiplier);
|
return #force_inline internal_int_mul(dest, src, multiplier);
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, allocator
|
|||||||
Early out if neither of the results is wanted.
|
Early out if neither of the results is wanted.
|
||||||
*/
|
*/
|
||||||
if quotient == nil && remainder == nil { return nil; }
|
if quotient == nil && remainder == nil { return nil; }
|
||||||
if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; }
|
internal_clear_if_uninitialized(numerator, denominator) or_return;
|
||||||
|
|
||||||
return #force_inline internal_divmod(quotient, remainder, numerator, denominator);
|
return #force_inline internal_divmod(quotient, remainder, numerator, denominator);
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocato
|
|||||||
assert_if_nil(quotient, numerator);
|
assert_if_nil(quotient, numerator);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(numerator); err != nil { return 0, err; }
|
internal_clear_if_uninitialized(numerator) or_return;
|
||||||
|
|
||||||
return #force_inline internal_divmod(quotient, numerator, denominator);
|
return #force_inline internal_divmod(quotient, numerator, denominator);
|
||||||
}
|
}
|
||||||
@@ -185,7 +185,7 @@ int_div :: proc(quotient, numerator, denominator: ^Int, allocator := context.all
|
|||||||
assert_if_nil(quotient, numerator, denominator);
|
assert_if_nil(quotient, numerator, denominator);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; }
|
internal_clear_if_uninitialized(numerator, denominator) or_return;
|
||||||
|
|
||||||
return #force_inline internal_divmod(quotient, nil, numerator, denominator);
|
return #force_inline internal_divmod(quotient, nil, numerator, denominator);
|
||||||
}
|
}
|
||||||
@@ -194,11 +194,10 @@ int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator :
|
|||||||
assert_if_nil(quotient, numerator);
|
assert_if_nil(quotient, numerator);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(numerator); err != nil { return err; }
|
internal_clear_if_uninitialized(numerator) or_return;
|
||||||
|
|
||||||
remainder: DIGIT;
|
_ = #force_inline internal_divmod(quotient, numerator, denominator) or_return;
|
||||||
remainder, err = #force_inline internal_divmod(quotient, numerator, denominator);
|
return;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
div :: proc { int_div, int_div_digit, };
|
div :: proc { int_div, int_div_digit, };
|
||||||
|
|
||||||
@@ -211,7 +210,7 @@ int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.al
|
|||||||
assert_if_nil(remainder, numerator, denominator);
|
assert_if_nil(remainder, numerator, denominator);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; }
|
internal_clear_if_uninitialized(numerator, denominator) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_mod(remainder, numerator, denominator);
|
return #force_inline internal_int_mod(remainder, numerator, denominator);
|
||||||
}
|
}
|
||||||
@@ -229,7 +228,7 @@ int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := contex
|
|||||||
assert_if_nil(remainder, number, addend);
|
assert_if_nil(remainder, number, addend);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(number, addend, modulus); err != nil { return err; }
|
internal_clear_if_uninitialized(number, addend, modulus) or_return;
|
||||||
|
|
||||||
return #force_inline internal_addmod(remainder, number, addend, modulus);
|
return #force_inline internal_addmod(remainder, number, addend, modulus);
|
||||||
}
|
}
|
||||||
@@ -242,7 +241,7 @@ int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := cont
|
|||||||
assert_if_nil(remainder, number, decrease);
|
assert_if_nil(remainder, number, decrease);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(number, decrease, modulus); err != nil { return err; }
|
internal_clear_if_uninitialized(number, decrease, modulus) or_return;
|
||||||
|
|
||||||
return #force_inline internal_submod(remainder, number, decrease, modulus);
|
return #force_inline internal_submod(remainder, number, decrease, modulus);
|
||||||
}
|
}
|
||||||
@@ -255,7 +254,7 @@ int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator :=
|
|||||||
assert_if_nil(remainder, number, multiplicand);
|
assert_if_nil(remainder, number, multiplicand);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(number, multiplicand, modulus); err != nil { return err; }
|
internal_clear_if_uninitialized(number, multiplicand, modulus) or_return;
|
||||||
|
|
||||||
return #force_inline internal_mulmod(remainder, number, multiplicand, modulus);
|
return #force_inline internal_mulmod(remainder, number, multiplicand, modulus);
|
||||||
}
|
}
|
||||||
@@ -268,7 +267,7 @@ int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.alloca
|
|||||||
assert_if_nil(remainder, number, modulus);
|
assert_if_nil(remainder, number, modulus);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(number, modulus); err != nil { return err; }
|
internal_clear_if_uninitialized(number, modulus) or_return;
|
||||||
|
|
||||||
return #force_inline internal_sqrmod(remainder, number, modulus);
|
return #force_inline internal_sqrmod(remainder, number, modulus);
|
||||||
}
|
}
|
||||||
@@ -312,14 +311,14 @@ int_choose_digit :: proc(res: ^Int, n, k: int, allocator := context.allocator) -
|
|||||||
n_fac, k_fac, n_minus_k_fac := &Int{}, &Int{}, &Int{};
|
n_fac, k_fac, n_minus_k_fac := &Int{}, &Int{}, &Int{};
|
||||||
defer internal_destroy(n_fac, k_fac, n_minus_k_fac);
|
defer internal_destroy(n_fac, k_fac, n_minus_k_fac);
|
||||||
|
|
||||||
if err = #force_inline internal_int_factorial(n_minus_k_fac, n - k); err != nil { return err; }
|
#force_inline internal_int_factorial(n_minus_k_fac, n - k) or_return;
|
||||||
if err = #force_inline internal_int_factorial(k_fac, k); err != nil { return err; }
|
#force_inline internal_int_factorial(k_fac, k) or_return;
|
||||||
if err = #force_inline internal_mul(k_fac, k_fac, n_minus_k_fac); err != nil { return err; }
|
#force_inline internal_mul(k_fac, k_fac, n_minus_k_fac) or_return;
|
||||||
|
|
||||||
if err = #force_inline internal_int_factorial(n_fac, n); err != nil { return err; }
|
#force_inline internal_int_factorial(n_fac, n) or_return;
|
||||||
if err = #force_inline internal_div(res, n_fac, k_fac); err != nil { return err; }
|
#force_inline internal_div(res, n_fac, k_fac) or_return;
|
||||||
|
|
||||||
return err;
|
return;
|
||||||
}
|
}
|
||||||
choose :: proc { int_choose_digit, };
|
choose :: proc { int_choose_digit, };
|
||||||
|
|
||||||
@@ -331,7 +330,7 @@ int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.allocator
|
|||||||
assert_if_nil(a, b);
|
assert_if_nil(a, b);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
|
internal_clear_if_uninitialized(a, b) or_return;
|
||||||
return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b);
|
return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b);
|
||||||
}
|
}
|
||||||
gcd_lcm :: proc { int_gcd_lcm, };
|
gcd_lcm :: proc { int_gcd_lcm, };
|
||||||
@@ -359,8 +358,8 @@ int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator := context
|
|||||||
assert_if_nil(remainder, numerator);
|
assert_if_nil(remainder, numerator);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(remainder, numerator); err != nil { return err; }
|
internal_clear_if_uninitialized(remainder, numerator) or_return;
|
||||||
if bits < 0 { return .Invalid_Argument; }
|
if bits < 0 { return .Invalid_Argument; }
|
||||||
|
|
||||||
return #force_inline internal_int_mod_bits(remainder, numerator, bits);
|
return #force_inline internal_int_mod_bits(remainder, numerator, bits);
|
||||||
}
|
}
|
||||||
@@ -375,7 +374,7 @@ int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) -> (res: i
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a); err != nil { return 0, err; }
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_log(a, base);
|
return #force_inline internal_int_log(a, base);
|
||||||
}
|
}
|
||||||
@@ -392,7 +391,7 @@ int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allocator) ->
|
|||||||
assert_if_nil(dest, base);
|
assert_if_nil(dest, base);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(dest, base); err != nil { return err; }
|
internal_clear_if_uninitialized(dest, base) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_pow(dest, base, power);
|
return #force_inline internal_int_pow(dest, base, power);
|
||||||
}
|
}
|
||||||
@@ -420,7 +419,7 @@ int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error
|
|||||||
assert_if_nil(dest, src);
|
assert_if_nil(dest, src);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
|
internal_clear_if_uninitialized(dest, src) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_sqrt(dest, src);
|
return #force_inline internal_int_sqrt(dest, src);
|
||||||
}
|
}
|
||||||
@@ -446,7 +445,7 @@ int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.allocator) -> (
|
|||||||
/*
|
/*
|
||||||
Initialize dest + src if needed.
|
Initialize dest + src if needed.
|
||||||
*/
|
*/
|
||||||
if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
|
internal_clear_if_uninitialized(dest, src) or_return;
|
||||||
|
|
||||||
return #force_inline internal_int_root_n(dest, src, n);
|
return #force_inline internal_int_root_n(dest, src, n);
|
||||||
}
|
}
|
||||||
@@ -466,7 +465,7 @@ int_is_zero :: proc(a: ^Int, allocator := context.allocator) -> (zero: bool, err
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
|
|
||||||
return #force_inline internal_is_zero(a), nil;
|
return #force_inline internal_is_zero(a), nil;
|
||||||
}
|
}
|
||||||
@@ -475,7 +474,7 @@ int_is_positive :: proc(a: ^Int, allocator := context.allocator) -> (positive: b
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
|
|
||||||
return #force_inline internal_is_positive(a), nil;
|
return #force_inline internal_is_positive(a), nil;
|
||||||
}
|
}
|
||||||
@@ -484,7 +483,7 @@ int_is_negative :: proc(a: ^Int, allocator := context.allocator) -> (negative: b
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
|
|
||||||
return #force_inline internal_is_negative(a), nil;
|
return #force_inline internal_is_negative(a), nil;
|
||||||
}
|
}
|
||||||
@@ -493,7 +492,7 @@ int_is_even :: proc(a: ^Int, allocator := context.allocator) -> (even: bool, err
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
|
|
||||||
return #force_inline internal_is_even(a), nil;
|
return #force_inline internal_is_even(a), nil;
|
||||||
}
|
}
|
||||||
@@ -502,7 +501,7 @@ int_is_odd :: proc(a: ^Int, allocator := context.allocator) -> (odd: bool, err:
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
|
|
||||||
return #force_inline internal_is_odd(a), nil;
|
return #force_inline internal_is_odd(a), nil;
|
||||||
}
|
}
|
||||||
@@ -515,7 +514,7 @@ int_is_power_of_two :: proc(a: ^Int, allocator := context.allocator) -> (res: bo
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
|
|
||||||
return #force_inline internal_is_power_of_two(a), nil;
|
return #force_inline internal_is_power_of_two(a), nil;
|
||||||
}
|
}
|
||||||
@@ -527,7 +526,7 @@ int_compare :: proc(a, b: ^Int, allocator := context.allocator) -> (comparison:
|
|||||||
assert_if_nil(a, b);
|
assert_if_nil(a, b);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a, b); err != nil { return 0, err; }
|
internal_clear_if_uninitialized(a, b) or_return;
|
||||||
|
|
||||||
return #force_inline internal_cmp(a, b), nil;
|
return #force_inline internal_cmp(a, b), nil;
|
||||||
}
|
}
|
||||||
@@ -540,7 +539,7 @@ int_compare_digit :: proc(a: ^Int, b: DIGIT, allocator := context.allocator) ->
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a); err != nil { return 0, err; }
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
|
|
||||||
return #force_inline internal_cmp_digit(a, b), nil;
|
return #force_inline internal_cmp_digit(a, b), nil;
|
||||||
}
|
}
|
||||||
@@ -553,7 +552,7 @@ int_compare_magnitude :: proc(a, b: ^Int, allocator := context.allocator) -> (re
|
|||||||
assert_if_nil(a, b);
|
assert_if_nil(a, b);
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if err = internal_clear_if_uninitialized(a, b); err != nil { return 0, err; }
|
internal_clear_if_uninitialized(a, b) or_return;
|
||||||
|
|
||||||
return #force_inline internal_cmp_mag(a, b), nil;
|
return #force_inline internal_cmp_mag(a, b), nil;
|
||||||
}
|
}
|
||||||
+19
-24
@@ -26,7 +26,7 @@ int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, alloc
|
|||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
a := a; radix := radix;
|
a := a; radix := radix;
|
||||||
if err = clear_if_uninitialized(a); err != nil { return "", err; }
|
clear_if_uninitialized(a) or_return;
|
||||||
/*
|
/*
|
||||||
Radix defaults to 10.
|
Radix defaults to 10.
|
||||||
*/
|
*/
|
||||||
@@ -39,14 +39,9 @@ int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, alloc
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate the size of the buffer we need, and
|
Calculate the size of the buffer we need, and
|
||||||
*/
|
|
||||||
size: int;
|
|
||||||
/*
|
|
||||||
Exit if calculating the size returned an error.
|
Exit if calculating the size returned an error.
|
||||||
*/
|
*/
|
||||||
if size, err = radix_size(a, radix, zero_terminate); err != nil {
|
size := radix_size(a, radix, zero_terminate) or_return;
|
||||||
return "", err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Allocate the buffer we need.
|
Allocate the buffer we need.
|
||||||
@@ -70,7 +65,7 @@ int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocato
|
|||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
a := a; radix := radix;
|
a := a; radix := radix;
|
||||||
if err = clear_if_uninitialized(a); err != nil { return "", err; }
|
clear_if_uninitialized(a) or_return;
|
||||||
/*
|
/*
|
||||||
Radix defaults to 10.
|
Radix defaults to 10.
|
||||||
*/
|
*/
|
||||||
@@ -104,7 +99,7 @@ int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocato
|
|||||||
int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
|
int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
|
||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
a := a; radix := radix; size := size;
|
a := a; radix := radix; size := size;
|
||||||
if err = clear_if_uninitialized(a); err != nil { return 0, err; }
|
clear_if_uninitialized(a) or_return;
|
||||||
/*
|
/*
|
||||||
Radix defaults to 10.
|
Radix defaults to 10.
|
||||||
*/
|
*/
|
||||||
@@ -117,9 +112,7 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter
|
|||||||
We weren't given a size. Let's compute it.
|
We weren't given a size. Let's compute it.
|
||||||
*/
|
*/
|
||||||
if size == -1 {
|
if size == -1 {
|
||||||
if size, err = radix_size(a, radix, zero_terminate); err != nil {
|
size = radix_size(a, radix, zero_terminate) or_return;
|
||||||
return 0, err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -256,12 +249,14 @@ int_atoi :: proc(res: ^Int, input: string, radix: i8, allocator := context.alloc
|
|||||||
/*
|
/*
|
||||||
Set the integer to the default of zero.
|
Set the integer to the default of zero.
|
||||||
*/
|
*/
|
||||||
if err = internal_zero(res); err != nil { return err; }
|
internal_zero(res) or_return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We'll interpret an empty string as zero.
|
We'll interpret an empty string as zero.
|
||||||
*/
|
*/
|
||||||
if len(input) == 0 { return nil; }
|
if len(input) == 0 {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If the leading digit is a minus set the sign to negative.
|
If the leading digit is a minus set the sign to negative.
|
||||||
@@ -301,8 +296,8 @@ int_atoi :: proc(res: ^Int, input: string, radix: i8, allocator := context.alloc
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = internal_mul(res, res, DIGIT(radix)); err != nil { return err; }
|
internal_mul(res, res, DIGIT(radix)) or_return;
|
||||||
if err = internal_add(res, res, DIGIT(y)); err != nil { return err; }
|
internal_add(res, res, DIGIT(y)) or_return;
|
||||||
|
|
||||||
input = input[1:];
|
input = input[1:];
|
||||||
}
|
}
|
||||||
@@ -333,7 +328,7 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con
|
|||||||
assert_if_nil(a);
|
assert_if_nil(a);
|
||||||
|
|
||||||
if radix < 2 || radix > 64 { return -1, .Invalid_Argument; }
|
if radix < 2 || radix > 64 { return -1, .Invalid_Argument; }
|
||||||
if err = clear_if_uninitialized(a); err != nil { return {}, err; }
|
clear_if_uninitialized(a) or_return;
|
||||||
|
|
||||||
if internal_is_zero(a) {
|
if internal_is_zero(a) {
|
||||||
if zero_terminate {
|
if zero_terminate {
|
||||||
@@ -352,22 +347,22 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con
|
|||||||
digit = a.digit,
|
digit = a.digit,
|
||||||
};
|
};
|
||||||
|
|
||||||
if size, err = internal_log(t, DIGIT(radix)); err != nil { return {}, err; }
|
size = internal_log(t, DIGIT(radix)) or_return;
|
||||||
} else {
|
} else {
|
||||||
la, k := &Int{}, &Int{};
|
la, k := &Int{}, &Int{};
|
||||||
defer internal_destroy(la, k);
|
defer internal_destroy(la, k);
|
||||||
|
|
||||||
/* la = floor(log_2(a)) + 1 */
|
/* la = floor(log_2(a)) + 1 */
|
||||||
bit_count := internal_count_bits(a);
|
bit_count := internal_count_bits(a);
|
||||||
if err = internal_set(la, bit_count); err != nil { return {}, err; }
|
internal_set(la, bit_count) or_return;
|
||||||
|
|
||||||
/* k = floor(2^29/log_2(radix)) + 1 */
|
/* k = floor(2^29/log_2(radix)) + 1 */
|
||||||
lb := _log_bases;
|
lb := _log_bases;
|
||||||
if err = internal_set(k, lb[radix]); err != nil { return {}, err; }
|
internal_set(k, lb[radix]) or_return;
|
||||||
|
|
||||||
/* n = floor((la * k) / 2^29) + 1 */
|
/* n = floor((la * k) / 2^29) + 1 */
|
||||||
if err = internal_mul(k, la, k); err != nil { return 0, err; }
|
internal_mul(k, la, k) or_return;
|
||||||
if err = internal_shr(k, k, _RADIX_SIZE_SCALE); err != nil { return {}, err; }
|
internal_shr(k, k, _RADIX_SIZE_SCALE) or_return;
|
||||||
|
|
||||||
/* The "+1" here is the "+1" in "floor((la * k) / 2^29) + 1" */
|
/* The "+1" here is the "+1" in "floor((la * k) / 2^29) + 1" */
|
||||||
/* n = n + 1 + EOS + sign */
|
/* n = n + 1 + EOS + sign */
|
||||||
@@ -440,8 +435,8 @@ _itoa_raw_full :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false
|
|||||||
|
|
||||||
temp, denominator := &Int{}, &Int{};
|
temp, denominator := &Int{}, &Int{};
|
||||||
|
|
||||||
if err = internal_copy(temp, a); err != nil { return 0, err; }
|
internal_copy(temp, a) or_return;
|
||||||
if err = internal_set(denominator, radix); err != nil { return 0, err; }
|
internal_set(denominator, radix) or_return;
|
||||||
|
|
||||||
available := len(buffer);
|
available := len(buffer);
|
||||||
if zero_terminate {
|
if zero_terminate {
|
||||||
|
|||||||
+14
-14
@@ -49,7 +49,7 @@ PyRes :: struct {
|
|||||||
if bb.used == 1 {
|
if bb.used == 1 {
|
||||||
if err = #force_inline internal_add(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }
|
if err = #force_inline internal_add(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }
|
||||||
} else {
|
} else {
|
||||||
if err = #force_inline internal_add(sum, aa, bb); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }
|
if err = #force_inline internal_add(sum, aa, bb); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }
|
||||||
}
|
}
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
@@ -70,7 +70,7 @@ PyRes :: struct {
|
|||||||
if bb.used == 1 {
|
if bb.used == 1 {
|
||||||
if err = #force_inline internal_sub(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
|
if err = #force_inline internal_sub(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
|
||||||
} else {
|
} else {
|
||||||
if err = #force_inline internal_sub(sum, aa, bb); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
|
if err = #force_inline internal_sub(sum, aa, bb); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
|
||||||
}
|
}
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
@@ -88,7 +88,7 @@ PyRes :: struct {
|
|||||||
|
|
||||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":mul:atoi(a):", err=err}; }
|
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":mul:atoi(a):", err=err}; }
|
||||||
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err}; }
|
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err}; }
|
||||||
if err = #force_inline internal_mul(product, aa, bb); err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err}; }
|
if err = #force_inline internal_mul(product, aa, bb); err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err}; }
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
r, err = int_itoa_cstring(product, 16, context.temp_allocator);
|
r, err = int_itoa_cstring(product, 16, context.temp_allocator);
|
||||||
@@ -104,7 +104,7 @@ PyRes :: struct {
|
|||||||
defer internal_destroy(aa, square);
|
defer internal_destroy(aa, square);
|
||||||
|
|
||||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":sqr:atoi(a):", err=err}; }
|
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":sqr:atoi(a):", err=err}; }
|
||||||
if err = #force_inline internal_sqr(square, aa); err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err}; }
|
if err = #force_inline internal_sqr(square, aa); err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err}; }
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
r, err = int_itoa_cstring(square, 16, context.temp_allocator);
|
r, err = int_itoa_cstring(square, 16, context.temp_allocator);
|
||||||
@@ -124,7 +124,7 @@ PyRes :: struct {
|
|||||||
|
|
||||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":div:atoi(a):", err=err}; }
|
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":div:atoi(a):", err=err}; }
|
||||||
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err}; }
|
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err}; }
|
||||||
if err = #force_inline internal_div(quotient, aa, bb); err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err}; }
|
if err = #force_inline internal_div(quotient, aa, bb); err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err}; }
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
r, err = int_itoa_cstring(quotient, 16, context.temp_allocator);
|
r, err = int_itoa_cstring(quotient, 16, context.temp_allocator);
|
||||||
@@ -145,7 +145,7 @@ PyRes :: struct {
|
|||||||
defer internal_destroy(aa);
|
defer internal_destroy(aa);
|
||||||
|
|
||||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":log:atoi(a):", err=err}; }
|
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":log:atoi(a):", err=err}; }
|
||||||
if l, err = #force_inline internal_log(aa, base); err != nil { return PyRes{res=":log:log(a, base):", err=err}; }
|
if l, err = #force_inline internal_log(aa, base); err != nil { return PyRes{res=":log:log(a, base):", err=err}; }
|
||||||
|
|
||||||
#force_inline internal_zero(aa);
|
#force_inline internal_zero(aa);
|
||||||
aa.digit[0] = DIGIT(l) & _MASK;
|
aa.digit[0] = DIGIT(l) & _MASK;
|
||||||
@@ -170,7 +170,7 @@ PyRes :: struct {
|
|||||||
defer internal_destroy(dest, bb);
|
defer internal_destroy(dest, bb);
|
||||||
|
|
||||||
if err = atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err}; }
|
if err = atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err}; }
|
||||||
if err = #force_inline internal_pow(dest, bb, power); err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err}; }
|
if err = #force_inline internal_pow(dest, bb, power); err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err}; }
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
|
r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
|
||||||
@@ -189,7 +189,7 @@ PyRes :: struct {
|
|||||||
defer internal_destroy(src);
|
defer internal_destroy(src);
|
||||||
|
|
||||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err}; }
|
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err}; }
|
||||||
if err = #force_inline internal_sqrt(src, src); err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err}; }
|
if err = #force_inline internal_sqrt(src, src); err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err}; }
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||||
@@ -208,7 +208,7 @@ PyRes :: struct {
|
|||||||
defer internal_destroy(src);
|
defer internal_destroy(src);
|
||||||
|
|
||||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err}; }
|
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err}; }
|
||||||
if err = #force_inline internal_root_n(src, src, power); err != nil { return PyRes{res=":root_n:root_n(src):", err=err}; }
|
if err = #force_inline internal_root_n(src, src, power); err != nil { return PyRes{res=":root_n:root_n(src):", err=err}; }
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||||
@@ -227,7 +227,7 @@ PyRes :: struct {
|
|||||||
defer internal_destroy(src);
|
defer internal_destroy(src);
|
||||||
|
|
||||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err}; }
|
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err}; }
|
||||||
if err = #force_inline internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err}; }
|
if err = #force_inline internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err}; }
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||||
@@ -246,7 +246,7 @@ PyRes :: struct {
|
|||||||
defer internal_destroy(src);
|
defer internal_destroy(src);
|
||||||
|
|
||||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err}; }
|
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err}; }
|
||||||
if err = #force_inline internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err}; }
|
if err = #force_inline internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err}; }
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||||
@@ -265,7 +265,7 @@ PyRes :: struct {
|
|||||||
defer internal_destroy(src);
|
defer internal_destroy(src);
|
||||||
|
|
||||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err}; }
|
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err}; }
|
||||||
if err = #force_inline internal_shr(src, src, bits); err != nil { return PyRes{res=":shr:shr(src, bits):", err=err}; }
|
if err = #force_inline internal_shr(src, src, bits); err != nil { return PyRes{res=":shr:shr(src, bits):", err=err}; }
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||||
@@ -284,7 +284,7 @@ PyRes :: struct {
|
|||||||
defer internal_destroy(src);
|
defer internal_destroy(src);
|
||||||
|
|
||||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err}; }
|
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err}; }
|
||||||
if err = #force_inline internal_shr_signed(src, src, bits); err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err}; }
|
if err = #force_inline internal_shr_signed(src, src, bits); err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err}; }
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||||
@@ -303,7 +303,7 @@ PyRes :: struct {
|
|||||||
defer internal_destroy(src);
|
defer internal_destroy(src);
|
||||||
|
|
||||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err}; }
|
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err}; }
|
||||||
if err = #force_inline internal_shl(src, src, bits); err != nil { return PyRes{res=":shl:shl(src, bits):", err=err}; }
|
if err = #force_inline internal_shl(src, src, bits); err != nil { return PyRes{res=":shl:shl(src, bits):", err=err}; }
|
||||||
|
|
||||||
r: cstring;
|
r: cstring;
|
||||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||||
|
|||||||
+15
-11
@@ -241,15 +241,6 @@ Field_Value :: struct {
|
|||||||
value: ^Expr,
|
value: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Ternary_Expr :: struct {
|
|
||||||
using node: Expr,
|
|
||||||
cond: ^Expr,
|
|
||||||
op1: tokenizer.Token,
|
|
||||||
x: ^Expr,
|
|
||||||
op2: tokenizer.Token,
|
|
||||||
y: ^Expr,
|
|
||||||
}
|
|
||||||
|
|
||||||
Ternary_If_Expr :: struct {
|
Ternary_If_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
x: ^Expr,
|
x: ^Expr,
|
||||||
@@ -261,13 +252,26 @@ Ternary_If_Expr :: struct {
|
|||||||
|
|
||||||
Ternary_When_Expr :: struct {
|
Ternary_When_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
x: ^Expr,
|
x: ^Expr,
|
||||||
op1: tokenizer.Token,
|
op1: tokenizer.Token,
|
||||||
cond: ^Expr,
|
cond: ^Expr,
|
||||||
op2: tokenizer.Token,
|
op2: tokenizer.Token,
|
||||||
y: ^Expr,
|
y: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Or_Else_Expr :: struct {
|
||||||
|
using node: Expr,
|
||||||
|
x: ^Expr,
|
||||||
|
token: tokenizer.Token,
|
||||||
|
y: ^Expr,
|
||||||
|
}
|
||||||
|
|
||||||
|
Or_Return_Expr :: struct {
|
||||||
|
using node: Expr,
|
||||||
|
expr: ^Expr,
|
||||||
|
token: tokenizer.Token,
|
||||||
|
}
|
||||||
|
|
||||||
Type_Assertion :: struct {
|
Type_Assertion :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
@@ -542,7 +546,7 @@ Field_Flag :: enum {
|
|||||||
No_Alias,
|
No_Alias,
|
||||||
C_Vararg,
|
C_Vararg,
|
||||||
Auto_Cast,
|
Auto_Cast,
|
||||||
In,
|
Any_Int,
|
||||||
|
|
||||||
Results,
|
Results,
|
||||||
Tags,
|
Tags,
|
||||||
|
|||||||
@@ -129,10 +129,6 @@ clone_node :: proc(node: ^Node) -> ^Node {
|
|||||||
case Field_Value:
|
case Field_Value:
|
||||||
r.field = clone(r.field);
|
r.field = clone(r.field);
|
||||||
r.value = clone(r.value);
|
r.value = clone(r.value);
|
||||||
case Ternary_Expr:
|
|
||||||
r.cond = clone(r.cond);
|
|
||||||
r.x = clone(r.x);
|
|
||||||
r.y = clone(r.y);
|
|
||||||
case Ternary_If_Expr:
|
case Ternary_If_Expr:
|
||||||
r.x = clone(r.x);
|
r.x = clone(r.x);
|
||||||
r.cond = clone(r.cond);
|
r.cond = clone(r.cond);
|
||||||
@@ -141,6 +137,11 @@ clone_node :: proc(node: ^Node) -> ^Node {
|
|||||||
r.x = clone(r.x);
|
r.x = clone(r.x);
|
||||||
r.cond = clone(r.cond);
|
r.cond = clone(r.cond);
|
||||||
r.y = clone(r.y);
|
r.y = clone(r.y);
|
||||||
|
case Or_Else_Expr:
|
||||||
|
r.x = clone(r.x);
|
||||||
|
r.y = clone(r.y);
|
||||||
|
case Or_Return_Expr:
|
||||||
|
r.expr = clone(r.expr);
|
||||||
case Type_Assertion:
|
case Type_Assertion:
|
||||||
r.expr = clone(r.expr);
|
r.expr = clone(r.expr);
|
||||||
r.type = clone(r.type);
|
r.type = clone(r.type);
|
||||||
|
|||||||
@@ -126,10 +126,6 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
case Field_Value:
|
case Field_Value:
|
||||||
walk(v, n.field);
|
walk(v, n.field);
|
||||||
walk(v, n.value);
|
walk(v, n.value);
|
||||||
case Ternary_Expr:
|
|
||||||
walk(v, n.cond);
|
|
||||||
walk(v, n.x);
|
|
||||||
walk(v, n.y);
|
|
||||||
case Ternary_If_Expr:
|
case Ternary_If_Expr:
|
||||||
walk(v, n.x);
|
walk(v, n.x);
|
||||||
walk(v, n.cond);
|
walk(v, n.cond);
|
||||||
@@ -138,6 +134,11 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
walk(v, n.x);
|
walk(v, n.x);
|
||||||
walk(v, n.cond);
|
walk(v, n.cond);
|
||||||
walk(v, n.y);
|
walk(v, n.y);
|
||||||
|
case Or_Else_Expr:
|
||||||
|
walk(v, n.x);
|
||||||
|
walk(v, n.y);
|
||||||
|
case Or_Return_Expr:
|
||||||
|
walk(v, n.expr);
|
||||||
case Type_Assertion:
|
case Type_Assertion:
|
||||||
walk(v, n.expr);
|
walk(v, n.expr);
|
||||||
if n.type != nil {
|
if n.type != nil {
|
||||||
|
|||||||
@@ -374,11 +374,14 @@ expect_token_after :: proc(p: ^Parser, kind: tokenizer.Token_Kind, msg: string)
|
|||||||
|
|
||||||
expect_operator :: proc(p: ^Parser) -> tokenizer.Token {
|
expect_operator :: proc(p: ^Parser) -> tokenizer.Token {
|
||||||
prev := p.curr_tok;
|
prev := p.curr_tok;
|
||||||
if prev.kind == .If || prev.kind == .When {
|
#partial switch prev.kind {
|
||||||
|
case .If, .When, .Or_Else, .Or_Return:
|
||||||
// okay
|
// okay
|
||||||
} else if !tokenizer.is_operator(prev.kind) {
|
case:
|
||||||
g := tokenizer.token_to_string(prev);
|
if !tokenizer.is_operator(prev.kind) {
|
||||||
error(p, prev.pos, "expected an operator, got '%s'", g);
|
g := tokenizer.token_to_string(prev);
|
||||||
|
error(p, prev.pos, "expected an operator, got '%s'", g);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
advance_token(p);
|
advance_token(p);
|
||||||
return prev;
|
return prev;
|
||||||
@@ -1366,9 +1369,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
stmt := parse_stmt(p);
|
stmt := parse_stmt(p);
|
||||||
switch name {
|
switch name {
|
||||||
case "bounds_check":
|
case "bounds_check":
|
||||||
stmt.state_flags |= {.Bounds_Check};
|
stmt.state_flags += {.Bounds_Check};
|
||||||
case "no_bounds_check":
|
case "no_bounds_check":
|
||||||
stmt.state_flags |= {.No_Bounds_Check};
|
stmt.state_flags += {.No_Bounds_Check};
|
||||||
}
|
}
|
||||||
return stmt;
|
return stmt;
|
||||||
case "partial":
|
case "partial":
|
||||||
@@ -1449,7 +1452,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
|
|
||||||
token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int {
|
token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int {
|
||||||
#partial switch kind {
|
#partial switch kind {
|
||||||
case .Question, .If, .When:
|
case .Question, .If, .When, .Or_Else, .Or_Return:
|
||||||
return 1;
|
return 1;
|
||||||
case .Ellipsis, .Range_Half, .Range_Full:
|
case .Ellipsis, .Range_Half, .Range_Full:
|
||||||
if !p.allow_range {
|
if !p.allow_range {
|
||||||
@@ -1578,8 +1581,8 @@ Field_Prefix :: enum {
|
|||||||
Using,
|
Using,
|
||||||
No_Alias,
|
No_Alias,
|
||||||
C_Vararg,
|
C_Vararg,
|
||||||
In,
|
|
||||||
Auto_Cast,
|
Auto_Cast,
|
||||||
|
Any_Int,
|
||||||
}
|
}
|
||||||
|
|
||||||
Field_Prefixes :: distinct bit_set[Field_Prefix];
|
Field_Prefixes :: distinct bit_set[Field_Prefix];
|
||||||
@@ -1626,19 +1629,15 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
|
is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
|
||||||
using Field_Prefix;
|
|
||||||
#partial switch p.curr_tok.kind {
|
#partial switch p.curr_tok.kind {
|
||||||
case .EOF:
|
case .EOF:
|
||||||
return Invalid;
|
return .Invalid;
|
||||||
case .Using:
|
case .Using:
|
||||||
advance_token(p);
|
advance_token(p);
|
||||||
return Using;
|
return .Using;
|
||||||
case .In:
|
|
||||||
advance_token(p);
|
|
||||||
return In;
|
|
||||||
case .Auto_Cast:
|
case .Auto_Cast:
|
||||||
advance_token(p);
|
advance_token(p);
|
||||||
return Auto_Cast;
|
return .Auto_Cast;
|
||||||
case .Hash:
|
case .Hash:
|
||||||
advance_token(p);
|
advance_token(p);
|
||||||
defer advance_token(p);
|
defer advance_token(p);
|
||||||
@@ -1646,14 +1645,16 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
|
|||||||
case .Ident:
|
case .Ident:
|
||||||
switch p.curr_tok.text {
|
switch p.curr_tok.text {
|
||||||
case "no_alias":
|
case "no_alias":
|
||||||
return No_Alias;
|
return .No_Alias;
|
||||||
case "c_vararg":
|
case "c_vararg":
|
||||||
return C_Vararg;
|
return .C_Vararg;
|
||||||
|
case "any_int":
|
||||||
|
return .Any_Int;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Unknown;
|
return .Unknown;
|
||||||
}
|
}
|
||||||
return Invalid;
|
return .Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
|
parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
|
||||||
@@ -1677,24 +1678,23 @@ parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
|
|||||||
|
|
||||||
for kind in Field_Prefix {
|
for kind in Field_Prefix {
|
||||||
count := counts[kind];
|
count := counts[kind];
|
||||||
using Field_Prefix;
|
|
||||||
switch kind {
|
switch kind {
|
||||||
case Invalid, Unknown: // Ignore
|
case .Invalid, .Unknown: // Ignore
|
||||||
case Using:
|
case .Using:
|
||||||
if count > 1 { error(p, p.curr_tok.pos, "multiple 'using' in this field list"); }
|
if count > 1 { error(p, p.curr_tok.pos, "multiple 'using' in this field list"); }
|
||||||
if count > 0 { flags |= {.Using}; }
|
if count > 0 { flags += {.Using}; }
|
||||||
case No_Alias:
|
case .No_Alias:
|
||||||
if count > 1 { error(p, p.curr_tok.pos, "multiple '#no_alias' in this field list"); }
|
if count > 1 { error(p, p.curr_tok.pos, "multiple '#no_alias' in this field list"); }
|
||||||
if count > 0 { flags |= {.No_Alias}; }
|
if count > 0 { flags += {.No_Alias}; }
|
||||||
case C_Vararg:
|
case .C_Vararg:
|
||||||
if count > 1 { error(p, p.curr_tok.pos, "multiple '#c_vararg' in this field list"); }
|
if count > 1 { error(p, p.curr_tok.pos, "multiple '#c_vararg' in this field list"); }
|
||||||
if count > 0 { flags |= {.C_Vararg}; }
|
if count > 0 { flags += {.C_Vararg}; }
|
||||||
case In:
|
case .Auto_Cast:
|
||||||
if count > 1 { error(p, p.curr_tok.pos, "multiple 'in' in this field list"); }
|
|
||||||
if count > 0 { flags |= {.In}; }
|
|
||||||
case Auto_Cast:
|
|
||||||
if count > 1 { error(p, p.curr_tok.pos, "multiple 'auto_cast' in this field list"); }
|
if count > 1 { error(p, p.curr_tok.pos, "multiple 'auto_cast' in this field list"); }
|
||||||
if count > 0 { flags |= {.Auto_Cast}; }
|
if count > 0 { flags += {.Auto_Cast}; }
|
||||||
|
case .Any_Int:
|
||||||
|
if count > 1 { error(p, p.curr_tok.pos, "multiple '#any_int' in this field list"); }
|
||||||
|
if count > 0 { flags += {.Any_Int}; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1705,7 +1705,7 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
|
|||||||
flags = set_flags;
|
flags = set_flags;
|
||||||
if name_count > 1 && .Using in flags {
|
if name_count > 1 && .Using in flags {
|
||||||
error(p, p.curr_tok.pos, "cannot apply 'using' to more than one of the same type");
|
error(p, p.curr_tok.pos, "cannot apply 'using' to more than one of the same type");
|
||||||
flags &~= {.Using};
|
flags -= {.Using};
|
||||||
}
|
}
|
||||||
|
|
||||||
for flag in ast.Field_Flag {
|
for flag in ast.Field_Flag {
|
||||||
@@ -1719,12 +1719,12 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
|
|||||||
error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list");
|
error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list");
|
||||||
case .Auto_Cast:
|
case .Auto_Cast:
|
||||||
error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list");
|
error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list");
|
||||||
case .In:
|
case .Any_Int:
|
||||||
error(p, p.curr_tok.pos, "'in' is not allowed within this field list");
|
error(p, p.curr_tok.pos, "'#any_int' is not allowed within this field list");
|
||||||
case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token:
|
case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token:
|
||||||
panic("Impossible prefixes");
|
panic("Impossible prefixes");
|
||||||
}
|
}
|
||||||
flags &~= {flag};
|
flags -= {flag};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2062,10 +2062,10 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) {
|
|||||||
ident := expect_token(p, .Ident);
|
ident := expect_token(p, .Ident);
|
||||||
|
|
||||||
switch ident.text {
|
switch ident.text {
|
||||||
case "bounds_check": tags |= {.Bounds_Check};
|
case "bounds_check": tags += {.Bounds_Check};
|
||||||
case "no_bounds_check": tags |= {.No_Bounds_Check};
|
case "no_bounds_check": tags += {.No_Bounds_Check};
|
||||||
case "optional_ok": tags |= {.Optional_Ok};
|
case "optional_ok": tags += {.Optional_Ok};
|
||||||
case "optional_second": tags |= {.Optional_Second};
|
case "optional_second": tags += {.Optional_Second};
|
||||||
case:
|
case:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2267,12 +2267,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
|||||||
|
|
||||||
switch name.text {
|
switch name.text {
|
||||||
case "bounds_check":
|
case "bounds_check":
|
||||||
operand.state_flags |= {.Bounds_Check};
|
operand.state_flags += {.Bounds_Check};
|
||||||
if .No_Bounds_Check in operand.state_flags {
|
if .No_Bounds_Check in operand.state_flags {
|
||||||
error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
|
error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
|
||||||
}
|
}
|
||||||
case "no_bounds_check":
|
case "no_bounds_check":
|
||||||
operand.state_flags |= {.No_Bounds_Check};
|
operand.state_flags += {.No_Bounds_Check};
|
||||||
if .Bounds_Check in operand.state_flags {
|
if .Bounds_Check in operand.state_flags {
|
||||||
error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
|
error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together");
|
||||||
}
|
}
|
||||||
@@ -3156,16 +3156,18 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for prec := token_precedence(p, p.curr_tok.kind); prec >= prec_in; prec -= 1 {
|
for prec := token_precedence(p, p.curr_tok.kind); prec >= prec_in; prec -= 1 {
|
||||||
for {
|
loop: for {
|
||||||
op := p.curr_tok;
|
op := p.curr_tok;
|
||||||
op_prec := token_precedence(p, op.kind);
|
op_prec := token_precedence(p, op.kind);
|
||||||
if op_prec != prec {
|
if op_prec != prec {
|
||||||
break;
|
break loop;
|
||||||
}
|
}
|
||||||
if op.kind == .If || op.kind == .When {
|
|
||||||
|
#partial switch op.kind {
|
||||||
|
case .If, .When, .Or_Return, .Or_Else:
|
||||||
if p.prev_tok.pos.line < op.pos.line {
|
if p.prev_tok.pos.line < op.pos.line {
|
||||||
// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
|
// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
|
||||||
break;
|
break loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3178,7 +3180,7 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
|
|||||||
x := parse_expr(p, lhs);
|
x := parse_expr(p, lhs);
|
||||||
colon := expect_token(p, .Colon);
|
colon := expect_token(p, .Colon);
|
||||||
y := parse_expr(p, lhs);
|
y := parse_expr(p, lhs);
|
||||||
te := ast.new(ast.Ternary_Expr, expr.pos, end_pos(p.prev_tok));
|
te := ast.new(ast.Ternary_If_Expr, expr.pos, end_pos(p.prev_tok));
|
||||||
te.cond = cond;
|
te.cond = cond;
|
||||||
te.op1 = op;
|
te.op1 = op;
|
||||||
te.x = x;
|
te.x = x;
|
||||||
@@ -3212,6 +3214,21 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
|
|||||||
te.y = y;
|
te.y = y;
|
||||||
|
|
||||||
expr = te;
|
expr = te;
|
||||||
|
case .Or_Else:
|
||||||
|
x := expr;
|
||||||
|
y := parse_expr(p, lhs);
|
||||||
|
oe := ast.new(ast.Or_Else_Expr, expr.pos, end_pos(p.prev_tok));
|
||||||
|
oe.x = x;
|
||||||
|
oe.token = op;
|
||||||
|
oe.y = y;
|
||||||
|
|
||||||
|
expr = oe;
|
||||||
|
case .Or_Return:
|
||||||
|
oe := ast.new(ast.Or_Return_Expr, expr.pos, end_pos(p.prev_tok));
|
||||||
|
oe.expr = expr;
|
||||||
|
oe.token = op;
|
||||||
|
|
||||||
|
expr = oe;
|
||||||
case:
|
case:
|
||||||
right := parse_binary_expr(p, false, prec+1);
|
right := parse_binary_expr(p, false, prec+1);
|
||||||
if right == nil {
|
if right == nil {
|
||||||
|
|||||||
@@ -944,12 +944,6 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
case Auto_Cast:
|
case 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_Expr:
|
|
||||||
visit_expr(p, v.cond);
|
|
||||||
push_generic_token(p, v.op1.kind, 1);
|
|
||||||
visit_expr(p, v.x);
|
|
||||||
push_generic_token(p, v.op2.kind, 1);
|
|
||||||
visit_expr(p, v.y);
|
|
||||||
case Ternary_If_Expr:
|
case 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);
|
||||||
@@ -962,6 +956,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
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:
|
||||||
|
visit_expr(p, v.x);
|
||||||
|
push_generic_token(p, v.token.kind, 1);
|
||||||
|
visit_expr(p, v.y);
|
||||||
|
case Or_Return_Expr:
|
||||||
|
visit_expr(p, v.expr);
|
||||||
|
push_generic_token(p, v.token.kind, 1);
|
||||||
case Selector_Call_Expr:
|
case 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);
|
||||||
|
|||||||
@@ -144,10 +144,12 @@ Token_Kind :: enum u32 {
|
|||||||
Transmute, // transmute
|
Transmute, // transmute
|
||||||
Distinct, // distinct
|
Distinct, // distinct
|
||||||
Using, // using
|
Using, // using
|
||||||
|
Context, // context
|
||||||
|
Or_Else, // or_else
|
||||||
|
Or_Return, // or_return
|
||||||
|
Asm, // asm
|
||||||
Inline, // inline
|
Inline, // inline
|
||||||
No_Inline, // no_inline
|
No_Inline, // no_inline
|
||||||
Context, // context
|
|
||||||
Asm, // asm
|
|
||||||
B_Keyword_End,
|
B_Keyword_End,
|
||||||
|
|
||||||
COUNT,
|
COUNT,
|
||||||
@@ -272,10 +274,12 @@ tokens := [Token_Kind.COUNT]string {
|
|||||||
"transmute",
|
"transmute",
|
||||||
"distinct",
|
"distinct",
|
||||||
"using",
|
"using",
|
||||||
|
"context",
|
||||||
|
"or_else",
|
||||||
|
"or_return",
|
||||||
|
"asm",
|
||||||
"inline",
|
"inline",
|
||||||
"no_inline",
|
"no_inline",
|
||||||
"context",
|
|
||||||
"asm",
|
|
||||||
"",
|
"",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -724,7 +724,7 @@ scan :: proc(t: ^Tokenizer) -> Token {
|
|||||||
case .Ident, .Context, .Typeid, .Break, .Continue, .Fallthrough, .Return,
|
case .Ident, .Context, .Typeid, .Break, .Continue, .Fallthrough, .Return,
|
||||||
.Integer, .Float, .Imag, .Rune, .String, .Undef,
|
.Integer, .Float, .Imag, .Rune, .String, .Undef,
|
||||||
.Question, .Pointer, .Close_Paren, .Close_Bracket, .Close_Brace,
|
.Question, .Pointer, .Close_Paren, .Close_Bracket, .Close_Brace,
|
||||||
.Increment, .Decrement:
|
.Increment, .Decrement, .Or_Return:
|
||||||
/*fallthrough*/
|
/*fallthrough*/
|
||||||
t.insert_semicolon = true;
|
t.insert_semicolon = true;
|
||||||
case:
|
case:
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ link_error_delete :: proc(lerr: Maybe(Link_Error)) {
|
|||||||
|
|
||||||
|
|
||||||
is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
|
is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
|
||||||
v := or_else(ferr.(Platform_Error), {});
|
v := ferr.(Platform_Error) or_else {};
|
||||||
return v.err, v.err != 0;
|
return v.err, v.err != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ error_to_io_error :: proc(ferr: Error) -> io.Error {
|
|||||||
if ferr == nil {
|
if ferr == nil {
|
||||||
return .None;
|
return .None;
|
||||||
}
|
}
|
||||||
return or_else(ferr.(io.Error), .Unknown);
|
return ferr.(io.Error) or_else .Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -298,10 +298,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]s
|
|||||||
|
|
||||||
for fi in fis {
|
for fi in fis {
|
||||||
n := fi.name;
|
n := fi.name;
|
||||||
matched, err := match(pattern, n);
|
matched := match(pattern, n) or_return;
|
||||||
if err != nil {
|
|
||||||
return m, err;
|
|
||||||
}
|
|
||||||
if matched {
|
if matched {
|
||||||
append(&m, join(dir, n));
|
append(&m, join(dir, n));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ _Recursive_Mutex :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
_recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
||||||
tid := runtime.current_thread_id();
|
tid := _current_thread_id();
|
||||||
if tid != m.impl.owner {
|
if tid != m.impl.owner {
|
||||||
mutex_lock(&m.impl.mutex);
|
mutex_lock(&m.impl.mutex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ Thread_Os_Specific :: struct {
|
|||||||
thread_create :: proc(procedure: Thread_Proc) -> ^Thread {
|
thread_create :: proc(procedure: Thread_Proc) -> ^Thread {
|
||||||
__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
|
__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
|
||||||
t := (^Thread)(t_);
|
t := (^Thread)(t_);
|
||||||
context = or_else(t.init_context.?, runtime.default_context());
|
context = t.init_context.? or_else runtime.default_context();
|
||||||
|
|
||||||
t.procedure(t);
|
t.procedure(t);
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^
|
|||||||
t.start_gate = {};
|
t.start_gate = {};
|
||||||
t.start_mutex = {};
|
t.start_mutex = {};
|
||||||
|
|
||||||
context = or_else(t.init_context.?, runtime.default_context());
|
context = t.init_context.? or_else runtime.default_context();
|
||||||
|
|
||||||
t.procedure(t);
|
t.procedure(t);
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^
|
|||||||
|
|
||||||
__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
|
__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
|
||||||
t := (^Thread)(t_);
|
t := (^Thread)(t_);
|
||||||
context = or_else(t.init_context.?, runtime.default_context());
|
context = t.init_context.? or_else runtime.default_context();
|
||||||
|
|
||||||
t.procedure(t);
|
t.procedure(t);
|
||||||
|
|
||||||
|
|||||||
+50
-50
@@ -3,57 +3,57 @@ package all
|
|||||||
// Imports every package
|
// Imports every package
|
||||||
// This is useful for knowing what exists and producing documentation with `odin doc`
|
// This is useful for knowing what exists and producing documentation with `odin doc`
|
||||||
|
|
||||||
import "core:bufio"
|
import bufio "core:bufio"
|
||||||
import "core:bytes"
|
import bytes "core:bytes"
|
||||||
import "core:c"
|
import c "core:c"
|
||||||
import c_tokenizer "core:c/frontend/tokenizer"
|
import c_tokenizer "core:c/frontend/tokenizer"
|
||||||
import c_preprocessor "core:c/frontend/preprocessor"
|
import c_preprocessor "core:c/frontend/preprocessor"
|
||||||
import "core:compress"
|
import compress "core:compress"
|
||||||
import "core:compress/gzip"
|
import gzip "core:compress/gzip"
|
||||||
import "core:compress/zlib"
|
import zlib "core:compress/zlib"
|
||||||
import "core:container"
|
import container "core:container"
|
||||||
import "core:dynlib"
|
import dynlib "core:dynlib"
|
||||||
import "core:encoding"
|
import encoding "core:encoding"
|
||||||
import "core:encoding/base32"
|
import base32 "core:encoding/base32"
|
||||||
import "core:encoding/base64"
|
import base64 "core:encoding/base64"
|
||||||
import "core:encoding/csv"
|
import csv "core:encoding/csv"
|
||||||
import "core:encoding/hxa"
|
import hxa "core:encoding/hxa"
|
||||||
import "core:encoding/json"
|
import json "core:encoding/json"
|
||||||
import "core:fmt"
|
import fmt "core:fmt"
|
||||||
import "core:hash"
|
import hash "core:hash"
|
||||||
import "core:image"
|
import image "core:image"
|
||||||
import "core:image/png"
|
import png "core:image/png"
|
||||||
import "core:io"
|
import io "core:io"
|
||||||
import "core:log"
|
import log "core:log"
|
||||||
import "core:math"
|
import math "core:math"
|
||||||
import "core:math/big"
|
import big "core:math/big"
|
||||||
import "core:math/bits"
|
import bits "core:math/bits"
|
||||||
import "core:math/fixed"
|
import fixed "core:math/fixed"
|
||||||
import "core:math/linalg"
|
import linalg "core:math/linalg"
|
||||||
import "core:math/rand"
|
import rand "core:math/rand"
|
||||||
import "core:mem"
|
import mem "core:mem"
|
||||||
import "core:odin/ast"
|
import ast "core:odin/ast"
|
||||||
import doc_format "core:odin/doc-format"
|
import doc_format "core:odin/doc-format"
|
||||||
import "core:odin/format"
|
import odin_format "core:odin/format"
|
||||||
import "core:odin/parser"
|
import odin_parser "core:odin/parser"
|
||||||
import "core:odin/printer"
|
import odin_printer "core:odin/printer"
|
||||||
import odin_tokenizer "core:odin/tokenizer"
|
import odin_tokenizer "core:odin/tokenizer"
|
||||||
import "core:os"
|
import os "core:os"
|
||||||
import "core:path"
|
import path "core:path"
|
||||||
import "core:path/filepath"
|
import filepath "core:path/filepath"
|
||||||
import "core:reflect"
|
import reflect "core:reflect"
|
||||||
import "core:runtime"
|
import runtime "core:runtime"
|
||||||
import "core:slice"
|
import slice "core:slice"
|
||||||
import "core:sort"
|
import sort "core:sort"
|
||||||
import "core:strconv"
|
import strconv "core:strconv"
|
||||||
import "core:strings"
|
import strings "core:strings"
|
||||||
import "core:sync"
|
import sync "core:sync"
|
||||||
import "core:sync/sync2"
|
import sync2 "core:sync/sync2"
|
||||||
import "core:text/scanner"
|
import scanner "core:text/scanner"
|
||||||
import "core:thread"
|
import thread "core:thread"
|
||||||
import "core:time"
|
import time "core:time"
|
||||||
import "core:unicode"
|
import unicode "core:unicode"
|
||||||
import "core:unicode/utf8"
|
import utf8 "core:unicode/utf8"
|
||||||
import "core:unicode/utf16"
|
import utf16 "core:unicode/utf16"
|
||||||
|
|
||||||
main :: proc(){}
|
main :: proc(){}
|
||||||
|
|||||||
+109
-8
@@ -1998,9 +1998,9 @@ relative_data_types :: proc() {
|
|||||||
fmt.println(rel_slice[1]);
|
fmt.println(rel_slice[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
or_else_procedure :: proc() {
|
or_else_operator :: proc() {
|
||||||
fmt.println("\n#'or_else'");
|
fmt.println("\n#'or_else'");
|
||||||
// IMPORTANT NOTE: 'or_else' is experimental features and subject to change/removal
|
// IMPORTANT NOTE: 'or_else' is an experimental feature and subject to change/removal
|
||||||
{
|
{
|
||||||
m: map[string]int;
|
m: map[string]int;
|
||||||
i: int;
|
i: int;
|
||||||
@@ -2010,7 +2010,7 @@ or_else_procedure :: proc() {
|
|||||||
i = 123;
|
i = 123;
|
||||||
}
|
}
|
||||||
// The above can be mapped to 'or_else'
|
// The above can be mapped to 'or_else'
|
||||||
i = or_else(m["hellope"], 123);
|
i = m["hellope"] or_else 123;
|
||||||
|
|
||||||
assert(i == 123);
|
assert(i == 123);
|
||||||
}
|
}
|
||||||
@@ -2019,16 +2019,117 @@ or_else_procedure :: proc() {
|
|||||||
// have optional ok semantics
|
// have optional ok semantics
|
||||||
v: union{int, f64};
|
v: union{int, f64};
|
||||||
i: int;
|
i: int;
|
||||||
i = or_else(v.(int), 123);
|
i = v.(int) or_else 123;
|
||||||
i = or_else(v.?, 123); // Type inference magic
|
i = v.? or_else 123; // Type inference magic
|
||||||
assert(i == 123);
|
assert(i == 123);
|
||||||
|
|
||||||
m: Maybe(int);
|
m: Maybe(int);
|
||||||
i = or_else(m.?, 456);
|
i = m.? or_else 456;
|
||||||
assert(i == 456);
|
assert(i == 456);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
or_return_operator :: proc() {
|
||||||
|
fmt.println("\n#'or_return'");
|
||||||
|
// IMPORTANT NOTE: 'or_return' is an experimental feature and subject to change/removal
|
||||||
|
//
|
||||||
|
// The concept of 'or_return' will work by popping off the end value in a multiple
|
||||||
|
// valued expression and checking whether it was not 'nil' or 'false', and if so,
|
||||||
|
// set the end return value to value if possible. If the procedure only has one
|
||||||
|
// return value, it will do a simple return. If the procedure had multiple return
|
||||||
|
// values, 'or_return' will require that all parameters be named so that the end
|
||||||
|
// value could be assigned to by name and then an empty return could be called.
|
||||||
|
|
||||||
|
Error :: enum {
|
||||||
|
None,
|
||||||
|
Something_Bad,
|
||||||
|
Something_Worse,
|
||||||
|
The_Worst,
|
||||||
|
Your_Mum,
|
||||||
|
};
|
||||||
|
|
||||||
|
caller_1 :: proc() -> Error {
|
||||||
|
return .None;
|
||||||
|
}
|
||||||
|
|
||||||
|
caller_2 :: proc() -> (int, Error) {
|
||||||
|
return 123, .None;
|
||||||
|
}
|
||||||
|
caller_3 :: proc() -> (int, int, Error) {
|
||||||
|
return 123, 345, .None;
|
||||||
|
}
|
||||||
|
|
||||||
|
foo_1 :: proc() -> Error {
|
||||||
|
// This can be a common idiom in many code bases
|
||||||
|
n0, err := caller_2();
|
||||||
|
if err != nil {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The above idiom can be transformed into the following
|
||||||
|
n1 := caller_2() or_return;
|
||||||
|
|
||||||
|
|
||||||
|
// And if the expression is 1-valued, it can be used like this
|
||||||
|
caller_1() or_return;
|
||||||
|
// which is functionally equivalent to
|
||||||
|
if err1 := caller_1(); err1 != nil {
|
||||||
|
return err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple return values still work with 'or_return' as it only
|
||||||
|
// pops off the end value in the multi-valued expression
|
||||||
|
n0, n1 = caller_3() or_return;
|
||||||
|
|
||||||
|
return .None;
|
||||||
|
}
|
||||||
|
foo_2 :: proc() -> (n: int, err: Error) {
|
||||||
|
// It is more common that your procedure turns multiple values
|
||||||
|
// If 'or_return' is used within a procedure multiple parameters (2+),
|
||||||
|
// then all the parameters must be named so that the remaining parameters
|
||||||
|
// so that a bare 'return' statement can be used
|
||||||
|
|
||||||
|
// This can be a common idiom in many code bases
|
||||||
|
x: int;
|
||||||
|
x, err = caller_2();
|
||||||
|
if err != nil {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The above idiom can be transformed into the following
|
||||||
|
y := caller_2() or_return;
|
||||||
|
_ = y;
|
||||||
|
|
||||||
|
// And if the expression is 1-valued, it can be used like this
|
||||||
|
caller_1() or_return;
|
||||||
|
|
||||||
|
// which is functionally equivalent to
|
||||||
|
if err1 := caller_1(); err1 != nil {
|
||||||
|
err = err1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If using a non-bare 'return' statement is required, setting the return values
|
||||||
|
// using the normal idiom is a better choice and clearer to read.
|
||||||
|
if z, zerr := caller_2(); zerr != nil {
|
||||||
|
return -345 * z, zerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the other return values need to be set depending on what the end value is,
|
||||||
|
// the 'defer if' idiom is can be used
|
||||||
|
defer if err != nil {
|
||||||
|
n = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = 123;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foo_1();
|
||||||
|
foo_2();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
when true {
|
when true {
|
||||||
the_basics();
|
the_basics();
|
||||||
@@ -2061,7 +2162,7 @@ main :: proc() {
|
|||||||
union_maybe();
|
union_maybe();
|
||||||
explicit_context_definition();
|
explicit_context_definition();
|
||||||
relative_data_types();
|
relative_data_types();
|
||||||
or_else_procedure();
|
or_else_operator();
|
||||||
|
or_return_operator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
+40
-51
@@ -48,6 +48,17 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end -
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type) {
|
||||||
|
if (right_type == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!is_type_boolean(right_type) && !type_has_nil(right_type)) {
|
||||||
|
gbString str = type_to_string(right_type);
|
||||||
|
error(expr, "'%.*s' expects an \"optional ok\" like value, or an n-valued expression where the last value is either a boolean or can be compared against 'nil', got %s", LIT(name), str);
|
||||||
|
gb_string_free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
|
void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
|
||||||
Type *left_type = nullptr;
|
Type *left_type = nullptr;
|
||||||
Type *right_type = nullptr;
|
Type *right_type = nullptr;
|
||||||
@@ -70,15 +81,11 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name
|
|||||||
if (left_type_) *left_type_ = left_type;
|
if (left_type_) *left_type_ = left_type;
|
||||||
if (right_type_) *right_type_ = right_type;
|
if (right_type_) *right_type_ = right_type;
|
||||||
|
|
||||||
if (!is_type_boolean(right_type)) {
|
check_or_else_right_type(c, x->expr, name, right_type);
|
||||||
gbString str = type_to_string(right_type);
|
|
||||||
error(x->expr, "'%.*s' expects an \"optional ok\" like value, got %s", LIT(name), str);
|
|
||||||
gb_string_free(str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void check_try_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) {
|
void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) {
|
||||||
// TODO(bill): better error message
|
// TODO(bill): better error message
|
||||||
gbString t = type_to_string(x.type);
|
gbString t = type_to_string(x.type);
|
||||||
error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t);
|
error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t);
|
||||||
@@ -108,6 +115,33 @@ void check_try_expr_no_value_error(CheckerContext *c, String const &name, Operan
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
|
||||||
|
Type *left_type = nullptr;
|
||||||
|
Type *right_type = nullptr;
|
||||||
|
if (x->type->kind == Type_Tuple) {
|
||||||
|
auto const &vars = x->type->Tuple.variables;
|
||||||
|
auto lhs = array_slice(vars, 0, vars.count-1);
|
||||||
|
auto rhs = vars[vars.count-1];
|
||||||
|
if (lhs.count == 1) {
|
||||||
|
left_type = lhs[0]->type;
|
||||||
|
} else if (lhs.count != 0) {
|
||||||
|
left_type = alloc_type_tuple();
|
||||||
|
left_type->Tuple.variables = array_make_from_ptr(lhs.data, lhs.count, lhs.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
right_type = rhs->type;
|
||||||
|
} else {
|
||||||
|
check_promote_optional_ok(c, x, &left_type, &right_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left_type_) *left_type_ = left_type;
|
||||||
|
if (right_type_) *right_type_ = right_type;
|
||||||
|
|
||||||
|
check_or_else_right_type(c, x->expr, name, right_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
|
bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
|
||||||
ast_node(ce, CallExpr, call);
|
ast_node(ce, CallExpr, call);
|
||||||
if (ce->inlining != ProcInlining_none) {
|
if (ce->inlining != ProcInlining_none) {
|
||||||
@@ -145,10 +179,6 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
// NOTE(bill): The first arg may be a Type, this will be checked case by case
|
// NOTE(bill): The first arg may be a Type, this will be checked case by case
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BuiltinProc_or_else:
|
|
||||||
// NOTE(bill): The arguments may be multi-expr
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BuiltinProc_DIRECTIVE: {
|
case BuiltinProc_DIRECTIVE: {
|
||||||
ast_node(bd, BasicDirective, ce->proc);
|
ast_node(bd, BasicDirective, ce->proc);
|
||||||
String name = bd->name.string;
|
String name = bd->name.string;
|
||||||
@@ -1800,47 +1830,6 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BuiltinProc_or_else: {
|
|
||||||
GB_ASSERT(ce->args.count == 2);
|
|
||||||
Ast *arg = ce->args[0];
|
|
||||||
Ast *default_value = ce->args[1];
|
|
||||||
|
|
||||||
Operand x = {};
|
|
||||||
Operand y = {};
|
|
||||||
check_multi_expr_with_type_hint(c, &x, arg, type_hint);
|
|
||||||
if (x.mode == Addressing_Invalid) {
|
|
||||||
operand->mode = Addressing_Value;
|
|
||||||
operand->type = t_invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
check_multi_expr_with_type_hint(c, &y, default_value, x.type);
|
|
||||||
error_operand_no_value(&y);
|
|
||||||
if (y.mode == Addressing_Invalid) {
|
|
||||||
operand->mode = Addressing_Value;
|
|
||||||
operand->type = t_invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type *left_type = nullptr;
|
|
||||||
Type *right_type = nullptr;
|
|
||||||
check_or_else_split_types(c, &x, builtin_name, &left_type, &right_type);
|
|
||||||
add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value);
|
|
||||||
|
|
||||||
if (left_type != nullptr) {
|
|
||||||
check_assignment(c, &y, left_type, builtin_name);
|
|
||||||
} else {
|
|
||||||
check_try_expr_no_value_error(c, builtin_name, x, type_hint);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (left_type == nullptr) {
|
|
||||||
left_type = t_invalid;
|
|
||||||
}
|
|
||||||
operand->mode = Addressing_Value;
|
|
||||||
operand->type = left_type;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BuiltinProc_simd_vector: {
|
case BuiltinProc_simd_vector: {
|
||||||
Operand x = {};
|
Operand x = {};
|
||||||
Operand y = {};
|
Operand y = {};
|
||||||
|
|||||||
@@ -114,6 +114,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
|
|
||||||
void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_);
|
void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_);
|
||||||
|
|
||||||
|
void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type);
|
||||||
|
void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_);
|
||||||
|
void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint);
|
||||||
|
void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_);
|
||||||
|
|
||||||
Entity *entity_from_expr(Ast *expr) {
|
Entity *entity_from_expr(Ast *expr) {
|
||||||
expr = unparen_expr(expr);
|
expr = unparen_expr(expr);
|
||||||
switch (expr->kind) {
|
switch (expr->kind) {
|
||||||
@@ -2960,6 +2965,25 @@ void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, bool final)
|
|||||||
update_untyped_expr_type(c, te->y, type, final);
|
update_untyped_expr_type(c, te->y, type, final);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ore, OrReturnExpr, e);
|
||||||
|
if (old->value.kind != ExactValue_Invalid) {
|
||||||
|
// See above note in UnaryExpr case
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_untyped_expr_type(c, ore->expr, type, final);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(oee, OrElseExpr, e);
|
||||||
|
if (old->value.kind != ExactValue_Invalid) {
|
||||||
|
// See above note in UnaryExpr case
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_untyped_expr_type(c, oee->x, type, final);
|
||||||
|
update_untyped_expr_type(c, oee->y, type, final);
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(pe, ParenExpr, e);
|
case_ast_node(pe, ParenExpr, e);
|
||||||
update_untyped_expr_type(c, pe->expr, type, final);
|
update_untyped_expr_type(c, pe->expr, type, final);
|
||||||
case_end;
|
case_end;
|
||||||
@@ -6602,6 +6626,123 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(oe, OrElseExpr, node);
|
||||||
|
String name = oe->token.string;
|
||||||
|
Ast *arg = oe->x;
|
||||||
|
Ast *default_value = oe->y;
|
||||||
|
|
||||||
|
Operand x = {};
|
||||||
|
Operand y = {};
|
||||||
|
check_multi_expr_with_type_hint(c, &x, arg, type_hint);
|
||||||
|
if (x.mode == Addressing_Invalid) {
|
||||||
|
o->mode = Addressing_Value;
|
||||||
|
o->type = t_invalid;
|
||||||
|
o->expr = node;
|
||||||
|
return Expr_Expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
check_multi_expr_with_type_hint(c, &y, default_value, x.type);
|
||||||
|
error_operand_no_value(&y);
|
||||||
|
if (y.mode == Addressing_Invalid) {
|
||||||
|
o->mode = Addressing_Value;
|
||||||
|
o->type = t_invalid;
|
||||||
|
o->expr = node;
|
||||||
|
return Expr_Expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *left_type = nullptr;
|
||||||
|
Type *right_type = nullptr;
|
||||||
|
check_or_else_split_types(c, &x, name, &left_type, &right_type);
|
||||||
|
add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value);
|
||||||
|
|
||||||
|
if (left_type != nullptr) {
|
||||||
|
check_assignment(c, &y, left_type, name);
|
||||||
|
} else {
|
||||||
|
check_or_else_expr_no_value_error(c, name, x, type_hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left_type == nullptr) {
|
||||||
|
left_type = t_invalid;
|
||||||
|
}
|
||||||
|
o->mode = Addressing_Value;
|
||||||
|
o->type = left_type;
|
||||||
|
o->expr = node;
|
||||||
|
return Expr_Expr;
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(re, OrReturnExpr, node);
|
||||||
|
String name = re->token.string;
|
||||||
|
Operand x = {};
|
||||||
|
check_multi_expr_with_type_hint(c, &x, re->expr, type_hint);
|
||||||
|
if (x.mode == Addressing_Invalid) {
|
||||||
|
o->mode = Addressing_Value;
|
||||||
|
o->type = t_invalid;
|
||||||
|
o->expr = node;
|
||||||
|
return Expr_Expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *left_type = nullptr;
|
||||||
|
Type *right_type = nullptr;
|
||||||
|
check_or_return_split_types(c, &x, name, &left_type, &right_type);
|
||||||
|
add_type_and_value(&c->checker->info, re->expr, x.mode, x.type, x.value);
|
||||||
|
|
||||||
|
if (right_type == nullptr) {
|
||||||
|
check_or_else_expr_no_value_error(c, name, x, type_hint);
|
||||||
|
} else {
|
||||||
|
Type *proc_type = base_type(c->curr_proc_sig);
|
||||||
|
GB_ASSERT(proc_type->kind == Type_Proc);
|
||||||
|
Type *result_type = proc_type->Proc.results;
|
||||||
|
if (result_type == nullptr) {
|
||||||
|
error(node, "'%.*s' requires the current procedure to have at least one return value", LIT(name));
|
||||||
|
} else {
|
||||||
|
GB_ASSERT(result_type->kind == Type_Tuple);
|
||||||
|
|
||||||
|
auto const &vars = result_type->Tuple.variables;
|
||||||
|
Type *end_type = vars[vars.count-1]->type;
|
||||||
|
|
||||||
|
if (vars.count > 1) {
|
||||||
|
if (!proc_type->Proc.has_named_results) {
|
||||||
|
error(node, "'%.*s' within a procedure with more than 1 return value requires that the return values are named, allowing for early return", LIT(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand rhs = {};
|
||||||
|
rhs.type = right_type;
|
||||||
|
rhs.mode = Addressing_Value;
|
||||||
|
|
||||||
|
// TODO(bill): better error message
|
||||||
|
if (!check_is_assignable_to(c, &rhs, end_type)) {
|
||||||
|
gbString a = type_to_string(right_type);
|
||||||
|
gbString b = type_to_string(end_type);
|
||||||
|
gbString ret_type = type_to_string(result_type);
|
||||||
|
error(node, "Cannot assign end value of type '%s' to '%s' in '%.*s'", a, b, LIT(name));
|
||||||
|
if (vars.count == 1) {
|
||||||
|
error_line("\tProcedure return value type: %s\n", ret_type);
|
||||||
|
} else {
|
||||||
|
error_line("\tProcedure return value types: (%s)\n", ret_type);
|
||||||
|
}
|
||||||
|
gb_string_free(ret_type);
|
||||||
|
gb_string_free(b);
|
||||||
|
gb_string_free(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
o->expr = node;
|
||||||
|
o->type = left_type;
|
||||||
|
if (left_type != nullptr) {
|
||||||
|
o->mode = Addressing_Value;
|
||||||
|
} else {
|
||||||
|
o->mode = Addressing_NoValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->curr_proc_sig == nullptr) {
|
||||||
|
error(node, "'%.*s' can only be used within a procedure", LIT(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Expr_Expr;
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(cl, CompoundLit, node);
|
case_ast_node(cl, CompoundLit, node);
|
||||||
Type *type = type_hint;
|
Type *type = type_hint;
|
||||||
if (type != nullptr && is_type_untyped(type)) {
|
if (type != nullptr && is_type_untyped(type)) {
|
||||||
@@ -8565,6 +8706,16 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
|
|||||||
str = write_expr_to_string(str, te->y, shorthand);
|
str = write_expr_to_string(str, te->y, shorthand);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(oe, OrElseExpr, node);
|
||||||
|
str = write_expr_to_string(str, oe->x, shorthand);
|
||||||
|
str = gb_string_appendc(str, " or_else ");
|
||||||
|
str = write_expr_to_string(str, oe->y, shorthand);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(oe, OrReturnExpr, node);
|
||||||
|
str = write_expr_to_string(str, oe->expr, shorthand);
|
||||||
|
str = gb_string_appendc(str, " or_return");
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(pe, ParenExpr, node);
|
case_ast_node(pe, ParenExpr, node);
|
||||||
str = gb_string_append_rune(str, '(');
|
str = gb_string_append_rune(str, '(');
|
||||||
|
|||||||
+6
-4
@@ -1480,8 +1480,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
if (kind == Expr_Stmt) {
|
if (kind == Expr_Stmt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (operand.expr->kind == Ast_CallExpr) {
|
Ast *expr = strip_or_return_expr(operand.expr);
|
||||||
AstCallExpr *ce = &operand.expr->CallExpr;
|
|
||||||
|
if (expr->kind == Ast_CallExpr) {
|
||||||
|
AstCallExpr *ce = &expr->CallExpr;
|
||||||
Type *t = type_of_expr(ce->proc);
|
Type *t = type_of_expr(ce->proc);
|
||||||
if (is_type_proc(t)) {
|
if (is_type_proc(t)) {
|
||||||
if (t->Proc.require_results) {
|
if (t->Proc.require_results) {
|
||||||
@@ -1491,8 +1493,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (operand.expr->kind == Ast_SelectorCallExpr) {
|
} else if (expr->kind == Ast_SelectorCallExpr) {
|
||||||
AstSelectorCallExpr *se = &operand.expr->SelectorCallExpr;
|
AstSelectorCallExpr *se = &expr->SelectorCallExpr;
|
||||||
ast_node(ce, CallExpr, se->call);
|
ast_node(ce, CallExpr, se->call);
|
||||||
Type *t = type_of_expr(ce->proc);
|
Type *t = type_of_expr(ce->proc);
|
||||||
if (is_type_proc(t)) {
|
if (is_type_proc(t)) {
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ enum BuiltinProcId {
|
|||||||
BuiltinProc_soa_zip,
|
BuiltinProc_soa_zip,
|
||||||
BuiltinProc_soa_unzip,
|
BuiltinProc_soa_unzip,
|
||||||
|
|
||||||
BuiltinProc_or_else,
|
|
||||||
|
|
||||||
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
|
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
|
||||||
|
|
||||||
// "Intrinsics"
|
// "Intrinsics"
|
||||||
@@ -265,8 +263,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
|||||||
{STR_LIT("soa_zip"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
|
{STR_LIT("soa_zip"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
|
||||||
{STR_LIT("soa_unzip"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
{STR_LIT("soa_unzip"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||||
|
|
||||||
{STR_LIT("or_else"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
|
|
||||||
|
|
||||||
{STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
|
{STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2305,6 +2305,14 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
|||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(oe, OrElseExpr, expr);
|
||||||
|
return lb_emit_or_else(p, oe->x, oe->y, tv);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(oe, OrReturnExpr, expr);
|
||||||
|
return lb_emit_or_return(p, oe->expr, tv);
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ta, TypeAssertion, expr);
|
case_ast_node(ta, TypeAssertion, expr);
|
||||||
TokenPos pos = ast_token(expr).pos;
|
TokenPos pos = ast_token(expr).pos;
|
||||||
Type *type = tv.type;
|
Type *type = tv.type;
|
||||||
|
|||||||
@@ -1252,9 +1252,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
|
|||||||
case BuiltinProc_soa_unzip:
|
case BuiltinProc_soa_unzip:
|
||||||
return lb_soa_unzip(p, ce, tv);
|
return lb_soa_unzip(p, ce, tv);
|
||||||
|
|
||||||
case BuiltinProc_or_else:
|
|
||||||
return lb_emit_or_else(p, ce->args[0], ce->args[1], tv);
|
|
||||||
|
|
||||||
// "Intrinsics"
|
// "Intrinsics"
|
||||||
|
|
||||||
case BuiltinProc_alloca:
|
case BuiltinProc_alloca:
|
||||||
|
|||||||
@@ -364,6 +364,48 @@ lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue c
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results);
|
||||||
|
void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res);
|
||||||
|
|
||||||
|
lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
|
||||||
|
lbValue lhs = {};
|
||||||
|
lbValue rhs = {};
|
||||||
|
lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs);
|
||||||
|
|
||||||
|
lbBlock *return_block = lb_create_block(p, "or_return.return");
|
||||||
|
lbBlock *continue_block = lb_create_block(p, "or_return.continue");
|
||||||
|
|
||||||
|
lb_emit_if(p, lb_emit_try_has_value(p, rhs), continue_block, return_block);
|
||||||
|
lb_start_block(p, return_block);
|
||||||
|
{
|
||||||
|
Type *proc_type = base_type(p->type);
|
||||||
|
Type *results = proc_type->Proc.results;
|
||||||
|
GB_ASSERT(results != nullptr && results->kind == Type_Tuple);
|
||||||
|
TypeTuple *tuple = &results->Tuple;
|
||||||
|
|
||||||
|
GB_ASSERT(tuple->variables.count != 0);
|
||||||
|
|
||||||
|
Entity *end_entity = tuple->variables[tuple->variables.count-1];
|
||||||
|
rhs = lb_emit_conv(p, rhs, end_entity->type);
|
||||||
|
if (p->type->Proc.has_named_results) {
|
||||||
|
GB_ASSERT(end_entity->token.string.len != 0);
|
||||||
|
|
||||||
|
// NOTE(bill): store the named values before returning
|
||||||
|
lbValue found = map_must_get(&p->module->values, hash_entity(end_entity));
|
||||||
|
lb_emit_store(p, found, rhs);
|
||||||
|
|
||||||
|
lb_build_return_stmt(p, {});
|
||||||
|
} else {
|
||||||
|
GB_ASSERT(tuple->variables.count == 1);
|
||||||
|
lb_build_return_stmt_internal(p, rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lb_start_block(p, continue_block);
|
||||||
|
if (tv.type != nullptr) {
|
||||||
|
return lb_emit_conv(p, lhs, tv.type);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void lb_emit_increment(lbProcedure *p, lbValue addr) {
|
void lb_emit_increment(lbProcedure *p, lbValue addr) {
|
||||||
|
|||||||
+57
-5
@@ -187,6 +187,13 @@ Ast *clone_ast(Ast *node) {
|
|||||||
n->TernaryWhenExpr.cond = clone_ast(n->TernaryWhenExpr.cond);
|
n->TernaryWhenExpr.cond = clone_ast(n->TernaryWhenExpr.cond);
|
||||||
n->TernaryWhenExpr.y = clone_ast(n->TernaryWhenExpr.y);
|
n->TernaryWhenExpr.y = clone_ast(n->TernaryWhenExpr.y);
|
||||||
break;
|
break;
|
||||||
|
case Ast_OrElseExpr:
|
||||||
|
n->OrElseExpr.x = clone_ast(n->OrElseExpr.x);
|
||||||
|
n->OrElseExpr.y = clone_ast(n->OrElseExpr.y);
|
||||||
|
break;
|
||||||
|
case Ast_OrReturnExpr:
|
||||||
|
n->OrReturnExpr.expr = clone_ast(n->OrReturnExpr.expr);
|
||||||
|
break;
|
||||||
case Ast_TypeAssertion:
|
case Ast_TypeAssertion:
|
||||||
n->TypeAssertion.expr = clone_ast(n->TypeAssertion.expr);
|
n->TypeAssertion.expr = clone_ast(n->TypeAssertion.expr);
|
||||||
n->TypeAssertion.type = clone_ast(n->TypeAssertion.type);
|
n->TypeAssertion.type = clone_ast(n->TypeAssertion.type);
|
||||||
@@ -685,6 +692,21 @@ Ast *ast_ternary_when_expr(AstFile *f, Ast *x, Ast *cond, Ast *y) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ast *ast_or_else_expr(AstFile *f, Ast *x, Token const &token, Ast *y) {
|
||||||
|
Ast *result = alloc_ast_node(f, Ast_OrElseExpr);
|
||||||
|
result->OrElseExpr.x = x;
|
||||||
|
result->OrElseExpr.token = token;
|
||||||
|
result->OrElseExpr.y = y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ast *ast_or_return_expr(AstFile *f, Ast *expr, Token const &token) {
|
||||||
|
Ast *result = alloc_ast_node(f, Ast_OrReturnExpr);
|
||||||
|
result->OrReturnExpr.expr = expr;
|
||||||
|
result->OrReturnExpr.token = token;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Ast *ast_type_assertion(AstFile *f, Ast *expr, Token dot, Ast *type) {
|
Ast *ast_type_assertion(AstFile *f, Ast *expr, Token dot, Ast *type) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_TypeAssertion);
|
Ast *result = alloc_ast_node(f, Ast_TypeAssertion);
|
||||||
result->TypeAssertion.expr = expr;
|
result->TypeAssertion.expr = expr;
|
||||||
@@ -1340,6 +1362,8 @@ Token expect_operator(AstFile *f) {
|
|||||||
// okay
|
// okay
|
||||||
} else if (prev.kind == Token_if || prev.kind == Token_when) {
|
} else if (prev.kind == Token_if || prev.kind == Token_when) {
|
||||||
// okay
|
// okay
|
||||||
|
} else if (prev.kind == Token_or_else || prev.kind == Token_or_return) {
|
||||||
|
// okay
|
||||||
} else if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) {
|
} else if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) {
|
||||||
String p = token_to_string(prev);
|
String p = token_to_string(prev);
|
||||||
syntax_error(f->curr_token, "Expected an operator, got '%.*s'",
|
syntax_error(f->curr_token, "Expected an operator, got '%.*s'",
|
||||||
@@ -1674,6 +1698,22 @@ Ast *unselector_expr(Ast *node) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ast *strip_or_return_expr(Ast *node) {
|
||||||
|
for (;;) {
|
||||||
|
if (node == nullptr) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
if (node->kind == Ast_OrReturnExpr) {
|
||||||
|
node = node->OrReturnExpr.expr;
|
||||||
|
} else if (node->kind == Ast_ParenExpr) {
|
||||||
|
node = node->ParenExpr.expr;
|
||||||
|
} else {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Ast *parse_value(AstFile *f);
|
Ast *parse_value(AstFile *f);
|
||||||
|
|
||||||
Array<Ast *> parse_element_list(AstFile *f) {
|
Array<Ast *> parse_element_list(AstFile *f) {
|
||||||
@@ -1892,7 +1932,7 @@ bool ast_on_same_line(Ast *x, Ast *y) {
|
|||||||
|
|
||||||
Ast *parse_force_inlining_operand(AstFile *f, Token token) {
|
Ast *parse_force_inlining_operand(AstFile *f, Token token) {
|
||||||
Ast *expr = parse_unary_expr(f, false);
|
Ast *expr = parse_unary_expr(f, false);
|
||||||
Ast *e = unparen_expr(expr);
|
Ast *e = strip_or_return_expr(expr);
|
||||||
if (e->kind != Ast_ProcLit && e->kind != Ast_CallExpr) {
|
if (e->kind != Ast_ProcLit && e->kind != Ast_CallExpr) {
|
||||||
syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind]));
|
syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind]));
|
||||||
return ast_bad_expr(f, token, f->curr_token);
|
return ast_bad_expr(f, token, f->curr_token);
|
||||||
@@ -2777,6 +2817,10 @@ Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
|
|||||||
operand = ast_deref_expr(f, operand, expect_token(f, Token_Pointer));
|
operand = ast_deref_expr(f, operand, expect_token(f, Token_Pointer));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Token_or_return:
|
||||||
|
operand = ast_or_return_expr(f, operand, expect_token(f, Token_or_return));
|
||||||
|
break;
|
||||||
|
|
||||||
case Token_OpenBrace:
|
case Token_OpenBrace:
|
||||||
if (!lhs && is_literal_type(operand) && f->expr_level >= 0) {
|
if (!lhs && is_literal_type(operand) && f->expr_level >= 0) {
|
||||||
operand = parse_literal_value(f, operand);
|
operand = parse_literal_value(f, operand);
|
||||||
@@ -2870,6 +2914,7 @@ i32 token_precedence(AstFile *f, TokenKind t) {
|
|||||||
case Token_Question:
|
case Token_Question:
|
||||||
case Token_if:
|
case Token_if:
|
||||||
case Token_when:
|
case Token_when:
|
||||||
|
case Token_or_else:
|
||||||
return 1;
|
return 1;
|
||||||
case Token_Ellipsis:
|
case Token_Ellipsis:
|
||||||
case Token_RangeFull:
|
case Token_RangeFull:
|
||||||
@@ -2924,14 +2969,16 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
|
|||||||
// NOTE(bill): This will also catch operators that are not valid "binary" operators
|
// NOTE(bill): This will also catch operators that are not valid "binary" operators
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (op.kind == Token_if || op.kind == Token_when) {
|
Token prev = f->prev_token;
|
||||||
Token prev = f->prev_token;
|
switch (op.kind) {
|
||||||
|
case Token_if:
|
||||||
|
case Token_when:
|
||||||
if (prev.pos.line < op.pos.line) {
|
if (prev.pos.line < op.pos.line) {
|
||||||
// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
|
// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
|
||||||
break;
|
goto loop_end;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
expect_operator(f); // NOTE(bill): error checks too
|
expect_operator(f); // NOTE(bill): error checks too
|
||||||
|
|
||||||
if (op.kind == Token_Question) {
|
if (op.kind == Token_Question) {
|
||||||
@@ -2955,6 +3002,10 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
|
|||||||
Token tok_else = expect_token(f, Token_else);
|
Token tok_else = expect_token(f, Token_else);
|
||||||
Ast *y = parse_expr(f, lhs);
|
Ast *y = parse_expr(f, lhs);
|
||||||
expr = ast_ternary_when_expr(f, x, cond, y);
|
expr = ast_ternary_when_expr(f, x, cond, y);
|
||||||
|
} else if (op.kind == Token_or_else) {
|
||||||
|
Ast *x = expr;
|
||||||
|
Ast *y = parse_expr(f, lhs);
|
||||||
|
expr = ast_or_else_expr(f, x, op, y);
|
||||||
} else {
|
} else {
|
||||||
Ast *right = parse_binary_expr(f, false, prec+1);
|
Ast *right = parse_binary_expr(f, false, prec+1);
|
||||||
if (right == nullptr) {
|
if (right == nullptr) {
|
||||||
@@ -2965,6 +3016,7 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
|
|||||||
|
|
||||||
lhs = false;
|
lhs = false;
|
||||||
}
|
}
|
||||||
|
loop_end:;
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -385,6 +385,8 @@ AST_KIND(_ExprBegin, "", bool) \
|
|||||||
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
||||||
AST_KIND(TernaryIfExpr, "ternary if expression", struct { Ast *x, *cond, *y; }) \
|
AST_KIND(TernaryIfExpr, "ternary if expression", struct { Ast *x, *cond, *y; }) \
|
||||||
AST_KIND(TernaryWhenExpr, "ternary when expression", struct { Ast *x, *cond, *y; }) \
|
AST_KIND(TernaryWhenExpr, "ternary when expression", struct { Ast *x, *cond, *y; }) \
|
||||||
|
AST_KIND(OrElseExpr, "or_else expression", struct { Ast *x; Token token; Ast *y; }) \
|
||||||
|
AST_KIND(OrReturnExpr, "or_return expression", struct { Ast *expr; Token token; }) \
|
||||||
AST_KIND(TypeAssertion, "type assertion", struct { \
|
AST_KIND(TypeAssertion, "type assertion", struct { \
|
||||||
Ast *expr; \
|
Ast *expr; \
|
||||||
Token dot; \
|
Token dot; \
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ Token ast_token(Ast *node) {
|
|||||||
case Ast_DerefExpr: return node->DerefExpr.op;
|
case Ast_DerefExpr: return node->DerefExpr.op;
|
||||||
case Ast_TernaryIfExpr: return ast_token(node->TernaryIfExpr.x);
|
case Ast_TernaryIfExpr: return ast_token(node->TernaryIfExpr.x);
|
||||||
case Ast_TernaryWhenExpr: return ast_token(node->TernaryWhenExpr.x);
|
case Ast_TernaryWhenExpr: return ast_token(node->TernaryWhenExpr.x);
|
||||||
|
case Ast_OrElseExpr: return ast_token(node->OrElseExpr.x);
|
||||||
|
case Ast_OrReturnExpr: return ast_token(node->OrReturnExpr.expr);
|
||||||
case Ast_TypeAssertion: return ast_token(node->TypeAssertion.expr);
|
case Ast_TypeAssertion: return ast_token(node->TypeAssertion.expr);
|
||||||
case Ast_TypeCast: return node->TypeCast.token;
|
case Ast_TypeCast: return node->TypeCast.token;
|
||||||
case Ast_AutoCast: return node->AutoCast.token;
|
case Ast_AutoCast: return node->AutoCast.token;
|
||||||
@@ -175,6 +177,8 @@ Token ast_end_token(Ast *node) {
|
|||||||
case Ast_DerefExpr: return node->DerefExpr.op;
|
case Ast_DerefExpr: return node->DerefExpr.op;
|
||||||
case Ast_TernaryIfExpr: return ast_end_token(node->TernaryIfExpr.y);
|
case Ast_TernaryIfExpr: return ast_end_token(node->TernaryIfExpr.y);
|
||||||
case Ast_TernaryWhenExpr: return ast_end_token(node->TernaryWhenExpr.y);
|
case Ast_TernaryWhenExpr: return ast_end_token(node->TernaryWhenExpr.y);
|
||||||
|
case Ast_OrElseExpr: return ast_end_token(node->OrElseExpr.y);
|
||||||
|
case Ast_OrReturnExpr: return node->OrReturnExpr.token;
|
||||||
case Ast_TypeAssertion: return ast_end_token(node->TypeAssertion.type);
|
case Ast_TypeAssertion: return ast_end_token(node->TypeAssertion.type);
|
||||||
case Ast_TypeCast: return ast_end_token(node->TypeCast.expr);
|
case Ast_TypeCast: return ast_end_token(node->TypeCast.expr);
|
||||||
case Ast_AutoCast: return ast_end_token(node->AutoCast.expr);
|
case Ast_AutoCast: return ast_end_token(node->AutoCast.expr);
|
||||||
|
|||||||
+5
-2
@@ -113,10 +113,12 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
|
|||||||
TOKEN_KIND(Token_transmute, "transmute"), \
|
TOKEN_KIND(Token_transmute, "transmute"), \
|
||||||
TOKEN_KIND(Token_distinct, "distinct"), \
|
TOKEN_KIND(Token_distinct, "distinct"), \
|
||||||
TOKEN_KIND(Token_using, "using"), \
|
TOKEN_KIND(Token_using, "using"), \
|
||||||
|
TOKEN_KIND(Token_context, "context"), \
|
||||||
|
TOKEN_KIND(Token_or_else, "or_else"), \
|
||||||
|
TOKEN_KIND(Token_or_return, "or_return"), \
|
||||||
|
TOKEN_KIND(Token_asm, "asm"), \
|
||||||
TOKEN_KIND(Token_inline, "inline"), \
|
TOKEN_KIND(Token_inline, "inline"), \
|
||||||
TOKEN_KIND(Token_no_inline, "no_inline"), \
|
TOKEN_KIND(Token_no_inline, "no_inline"), \
|
||||||
TOKEN_KIND(Token_context, "context"), \
|
|
||||||
TOKEN_KIND(Token_asm, "asm"), \
|
|
||||||
TOKEN_KIND(Token__KeywordEnd, ""), \
|
TOKEN_KIND(Token__KeywordEnd, ""), \
|
||||||
TOKEN_KIND(Token_Count, "")
|
TOKEN_KIND(Token_Count, "")
|
||||||
|
|
||||||
@@ -1508,6 +1510,7 @@ semicolon_check:;
|
|||||||
case Token_continue:
|
case Token_continue:
|
||||||
case Token_fallthrough:
|
case Token_fallthrough:
|
||||||
case Token_return:
|
case Token_return:
|
||||||
|
case Token_or_return:
|
||||||
/*fallthrough*/
|
/*fallthrough*/
|
||||||
case Token_Integer:
|
case Token_Integer:
|
||||||
case Token_Float:
|
case Token_Float:
|
||||||
|
|||||||
Reference in New Issue
Block a user