Fix #809 missing checks on generic types, accepting both types where constants should be and vice versa.

This commit is contained in:
Christoffer Lerno
2023-07-01 23:58:00 +02:00
parent 45820d45e5
commit 21d8a8b6da
9 changed files with 329 additions and 307 deletions

View File

@@ -5,19 +5,19 @@ struct EnumMap
ValueType[Enum.len] values; ValueType[Enum.len] values;
} }
fn void EnumMap.init(EnumMap* this, ValueType init_value) fn void EnumMap.init(&self, ValueType init_value)
{ {
foreach(&a : this.values) foreach(&a : self.values)
{ {
*a = init_value; *a = init_value;
} }
} }
fn void! EnumMap.to_format(EnumMap* map, Formatter* formatter) @dynamic fn void! EnumMap.to_format(&self, Formatter* formatter) @dynamic
{ {
formatter.print("{ ")!; formatter.print("{ ")!;
foreach (i, &value : map.values) foreach (i, &value : self.values)
{ {
if (i != 0) formatter.print(", ")!; if (i != 0) formatter.print(", ")!;
formatter.printf("%s: %s", (Enum)i, *value)!; formatter.printf("%s: %s", (Enum)i, *value)!;
@@ -25,11 +25,11 @@ fn void! EnumMap.to_format(EnumMap* map, Formatter* formatter) @dynamic
formatter.print(" }")!; formatter.print(" }")!;
} }
fn String EnumMap.to_string(EnumMap* map, Allocator* using = mem::heap()) @dynamic fn String EnumMap.to_string(&self, Allocator* using = mem::heap()) @dynamic
{ {
return string::printf("%s", *map); return string::printf("%s", *self);
} }
fn uint EnumMap.len(EnumMap* this) @operator(len) => this.values.len; fn uint EnumMap.len(&self) @operator(len) => self.values.len;
fn ValueType EnumMap.get(EnumMap* this, Enum key) @operator([]) => this.values[key.ordinal]; fn ValueType EnumMap.get(&self, Enum key) @operator([]) => self.values[key.ordinal];
fn void EnumMap.set(EnumMap* this, Enum key, ValueType value) @operator([]=) => this.values[key.ordinal] = value; fn void EnumMap.set(&self, Enum key, ValueType value) @operator([]=) => self.values[key.ordinal] = value;

View File

@@ -1,5 +1,5 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved. // Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license // Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file. // a copy of which can be found in the LICENSE_STDLIB file.
/** /**
@@ -12,120 +12,120 @@ def EnumSetType = $typefrom(private::type_for_enum_elements(Enum.elements)) @pri
const IS_CHAR_ARRAY = Enum.elements > 128; const IS_CHAR_ARRAY = Enum.elements > 128;
def EnumSet = distinct EnumSetType; def EnumSet = distinct EnumSetType;
fn void EnumSet.add(EnumSet* this, Enum v) fn void EnumSet.add(&self, Enum v)
{ {
$if IS_CHAR_ARRAY: $if IS_CHAR_ARRAY:
(*this)[(usz)v / 8] |= (char)(1u << ((usz)v % 8)); (*self)[(usz)v / 8] |= (char)(1u << ((usz)v % 8));
$else $else
*this = (EnumSet)((EnumSetType)*this | 1u << (EnumSetType)v); *self = (EnumSet)((EnumSetType)*self | 1u << (EnumSetType)v);
$endif $endif
} }
fn void EnumSet.clear(EnumSet* this) fn void EnumSet.clear(&self)
{ {
$if IS_CHAR_ARRAY: $if IS_CHAR_ARRAY:
*this = {}; *self = {};
$else $else
*this = 0; *self = 0;
$endif $endif
} }
fn bool EnumSet.remove(EnumSet* this, Enum v) fn bool EnumSet.remove(&self, Enum v)
{ {
$if IS_CHAR_ARRAY: $if IS_CHAR_ARRAY:
if (!this.has(v) @inline) return false; if (!self.has(v) @inline) return false;
(*this)[(usz)v / 8] &= (char)~(1u << ((usz)v % 8)); (*self)[(usz)v / 8] &= (char)~(1u << ((usz)v % 8));
return true; return true;
$else $else
EnumSetType old = (EnumSetType)*this; EnumSetType old = (EnumSetType)*self;
EnumSetType new = old & ~(1u << (EnumSetType)v); EnumSetType new = old & ~(1u << (EnumSetType)v);
*this = (EnumSet)new; *self = (EnumSet)new;
return old != new; return old != new;
$endif $endif
} }
fn bool EnumSet.has(EnumSet* this, Enum v) fn bool EnumSet.has(&self, Enum v)
{ {
$if IS_CHAR_ARRAY: $if IS_CHAR_ARRAY:
return (bool)(((*this)[(usz)v / 8] << ((usz)v % 8)) & 0x01); return (bool)(((*self)[(usz)v / 8] << ((usz)v % 8)) & 0x01);
$else $else
return ((EnumSetType)*this & (1u << (EnumSetType)v)) != 0; return ((EnumSetType)*self & (1u << (EnumSetType)v)) != 0;
$endif $endif
} }
fn void EnumSet.add_all(EnumSet* this, EnumSet s) fn void EnumSet.add_all(&self, EnumSet s)
{ {
$if IS_CHAR_ARRAY: $if IS_CHAR_ARRAY:
foreach (i, c : s) (*this)[i] |= c; foreach (i, c : s) (*self)[i] |= c;
$else $else
*this = (EnumSet)((EnumSetType)*this | (EnumSetType)s); *self = (EnumSet)((EnumSetType)*self | (EnumSetType)s);
$endif $endif
} }
fn void EnumSet.retain_all(EnumSet* this, EnumSet s) fn void EnumSet.retain_all(&self, EnumSet s)
{ {
$if IS_CHAR_ARRAY: $if IS_CHAR_ARRAY:
foreach (i, c : s) (*this)[i] &= c; foreach (i, c : s) (*self)[i] &= c;
$else $else
*this = (EnumSet)((EnumSetType)*this & (EnumSetType)s); *self = (EnumSet)((EnumSetType)*self & (EnumSetType)s);
$endif $endif
} }
fn void EnumSet.remove_all(EnumSet* this, EnumSet s) fn void EnumSet.remove_all(&self, EnumSet s)
{ {
$if IS_CHAR_ARRAY: $if IS_CHAR_ARRAY:
foreach (i, c : s) (*this)[i] &= ~c; foreach (i, c : s) (*self)[i] &= ~c;
$else $else
*this = (EnumSet)((EnumSetType)*this & ~(EnumSetType)s); *self = (EnumSet)((EnumSetType)*self & ~(EnumSetType)s);
$endif $endif
} }
fn EnumSet EnumSet.and_of(EnumSet* this, EnumSet s) fn EnumSet EnumSet.and_of(&self, EnumSet s)
{ {
$if IS_CHAR_ARRAY: $if IS_CHAR_ARRAY:
EnumSet copy = *this; EnumSet copy = *self;
copy.retain_all(s); copy.retain_all(s);
return copy; return copy;
$else $else
return (EnumSet)((EnumSetType)*this & (EnumSetType)s); return (EnumSet)((EnumSetType)*self & (EnumSetType)s);
$endif $endif
} }
fn EnumSet EnumSet.or_of(EnumSet* this, EnumSet s) fn EnumSet EnumSet.or_of(&self, EnumSet s)
{ {
$if IS_CHAR_ARRAY: $if IS_CHAR_ARRAY:
EnumSet copy = *this; EnumSet copy = *self;
copy.add_all(s); copy.add_all(s);
return copy; return copy;
$else $else
return (EnumSet)((EnumSetType)*this | (EnumSetType)s); return (EnumSet)((EnumSetType)*self | (EnumSetType)s);
$endif $endif
} }
fn EnumSet EnumSet.diff_of(EnumSet* this, EnumSet s) fn EnumSet EnumSet.diff_of(&self, EnumSet s)
{ {
$if IS_CHAR_ARRAY: $if IS_CHAR_ARRAY:
EnumSet copy = *this; EnumSet copy = *self;
copy.remove_all(s); copy.remove_all(s);
return copy; return copy;
$else $else
return (EnumSet)((EnumSetType)*this & ~(EnumSetType)s); return (EnumSet)((EnumSetType)*self & ~(EnumSetType)s);
$endif $endif
} }
fn EnumSet EnumSet.xor_of(EnumSet* this, EnumSet s) fn EnumSet EnumSet.xor_of(&self, EnumSet s)
{ {
$if IS_CHAR_ARRAY: $if IS_CHAR_ARRAY:
EnumSet copy = *this; EnumSet copy = *self;
foreach (i, c : s) copy[i] ^= c; foreach (i, c : s) copy[i] ^= c;
return copy; return copy;
$else $else
return (EnumSet)((EnumSetType)*this ^ (EnumSetType)s); return (EnumSet)((EnumSetType)*self ^ (EnumSetType)s);
$endif $endif
} }
fn void! EnumSet.to_format(EnumSet* set, Formatter* formatter) @dynamic fn void! EnumSet.to_format(&set, Formatter* formatter) @dynamic
{ {
formatter.print("[")!; formatter.print("[")!;
bool found = false; bool found = false;
@@ -139,7 +139,7 @@ fn void! EnumSet.to_format(EnumSet* set, Formatter* formatter) @dynamic
formatter.print("]")!; formatter.print("]")!;
} }
fn String EnumSet.to_string(EnumSet* set, Allocator* using = mem::heap()) @dynamic fn String EnumSet.to_string(&set, Allocator* using = mem::heap()) @dynamic
{ {
return string::printf("%s", *set); return string::printf("%s", *set);
} }

View File

@@ -1,5 +1,5 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved. // Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license // Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file. // a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::linkedlist<Type>; module std::collections::linkedlist<Type>;
@@ -18,161 +18,161 @@ struct LinkedList
Node *_last; Node *_last;
} }
fn void LinkedList.push(LinkedList* list, Type value) fn void LinkedList.push(&self, Type value)
{ {
list.link_first(value); self.link_first(value);
} }
fn void LinkedList.push_last(LinkedList* list, Type value) fn void LinkedList.push_last(&self, Type value)
{ {
list.link_last(value); self.link_last(value);
} }
fn void LinkedList.init(LinkedList* list, Allocator* using = mem::heap()) fn void LinkedList.init(&self, Allocator* using = mem::heap())
{ {
*list = { .allocator = using }; *self = { .allocator = using };
} }
fn void LinkedList.tinit(LinkedList* list) => list.init(mem::temp()) @inline; fn void LinkedList.tinit(&self) => self.init(mem::temp()) @inline;
/** /**
* @require list.allocator * @require self.allocator
**/ **/
macro void LinkedList.@free_node(LinkedList &list, Node* node) @private macro void LinkedList.free_node(&self, Node* node) @private
{ {
list.allocator.free(node)!!; self.allocator.free(node)!!;
} }
macro Node* LinkedList.@alloc_node(LinkedList &list) @private macro Node* LinkedList.alloc_node(&self) @private
{ {
if (!list.allocator) list.allocator = mem::heap(); if (!self.allocator) self.allocator = mem::heap();
return malloc(Node, .using = list.allocator); return malloc(Node, .using = self.allocator);
} }
fn void LinkedList.link_first(LinkedList* list, Type value) @private fn void LinkedList.link_first(&self, Type value) @private
{ {
Node *first = list._first; Node *first = self._first;
Node *new_node = list.@alloc_node(); Node *new_node = self.alloc_node();
*new_node = { .next = first, .value = value }; *new_node = { .next = first, .value = value };
list._first = new_node; self._first = new_node;
if (!first) if (!first)
{ {
list._last = new_node; self._last = new_node;
} }
else else
{ {
first.prev = new_node; first.prev = new_node;
} }
list.size++; self.size++;
} }
fn void LinkedList.link_last(LinkedList* list, Type value) @private fn void LinkedList.link_last(&self, Type value) @private
{ {
Node *last = list._last; Node *last = self._last;
Node *new_node = list.@alloc_node(); Node *new_node = self.alloc_node();
*new_node = { .prev = last, .value = value }; *new_node = { .prev = last, .value = value };
list._last = new_node; self._last = new_node;
if (!last) if (!last)
{ {
list._first = new_node; self._first = new_node;
} }
else else
{ {
last.next = new_node; last.next = new_node;
} }
list.size++; self.size++;
} }
fn Type! LinkedList.peek(LinkedList* list) => list.first() @inline; fn Type! LinkedList.peek(&self) => self.first() @inline;
fn Type! LinkedList.peek_last(LinkedList* list) => list.last() @inline; fn Type! LinkedList.peek_last(&self) => self.last() @inline;
fn Type! LinkedList.first(LinkedList *list) fn Type! LinkedList.first(&self)
{ {
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?; if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
return list._first.value; return self._first.value;
} }
fn Type! LinkedList.last(LinkedList* list) fn Type! LinkedList.last(&self)
{ {
if (!list._last) return IteratorResult.NO_MORE_ELEMENT?; if (!self._last) return IteratorResult.NO_MORE_ELEMENT?;
return list._last.value; return self._last.value;
} }
fn void LinkedList.free(LinkedList* list) => list.clear() @inline; fn void LinkedList.free(&self) => self.clear() @inline;
fn void LinkedList.clear(LinkedList* list) fn void LinkedList.clear(&self)
{ {
for (Node* node = list._first; node != null;) for (Node* node = self._first; node != null;)
{ {
Node* next = node.next; Node* next = node.next;
list.@free_node(node); self.free_node(node);
node = next; node = next;
} }
list._first = null; self._first = null;
list._last = null; self._last = null;
list.size = 0; self.size = 0;
} }
fn usz LinkedList.len(LinkedList* list) @inline => list.size; fn usz LinkedList.len(&self) @inline => self.size;
/** /**
* @require index < list.size * @require index < self.size
**/ **/
macro Node* LinkedList.node_at_index(LinkedList* list, usz index) macro Node* LinkedList.node_at_index(&self, usz index)
{ {
if (index * 2 >= list.size) if (index * 2 >= self.size)
{ {
Node* node = list._last; Node* node = self._last;
index = list.size - index - 1; index = self.size - index - 1;
while (index--) node = node.prev; while (index--) node = node.prev;
return node; return node;
} }
Node* node = list._first; Node* node = self._first;
while (index--) node = node.next; while (index--) node = node.next;
return node; return node;
} }
/** /**
* @require index < list.size * @require index < self.size
**/ **/
fn Type LinkedList.get(LinkedList* list, usz index) fn Type LinkedList.get(&self, usz index)
{ {
return list.node_at_index(index).value; return self.node_at_index(index).value;
} }
/** /**
* @require index < list.size * @require index < self.size
**/ **/
fn void LinkedList.set(LinkedList* list, usz index, Type element) fn void LinkedList.set(&self, usz index, Type element)
{ {
list.node_at_index(index).value = element; self.node_at_index(index).value = element;
} }
/** /**
* @require index < list.size * @require index < self.size
**/ **/
fn void LinkedList.remove(LinkedList* list, usz index) fn void LinkedList.remove(&self, usz index)
{ {
list.unlink(list.node_at_index(index)); self.unlink(self.node_at_index(index));
} }
/** /**
* @require index <= list.size * @require index <= self.size
**/ **/
fn void LinkedList.insert(LinkedList* list, usz index, Type element) fn void LinkedList.insert(&self, usz index, Type element)
{ {
switch (index) switch (index)
{ {
case 0: case 0:
list.push(element); self.push(element);
case list.size: case self.size:
list.push_last(element); self.push_last(element);
default: default:
list.link_before(list.node_at_index(index), element); self.link_before(self.node_at_index(index), element);
} }
} }
/** /**
* @require succ != null * @require succ != null
**/ **/
fn void LinkedList.link_before(LinkedList *list, Node *succ, Type value) @private fn void LinkedList.link_before(&self, Node *succ, Type value) @private
{ {
Node* pred = succ.prev; Node* pred = succ.prev;
Node* new_node = malloc(Node); Node* new_node = malloc(Node);
@@ -180,120 +180,110 @@ fn void LinkedList.link_before(LinkedList *list, Node *succ, Type value) @privat
succ.prev = new_node; succ.prev = new_node;
if (!pred) if (!pred)
{ {
list._first = new_node; self._first = new_node;
} }
else else
{ {
pred.next = new_node; pred.next = new_node;
} }
list.size++; self.size++;
} }
/** /**
* @require list && list._first * @require self._first
**/ **/
fn void LinkedList.unlink_first(LinkedList* list) @private fn void LinkedList.unlink_first(&self) @private
{ {
Node* f = list._first; Node* f = self._first;
Node* next = f.next; Node* next = f.next;
list.@free_node(f); self.free_node(f);
list._first = next; self._first = next;
if (!next) if (!next)
{ {
list._last = null; self._last = null;
} }
else else
{ {
next.prev = null; next.prev = null;
} }
list.size--; self.size--;
} }
fn bool LinkedList.remove_value(LinkedList* list, Type t) fn bool LinkedList.remove_value(&self, Type t)
{ {
for (Node* node = list._first; node != null; node = node.next) for (Node* node = self._first; node != null; node = node.next)
{ {
if (node.value == t) if (node.value == t)
{ {
list.unlink(node); self.unlink(node);
return true; return true;
} }
} }
return false; return false;
} }
fn bool LinkedList.remove_last_value(LinkedList* list, Type t) fn bool LinkedList.remove_last_value(&self, Type t)
{ {
for (Node* node = list._last; node != null; node = node.prev) for (Node* node = self._last; node != null; node = node.prev)
{ {
if (node.value == t) if (node.value == t)
{ {
list.unlink(node); self.unlink(node);
return true; return true;
} }
} }
return false; return false;
} }
/** fn Type! LinkedList.pop(&self)
* @param [&inout] list
**/
fn Type! LinkedList.pop(LinkedList* list)
{ {
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?; if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
defer list.unlink_first(); defer self.unlink_first();
return list._first.value; return self._first.value;
}
fn void! LinkedList.remove_last(&self)
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
self.unlink_last();
}
fn void! LinkedList.remove_first(&self)
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
self.unlink_first();
} }
/** /**
* @param [&inout] list * @require self._last
**/ **/
fn void! LinkedList.remove_last(LinkedList* list) fn void LinkedList.unlink_last(&self) @inline @private
{ {
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?; Node* l = self._last;
list.unlink_last();
}
/**
* @param [&inout] list
**/
fn void! LinkedList.remove_first(LinkedList* list)
{
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?;
list.unlink_first();
}
/**
* @param [&inout] list
* @require list._last
**/
fn void LinkedList.unlink_last(LinkedList *list) @inline @private
{
Node* l = list._last;
Node* prev = l.prev; Node* prev = l.prev;
list._last = prev; self._last = prev;
list.@free_node(l); self.free_node(l);
if (!prev) if (!prev)
{ {
list._first = null; self._first = null;
} }
else else
{ {
prev.next = null; prev.next = null;
} }
list.size--; self.size--;
} }
/** /**
* @require list != null, x != null * @require x != null
**/ **/
fn void LinkedList.unlink(LinkedList* list, Node* x) @private fn void LinkedList.unlink(&self, Node* x) @private
{ {
Node* next = x.next; Node* next = x.next;
Node* prev = x.prev; Node* prev = x.prev;
if (!prev) if (!prev)
{ {
list._first = next; self._first = next;
} }
else else
{ {
@@ -301,12 +291,12 @@ fn void LinkedList.unlink(LinkedList* list, Node* x) @private
} }
if (!next) if (!next)
{ {
list._last = prev; self._last = prev;
} }
else else
{ {
next.prev = prev; next.prev = prev;
} }
list.@free_node(x); self.free_node(x);
list.size--; self.size--;
} }

