Skip to content

Commit

Permalink
0.5.2: Allow trailing comma in calls and parameter declarations #1092.…
Browse files Browse the repository at this point in the history
… Fixes issue where single character filenames like 'a.c3' would be rejected. Improve error messages for incorrect user defined foreach.
  • Loading branch information
lerno committed Dec 18, 2023
1 parent 0870c61 commit 7de5674
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 23 deletions.
48 changes: 26 additions & 22 deletions lib/std/core/string.c3
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,11 @@ fn usz String.utf8_codepoints(s)
return len;
}

macro String.to_integer(string, $Type)

/**
* @require (base <= 10 && base > 1) || base == 16 : "Unsupported base"
**/
macro String.to_integer(string, $Type, int base = 10)
{
usz len = string.len;
usz index = 0;
Expand All @@ -515,24 +519,24 @@ macro String.to_integer(string, $Type)
break;
}
if (len == index) return NumberConversion.MALFORMED_INTEGER?;
$Type base = 10;
if (string[index] == '0')
$Type base_used = ($Type)base;
if (string[index] == '0' && base == 10)
{
index++;
if (index == len) return ($Type)0;
switch (string[index])
{
case 'x':
case 'X':
base = 16;
base_used = 16;
index++;
case 'b':
case 'B':
base = 2;
base_used = 2;
index++;
case 'o':
case 'O':
base = 8;
base_used = 8;
index++;
default:
break;
Expand All @@ -544,39 +548,39 @@ macro String.to_integer(string, $Type)
{
char c = {|
char ch = string[index++];
if (base != 16 || ch < 'A') return (char)(ch - '0');
if (ch <= 'F') return (char)(ch - 'A');
if (base_used != 16 || ch < 'A') return (char)(ch - '0');
if (ch <= 'F') return (char)(ch - 'A' + 10);
if (ch < 'a') return NumberConversion.MALFORMED_INTEGER?;
if (ch > 'f') return NumberConversion.MALFORMED_INTEGER?;
return (char)(ch - 'a');
return (char)(ch - 'a' + 10);
|}!;
if (c >= base) return NumberConversion.MALFORMED_INTEGER?;
if (c >= base_used) return NumberConversion.MALFORMED_INTEGER?;
value = {|
if (is_negative)
{
$Type new_value = value * base - c;
$Type new_value = value * base_used - c;
if (new_value > value) return NumberConversion.INTEGER_OVERFLOW?;
return new_value;
}
$Type new_value = value * base + c;
$Type new_value = value * base_used + c;
if (new_value < value) return NumberConversion.INTEGER_OVERFLOW?;
return new_value;
|}!;
}
return value;
}

fn int128! String.to_int128(s) => s.to_integer(int128);
fn long! String.to_long(s) => s.to_integer(long);
fn int! String.to_int(s) => s.to_integer(int);
fn short! String.to_short(s) => s.to_integer(short);
fn ichar! String.to_ichar(s) => s.to_integer(ichar);
fn int128! String.to_int128(s, int base = 10) => s.to_integer(int128, base);
fn long! String.to_long(s, int base = 10) => s.to_integer(long, base);
fn int! String.to_int(s, int base = 10) => s.to_integer(int, base);
fn short! String.to_short(s, int base = 10) => s.to_integer(short, base);
fn ichar! String.to_ichar(s, int base = 10) => s.to_integer(ichar, base);

fn uint128! String.to_uint128(s) => s.to_integer(uint128);
fn ulong! String.to_ulong(s) => s.to_integer(ulong);
fn uint! String.to_uint(s) => s.to_integer(uint);
fn ushort! String.to_ushort(s) => s.to_integer(ushort);
fn char! String.to_uchar(s) => s.to_integer(char);
fn uint128! String.to_uint128(s, int base = 10) => s.to_integer(uint128, base);
fn ulong! String.to_ulong(s, int base = 10) => s.to_integer(ulong, base);
fn uint! String.to_uint(s, int base = 10) => s.to_integer(uint, base);
fn ushort! String.to_ushort(s, int base = 10) => s.to_integer(ushort, base);
fn char! String.to_uchar(s, int base = 10) => s.to_integer(char, base);

fn double! String.to_double(s) => s.to_real(double);
fn float! String.to_float(s) => s.to_real(float);
Expand Down
3 changes: 3 additions & 0 deletions releasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@

### Fixes
- Fixes issue where single character filenames like 'a.c3' would be rejected.
- Better errors when index type doesn't match len() when doing user defined foreach.
- Fixes to `to_int` for hexadecimal strings.

### Stdlib changes
- Allow `to_int` family functions take a base, parsing base 2-10 and 16.

## 0.5.1 Change list

Expand Down
20 changes: 19 additions & 1 deletion src/compiler/sema_stmts.c
Original file line number Diff line number Diff line change
Expand Up @@ -1426,6 +1426,7 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
SEMA_ERROR(enumerator, "%s does not support 'foreach' with the value by reference.", type_quoted_error_string(enumerator->type));
return false;
}
if (!decl_ok(len) || !decl_ok(by_val) || !decl_ok(by_ref)) return false;
index_macro = value_by_ref ? by_ref : by_val;
assert(index_macro);
index_type = index_macro->func_decl.signature.params[1]->type;
Expand Down Expand Up @@ -1559,7 +1560,24 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
if (len_call)
{
len_decl = decl_new_generated_var(index_type, VARDECL_LOCAL, enumerator->span);
if (!cast_implicit(context, len_call, index_type)) return false;
if (!cast_implicit_silent(context, len_call, index_type))
{
SEMA_ERROR(enumerator,
"'foreach' is not supported, as the length %s cannot "
"be cast implicitly cast to %s - please update your definition.",
type_quoted_error_string(len_call->type), type_quoted_error_string(index_type));
if (len)
{
SEMA_NOTE(len, "The definition of 'len()' is here.");
decl_poison(len);
}
if (index_macro)
{
SEMA_NOTE(index_macro, "The index definition is here.");
decl_poison(index_macro);
}
return false;
}
vec_add(expressions, expr_generate_decl(len_decl, len_call));
}
Expr *idx_init = expr_new_const_int(idx_decl->span, index_type, 0);
Expand Down
6 changes: 6 additions & 0 deletions test/unit/stdlib/core/string.c3
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,10 @@ fn void! test_rindex_of_char()
assert(test.rindex_of_char('l')! == 15);
assert(test.rindex_of_char('h')! == 12);
assert(@catch(test.index_of_char('x')));
}

fn void! test_hex_conversion()
{
assert("0x123aCd".to_long()! == 0x123acd);
assert("123acD".to_long(16)! == 0x123acd);
}

0 comments on commit 7de5674

Please sign in to comment.