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. Fix bug with generics in generics. Fix to error with modified vector parameters. Crash with lhs vector inference. Fixes to priority queue.
  • Loading branch information
lerno committed Dec 23, 2023
1 parent 2595ed5 commit e91f6e2
Show file tree
Hide file tree
Showing 22 changed files with 291 additions and 102 deletions.
41 changes: 22 additions & 19 deletions lib/std/collections/priorityqueue.c3
Original file line number Diff line number Diff line change
Expand Up @@ -74,29 +74,32 @@ fn Type! PrivatePriorityQueue.pop(&self)
usz i = 0;
usz len = self.heap.len();
if (!len) return IteratorResult.NO_MORE_ELEMENT?;
usz newCount = len - 1;
self.heap.swap(0, newCount);
while ((2 * i + 1) < newCount)
usz new_count = len - 1;
self.heap.swap(0, new_count);
while OUTER: ((2 * i + 1) < new_count)
{
usz j = 2 * i + 1;
Type itemj = self.heap[j];
if ((j + 1) < newCount)
Type left = self.heap[j];
Type item = self.heap[i];
switch
{
Type nextj = self.heap[j + 1];
$if MAX:
bool ok = greater(nextj, itemj);
$else
bool ok = less(nextj, itemj);
$endif
if (ok) j++;
case j + 1 < new_count:
Type right = self.heap[j + 1];
$if MAX:
if (!greater(right, left)) nextcase;
if (!greater(right, item)) break OUTER;
$else
if (!greater(left, right)) nextcase;
if (!greater(item, right)) break OUTER;
$endif
j++;
default:
$if MAX:
if (!greater(left, item)) break OUTER;
$else
if (!greater(item, left)) break OUTER;
$endif
}
Type item = self.heap[i];
$if MAX:
bool ok = less(item, itemj);
$else
bool ok = greater(item, itemj);
$endif
if (!ok) break;
self.heap.swap(i, j);
i = j;
}
Expand Down
77 changes: 77 additions & 0 deletions lib/std/core/array.c3
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module std::core::array;
import std::core::array::slice;

/**
* @param [in] array
Expand All @@ -15,6 +16,19 @@ macro index_of(array, element)
return SearchResult.MISSING?;
}

/**
* @require @typekind(array) == VECTOR || @typekind(array) == ARRAY
* @require @typekind(array[0]) == VECTOR || @typekind(array[0]) == ARRAY
**/
macro slice2d(array, x = 0, xlen = 0, y = 0, ylen = 0)
{
if (xlen < 1) xlen = $typeof(array[0]).len + xlen;
if (ylen < 1) ylen = $typeof(array).len + ylen;
var $ElementType = $typeof(array[0][0]);
return Slice2d(<$ElementType>) { ($ElementType*)&array, $typeof(array[0]).len, y, ylen, x, xlen };
}


/**
* @param [in] array
* @param [in] element
Expand Down Expand Up @@ -68,3 +82,66 @@ macro concat_new(arr1, arr2, Allocator* allocator = mem::heap())
* @ensure result.len == arr1.len + arr2.len
**/
macro tconcat(arr1, arr2) => concat(arr1, arr2, mem::temp());

module std::core::array::slice(<Type>);

struct Slice2d
{
Type* ptr;
usz inner_len;
usz ystart;
usz ylen;
usz xstart;
usz xlen;
}

fn usz Slice2d.len(&self) @operator(len)
{
return self.ylen;
}

fn usz Slice2d.count(&self)
{
return self.ylen * self.xlen;
}

macro void Slice2d.@each(&self; @body(usz[<2>], Type))
{
foreach (y, line : *self)
{
foreach (x, val : line)
{
@body({ x, y }, val);
}
}
}

macro void Slice2d.@each_ref(&self; @body(usz[<2>], Type*))
{
foreach (y, line : *self)
{
foreach (x, &val : line)
{
@body({ x, y }, val);
}
}
}

/**
* @require idy >= 0 && idy < self.ylen
**/
macro Type[] Slice2d.get(self, usz idy) @operator([])
{
return (self.ptr + self.inner_len * (idy + self.ystart))[self.xstart:self.xlen];
}