View File

@@ -1,5 +1,5 @@
// Copyright (c) 2021 Christoffer Lerno. All rights reserved. // Copyright (c) 2021 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license // Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file. // a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::list<Type>; module std::collections::list<Type>;
import std::math; import std::math;
@@ -19,38 +19,38 @@ struct List
/** /**
* @require using != null "A valid allocator must be provided" * @require using != null "A valid allocator must be provided"
**/ **/
fn void List.init(List* list, usz initial_capacity = 16, Allocator* using = mem::heap()) fn void List.init(&self, usz initial_capacity = 16, Allocator* using = mem::heap())
{ {
list.allocator = using; self.allocator = using;
list.size = 0; self.size = 0;
if (initial_capacity > 0) if (initial_capacity > 0)
{ {
initial_capacity = math::next_power_of_2(initial_capacity); initial_capacity = math::next_power_of_2(initial_capacity);
list.entries = malloc_aligned(Type, initial_capacity, .alignment = Type[1].alignof, .using = using)!!; self.entries = malloc_aligned(Type, initial_capacity, .alignment = Type[1].alignof, .using = using)!!;
} }
else else
{ {
list.entries = null; self.entries = null;
} }
list.capacity = initial_capacity; self.capacity = initial_capacity;
} }
fn void List.tinit(List* list, usz initial_capacity = 16) fn void List.tinit(&self, usz initial_capacity = 16)
{ {
list.init(initial_capacity, mem::temp()) @inline; self.init(initial_capacity, mem::temp()) @inline;
} }
fn void! List.to_format(List* list, Formatter* formatter) @dynamic fn void! List.to_format(&self, Formatter* formatter) @dynamic
{ {
switch (list.size) switch (self.size)
{ {
case 0: case 0:
formatter.print("[]")!; formatter.print("[]")!;
case 1: case 1:
formatter.printf("[%s]", list.entries[0])!; formatter.printf("[%s]", self.entries[0])!;
default: default:
formatter.print("[")!; formatter.print("[")!;
foreach (i, element : list.entries[:list.size]) foreach (i, element : self.entries[:self.size])
{ {
if (i != 0) formatter.print(", ")!; if (i != 0) formatter.print(", ")!;
formatter.printf("%s", element)!; formatter.printf("%s", element)!;
@@ -59,277 +59,273 @@ fn void! List.to_format(List* list, Formatter* formatter) @dynamic
} }
} }
fn String List.to_string(List* list, Allocator* using = mem::heap()) @dynamic fn String List.to_string(&self, Allocator* using = mem::heap()) @dynamic
{ {
return string::printf("%s", *list); return string::printf("%s", *self);
} }
fn void List.push(List* list, Type element) @inline fn void List.push(&self, Type element) @inline
{ {
list.append(element); self.append(element);
} }
fn void List.append(List* list, Type element) fn void List.append(&self, Type element)
{ {
list.ensure_capacity(); self.ensure_capacity();
list.entries[list.size++] = element; self.entries[self.size++] = element;
} }
/** /**
* @require list.size > 0 * @require self.size > 0
*/ */
fn Type List.pop(List* list) fn Type List.pop(&self)
{ {
return list.entries[--list.size]; return self.entries[--self.size];
} }
fn void List.clear(List* list) fn void List.clear(&self)
{ {
list.size = 0; self.size = 0;
} }
/** /**
* @require list.size > 0 * @require self.size > 0
*/ */
fn Type List.pop_first(List* list) fn Type List.pop_first(&self)
{ {
Type value = list.entries[0]; Type value = self.entries[0];
list.remove_at(0); self.remove_at(0);
return value; return value;
} }
fn void List.remove_at(List* list, usz index) fn void List.remove_at(&self, usz index)
{ {
for (usz i = index + 1; i < list.size; i++) for (usz i = index + 1; i < self.size; i++)
{ {
list.entries[i - 1] = list.entries[i]; self.entries[i - 1] = self.entries[i];
} }
list.size--; self.size--;
} }
fn void List.add_all(List* list, List* other_list) fn void List.add_all(&self, List* other_list)
{ {
if (!other_list.size) return; if (!other_list.size) return;
list.reserve(other_list.size); self.reserve(other_list.size);
foreach (&value : other_list) foreach (&value : other_list)
{ {
list.entries[list.size++] = *value; self.entries[self.size++] = *value;
} }
} }
fn Type[] List.to_array(List* list, Allocator* using = mem::heap()) fn Type[] List.to_array(&self, Allocator* using = mem::heap())
{ {
if (!list.size) return Type[] {}; if (!self.size) return Type[] {};
Type[] result = malloc(Type, list.size, .using = using); Type[] result = malloc(Type, self.size, .using = using);
result[..] = list.entries[:list.size]; result[..] = self.entries[:self.size];
return result; return result;
} }
/** /**
* Reverse the elements in a list. * Reverse the elements in a list.
*
* @param [&inout] list "The list to reverse"
**/ **/
fn void List.reverse(List* list) fn void List.reverse(&self)
{ {
if (list.size < 2) return; if (self.size < 2) return;
usz half = list.size / 2U; usz half = self.size / 2U;
usz end = list.size - 1; usz end = self.size - 1;
for (usz i = 0; i < half; i++) for (usz i = 0; i < half; i++)
{ {
@swap(list.entries[i], list.entries[end - i]); @swap(self.entries[i], self.entries[end - i]);
} }
} }
fn Type[] List.array_view(List* list) fn Type[] List.array_view(&self)
{ {
return list.entries[:list.size]; return self.entries[:self.size];
} }
fn void List.add_array(List* list, Type[] array) fn void List.add_array(&self, Type[] array)
{ {
if (!array.len) return; if (!array.len) return;
list.reserve(array.len); self.reserve(array.len);
foreach (&value : array) foreach (&value : array)
{ {
list.entries[list.size++] = *value; self.entries[self.size++] = *value;
} }
} }
fn void List.push_front(List* list, Type type) @inline fn void List.push_front(&self, Type type) @inline
{ {
list.insert_at(0, type); self.insert_at(0, type);
} }
fn void List.insert_at(List* list, usz index, Type type) fn void List.insert_at(&self, usz index, Type type)
{ {
list.ensure_capacity(); self.ensure_capacity();
for (usz i = list.size; i > index; i--) for (usz i = self.size; i > index; i--)
{ {
list.entries[i] = list.entries[i - 1]; self.entries[i] = self.entries[i - 1];
} }
list.size++; self.size++;
list.entries[index] = type; self.entries[index] = type;
} }
/** /**
* @require index < list.size * @require index < self.size
**/ **/
fn void List.set_at(List* list, usz index, Type type) fn void List.set_at(&self, usz index, Type type)
{ {
list.entries[index] = type; self.entries[index] = type;
} }
fn void List.remove_last(List* list) fn void List.remove_last(&self)
{ {
list.size--; self.size--;
} }
fn void List.remove_first(List* list) fn void List.remove_first(&self)
{ {
list.remove_at(0); self.remove_at(0);
} }
fn Type* List.first(List* list) fn Type* List.first(&self)
{ {
return list.size ? &list.entries[0] : null; return self.size ? &self.entries[0] : null;
} }
fn Type* List.last(List* list) fn Type* List.last(&self)
{ {
return list.size ? &list.entries[list.size - 1] : null; return self.size ? &self.entries[self.size - 1] : null;
} }
fn bool List.is_empty(List* list) fn bool List.is_empty(&self)
{ {
return !list.size; return !self.size;
} }
fn usz List.len(List* list) @operator(len) fn usz List.len(&self) @operator(len)
{ {
return list.size; return self.size;
} }
fn Type List.get(List* list, usz index) fn Type List.get(&self, usz index)
{ {
return list.entries[index]; return self.entries[index];
} }
fn void List.free(List* list) fn void List.free(&self)
{ {
if (!list.allocator) return; if (!self.allocator) return;
free_aligned(list.entries, .using = list.allocator); free_aligned(self.entries, .using = self.allocator);
list.capacity = 0; self.capacity = 0;
list.size = 0; self.size = 0;
list.entries = null; self.entries = null;
} }
fn void List.swap(List* list, usz i, usz j) fn void List.swap(&self, usz i, usz j)
{ {
@swap(list.entries[i], list.entries[j]); @swap(self.entries[i], self.entries[j]);
} }
/** /**
* @param [&inout] list "The list to remove elements from"
* @param filter "The function to determine if it should be removed or not" * @param filter "The function to determine if it should be removed or not"
* @return "the number of deleted elements" * @return "the number of deleted elements"
**/ **/
fn usz List.remove_if(List* list, ElementPredicate filter) fn usz List.remove_if(&self, ElementPredicate filter)
{ {
usz size = list.size; usz size = self.size;
for (usz i = size; i > 0; i--) for (usz i = size; i > 0; i--)
{ {
if (filter(&list.entries[i - 1])) continue; if (filter(&self.entries[i - 1])) continue;
for (usz j = i; j < size; j++) for (usz j = i; j < size; j++)
{ {
list.entries[j - 1] = list.entries[j]; self.entries[j - 1] = self.entries[j];
} }
list.size--; self.size--;
} }
return size - list.size; return size - self.size;
} }
/** /**
* @param [&inout] list "The list to remove elements from"
* @param selection "The function to determine if it should be kept or not" * @param selection "The function to determine if it should be kept or not"
* @return "the number of deleted elements" * @return "the number of deleted elements"
**/ **/
fn usz List.retain_if(List* list, ElementPredicate selection) fn usz List.retain_if(&self, ElementPredicate selection)
{ {
usz size = list.size; usz size = self.size;
for (usz i = size; i > 0; i--) for (usz i = size; i > 0; i--)
{ {
if (!selection(&list.entries[i - 1])) continue; if (!selection(&self.entries[i - 1])) continue;
for (usz j = i; j < size; j++) for (usz j = i; j < size; j++)
{ {
list.entries[j - 1] = list.entries[j]; self.entries[j - 1] = self.entries[j];
} }
list.size--; self.size--;
} }
return size - list.size; return size - self.size;
} }
/** /**
* Reserve at least min_capacity * Reserve at least min_capacity
**/ **/
fn void List.reserve(List* list, usz min_capacity) fn void List.reserve(&self, usz min_capacity)
{ {
if (!min_capacity) return; if (!min_capacity) return;
if (list.capacity >= min_capacity) return; if (self.capacity >= min_capacity) return;
if (!list.allocator) list.allocator = mem::heap(); if (!self.allocator) self.allocator = mem::heap();
min_capacity = math::next_power_of_2(min_capacity); min_capacity = math::next_power_of_2(min_capacity);
list.entries = realloc_aligned(list.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof, .using = list.allocator) ?? null; self.entries = realloc_aligned(self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof, .using = self.allocator) ?? null;
list.capacity = min_capacity; self.capacity = min_capacity;
} }
macro Type List.@item_at(List &list, usz index) @operator([]) macro Type List.@item_at(&self, usz index) @operator([])
{ {
return list.entries[index]; return self.entries[index];
} }
fn Type* List.get_ref(List* list, usz index) @operator(&[]) @inline fn Type* List.get_ref(&self, usz index) @operator(&[]) @inline
{ {
return &list.entries[index]; return &self.entries[index];
} }
fn void List.ensure_capacity(List* list, usz added = 1) @inline @private fn void List.ensure_capacity(&self, usz added = 1) @inline @private
{ {
usz new_size = list.size + added; usz new_size = self.size + added;
if (list.capacity > new_size) return; if (self.capacity > new_size) return;
assert(new_size < usz.max / 2U); assert(new_size < usz.max / 2U);
usz new_capacity = list.capacity ? 2U * list.capacity : 16U; usz new_capacity = self.capacity ? 2U * self.capacity : 16U;
while (new_size >= new_capacity) new_capacity *= 2U; while (new_size >= new_capacity) new_capacity *= 2U;
list.reserve(new_capacity); self.reserve(new_capacity);
} }
// Functions for equatable types // Functions for equatable types
fn usz! List.index_of(List* list, Type type) @if(ELEMENT_IS_EQUATABLE) fn usz! List.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
{ {
foreach (i, v : list) foreach (i, v : self)
{ {
if (v == type) return i; if (v == type) return i;
} }
return SearchResult.MISSING?; return SearchResult.MISSING?;
} }
fn usz! List.rindex_of(List* list, Type type) @if(ELEMENT_IS_EQUATABLE) fn usz! List.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
{ {
foreach_r (i, v : list) foreach_r (i, v : self)
{ {
if (v == type) return i; if (v == type) return i;
} }
return SearchResult.MISSING?; return SearchResult.MISSING?;
} }
fn bool List.equals(List* list, List other_list) @if(ELEMENT_IS_EQUATABLE) fn bool List.equals(&self, List other_list) @if(ELEMENT_IS_EQUATABLE)
{ {
if (list.size != other_list.size) return false; if (self.size != other_list.size) return false;
foreach (i, v : list) foreach (i, v : self)
{ {
if (v != other_list.entries[i]) return false; if (v != other_list.entries[i]) return false;
} }
@@ -339,13 +335,13 @@ fn bool List.equals(List* list, List other_list) @if(ELEMENT_IS_EQUATABLE)
/** /**
* Check for presence of a value in a list. * Check for presence of a value in a list.
* *
* @param [&in] list "the list to find elements in" * @param [&in] self "the list to find elements in"
* @param value "The value to search for" * @param value "The value to search for"
* @return "True if the value is found, false otherwise" * @return "True if the value is found, false otherwise"
**/ **/
fn bool List.contains(List* list, Type value) @if(ELEMENT_IS_EQUATABLE) fn bool List.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{ {
foreach (i, v : list) foreach (i, v : self)
{ {
if (v == value) return true; if (v == value) return true;
} }
@@ -354,53 +350,53 @@ fn bool List.contains(List* list, Type value) @if(ELEMENT_IS_EQUATABLE)
/** /**
* @param [&inout] list "The list to remove elements from" * @param [&inout] self "The list to remove elements from"
* @param value "The value to remove" * @param value "The value to remove"
* @return "the number of deleted elements." * @return "the number of deleted elements."
**/ **/
fn usz List.remove(List* list, Type value) @if(ELEMENT_IS_EQUATABLE) fn usz List.remove(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{ {
usz size = list.size; usz size = self.size;
for (usz i = size; i > 0; i--) for (usz i = size; i > 0; i--)
{ {
if (list.entries[i - 1] != value) continue; if (self.entries[i - 1] != value) continue;
for (usz j = i; j < size; j++) for (usz j = i; j < size; j++)
{ {
list.entries[j - 1] = list.entries[j]; self.entries[j - 1] = self.entries[j];
} }
list.size--; self.size--;
} }
return size - list.size; return size - self.size;
} }
fn void List.remove_all(List* list, List* other_list) @if(ELEMENT_IS_EQUATABLE) fn void List.remove_all(&self, List* other_list) @if(ELEMENT_IS_EQUATABLE)
{ {
if (!other_list.size) return; if (!other_list.size) return;
foreach (v : other_list) list.remove(v); foreach (v : other_list) self.remove(v);
} }
/** /**
* @param [&in] list * @param [&in] self
* @return "The number non-null values in the list" * @return "The number non-null values in the list"
**/ **/
fn usz List.compact_count(List* list) @if(ELEMENT_IS_POINTER) fn usz List.compact_count(&self) @if(ELEMENT_IS_POINTER)
{ {
usz vals = 0; usz vals = 0;
foreach (v : list) if (v) vals++; foreach (v : self) if (v) vals++;
return vals; return vals;
} }
fn usz List.compact(List* list) @if(ELEMENT_IS_POINTER) fn usz List.compact(&self) @if(ELEMENT_IS_POINTER)
{ {
usz size = list.size; usz size = self.size;
for (usz i = size; i > 0; i--) for (usz i = size; i > 0; i--)
{ {
if (list.entries[i - 1]) continue; if (self.entries[i - 1]) continue;
for (usz j = i; j < size; j++) for (usz j = i; j < size; j++)
{ {
list.entries[j - 1] = list.entries[j]; self.entries[j - 1] = self.entries[j];
} }
list.size--; self.size--;
} }
return size - list.size; return size - self.size;
} }

View File

@@ -3005,9 +3005,15 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module,
VECEACH(module->parameters, i) VECEACH(module->parameters, i)
{ {
const char *param_name = module->parameters[i]; const char *param_name = module->parameters[i];
bool is_value = str_is_valid_constant(param_name);
Expr *param = params[i]; Expr *param = params[i];
if (param->expr_kind != EXPR_TYPEINFO) if (param->expr_kind != EXPR_TYPEINFO)
{ {
if (!is_value)
{
SEMA_ERROR(param, "Expected a type, not a value.");
return NULL;
}
Decl *decl = decl_new_var(param_name, param->span, NULL, VARDECL_CONST); Decl *decl = decl_new_var(param_name, param->span, NULL, VARDECL_CONST);
decl->var.init_expr = param; decl->var.init_expr = param;
decl->type = param->type; decl->type = param->type;
@@ -3015,6 +3021,11 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module,
vec_add(first_context->global_decls, decl); vec_add(first_context->global_decls, decl);
continue; continue;
} }
if (is_value)
{
SEMA_ERROR(param, "Expected a value, not a type.");
return NULL;
}
Decl *decl = decl_new_with_type(param_name, params[i]->span, DECL_TYPEDEF); Decl *decl = decl_new_with_type(param_name, params[i]->span, DECL_TYPEDEF);
decl->resolve_status = RESOLVE_DONE; decl->resolve_status = RESOLVE_DONE;
TypeInfo *type_info = param->type_expr; TypeInfo *type_info = param->type_expr;
@@ -3233,6 +3244,7 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
path->len = scratch_buffer.len; path->len = scratch_buffer.len;
instantiated_module = module_instantiate_generic(c, module, path, instantiated_module = module_instantiate_generic(c, module, path,
decl->define_decl.generic_params, decl->span); decl->define_decl.generic_params, decl->span);
if (!instantiated_module) return decl_poison(decl);
sema_analyze_stage(instantiated_module, c->unit->module->stage - 1); sema_analyze_stage(instantiated_module, c->unit->module->stage - 1);
} }
if (global_context.errors_found) return decl_poison(decl); if (global_context.errors_found) return decl_poison(decl);

View File

@@ -115,6 +115,7 @@ char *str_printf(const char *var, ...) __printflike(1, 2);
char *str_vprintf(const char *var, va_list list); char *str_vprintf(const char *var, va_list list);
void str_ellide_in_place(char *string, size_t max_size_shown); void str_ellide_in_place(char *string, size_t max_size_shown);
bool str_is_valid_lowercase_name(const char *string); bool str_is_valid_lowercase_name(const char *string);
bool str_is_valid_constant(const char *string);
bool str_has_no_uppercase(const char *string); bool str_has_no_uppercase(const char *string);
char *str_copy(const char *start, size_t str_len); char *str_copy(const char *start, size_t str_len);

View File

@@ -43,6 +43,18 @@ bool str_is_valid_lowercase_name(const char *string)
return true; return true;
} }
bool str_is_valid_constant(const char *string)
{
char c;
// Must start with a lower case
int length = 0;
while ((c = *(string++)) != '\0')
{
if (!char_is_upper(c) && c != '_') return false;
}
return true;
}
void str_ellide_in_place(char *string, size_t max_size_shown) void str_ellide_in_place(char *string, size_t max_size_shown)
{ {
size_t len = strlen(string); size_t len = strlen(string);

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.547" #define COMPILER_VERSION "0.4.548"

View File

@@ -0,0 +1,11 @@
module foo<Type, SIZE>;
struct Foo
{
Type[SIZE] x;
}
module bar;
import foo;
def Bar = Foo<int, int>; // #error: Expected a value, not a type
def Baz = Foo<5, 4>; // #error: Expected a type, not a value