mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-13 01:21:38 -07:00
Default result values for procedure types; Named result values in return statements
This commit is contained in:
+25
-35
@@ -121,9 +121,8 @@ var (
|
||||
)
|
||||
|
||||
proc type_info_base(info: ^TypeInfo) -> ^TypeInfo {
|
||||
if info == nil {
|
||||
return nil;
|
||||
}
|
||||
if info == nil -> return nil;
|
||||
|
||||
var base = info;
|
||||
match i in base {
|
||||
case TypeInfo.Named:
|
||||
@@ -134,9 +133,8 @@ proc type_info_base(info: ^TypeInfo) -> ^TypeInfo {
|
||||
|
||||
|
||||
proc type_info_base_without_enum(info: ^TypeInfo) -> ^TypeInfo {
|
||||
if info == nil {
|
||||
return nil;
|
||||
}
|
||||
if info == nil -> return nil;
|
||||
|
||||
var base = info;
|
||||
match i in base {
|
||||
case TypeInfo.Named:
|
||||
@@ -202,16 +200,20 @@ proc make_source_code_location(file: string, line, column: i64, procedure: strin
|
||||
const DEFAULT_ALIGNMENT = align_of([vector 4]f32);
|
||||
|
||||
proc __init_context_from_ptr(c: ^Context, other: ^Context) #cc_contextless {
|
||||
if c == nil {
|
||||
return;
|
||||
}
|
||||
if c == nil -> return;
|
||||
c^ = other^;
|
||||
|
||||
if c.allocator.procedure == nil {
|
||||
c.allocator = default_allocator();
|
||||
}
|
||||
if c.thread_id == 0 {
|
||||
c.thread_id = os.current_thread_id();
|
||||
}
|
||||
}
|
||||
|
||||
proc __init_context(c: ^Context) #cc_contextless {
|
||||
if c == nil {
|
||||
return;
|
||||
}
|
||||
if c == nil -> return;
|
||||
|
||||
if c.allocator.procedure == nil {
|
||||
c.allocator = default_allocator();
|
||||
}
|
||||
@@ -497,9 +499,7 @@ proc __dynamic_array_make(array_: rawptr, elem_size, elem_align: int, len, cap:
|
||||
proc __dynamic_array_reserve(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool {
|
||||
var array = ^raw.DynamicArray(array_);
|
||||
|
||||
if cap <= array.cap {
|
||||
return true;
|
||||
}
|
||||
if cap <= array.cap -> return true;
|
||||
|
||||
// __check_context();
|
||||
if array.allocator.procedure == nil {
|
||||
@@ -512,9 +512,7 @@ proc __dynamic_array_reserve(array_: rawptr, elem_size, elem_align: int, cap: in
|
||||
var allocator = array.allocator;
|
||||
|
||||
var new_data = allocator.procedure(allocator.data, AllocatorMode.Resize, new_size, elem_align, array.data, old_size, 0);
|
||||
if new_data == nil {
|
||||
return false;
|
||||
}
|
||||
if new_data == nil -> return false;
|
||||
|
||||
array.data = new_data;
|
||||
array.cap = cap;
|
||||
@@ -525,9 +523,7 @@ proc __dynamic_array_resize(array_: rawptr, elem_size, elem_align: int, len: int
|
||||
var array = ^raw.DynamicArray(array_);
|
||||
|
||||
var ok = __dynamic_array_reserve(array_, elem_size, elem_align, len);
|
||||
if ok {
|
||||
array.len = len;
|
||||
}
|
||||
if ok -> array.len = len;
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -546,10 +542,9 @@ proc __dynamic_array_append(array_: rawptr, elem_size, elem_align: int,
|
||||
var cap = 2 * array.cap + max(8, item_count);
|
||||
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
|
||||
}
|
||||
if !ok {
|
||||
// TODO(bill): Better error handling for failed reservation
|
||||
return array.len;
|
||||
}
|
||||
// TODO(bill): Better error handling for failed reservation
|
||||
if !ok -> return array.len;
|
||||
|
||||
var data = ^u8(array.data);
|
||||
assert(data != nil);
|
||||
__mem_copy(data + (elem_size*array.len), items, elem_size * item_count);
|
||||
@@ -565,10 +560,9 @@ proc __dynamic_array_append_nothing(array_: rawptr, elem_size, elem_align: int)
|
||||
var cap = 2 * array.cap + max(8, 1);
|
||||
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
|
||||
}
|
||||
if !ok {
|
||||
// TODO(bill): Better error handling for failed reservation
|
||||
return array.len;
|
||||
}
|
||||
// TODO(bill): Better error handling for failed reservation
|
||||
if !ok -> return array.len;
|
||||
|
||||
var data = ^u8(array.data);
|
||||
assert(data != nil);
|
||||
__mem_zero(data + (elem_size*array.len), elem_size);
|
||||
@@ -658,9 +652,7 @@ proc __dynamic_map_rehash(using header: __MapHeader, new_count: int) {
|
||||
|
||||
__dynamic_array_resize(nm_hashes, size_of(int), align_of(int), new_count);
|
||||
__dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len);
|
||||
for i in 0..<new_count {
|
||||
nm.hashes[i] = -1;
|
||||
}
|
||||
for i in 0..<new_count -> nm.hashes[i] = -1;
|
||||
|
||||
for var i = 0; i < m.entries.len; i++ {
|
||||
if len(nm.hashes) == 0 {
|
||||
@@ -750,9 +742,7 @@ proc __dynamic_map_full(using h: __MapHeader) -> bool {
|
||||
|
||||
proc __dynamic_map_hash_equal(h: __MapHeader, a, b: __MapKey) -> bool {
|
||||
if a.hash == b.hash {
|
||||
if h.is_key_string {
|
||||
return a.str == b.str;
|
||||
}
|
||||
if h.is_key_string -> return a.str == b.str;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
+2
-6
@@ -11,9 +11,7 @@ type Decimal struct {
|
||||
|
||||
proc decimal_to_string(buf: []u8, a: ^Decimal) -> string {
|
||||
proc digit_zero(buf: []u8) -> int {
|
||||
for _, i in buf {
|
||||
buf[i] = '0';
|
||||
}
|
||||
for _, i in buf -> buf[i] = '0';
|
||||
return len(buf);
|
||||
}
|
||||
|
||||
@@ -198,9 +196,7 @@ proc shift(a: ^Decimal, k: int) {
|
||||
proc can_round_up(a: ^Decimal, nd: int) -> bool {
|
||||
if nd < 0 || nd >= a.count { return false ; }
|
||||
if a.digits[nd] == '5' && nd+1 == a.count {
|
||||
if a.trunc {
|
||||
return true;
|
||||
}
|
||||
if a.trunc -> return true;
|
||||
return nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
|
||||
}
|
||||
|
||||
|
||||
+44
-88
@@ -189,9 +189,7 @@ proc fprint_type(fd: os.Handle, info: ^TypeInfo) {
|
||||
}
|
||||
|
||||
proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
|
||||
if ti == nil {
|
||||
return;
|
||||
}
|
||||
if ti == nil -> return;
|
||||
|
||||
using TypeInfo;
|
||||
match info in ti {
|
||||
@@ -242,7 +240,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
|
||||
var t = info.params.(^Tuple);
|
||||
write_string(buf, "(");
|
||||
for t, i in t.types {
|
||||
if i > 0 { write_string(buf, ", "); }
|
||||
if i > 0 -> write_string(buf, ", ");
|
||||
write_type(buf, t);
|
||||
}
|
||||
write_string(buf, ")");
|
||||
@@ -253,9 +251,9 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
|
||||
}
|
||||
case Tuple:
|
||||
var count = len(info.names);
|
||||
if count != 1 { write_string(buf, "("); }
|
||||
if count != 1 -> write_string(buf, "(");
|
||||
for name, i in info.names {
|
||||
if i > 0 { write_string(buf, ", "); }
|
||||
if i > 0 -> write_string(buf, ", ");
|
||||
|
||||
var t = info.types[i];
|
||||
|
||||
@@ -265,7 +263,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
|
||||
}
|
||||
write_type(buf, t);
|
||||
}
|
||||
if count != 1 { write_string(buf, ")"); }
|
||||
if count != 1 -> write_string(buf, ")");
|
||||
|
||||
case Array:
|
||||
write_string(buf, "[");
|
||||
@@ -293,8 +291,8 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
|
||||
|
||||
case Struct:
|
||||
write_string(buf, "struct ");
|
||||
if info.packed { write_string(buf, "#packed "); }
|
||||
if info.ordered { write_string(buf, "#ordered "); }
|
||||
if info.packed -> write_string(buf, "#packed ");
|
||||
if info.ordered -> write_string(buf, "#ordered ");
|
||||
if info.custom_align {
|
||||
write_string(buf, "#align ");
|
||||
write_int(buf, i64(info.align), 10);
|
||||
@@ -302,9 +300,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
|
||||
}
|
||||
write_byte(buf, '{');
|
||||
for name, i in info.names {
|
||||
if i > 0 {
|
||||
write_string(buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_type(buf, info.types[i]);
|
||||
@@ -316,18 +312,14 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
|
||||
var cf = info.common_fields;
|
||||
var total_count = 0;
|
||||
for name, i in cf.names {
|
||||
if i > 0 {
|
||||
write_string(buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_type(buf, cf.types[i]);
|
||||
total_count++;
|
||||
}
|
||||
for name, i in info.variant_names {
|
||||
if total_count > 0 || i > 0 {
|
||||
write_string(buf, ", ");
|
||||
}
|
||||
if total_count > 0 || i > 0 -> write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_byte(buf, '{');
|
||||
defer write_byte(buf, '}');
|
||||
@@ -337,9 +329,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
|
||||
|
||||
var vc = len(variant.names)-len(cf.names);
|
||||
for j in 0..vc {
|
||||
if j > 0 {
|
||||
write_string(buf, ", ");
|
||||
}
|
||||
if j > 0 -> write_string(buf, ", ");
|
||||
var index = j + len(cf.names);
|
||||
write_string(buf, variant.names[index]);
|
||||
write_string(buf, ": ");
|
||||
@@ -351,9 +341,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
|
||||
case RawUnion:
|
||||
write_string(buf, "raw_union {");
|
||||
for name, i in info.names {
|
||||
if i > 0 {
|
||||
write_string(buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_type(buf, info.types[i]);
|
||||
@@ -365,9 +353,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
|
||||
write_type(buf, info.base);
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 {
|
||||
write_string(buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
}
|
||||
write_string(buf, "}");
|
||||
@@ -380,9 +366,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) {
|
||||
}
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 {
|
||||
write_string(buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_int(buf, i64(info.bits[i]), 10);
|
||||
@@ -404,9 +388,7 @@ proc _parse_int(s: string, offset: int) -> (result: int, offset: int, ok: bool)
|
||||
var i = 0;
|
||||
for i < len(s[offset..]) {
|
||||
var c = rune(s[offset+i]);
|
||||
if !is_digit(c) {
|
||||
break;
|
||||
}
|
||||
if !is_digit(c) -> break;
|
||||
i++;
|
||||
|
||||
result *= 10;
|
||||
@@ -500,19 +482,13 @@ proc fmt_bool(using fi: ^FmtInfo, b: bool, verb: rune) {
|
||||
|
||||
|
||||
proc fmt_write_padding(fi: ^FmtInfo, width: int) {
|
||||
if width <= 0 {
|
||||
return;
|
||||
}
|
||||
var pad_byte: u8 = '0';
|
||||
if fi.space {
|
||||
pad_byte = ' ';
|
||||
}
|
||||
if width <= 0 -> return;
|
||||
|
||||
var pad_byte: u8 = fi.space ? ' ' : '0';
|
||||
|
||||
var data = string_buffer_data(fi.buf^);
|
||||
var count = min(width, cap(data)-len(data));
|
||||
for _ in 0..<count {
|
||||
write_byte(fi.buf, pad_byte);
|
||||
}
|
||||
for _ in 0..<count -> write_byte(fi.buf, pad_byte);
|
||||
}
|
||||
|
||||
proc _fmt_int(fi: ^FmtInfo, u: u128, base: int, is_signed: bool, bit_size: int, digits: string) {
|
||||
@@ -557,9 +533,9 @@ proc _fmt_int(fi: ^FmtInfo, u: u128, base: int, is_signed: bool, bit_size: int,
|
||||
|
||||
|
||||
var flags: strconv.IntFlag;
|
||||
if fi.hash && !fi.zero { flags |= strconv.IntFlag.Prefix; }
|
||||
if fi.plus { flags |= strconv.IntFlag.Plus; }
|
||||
if fi.space { flags |= strconv.IntFlag.Space; }
|
||||
if fi.hash && !fi.zero -> flags |= strconv.IntFlag.Prefix;
|
||||
if fi.plus -> flags |= strconv.IntFlag.Plus;
|
||||
if fi.space -> flags |= strconv.IntFlag.Space;
|
||||
var s = strconv.append_bits(buf[start..<start], u128(u), base, is_signed, bit_size, digits, flags);
|
||||
|
||||
if fi.hash && fi.zero {
|
||||
@@ -642,11 +618,8 @@ proc fmt_float(fi: ^FmtInfo, v: f64, bit_size: int, verb: rune) {
|
||||
// case 'f', 'F', 'v':
|
||||
|
||||
case 'f', 'F', 'v':
|
||||
var prec: int = 3;
|
||||
var prec: int = fi.prec_set ? fi.prec : 3;
|
||||
var buf: [386]u8;
|
||||
if fi.prec_set {
|
||||
prec = fi.prec;
|
||||
}
|
||||
|
||||
var str = strconv.append_float(buf[1..<1], v, 'f', prec, bit_size);
|
||||
str = string(buf[0..len(str)]);
|
||||
@@ -692,9 +665,7 @@ proc fmt_string(fi: ^FmtInfo, s: string, verb: rune) {
|
||||
defer fi.space = space;
|
||||
|
||||
for i in 0..<len(s) {
|
||||
if i > 0 && space {
|
||||
write_byte(fi.buf, ' ');
|
||||
}
|
||||
if i > 0 && space -> write_byte(fi.buf, ' ');
|
||||
_fmt_int(fi, u128(s[i]), 16, false, 8, verb == 'x' ? __DIGITS_LOWER : __DIGITS_UPPER);
|
||||
}
|
||||
|
||||
@@ -810,9 +781,7 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
|
||||
write_string(fi.buf, info.name);
|
||||
write_byte(fi.buf, '{');
|
||||
for _, i in b.names {
|
||||
if i > 0 {
|
||||
write_string(fi.buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(fi.buf, ", ");
|
||||
write_string(fi.buf, b.names[i]);
|
||||
write_string(fi.buf, " = ");
|
||||
|
||||
@@ -846,9 +815,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
|
||||
write_byte(fi.buf, '[');
|
||||
defer write_byte(fi.buf, ']');
|
||||
for i in 0..<info.count {
|
||||
if i > 0 {
|
||||
write_string(fi.buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(fi.buf, ", ");
|
||||
|
||||
var data = ^u8(v.data) + i*info.elem_size;
|
||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||
}
|
||||
@@ -858,9 +826,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
|
||||
defer write_byte(fi.buf, ']');
|
||||
var array = ^raw.DynamicArray(v.data);
|
||||
for i in 0..<array.len {
|
||||
if i > 0 {
|
||||
write_string(fi.buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(fi.buf, ", ");
|
||||
|
||||
var data = ^u8(array.data) + i*info.elem_size;
|
||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||
}
|
||||
@@ -870,9 +837,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
|
||||
defer write_byte(fi.buf, ']');
|
||||
var slice = ^[]u8(v.data);
|
||||
for _, i in slice {
|
||||
if i > 0 {
|
||||
write_string(fi.buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(fi.buf, ", ");
|
||||
|
||||
var data = &slice[0] + i*info.elem_size;
|
||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||
}
|
||||
@@ -882,9 +848,7 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
|
||||
defer write_byte(fi.buf, '>');
|
||||
|
||||
for i in 0..<info.count {
|
||||
if i > 0 {
|
||||
write_string(fi.buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(fi.buf, ", ");
|
||||
|
||||
var data = ^u8(v.data) + i*info.elem_size;
|
||||
fmt_value(fi, any{rawptr(data), info.elem}, verb);
|
||||
@@ -906,9 +870,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
|
||||
entry_size = ed.elem_size;
|
||||
)
|
||||
for i in 0..<entries.len {
|
||||
if i > 0 {
|
||||
write_string(fi.buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(fi.buf, ", ");
|
||||
|
||||
var data = ^u8(entries.data) + i*entry_size;
|
||||
var header = ^__MapEntryHeader(data);
|
||||
|
||||
@@ -932,9 +895,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
|
||||
defer write_byte(fi.buf, '}');
|
||||
|
||||
for _, i in info.names {
|
||||
if i > 0 {
|
||||
write_string(fi.buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(fi.buf, ", ");
|
||||
|
||||
write_string(fi.buf, info.names[i]);
|
||||
write_string(fi.buf, " = ");
|
||||
var data = ^u8(v.data) + info.offsets[i];
|
||||
@@ -947,9 +909,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) {
|
||||
|
||||
var cf = info.common_fields;
|
||||
for _, i in cf.names {
|
||||
if i > 0 {
|
||||
write_string(fi.buf, ", ");
|
||||
}
|
||||
if i > 0 -> write_string(fi.buf, ", ");
|
||||
|
||||
write_string(fi.buf, cf.names[i]);
|
||||
write_string(fi.buf, " = ");
|
||||
var data = ^u8(v.data) + cf.offsets[i];
|
||||
@@ -1071,9 +1032,8 @@ proc sbprintln(buf: ^StringBuffer, args: ..any) -> string {
|
||||
fi.buf = buf;
|
||||
|
||||
for arg, i in args {
|
||||
if i > 0 {
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
if i > 0 -> write_byte(buf, ' ');
|
||||
|
||||
fmt_value(&fi, args[i], 'v');
|
||||
}
|
||||
write_byte(buf, '\n');
|
||||
@@ -1200,14 +1160,10 @@ proc sbprintf(b: ^StringBuffer, fmt: string, args: ..any) -> string {
|
||||
if !fi.reordered && arg_index < len(args) {
|
||||
write_string(b, "%!(EXTRA ");
|
||||
for arg, index in args[arg_index..] {
|
||||
if index > 0 {
|
||||
write_string(b, ", ");
|
||||
}
|
||||
if arg == nil {
|
||||
write_string(b, "<nil>");
|
||||
} else {
|
||||
fmt_arg(&fi, args[index], 'v');
|
||||
}
|
||||
if index > 0 -> write_string(b, ", ");
|
||||
|
||||
if arg == nil -> write_string(b, "<nil>");
|
||||
else -> fmt_arg(&fi, args[index], 'v');
|
||||
}
|
||||
write_string(b, ")");
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
@echo off
|
||||
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
|
||||
set _NO_DEBUG_HEAP=1
|
||||
|
||||
set path=w:\Odin\misc;%path%
|
||||
|
||||
+72
-7
@@ -1221,15 +1221,64 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
|
||||
isize variable_index = 0;
|
||||
for_array(i, results) {
|
||||
ast_node(field, Field, results[i]);
|
||||
Type *type = check_type(c, field->type);
|
||||
AstNode *default_value = unparen_expr(field->default_value);
|
||||
ExactValue value = {};
|
||||
bool default_is_nil = false;
|
||||
|
||||
Type *type = NULL;
|
||||
if (field->type == NULL) {
|
||||
Operand o = {};
|
||||
check_expr(c, &o, default_value);
|
||||
if (is_operand_nil(o)) {
|
||||
default_is_nil = true;
|
||||
} else if (o.mode != Addressing_Constant) {
|
||||
error(default_value, "Default parameter must be a constant");
|
||||
} else {
|
||||
value = o.value;
|
||||
}
|
||||
|
||||
type = default_type(o.type);
|
||||
} else {
|
||||
type = check_type(c, field->type);
|
||||
|
||||
if (default_value != NULL) {
|
||||
Operand o = {};
|
||||
check_expr_with_type_hint(c, &o, default_value, type);
|
||||
|
||||
if (is_operand_nil(o)) {
|
||||
default_is_nil = true;
|
||||
} else if (o.mode != Addressing_Constant) {
|
||||
error(default_value, "Default parameter must be a constant");
|
||||
} else {
|
||||
value = o.value;
|
||||
}
|
||||
check_is_assignable_to(c, &o, type);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == NULL) {
|
||||
error(results[i], "Invalid parameter type");
|
||||
type = t_invalid;
|
||||
}
|
||||
if (is_type_untyped(type)) {
|
||||
error(results[i], "Cannot determine parameter type from a nil");
|
||||
type = t_invalid;
|
||||
}
|
||||
|
||||
|
||||
if (field->names.count == 0) {
|
||||
Token token = ast_node_token(field->type);
|
||||
token.string = str_lit("");
|
||||
Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
variables[variable_index++] = param;
|
||||
} else {
|
||||
for_array(j, field->names) {
|
||||
Token token = ast_node_token(field->type);
|
||||
Token token = ast_node_token(results[i]);
|
||||
if (field->type != NULL) {
|
||||
token = ast_node_token(field->type);
|
||||
}
|
||||
token.string = str_lit("");
|
||||
|
||||
AstNode *name = field->names[j];
|
||||
@@ -1240,6 +1289,8 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
|
||||
}
|
||||
|
||||
Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
variables[variable_index++] = param;
|
||||
}
|
||||
}
|
||||
@@ -5002,6 +5053,20 @@ isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
isize lookup_procedure_result(TypeProc *pt, String result_name) {
|
||||
isize result_count = pt->result_count;
|
||||
for (isize i = 0; i < result_count; i++) {
|
||||
Entity *e = pt->results->Tuple.variables[i];
|
||||
String name = e->token.string;
|
||||
if (name == "_") {
|
||||
continue;
|
||||
}
|
||||
if (name == result_name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
@@ -5013,7 +5078,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
CallArgumentError err = CallArgumentError_None;
|
||||
|
||||
isize param_count = pt->param_count;
|
||||
bool *params_visited = gb_alloc_array(c->allocator, bool, param_count);
|
||||
bool *visited = gb_alloc_array(c->allocator, bool, param_count);
|
||||
|
||||
for_array(i, ce->args) {
|
||||
AstNode *arg = ce->args[i];
|
||||
@@ -5036,7 +5101,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
err = CallArgumentError_ParameterNotFound;
|
||||
continue;
|
||||
}
|
||||
if (params_visited[index]) {
|
||||
if (visited[index]) {
|
||||
if (show_error) {
|
||||
error(arg, "Duplicate parameter `%.*s` in procedure call", LIT(name));
|
||||
}
|
||||
@@ -5044,7 +5109,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
continue;
|
||||
}
|
||||
|
||||
params_visited[index] = true;
|
||||
visited[index] = true;
|
||||
Operand *o = &operands[i];
|
||||
Entity *e = pt->params->Tuple.variables[index];
|
||||
|
||||
@@ -5076,7 +5141,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
param_count_to_check--;
|
||||
}
|
||||
for (isize i = 0; i < param_count_to_check; i++) {
|
||||
if (!params_visited[i]) {
|
||||
if (!visited[i]) {
|
||||
Entity *e = pt->params->Tuple.variables[i];
|
||||
if (e->token.string == "_") {
|
||||
continue;
|
||||
@@ -5095,7 +5160,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
if (show_error) {
|
||||
gbString str = type_to_string(e->type);
|
||||
error(call, "Parameter `%.*s` of type `%s` is missing in procedure call",
|
||||
LIT(e->token.string), str);
|
||||
LIT(e->token.string), str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
err = CallArgumentError_ParameterMissing;
|
||||
|
||||
+126
-22
@@ -786,37 +786,141 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool first_is_field_value = false;
|
||||
if (rs->results.count > 0) {
|
||||
bool fail = false;
|
||||
first_is_field_value = (rs->results[0]->kind == AstNode_FieldValue);
|
||||
for_array(i, rs->results) {
|
||||
AstNode *arg = rs->results[i];
|
||||
bool mix = false;
|
||||
if (first_is_field_value) {
|
||||
mix = arg->kind != AstNode_FieldValue;
|
||||
} else {
|
||||
mix = arg->kind == AstNode_FieldValue;
|
||||
}
|
||||
if (mix) {
|
||||
error(arg, "Mixture of `field = value` and value elements in a procedure all is not allowed");
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Type *proc_type = c->proc_stack[c->proc_stack.count-1];
|
||||
TypeProc *pt = &proc_type->Proc;
|
||||
isize result_count = 0;
|
||||
if (proc_type->Proc.results) {
|
||||
if (pt->results) {
|
||||
result_count = proc_type->Proc.results->Tuple.variable_count;
|
||||
}
|
||||
|
||||
if (result_count > 0) {
|
||||
Entity **variables = NULL;
|
||||
if (proc_type->Proc.results != NULL) {
|
||||
TypeTuple *tuple = &proc_type->Proc.results->Tuple;
|
||||
variables = tuple->variables;
|
||||
|
||||
isize result_count_excluding_defaults = result_count;
|
||||
for (isize i = result_count-1; i >= 0; i--) {
|
||||
Entity *e = pt->results->Tuple.variables[i];
|
||||
if (e->kind == Entity_TypeName) {
|
||||
break;
|
||||
}
|
||||
if (rs->results.count == 0) {
|
||||
error(node, "Expected %td return values, got 0", result_count);
|
||||
} else {
|
||||
// TokenPos pos = rs->token.pos;
|
||||
// if (pos.line == 10) {
|
||||
// gb_printf_err("%s\n", type_to_string(variables[0]->type));
|
||||
// }
|
||||
check_init_variables(c, variables, result_count,
|
||||
rs->results, str_lit("return statement"));
|
||||
// if (pos.line == 10) {
|
||||
// AstNode *x = rs->results[0];
|
||||
// gb_printf_err("%s\n", expr_to_string(x));
|
||||
// gb_printf_err("%s\n", type_to_string(type_of_expr(&c->info, x)));
|
||||
// }
|
||||
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid ||
|
||||
e->Variable.default_is_nil) {
|
||||
result_count_excluding_defaults--;
|
||||
continue;
|
||||
}
|
||||
} else if (rs->results.count > 0) {
|
||||
error(rs->results[0], "No return values expected");
|
||||
break;
|
||||
}
|
||||
|
||||
Array<Operand> operands = {};
|
||||
defer (array_free(&operands));
|
||||
|
||||
if (first_is_field_value) {
|
||||
array_init_count(&operands, heap_allocator(), rs->results.count);
|
||||
for_array(i, rs->results) {
|
||||
AstNode *arg = rs->results[i];
|
||||
ast_node(fv, FieldValue, arg);
|
||||
check_expr(c, &operands[i], fv->value);
|
||||
}
|
||||
} else {
|
||||
array_init(&operands, heap_allocator(), 2*rs->results.count);
|
||||
check_unpack_arguments(c, -1, &operands, rs->results, false);
|
||||
}
|
||||
|
||||
|
||||
if (first_is_field_value) {
|
||||
bool *visited = gb_alloc_array(c->allocator, bool, result_count);
|
||||
|
||||
for_array(i, rs->results) {
|
||||
AstNode *arg = rs->results[i];
|
||||
ast_node(fv, FieldValue, arg);
|
||||
if (fv->field->kind != AstNode_Ident) {
|
||||
gbString expr_str = expr_to_string(fv->field);
|
||||
error(arg, "Invalid parameter name `%s` in return statement", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
continue;
|
||||
}
|
||||
String name = fv->field->Ident.string;
|
||||
isize index = lookup_procedure_result(pt, name);
|
||||
if (index < 0) {
|
||||
error(arg, "No result named `%.*s` for this procedure type", LIT(name));
|
||||
continue;
|
||||
}
|
||||
if (visited[index]) {
|
||||
error(arg, "Duplicate result `%.*s` in return statement", LIT(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
visited[index] = true;
|
||||
Operand *o = &operands[i];
|
||||
Entity *e = pt->results->Tuple.variables[index];
|
||||
check_assignment(c, &operands[i], e->type, str_lit("return statement"));
|
||||
}
|
||||
|
||||
for (isize i = 0; i < result_count; i++) {
|
||||
if (!visited[i]) {
|
||||
Entity *e = pt->results->Tuple.variables[i];
|
||||
if (e->token.string == "_") {
|
||||
continue;
|
||||
}
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e->Variable.default_is_nil) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gbString str = type_to_string(e->type);
|
||||
error(node, "Return value `%.*s` of type `%s` is missing in return statement",
|
||||
LIT(e->token.string), str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO(bill): Cleanup this checking of variables
|
||||
if (result_count == 0 && rs->results.count > 0) {
|
||||
error(rs->results[0], "No return values expected");
|
||||
} else if (operands.count > result_count) {
|
||||
error(node, "Expected a maximum of %td return values, got %td", result_count, operands.count);
|
||||
} else if (operands.count < result_count_excluding_defaults) {
|
||||
error(node, "Expected %td return values, got %td", result_count_excluding_defaults, operands.count);
|
||||
} else if (result_count_excluding_defaults == 0) {
|
||||
return;
|
||||
} else if (rs->results.count == 0) {
|
||||
error(node, "Expected %td return values, got 0", result_count_excluding_defaults);
|
||||
} else {
|
||||
isize max_count = rs->results.count;
|
||||
for (isize i = 0; i < max_count; i++) {
|
||||
Entity *e = pt->results->Tuple.variables[i];
|
||||
check_assignment(c, &operands[i], e->type, str_lit("return statement"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case_end;
|
||||
|
||||
case_ast_node(fs, ForStmt, node);
|
||||
|
||||
@@ -117,6 +117,39 @@ f64 float_from_string(String string) {
|
||||
i++;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (len-i > 2 &&
|
||||
str[i] == '0' &&
|
||||
str[i+1] == 'h') {
|
||||
i += 2;
|
||||
u8 *text = string.text;
|
||||
isize len = string.len;
|
||||
if (has_prefix) {
|
||||
text += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
u64 base = 16;
|
||||
|
||||
u64 result = {0};
|
||||
for (isize i = 0; i < len; i++) {
|
||||
Rune r = cast(Rune)text[i];
|
||||
if (r == '_') {
|
||||
continue;
|
||||
}
|
||||
u64 v = bit128__digit_value(r);
|
||||
if (v >= base) {
|
||||
break;
|
||||
}
|
||||
result *= base;
|
||||
result += v;
|
||||
}
|
||||
|
||||
|
||||
return *cast(f64 *)&result;
|
||||
}
|
||||
#endif
|
||||
|
||||
f64 value = 0.0;
|
||||
for (; i < len; i++) {
|
||||
Rune r = cast(Rune)str[i];
|
||||
|
||||
+82
-8
@@ -6120,21 +6120,81 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||
case_ast_node(rs, ReturnStmt, node);
|
||||
ir_emit_comment(proc, str_lit("ReturnStmt"));
|
||||
irValue *v = NULL;
|
||||
TypeTuple *return_type_tuple = &proc->type->Proc.results->Tuple;
|
||||
TypeTuple *tuple = &proc->type->Proc.results->Tuple;
|
||||
isize return_count = proc->type->Proc.result_count;
|
||||
if (return_count == 0) {
|
||||
isize res_count = rs->results.count;
|
||||
|
||||
if (res_count > 0 &&
|
||||
rs->results[0]->kind == AstNode_FieldValue) {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
Array<irValue *> results;
|
||||
array_init_count(&results, proc->module->tmp_allocator, return_count);
|
||||
|
||||
for_array(arg_index, rs->results) {
|
||||
AstNode *arg = rs->results[arg_index];
|
||||
ast_node(fv, FieldValue, arg);
|
||||
GB_ASSERT(fv->field->kind == AstNode_Ident);
|
||||
String name = fv->field->Ident.string;
|
||||
isize index = lookup_procedure_result(&proc->type->Proc, name);
|
||||
GB_ASSERT(index >= 0);
|
||||
irValue *expr = ir_build_expr(proc, fv->value);
|
||||
results[index] = expr;
|
||||
}
|
||||
for (isize i = 0; i < return_count; i++) {
|
||||
Entity *e = tuple->variables[i];
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
if (results[i] == NULL) {
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
||||
results[i] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
|
||||
} else {
|
||||
results[i] = ir_value_nil(proc->module->allocator, e->type);
|
||||
}
|
||||
} else {
|
||||
results[i] = ir_emit_conv(proc, results[i], e->type);
|
||||
}
|
||||
}
|
||||
|
||||
if (results.count == 1) {
|
||||
v = results[0];
|
||||
} else {
|
||||
GB_ASSERT(results.count == return_count);
|
||||
|
||||
Type *ret_type = proc->type->Proc.results;
|
||||
v = ir_add_local_generated(proc, ret_type);
|
||||
for_array(i, results) {
|
||||
irValue *field = ir_emit_struct_ep(proc, v, i);
|
||||
irValue *res = results[i];
|
||||
ir_emit_store(proc, field, res);
|
||||
}
|
||||
|
||||
v = ir_emit_load(proc, v);
|
||||
}
|
||||
} else if (return_count == 0) {
|
||||
// No return values
|
||||
} else if (return_count == 1) {
|
||||
Entity *e = return_type_tuple->variables[0];
|
||||
v = ir_build_expr(proc, rs->results[0]);
|
||||
v = ir_emit_conv(proc, v, e->type);
|
||||
Entity *e = tuple->variables[0];
|
||||
if (res_count == 0) {
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
||||
v = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
|
||||
} else {
|
||||
v = ir_value_nil(proc->module->allocator, e->type);
|
||||
}
|
||||
} else {
|
||||
v = ir_build_expr(proc, rs->results[0]);
|
||||
v = ir_emit_conv(proc, v, e->type);
|
||||
}
|
||||
} else {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
Array<irValue *> results;
|
||||
array_init(&results, proc->module->tmp_allocator, return_count);
|
||||
|
||||
for_array(res_index, rs->results) {
|
||||
isize total_index = 0;
|
||||
isize res_index = 0;
|
||||
for (; res_index < res_count; res_index++) {
|
||||
irValue *res = ir_build_expr(proc, rs->results[res_index]);
|
||||
Type *t = ir_type(res);
|
||||
if (t->kind == Type_Tuple) {
|
||||
@@ -6142,16 +6202,31 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||
Entity *e = t->Tuple.variables[i];
|
||||
irValue *v = ir_emit_struct_ev(proc, res, i);
|
||||
array_add(&results, v);
|
||||
total_index++;
|
||||
}
|
||||
} else {
|
||||
array_add(&results, res);
|
||||
total_index++;
|
||||
}
|
||||
}
|
||||
while (total_index < return_count) {
|
||||
Entity *e = tuple->variables[total_index];
|
||||
irValue *res = NULL;
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
||||
res = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
|
||||
} else {
|
||||
res = ir_value_nil(proc->module->allocator, e->type);
|
||||
}
|
||||
array_add(&results, res);
|
||||
total_index++;
|
||||
}
|
||||
|
||||
GB_ASSERT(results.count == return_count);
|
||||
|
||||
Type *ret_type = proc->type->Proc.results;
|
||||
v = ir_add_local_generated(proc, ret_type);
|
||||
for_array(i, results) {
|
||||
Entity *e = return_type_tuple->variables[i];
|
||||
Entity *e = tuple->variables[i];
|
||||
irValue *res = ir_emit_conv(proc, results[i], e->type);
|
||||
irValue *field = ir_emit_struct_ep(proc, v, i);
|
||||
ir_emit_store(proc, field, res);
|
||||
@@ -6159,7 +6234,6 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||
|
||||
v = ir_emit_load(proc, v);
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
}
|
||||
|
||||
ir_emit_return(proc, v);
|
||||
|
||||
+90
-25
@@ -3158,7 +3158,7 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
|
||||
return parse_body(f);
|
||||
}
|
||||
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow);
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters);
|
||||
|
||||
|
||||
AstNode *parse_results(AstFile *f) {
|
||||
@@ -3170,7 +3170,7 @@ AstNode *parse_results(AstFile *f) {
|
||||
CommentGroup empty_group = {};
|
||||
Token begin_token = f->curr_token;
|
||||
Array<AstNode *> empty_names = {};
|
||||
Array<AstNode *> list = make_ast_node_array(f);
|
||||
Array<AstNode *> list = make_ast_node_array(f, 1);
|
||||
AstNode *type = parse_type(f);
|
||||
array_add(&list, ast_field(f, empty_names, type, NULL, 0, empty_group, empty_group));
|
||||
return ast_field_list(f, begin_token, list);
|
||||
@@ -3178,7 +3178,7 @@ AstNode *parse_results(AstFile *f) {
|
||||
|
||||
AstNode *list = NULL;
|
||||
expect_token(f, Token_OpenParen);
|
||||
list = parse_field_list(f, NULL, 0, Token_CloseParen);
|
||||
list = parse_field_list(f, NULL, 0, Token_CloseParen, true);
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
return list;
|
||||
}
|
||||
@@ -3188,7 +3188,7 @@ AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) {
|
||||
AstNode *results = NULL;
|
||||
|
||||
expect_token(f, Token_OpenParen);
|
||||
params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen);
|
||||
params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen, true);
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
results = parse_results(f);
|
||||
|
||||
@@ -3357,7 +3357,7 @@ bool parse_expect_field_separator(AstFile *f, AstNode *param) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow) {
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters) {
|
||||
TokenKind separator = Token_Comma;
|
||||
Token start_token = f->curr_token;
|
||||
|
||||
@@ -3370,13 +3370,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
|
||||
isize total_name_count = 0;
|
||||
bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis;
|
||||
bool is_procedure = allowed_flags == FieldFlag_Signature;
|
||||
|
||||
while (f->curr_token.kind != follow &&
|
||||
f->curr_token.kind != Token_Colon &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
u32 flags = parse_field_prefixes(f);
|
||||
AstNode *param = parse_var_type(f, allow_ellipsis, is_procedure);
|
||||
AstNode *param = parse_var_type(f, allow_ellipsis, allow_default_parameters);
|
||||
AstNodeAndFlags naf = {param, flags};
|
||||
array_add(&list, naf);
|
||||
if (f->curr_token.kind != Token_Comma) {
|
||||
@@ -3403,12 +3402,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
|
||||
if (f->curr_token.kind != Token_Eq) {
|
||||
expect_token_after(f, Token_Colon, "field list");
|
||||
type = parse_var_type(f, allow_ellipsis, is_procedure);
|
||||
type = parse_var_type(f, allow_ellipsis, allow_default_parameters);
|
||||
}
|
||||
if (allow_token(f, Token_Eq)) {
|
||||
// TODO(bill): Should this be true==lhs or false==rhs?
|
||||
default_value = parse_expr(f, false);
|
||||
if (!is_procedure) {
|
||||
if (!allow_default_parameters) {
|
||||
syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
|
||||
}
|
||||
}
|
||||
@@ -3439,12 +3438,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
AstNode *default_value = NULL;
|
||||
if (f->curr_token.kind != Token_Eq) {
|
||||
expect_token_after(f, Token_Colon, "field list");
|
||||
type = parse_var_type(f, allow_ellipsis, is_procedure);
|
||||
type = parse_var_type(f, allow_ellipsis, allow_default_parameters);
|
||||
}
|
||||
if (allow_token(f, Token_Eq)) {
|
||||
// TODO(bill): Should this be true==lhs or false==rhs?
|
||||
default_value = parse_expr(f, false);
|
||||
if (!is_procedure) {
|
||||
if (!allow_default_parameters) {
|
||||
syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
|
||||
}
|
||||
}
|
||||
@@ -3486,7 +3485,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
|
||||
|
||||
AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
|
||||
return parse_field_list(f, field_count_, flags, Token_CloseBrace);
|
||||
return parse_field_list(f, field_count_, flags, Token_CloseBrace, false);
|
||||
}
|
||||
|
||||
AstNode *parse_type_or_ident(AstFile *f) {
|
||||
@@ -3821,7 +3820,14 @@ AstNode *parse_if_stmt(AstFile *f) {
|
||||
syntax_error(f->curr_token, "Expected condition for if statement");
|
||||
}
|
||||
|
||||
body = parse_block_stmt(f, false);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} else {
|
||||
body = parse_block_stmt(f, false);
|
||||
}
|
||||
|
||||
if (allow_token(f, Token_else)) {
|
||||
switch (f->curr_token.kind) {
|
||||
@@ -3831,6 +3837,13 @@ AstNode *parse_if_stmt(AstFile *f) {
|
||||
case Token_OpenBrace:
|
||||
else_stmt = parse_block_stmt(f, false);
|
||||
break;
|
||||
case Token_ArrowRight: {
|
||||
Token arrow = expect_token(f, Token_ArrowRight);
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
syntax_error(f->curr_token, "Expected if statement block statement");
|
||||
else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]);
|
||||
@@ -3858,7 +3871,14 @@ AstNode *parse_when_stmt(AstFile *f) {
|
||||
syntax_error(f->curr_token, "Expected condition for when statement");
|
||||
}
|
||||
|
||||
body = parse_block_stmt(f, true);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} else {
|
||||
body = parse_block_stmt(f, true);
|
||||
}
|
||||
|
||||
if (allow_token(f, Token_else)) {
|
||||
switch (f->curr_token.kind) {
|
||||
@@ -3868,6 +3888,13 @@ AstNode *parse_when_stmt(AstFile *f) {
|
||||
case Token_OpenBrace:
|
||||
else_stmt = parse_block_stmt(f, true);
|
||||
break;
|
||||
case Token_ArrowRight: {
|
||||
Token arrow = expect_token(f, Token_ArrowRight);
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
syntax_error(f->curr_token, "Expected when statement block statement");
|
||||
else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]);
|
||||
@@ -3890,11 +3917,22 @@ AstNode *parse_return_stmt(AstFile *f) {
|
||||
}
|
||||
|
||||
Token token = expect_token(f, Token_return);
|
||||
Array<AstNode *> results;
|
||||
if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
|
||||
results = parse_rhs_expr_list(f);
|
||||
} else {
|
||||
results = make_ast_node_array(f);
|
||||
Array<AstNode *> results = make_ast_node_array(f);
|
||||
|
||||
while (f->curr_token.kind != Token_Semicolon) {
|
||||
AstNode *arg = parse_expr(f, false);
|
||||
if (f->curr_token.kind == Token_Eq) {
|
||||
Token eq = expect_token(f, Token_Eq);
|
||||
AstNode *value = parse_value(f);
|
||||
arg = ast_field_value(f, arg, value, eq);
|
||||
}
|
||||
|
||||
array_add(&results, arg);
|
||||
if (f->curr_token.kind != Token_Comma ||
|
||||
f->curr_token.kind == Token_EOF) {
|
||||
break;
|
||||
}
|
||||
next_token(f);
|
||||
}
|
||||
|
||||
AstNode *end = NULL;
|
||||
@@ -3952,7 +3990,8 @@ AstNode *parse_for_stmt(AstFile *f) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_range && f->curr_token.kind == Token_Semicolon) {
|
||||
if (!is_range && (f->curr_token.kind == Token_Semicolon ||
|
||||
f->curr_token.kind == Token_ArrowRight)) {
|
||||
next_token(f);
|
||||
init = cond;
|
||||
cond = NULL;
|
||||
@@ -3960,7 +3999,8 @@ AstNode *parse_for_stmt(AstFile *f) {
|
||||
cond = parse_simple_stmt(f, StmtAllowFlag_None);
|
||||
}
|
||||
expect_semicolon(f, cond);
|
||||
if (f->curr_token.kind != Token_OpenBrace) {
|
||||
if (f->curr_token.kind != Token_OpenBrace &&
|
||||
f->curr_token.kind != Token_ArrowRight) {
|
||||
post = parse_simple_stmt(f, StmtAllowFlag_None);
|
||||
}
|
||||
}
|
||||
@@ -3968,7 +4008,14 @@ AstNode *parse_for_stmt(AstFile *f) {
|
||||
f->expr_level = prev_level;
|
||||
}
|
||||
|
||||
body = parse_block_stmt(f, false);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} else {
|
||||
body = parse_block_stmt(f, false);
|
||||
}
|
||||
|
||||
if (is_range) {
|
||||
GB_ASSERT(cond->kind == AstNode_AssignStmt);
|
||||
@@ -4002,7 +4049,7 @@ AstNode *parse_for_stmt(AstFile *f) {
|
||||
|
||||
AstNode *parse_case_clause(AstFile *f, bool is_type) {
|
||||
Token token = f->curr_token;
|
||||
Array<AstNode *> list = make_ast_node_array(f);
|
||||
Array<AstNode *> list = {};
|
||||
expect_token(f, Token_case);
|
||||
bool prev_allow_range = f->allow_range;
|
||||
f->allow_range = !is_type;
|
||||
@@ -4224,23 +4271,41 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
|
||||
case Token_push_allocator: {
|
||||
next_token(f);
|
||||
AstNode *body = NULL;
|
||||
isize prev_level = f->expr_level;
|
||||
f->expr_level = -1;
|
||||
AstNode *expr = parse_expr(f, false);
|
||||
f->expr_level = prev_level;
|
||||
|
||||
AstNode *body = parse_block_stmt(f, false);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} else {
|
||||
body = parse_block_stmt(f, false);
|
||||
}
|
||||
|
||||
return ast_push_allocator(f, token, expr, body);
|
||||
} break;
|
||||
|
||||
case Token_push_context: {
|
||||
next_token(f);
|
||||
AstNode *body = NULL;
|
||||
isize prev_level = f->expr_level;
|
||||
f->expr_level = -1;
|
||||
AstNode *expr = parse_expr(f, false);
|
||||
f->expr_level = prev_level;
|
||||
|
||||
AstNode *body = parse_block_stmt(f, false);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} else {
|
||||
body = parse_block_stmt(f, false);
|
||||
}
|
||||
|
||||
return ast_push_context(f, token, expr, body);
|
||||
} break;
|
||||
|
||||
|
||||
+8
-1
@@ -546,7 +546,14 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
||||
if (t->curr - prev <= 2) {
|
||||
token.kind = Token_Invalid;
|
||||
}
|
||||
} else {
|
||||
} /* else if (t->curr_rune == 'h') { // Hexadecimal Float
|
||||
token.kind = Token_Float;
|
||||
advance_to_next_rune(t);
|
||||
scan_mantissa(t, 16);
|
||||
if (t->curr - prev <= 2) {
|
||||
token.kind = Token_Invalid;
|
||||
}
|
||||
} */ else {
|
||||
seen_decimal_point = false;
|
||||
scan_mantissa(t, 10);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user