/**
* @require y >= 0 && y < self.ylen
* @require x >= 0 && x < self.xlen
**/
fn Slice2d Slice2d.slice(&self, isz x = 0, isz xlen = 0, isz y = 0, isz ylen = 0)
{
if (xlen < 1) xlen = self.xlen + xlen;
if (ylen < 1) ylen = self.ylen + ylen;
return { self.ptr, self.inner_len, y + self.ystart, ylen, x + self.xstart, xlen };
}
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
20 changes: 19 additions & 1 deletion releasenotes.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
# C3C Release Notes

## 0.5.2 Change list

### Changes / improvements
- Allow trailing comma in calls and parameters #1092.

### 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.
- Fixed issue when using a generic type from a generic type.
- Bug with vector parameters when the size > 2 and modified.
- Missing error on assigning to in-parameters through subscripting.
- Inference of a vector on the lhs of a binary expression would cause a crash.
- Fixes to PriorityQueue

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

## 0.5.1 Change list

### Changes / improvements
- Improved error messages for const errors.
- Do not link with debug libraries unless using static libraries.
- Add 'print-linking' build option.
- System linker may be used even if the target arch is different from current.
- Slice -> array/vector works for constant slice lenghts.
- Slice -> array/vector works for constant slice lengths.

### Fixes
- On Aarch64 use the correct frame pointer type.
Expand Down
33 changes: 16 additions & 17 deletions resources/grammar/grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -443,23 +443,21 @@ arg : param_path '=' expr
arg_list
: arg
| arg_list ',' arg
| arg_list ','
;

call_arg_list
opt_arg_list
: arg_list
| arg_list ';'
| arg_list ';' parameters
| ';'
| ';' parameters
| empty
;

opt_arg_list_trailing
: arg_list
| arg_list ','
| empty
call_arg_list
: opt_arg_list
| opt_arg_list ';'
| opt_arg_list ';' parameters
;


interfaces
: TYPE_IDENT opt_generic_parameters
| interfaces ',' TYPE_IDENT opt_generic_parameters
Expand All @@ -483,7 +481,6 @@ enum_list
enum_constant
: CONST_IDENT opt_attributes
| CONST_IDENT '(' arg_list ')' opt_attributes
| CONST_IDENT '(' arg_list ',' ')' opt_attributes
;

identifier_list
Expand Down Expand Up @@ -573,7 +570,7 @@ var_decl
;

initializer_list
: '{' opt_arg_list_trailing '}'
: '{' opt_arg_list '}'
;

ct_case_stmt
Expand Down Expand Up @@ -1070,11 +1067,15 @@ fn_parameter_list
| '(' ')'
;

parameter_default
: parameter
| parameter '=' expr
;

parameters
: parameter '=' expr
| parameter
| parameters ',' parameter
| parameters ',' parameter '=' expr
: parameter_default
| parameters ',' parameter_default
| parameters ','
;

parameter
Expand Down Expand Up @@ -1178,8 +1179,6 @@ opt_generic_parameters
| empty
;



define_ident
: IDENT '=' path_ident opt_generic_parameters
| CONST_IDENT '=' path_const opt_generic_parameters
Expand Down
6 changes: 6 additions & 0 deletions src/compiler/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type)
return decl;
}

const char *decl_safe_name(Decl *decl)
{
if (!decl) return "<no decl>";
if (decl->name) return decl->name;
return decl_to_name(decl);
}
const char *decl_to_name(Decl *decl)
{
const char *name = decl_to_a_name(decl);
Expand Down
5 changes: 2 additions & 3 deletions src/compiler/compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -604,8 +604,7 @@ static const char **target_expand_source_names(const char** dirs, const char **s
}
goto INVALID_NAME;
}
if (name_len < 4) goto INVALID_NAME;
if (name_len < 5 || !file_has_suffix_in_list(name, name_len, suffix_list, suffix_count)) goto INVALID_NAME;
if (!file_has_suffix_in_list(name, name_len, suffix_list, suffix_count)) goto INVALID_NAME;
vec_add(files, name);
continue;
INVALID_NAME:
Expand All @@ -615,7 +614,7 @@ static const char **target_expand_source_names(const char** dirs, const char **s
continue;
}
if (!error_on_mismatch) continue;
error_exit("File names must end with %s or they cannot be compiled: '%s' is invalid.", suffix_list[0], name);
error_exit("File names must be a non-empty name followed by %s or they cannot be compiled: '%s' is invalid.", suffix_list[0], name);
}
return files;
}
Expand Down
Loading

0 comments on commit e91f6e2

Please sign in to comment.