mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
@ is now part of the name of an attribute or a macro. Macros without '@' must be function-like.
This commit is contained in:
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -78,7 +78,7 @@ jobs:
|
|||||||
|
|
||||||
build-msys2-clang:
|
build-msys2-clang:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
#if: ${{ false }}
|
if: ${{ false }}
|
||||||
strategy:
|
strategy:
|
||||||
# Don't abort runners if a single one fails
|
# Don't abort runners if a single one fails
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import std::mem;
|
|||||||
**/
|
**/
|
||||||
macro alloc($Type, usize elements)
|
macro alloc($Type, usize elements)
|
||||||
{
|
{
|
||||||
assert($Type.max / elements < $Type.sizeof);
|
|
||||||
$Type* ptr = mem::alloc($Type.sizeof * elements, $alignof($Type));
|
$Type* ptr = mem::alloc($Type.sizeof * elements, $alignof($Type));
|
||||||
return ptr[0..(elements - 1)];
|
return ptr[0..(elements - 1)];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ fault VarCastResult
|
|||||||
*
|
*
|
||||||
* @param variable `the variable to store and restore`
|
* @param variable `the variable to store and restore`
|
||||||
**/
|
**/
|
||||||
macro void scope(&variable; @body) @autoimport
|
macro void @scope(&variable; @body) @autoimport
|
||||||
{
|
{
|
||||||
$typeof(variable) temp = variable;
|
$typeof(variable) temp = variable;
|
||||||
defer variable = temp;
|
defer variable = temp;
|
||||||
@@ -51,15 +51,15 @@ fn void panic(char* message, char *file, char *function, uint line) @autoimport
|
|||||||
if (stack) stack = stack.prev;
|
if (stack) stack = stack.prev;
|
||||||
if (stack)
|
if (stack)
|
||||||
{
|
{
|
||||||
libc::fprintf(@libc::stderr(), "\nERROR: '%s'\n", message);
|
libc::fprintf(libc::stderr(), "\nERROR: '%s'\n", message);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
libc::fprintf(@libc::stderr(), "\nERROR: '%s', function %s (%s:%d)\n", message, function, file, line);
|
libc::fprintf(libc::stderr(), "\nERROR: '%s', function %s (%s:%d)\n", message, function, file, line);
|
||||||
}
|
}
|
||||||
while (stack)
|
while (stack)
|
||||||
{
|
{
|
||||||
libc::fprintf(@libc::stderr(), " at function %s (%s:%u)\n", stack.function, stack.file, stack.line);
|
libc::fprintf(libc::stderr(), " at function %s (%s:%u)\n", stack.function, stack.file, stack.line);
|
||||||
if (stack == stack.prev) break;
|
if (stack == stack.prev) break;
|
||||||
stack = stack.prev;
|
stack = stack.prev;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ fn void LinkedList.push(LinkedList *list, Type value)
|
|||||||
private fn void LinkedList.linkFirst(LinkedList *list, Type value)
|
private fn void LinkedList.linkFirst(LinkedList *list, Type value)
|
||||||
{
|
{
|
||||||
Node *first = list.first;
|
Node *first = list.first;
|
||||||
Node *new_node = @mem::malloc(Node);
|
Node *new_node = mem::malloc(Node);
|
||||||
*new_node = { .next = first, .value = value };
|
*new_node = { .next = first, .value = value };
|
||||||
list.first = new_node;
|
list.first = new_node;
|
||||||
if (!first)
|
if (!first)
|
||||||
@@ -90,7 +90,7 @@ fn Type LinkedList.get(LinkedList* list, usize index)
|
|||||||
private fn void LinkedList.linkBefore(LinkedList *list, Node *succ, Type value)
|
private fn void LinkedList.linkBefore(LinkedList *list, Node *succ, Type value)
|
||||||
{
|
{
|
||||||
Node* pred = succ.prev;
|
Node* pred = succ.prev;
|
||||||
Node* new_node = @mem::malloc(Node);
|
Node* new_node = mem::malloc(Node);
|
||||||
*new_node = { .prev = pred, .next = succ, .value = value };
|
*new_node = { .prev = pred, .next = succ, .value = value };
|
||||||
succ.prev = new_node;
|
succ.prev = new_node;
|
||||||
if (!pred)
|
if (!pred)
|
||||||
|
|||||||
@@ -117,12 +117,12 @@ fn void List.free(List *list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
macro Type List.item_at(List &list, usize index) @operator(elementat)
|
macro Type List.@item_at(List &list, usize index) @operator(elementat)
|
||||||
{
|
{
|
||||||
return list.entries[index];
|
return list.entries[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
macro Type* List.item_ref(List &list, usize index) @operator(elementref)
|
macro Type* List.@item_ref(List &list, usize index) @operator(elementref)
|
||||||
{
|
{
|
||||||
return &list.entries[index];
|
return &list.entries[index];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,18 @@
|
|||||||
// 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::mem;
|
module std::mem;
|
||||||
|
|
||||||
macro volatile_load(&x)
|
macro @volatile_load(&x)
|
||||||
{
|
{
|
||||||
return $$volatile_load(&x);
|
return $$volatile_load(&x);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro volatile_store(&x, y)
|
macro @volatile_store(&x, y)
|
||||||
{
|
{
|
||||||
return $$volatile_store(&x, y);
|
return $$volatile_store(&x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require @math::is_power_of_2(alignment)
|
* @require math::is_power_of_2(alignment)
|
||||||
**/
|
**/
|
||||||
fn usize aligned_offset(usize offset, usize alignment)
|
fn usize aligned_offset(usize offset, usize alignment)
|
||||||
{
|
{
|
||||||
@@ -23,7 +23,7 @@ fn usize aligned_offset(usize offset, usize alignment)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require @math::is_power_of_2(alignment)
|
* @require math::is_power_of_2(alignment)
|
||||||
**/
|
**/
|
||||||
fn bool ptr_is_aligned(void* ptr, usize alignment) @inline
|
fn bool ptr_is_aligned(void* ptr, usize alignment) @inline
|
||||||
{
|
{
|
||||||
@@ -32,7 +32,7 @@ fn bool ptr_is_aligned(void* ptr, usize alignment) @inline
|
|||||||
|
|
||||||
fn void copy(char* dst, char* src, usize size) @inline
|
fn void copy(char* dst, char* src, usize size) @inline
|
||||||
{
|
{
|
||||||
@memcpy(dst, src, size);
|
memcpy(dst, src, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro void memcpy(void* dst, void* src, usize size, bool $is_volatile = false, usize $dst_align = 0, usize $src_align = 0)
|
macro void memcpy(void* dst, void* src, usize size, bool $is_volatile = false, usize $dst_align = 0, usize $src_align = 0)
|
||||||
@@ -42,7 +42,7 @@ macro void memcpy(void* dst, void* src, usize size, bool $is_volatile = false, u
|
|||||||
|
|
||||||
fn void set(void* dst, char val, usize bytes) @inline
|
fn void set(void* dst, char val, usize bytes) @inline
|
||||||
{
|
{
|
||||||
@memset(dst, val, bytes);
|
memset(dst, val, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro void memset(void* dst, char val, usize bytes, bool $is_volatile = false, usize $dst_align = 0)
|
macro void memset(void* dst, char val, usize bytes, bool $is_volatile = false, usize $dst_align = 0)
|
||||||
@@ -94,7 +94,7 @@ fn char[] alloc_bytes(usize bytes) @inline
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
*/
|
*/
|
||||||
fn void* alloc(usize size, usize alignment = 0)
|
fn void* alloc(usize size, usize alignment = 0)
|
||||||
{
|
{
|
||||||
@@ -102,7 +102,7 @@ fn void* alloc(usize size, usize alignment = 0)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
*/
|
*/
|
||||||
fn void*! alloc_checked(usize size, usize alignment = 0)
|
fn void*! alloc_checked(usize size, usize alignment = 0)
|
||||||
{
|
{
|
||||||
@@ -111,7 +111,7 @@ fn void*! alloc_checked(usize size, usize alignment = 0)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
*/
|
*/
|
||||||
fn void* calloc(usize size, usize alignment = 0)
|
fn void* calloc(usize size, usize alignment = 0)
|
||||||
{
|
{
|
||||||
@@ -119,7 +119,7 @@ fn void* calloc(usize size, usize alignment = 0)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
*/
|
*/
|
||||||
fn void*! calloc_checked(usize size, usize alignment = 0)
|
fn void*! calloc_checked(usize size, usize alignment = 0)
|
||||||
{
|
{
|
||||||
@@ -127,7 +127,7 @@ fn void*! calloc_checked(usize size, usize alignment = 0)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
*/
|
*/
|
||||||
fn void* realloc(void *ptr, usize new_size, usize alignment = 0)
|
fn void* realloc(void *ptr, usize new_size, usize alignment = 0)
|
||||||
{
|
{
|
||||||
@@ -135,7 +135,7 @@ fn void* realloc(void *ptr, usize new_size, usize alignment = 0)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
*/
|
*/
|
||||||
fn void*! realloc_checked(void *ptr, usize new_size, usize alignment = 0)
|
fn void*! realloc_checked(void *ptr, usize new_size, usize alignment = 0)
|
||||||
{
|
{
|
||||||
@@ -150,7 +150,7 @@ fn void free(void* ptr)
|
|||||||
/**
|
/**
|
||||||
* Run with a specific allocator inside of the macro body.
|
* Run with a specific allocator inside of the macro body.
|
||||||
**/
|
**/
|
||||||
macro void with_allocator(Allocator allocator; @body())
|
macro void @with_allocator(Allocator allocator; @body())
|
||||||
{
|
{
|
||||||
Allocator old_allocator = thread_allocator;
|
Allocator old_allocator = thread_allocator;
|
||||||
thread_allocator = allocator;
|
thread_allocator = allocator;
|
||||||
@@ -172,7 +172,7 @@ struct MemoryArena
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @require alignment > 0 `alignment must be non zero`
|
* @require alignment > 0 `alignment must be non zero`
|
||||||
* @require @math::is_power_of_2(alignment)
|
* @require math::is_power_of_2(alignment)
|
||||||
* @require size > 0
|
* @require size > 0
|
||||||
* @require alignment <= MAX_MEMORY_ALIGNMENT `alignment too big`
|
* @require alignment <= MAX_MEMORY_ALIGNMENT `alignment too big`
|
||||||
* @require this != null
|
* @require this != null
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const AllocatorFunction NULL_ALLOCATOR = &null_allocator_fn;
|
|||||||
const AllocatorFunction SYSTEM_ALLOCATOR = &libc_allocator_fn;
|
const AllocatorFunction SYSTEM_ALLOCATOR = &libc_allocator_fn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
*/
|
*/
|
||||||
fn void*! Allocator.alloc(Allocator *allocator, usize size, usize alignment = 0) @inline
|
fn void*! Allocator.alloc(Allocator *allocator, usize size, usize alignment = 0) @inline
|
||||||
{
|
{
|
||||||
@@ -21,7 +21,7 @@ fn void*! Allocator.alloc(Allocator *allocator, usize size, usize alignment = 0)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
*/
|
*/
|
||||||
fn void*! Allocator.realloc(Allocator *allocator, void* old_pointer, usize size, usize alignment = 0) @inline
|
fn void*! Allocator.realloc(Allocator *allocator, void* old_pointer, usize size, usize alignment = 0) @inline
|
||||||
{
|
{
|
||||||
@@ -29,7 +29,7 @@ fn void*! Allocator.realloc(Allocator *allocator, void* old_pointer, usize size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
*/
|
*/
|
||||||
fn void*! Allocator.calloc(Allocator *allocator, usize size, usize alignment = 0) @inline
|
fn void*! Allocator.calloc(Allocator *allocator, usize size, usize alignment = 0) @inline
|
||||||
{
|
{
|
||||||
@@ -68,7 +68,7 @@ private fn usize alignment_for_allocation(usize alignment) @inline
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
* @require data `unexpectedly missing the allocator`
|
* @require data `unexpectedly missing the allocator`
|
||||||
*/
|
*/
|
||||||
fn void*! arena_allocator_function(void* data, usize size, usize alignment, void* old_pointer, AllocationKind kind)
|
fn void*! arena_allocator_function(void* data, usize size, usize alignment, void* old_pointer, AllocationKind kind)
|
||||||
@@ -126,7 +126,7 @@ fn void*! arena_allocator_function(void* data, usize size, usize alignment, void
|
|||||||
arena.used = 0;
|
arena.used = 0;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DynamicArenaAllocator
|
struct DynamicArenaAllocator
|
||||||
@@ -148,7 +148,7 @@ private struct DynamicArenaPage
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
* @require data `unexpectedly missing the allocator`
|
* @require data `unexpectedly missing the allocator`
|
||||||
*/
|
*/
|
||||||
fn void*! dynamic_arena_allocator_function(void* data, usize size, usize alignment, void* old_pointer, AllocationKind kind)
|
fn void*! dynamic_arena_allocator_function(void* data, usize size, usize alignment, void* old_pointer, AllocationKind kind)
|
||||||
@@ -184,7 +184,7 @@ fn void*! dynamic_arena_allocator_function(void* data, usize size, usize alignme
|
|||||||
allocator.reset();
|
allocator.reset();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -287,12 +287,12 @@ private fn void DynamicArenaAllocator.reset(DynamicArenaAllocator* this)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require @math::is_power_of_2(alignment)
|
* @require math::is_power_of_2(alignment)
|
||||||
* @require size > 0
|
* @require size > 0
|
||||||
*/
|
*/
|
||||||
private fn void*! DynamicArenaAllocator.alloc_new(DynamicArenaAllocator* this, usize size, usize alignment)
|
private fn void*! DynamicArenaAllocator.alloc_new(DynamicArenaAllocator* this, usize size, usize alignment)
|
||||||
{
|
{
|
||||||
usize page_size = @max(this.page_size, size + DEFAULT_SIZE_PREFIX + alignment);
|
usize page_size = max(this.page_size, size + DEFAULT_SIZE_PREFIX + alignment);
|
||||||
void* mem = this.backing_allocator.alloc(page_size)?;
|
void* mem = this.backing_allocator.alloc(page_size)?;
|
||||||
DynamicArenaPage*! page = this.backing_allocator.alloc(DynamicArenaPage.sizeof);
|
DynamicArenaPage*! page = this.backing_allocator.alloc(DynamicArenaPage.sizeof);
|
||||||
if (catch err = page)
|
if (catch err = page)
|
||||||
@@ -313,7 +313,7 @@ private fn void*! DynamicArenaAllocator.alloc_new(DynamicArenaAllocator* this, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require !alignment || @math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
* @require size > 0
|
* @require size > 0
|
||||||
* @require this
|
* @require this
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ private fn void*! null_allocator_fn(void *data, usize bytes, usize alignment, vo
|
|||||||
fn void*! libc_allocator_fn(void *unused, usize bytes, usize alignment, void* old_pointer, AllocationKind kind) @inline
|
fn void*! libc_allocator_fn(void *unused, usize bytes, usize alignment, void* old_pointer, AllocationKind kind) @inline
|
||||||
{
|
{
|
||||||
if (!alignment) alignment = DEFAULT_MEM_ALIGNMENT;
|
if (!alignment) alignment = DEFAULT_MEM_ALIGNMENT;
|
||||||
assert(@math::is_power_of_2(alignment), "Alignment was not a power of 2");
|
assert(math::is_power_of_2(alignment), "Alignment was not a power of 2");
|
||||||
|
|
||||||
void* data;
|
void* data;
|
||||||
switch (kind)
|
switch (kind)
|
||||||
@@ -60,5 +60,5 @@ fn void*! libc_allocator_fn(void *unused, usize bytes, usize alignment, void* ol
|
|||||||
libc::free(old_pointer);
|
libc::free(old_pointer);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ macro int factorial($n)
|
|||||||
$if ($n == 0):
|
$if ($n == 0):
|
||||||
return 1;
|
return 1;
|
||||||
$else:
|
$else:
|
||||||
return $n * @factorial($n - 1);
|
return $n * factorial($n - 1);
|
||||||
$endif;
|
$endif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,6 +11,6 @@ extern fn void printf(char *fmt, ...);
|
|||||||
|
|
||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
int x = @factorial(12);
|
int x = factorial(12);
|
||||||
printf("12! = %d\n", x);
|
printf("12! = %d\n", x);
|
||||||
}
|
}
|
||||||
@@ -3,16 +3,12 @@ import std::array;
|
|||||||
import libc;
|
import libc;
|
||||||
import std::mem;
|
import std::mem;
|
||||||
|
|
||||||
macro int max(int a, int b)
|
|
||||||
{
|
|
||||||
return a > b ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn int fannkuchredux(int n)
|
fn int fannkuchredux(int n)
|
||||||
{
|
{
|
||||||
int* perm = @array::make(int, n);
|
int* perm = array::alloc(int, n);
|
||||||
int* perm1 = @array::make(int, n);
|
int* perm1 = array::alloc(int, n);
|
||||||
int* count = @array::make(int, n);
|
int* count = array::alloc(int, n);
|
||||||
int max_flips_count;
|
int max_flips_count;
|
||||||
int perm_count;
|
int perm_count;
|
||||||
int checksum;
|
int checksum;
|
||||||
@@ -42,7 +38,7 @@ fn int fannkuchredux(int n)
|
|||||||
flips_count++;
|
flips_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
max_flips_count = @max(max_flips_count, flips_count);
|
max_flips_count = max(max_flips_count, flips_count);
|
||||||
checksum += perm_count % 2 == 0 ? flips_count : -flips_count;
|
checksum += perm_count % 2 == 0 ? flips_count : -flips_count;
|
||||||
|
|
||||||
/* Use incremental change to generate another permutation */
|
/* Use incremental change to generate another permutation */
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
module game_of_life;
|
module game_of_life;
|
||||||
|
|
||||||
extern fn void printf(char *fmt, ...);
|
|
||||||
extern fn int atoi(char *val);
|
|
||||||
extern void *__stdoutp;
|
|
||||||
extern fn void fflush(void *std);
|
|
||||||
extern fn int rand();
|
|
||||||
extern fn void* malloc(usize size);
|
|
||||||
extern fn void usleep(int time);
|
extern fn void usleep(int time);
|
||||||
|
|
||||||
|
|
||||||
@@ -20,18 +14,18 @@ struct GameBoard
|
|||||||
fn void GameBoard.show(GameBoard *board)
|
fn void GameBoard.show(GameBoard *board)
|
||||||
{
|
{
|
||||||
|
|
||||||
printf("\e[H");
|
libc::printf("\e[H");
|
||||||
char* current = board.world;
|
char* current = board.world;
|
||||||
for (int y = 0; y < board.h; y++)
|
for (int y = 0; y < board.h; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < board.w; x++)
|
for (int x = 0; x < board.w; x++)
|
||||||
{
|
{
|
||||||
printf(*current ? "\e[07m \e[m" : " ");
|
libc::printf(*current ? "\e[07m \e[m" : " ");
|
||||||
current++;
|
current++;
|
||||||
}
|
}
|
||||||
printf("\e[E");
|
libc::printf("\e[E");
|
||||||
}
|
}
|
||||||
fflush(__stdoutp);
|
libc::fflush(libc::stdout());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void GameBoard.evolve(GameBoard *board)
|
fn void GameBoard.evolve(GameBoard *board)
|
||||||
@@ -65,20 +59,20 @@ fn int main(int c, char** v)
|
|||||||
{
|
{
|
||||||
int w = 0;
|
int w = 0;
|
||||||
int h = 0;
|
int h = 0;
|
||||||
if (c > 1) w = atoi(v[1]);
|
if (c > 1) w = libc::atoi(v[1]);
|
||||||
if (c > 2) h = atoi(v[2]);
|
if (c > 2) h = libc::atoi(v[2]);
|
||||||
if (w <= 0) w = 30;
|
if (w <= 0) w = 30;
|
||||||
if (h <= 0) h = 30;
|
if (h <= 0) h = 30;
|
||||||
|
|
||||||
GameBoard board;
|
GameBoard board;
|
||||||
board.w = w;
|
board.w = w;
|
||||||
board.h = h;
|
board.h = h;
|
||||||
board.world = malloc((ulong)(h * w));
|
board.world = libc::malloc((ulong)(h * w));
|
||||||
board.temp = malloc((ulong)(h * w));
|
board.temp = libc::malloc((ulong)(h * w));
|
||||||
|
|
||||||
for (int i = h * w - 1; i >= 0; i--)
|
for (int i = h * w - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
board.world[i] = rand() % 10 == 0 ? 1 : 0;
|
board.world[i] = libc::rand() % 10 == 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
for (int j = 0; j < 1000; j++)
|
for (int j = 0; j < 1000; j++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import std::mem;
|
|||||||
import std::io;
|
import std::io;
|
||||||
import libc;
|
import libc;
|
||||||
|
|
||||||
extern fn void printf(char*, ...);
|
|
||||||
extern fn isize getline(char** linep, usize* linecapp, CFile stream);
|
extern fn isize getline(char** linep, usize* linecapp, CFile stream);
|
||||||
|
|
||||||
struct Game
|
struct Game
|
||||||
@@ -24,7 +23,7 @@ int err_count = 0;
|
|||||||
|
|
||||||
fn int! askGuess(int high)
|
fn int! askGuess(int high)
|
||||||
{
|
{
|
||||||
printf("Guess a number between 1 and %d: ", high);
|
libc::printf("Guess a number between 1 and %d: ", high);
|
||||||
char[] text = readLine()?;
|
char[] text = readLine()?;
|
||||||
char* end = null;
|
char* end = null;
|
||||||
int value = (int)libc::strtol(text.ptr, &end, 10);
|
int value = (int)libc::strtol(text.ptr, &end, 10);
|
||||||
@@ -35,7 +34,7 @@ fn int! askGuess(int high)
|
|||||||
fn char[]! readLine()
|
fn char[]! readLine()
|
||||||
{
|
{
|
||||||
char* chars = mem::talloc(1024)?;
|
char* chars = mem::talloc(1024)?;
|
||||||
isize loaded = getline(&chars, &&(usize)1023, @libc::stdin());
|
isize loaded = getline(&chars, &&(usize)1023, 2libc::stdin());
|
||||||
if (loaded < 0) return InputResult.FAILED_TO_READ!;
|
if (loaded < 0) return InputResult.FAILED_TO_READ!;
|
||||||
chars[loaded] = 0;
|
chars[loaded] = 0;
|
||||||
return chars[0..(loaded - 1)];
|
return chars[0..(loaded - 1)];
|
||||||
@@ -48,13 +47,13 @@ fn int! askGuessMulti(int high)
|
|||||||
int! result = askGuess(high);
|
int! result = askGuess(high);
|
||||||
if (catch(result) == InputResult.NOT_AN_INT)
|
if (catch(result) == InputResult.NOT_AN_INT)
|
||||||
{
|
{
|
||||||
printf("I didn't understand that.\n");
|
libc::printf("I didn't understand that.\n");
|
||||||
err_count++;
|
err_count++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void! Game.play(Game *game)
|
fn void! Game.play(Game *game)
|
||||||
@@ -74,7 +73,7 @@ fn void Game.report(Game *game, int guess)
|
|||||||
if (guess > game.answer) return "too high";
|
if (guess > game.answer) return "too high";
|
||||||
return "the answer";
|
return "the answer";
|
||||||
|};
|
|};
|
||||||
printf("%d is %.*s.\n", guess, (int)desc.len, desc.ptr);
|
libc::printf("%d is %.*s.\n", guess, (int)desc.len, desc.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void Game.update(Game *game, int guess)
|
fn void Game.update(Game *game, int guess)
|
||||||
@@ -90,6 +89,6 @@ fn void! main()
|
|||||||
int answer = libc::rand() % high + 1;
|
int answer = libc::rand() % high + 1;
|
||||||
Game game = { .answer = answer, .high = high };
|
Game game = { .answer = answer, .high = high };
|
||||||
game.play();
|
game.play();
|
||||||
printf("Finished in %d guesses.\n", game.guesses);
|
libc::printf("Finished in %d guesses.\n", game.guesses);
|
||||||
printf("Total input errors: %d.\n", err_count);
|
libc::printf("Total input errors: %d.\n", err_count);
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ fn void main()
|
|||||||
|
|
||||||
Regex r;
|
Regex r;
|
||||||
|
|
||||||
r.initWithOptions("<.+?>", RegexOpt.GLOBAL) else @unreachable;
|
r.initWithOptions("<.+?>", RegexOpt.GLOBAL) else unreachable;
|
||||||
defer r.destroy();
|
defer r.destroy();
|
||||||
|
|
||||||
foreach (RegexMatch* match : r.match(story))
|
foreach (RegexMatch* match : r.match(story))
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ fn void update_game()
|
|||||||
snake[0].position.x += -SQUARE_SIZE;
|
snake[0].position.x += -SQUARE_SIZE;
|
||||||
snake[0].position.y += 0;
|
snake[0].position.y += 0;
|
||||||
default:
|
default:
|
||||||
@unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
for (int i = 1; i < counter_tail; i++)
|
for (int i = 1; i < counter_tail; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ fn void get_random_piece()
|
|||||||
incoming_piece[2][1] = MOVING;
|
incoming_piece[2][1] = MOVING;
|
||||||
incoming_piece[3][1] = MOVING; //S inversa
|
incoming_piece[3][1] = MOVING; //S inversa
|
||||||
default:
|
default:
|
||||||
@unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ fn void eval_AtA_times_u(double[] u, double[] atau) @noinline
|
|||||||
fn int main(int argc, char **argv)
|
fn int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int n = (argc == 2) ? atoi(argv[1]) : 2000;
|
int n = (argc == 2) ? atoi(argv[1]) : 2000;
|
||||||
temparr = @array::make(double, n);
|
temparr = array::alloc(double, n);
|
||||||
double[] u = @array::make(double, n);
|
double[] u = array::alloc(double, n);
|
||||||
double[] v = @array::make(double, n);
|
double[] v = array::alloc(double, n);
|
||||||
foreach(&uval : u) *uval = 1;
|
foreach(&uval : u) *uval = 1;
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,13 +52,13 @@ fn Doc! readDoc(char[] url)
|
|||||||
{
|
{
|
||||||
if (contains(url, "fail")) return ReadError.BAD_READ!;
|
if (contains(url, "fail")) return ReadError.BAD_READ!;
|
||||||
if (contains(url, "head-missing")) return { .head = null };
|
if (contains(url, "head-missing")) return { .head = null };
|
||||||
if (contains(url, "title-missing")) return { @dupe(Head { .title = null })? };
|
if (contains(url, "title-missing")) return { dupe(Head { .title = null })? };
|
||||||
if (contains(url, "title-empty")) return { @dupe(Head { .title = @dupe((char[])"")? })? };
|
if (contains(url, "title-empty")) return { dupe(Head { .title = dupe((char[])"")? })? };
|
||||||
// Not particularly elegant due to missing string functions.
|
// Not particularly elegant due to missing string functions.
|
||||||
int len = libc::snprintf(null, 0, "Title of %.*s", (int)url.len, url.ptr);
|
int len = libc::snprintf(null, 0, "Title of %.*s", (int)url.len, url.ptr);
|
||||||
char* str = mem::alloc_checked(len + 1)?;
|
char* str = mem::alloc_checked(len + 1)?;
|
||||||
libc::snprintf(str, len + 1, "Title of %.*s", (int)url.len, url.ptr);
|
libc::snprintf(str, len + 1, "Title of %.*s", (int)url.len, url.ptr);
|
||||||
return { @dupe(Head { .title = @dupe(str[..len - 1])? })? };
|
return { dupe(Head { .title = dupe(str[..len - 1])? })? };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Summary buildSummary(Doc doc)
|
fn Summary buildSummary(Doc doc)
|
||||||
@@ -132,13 +132,13 @@ fn void main()
|
|||||||
Allocator allocator = mem::dynamic_arena_allocator(&dynamic_arena);
|
Allocator allocator = mem::dynamic_arena_allocator(&dynamic_arena);
|
||||||
foreach (char[] url : URLS)
|
foreach (char[] url : URLS)
|
||||||
{
|
{
|
||||||
@mem::with_allocator(allocator)
|
mem::@with_allocator(allocator)
|
||||||
{
|
{
|
||||||
// Yes, it's pretty onerous to print strings for the moment in C3
|
// Yes, it's pretty onerous to print strings for the moment in C3
|
||||||
libc::printf(`Checking "https://%.*s/":` "\n", (int)url.len, url.ptr);
|
libc::printf(`Checking "https://%.*s/":` "\n", (int)url.len, url.ptr);
|
||||||
Summary summary = readAndBuildSummary(url);
|
Summary summary = readAndBuildSummary(url);
|
||||||
libc::printf(" Summary: ");
|
libc::printf(" Summary: ");
|
||||||
summary.print(@libc::stdout());
|
summary.print(libc::stdout());
|
||||||
libc::printf("\n");
|
libc::printf("\n");
|
||||||
char[] title_sure = summary.title ? *summary.title : "";
|
char[] title_sure = summary.title ? *summary.title : "";
|
||||||
libc::printf(" Title: %.*s\n", (int)title_sure.len, title_sure.ptr);
|
libc::printf(" Title: %.*s\n", (int)title_sure.len, title_sure.ptr);
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ fn void get_random_piece()
|
|||||||
incoming_piece[2][1] = MOVING;
|
incoming_piece[2][1] = MOVING;
|
||||||
incoming_piece[3][1] = MOVING; //S inversa
|
incoming_piece[3][1] = MOVING; //S inversa
|
||||||
default:
|
default:
|
||||||
@unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,15 +25,15 @@ struct TopoList
|
|||||||
|
|
||||||
fn void sort(InputPair[] pairs, uint elements)
|
fn void sort(InputPair[] pairs, uint elements)
|
||||||
{
|
{
|
||||||
InputPair[] result = @array::make(InputPair, pairs.len);
|
InputPair[] result = array::alloc(InputPair, pairs.len);
|
||||||
TopoList* top = @array::make(TopoList, elements);
|
TopoList* top = array::alloc(TopoList, elements);
|
||||||
for (int i = 0; i < pairs.len; i++)
|
for (int i = 0; i < pairs.len; i++)
|
||||||
{
|
{
|
||||||
InputPair pair = pairs[i];
|
InputPair pair = pairs[i];
|
||||||
assert(pair.value >= 0 && pair.value < elements);
|
assert(pair.value >= 0 && pair.value < elements);
|
||||||
assert(pair.successor >= 0 && pair.successor < elements);
|
assert(pair.successor >= 0 && pair.successor < elements);
|
||||||
top[pair.successor].count++;
|
top[pair.successor].count++;
|
||||||
Entry* successor_entry = @mem::malloc(Entry);
|
Entry* successor_entry = mem::malloc(Entry);
|
||||||
*successor_entry = { pair.successor, null };
|
*successor_entry = { pair.successor, null };
|
||||||
Entry** next_ref = &top[pair.value].next;
|
Entry** next_ref = &top[pair.value].next;
|
||||||
while (*next_ref)
|
while (*next_ref)
|
||||||
@@ -42,7 +42,7 @@ fn void sort(InputPair[] pairs, uint elements)
|
|||||||
}
|
}
|
||||||
*next_ref = successor_entry;
|
*next_ref = successor_entry;
|
||||||
}
|
}
|
||||||
int[] intout = @array::make(int, elements);
|
int[] intout = array::alloc(int, elements);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while LOOP: (1)
|
while LOOP: (1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -275,7 +275,6 @@ bool expr_is_pure(Expr *expr)
|
|||||||
case EXPR_RETHROW:
|
case EXPR_RETHROW:
|
||||||
case EXPR_HASH_IDENT:
|
case EXPR_HASH_IDENT:
|
||||||
case EXPR_MACRO_BLOCK:
|
case EXPR_MACRO_BLOCK:
|
||||||
case EXPR_MACRO_EXPANSION:
|
|
||||||
case EXPR_FLATPATH:
|
case EXPR_FLATPATH:
|
||||||
case EXPR_INITIALIZER_LIST:
|
case EXPR_INITIALIZER_LIST:
|
||||||
case EXPR_DESIGNATED_INITIALIZER_LIST:
|
case EXPR_DESIGNATED_INITIALIZER_LIST:
|
||||||
@@ -490,4 +489,15 @@ bool ast_is_not_empty(Ast *ast)
|
|||||||
return ast_is_not_empty(stmt);
|
return ast_is_not_empty(stmt);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AttributeType attribute_by_name(Attr *attr)
|
||||||
|
{
|
||||||
|
const char *attribute = attr->name;
|
||||||
|
for (unsigned i = 0; i < NUMBER_OF_ATTRIBUTES; i++)
|
||||||
|
{
|
||||||
|
if (attribute_list[i] == attribute) return (AttributeType)i;
|
||||||
|
}
|
||||||
|
return ATTRIBUTE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -793,12 +793,6 @@ typedef struct
|
|||||||
};
|
};
|
||||||
} ExprCtCall;
|
} ExprCtCall;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Expr *inner;
|
|
||||||
Decl *decl;
|
|
||||||
} ExprMacroExpansion;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
CastKind kind : 8;
|
CastKind kind : 8;
|
||||||
@@ -955,7 +949,6 @@ struct Expr_
|
|||||||
ExprIdentifierRaw ct_ident_expr; // 24
|
ExprIdentifierRaw ct_ident_expr; // 24
|
||||||
ExprCtCall ct_call_expr; // 24
|
ExprCtCall ct_call_expr; // 24
|
||||||
ExprIdentifierRaw ct_macro_ident_expr; // 24
|
ExprIdentifierRaw ct_macro_ident_expr; // 24
|
||||||
ExprMacroExpansion macro_expansion_expr; // 16
|
|
||||||
ExprIdentifierRaw hash_ident_expr; // 24
|
ExprIdentifierRaw hash_ident_expr; // 24
|
||||||
TypeInfo *typeid_expr; // 8
|
TypeInfo *typeid_expr; // 8
|
||||||
ExprBodyExpansion body_expansion_expr; // 24
|
ExprBodyExpansion body_expansion_expr; // 24
|
||||||
@@ -1614,6 +1607,13 @@ extern const char *kw_check_assign;
|
|||||||
extern const char *kw_argc;
|
extern const char *kw_argc;
|
||||||
extern const char *kw_argv;
|
extern const char *kw_argv;
|
||||||
extern const char *kw_mainstub;
|
extern const char *kw_mainstub;
|
||||||
|
extern const char *kw_at_ensure;
|
||||||
|
extern const char *kw_at_require;
|
||||||
|
extern const char *kw_at_pure;
|
||||||
|
extern const char *kw_at_optreturn;
|
||||||
|
extern const char *kw_at_param;
|
||||||
|
extern const char *kw_at_return;
|
||||||
|
extern const char *kw_at_checked;
|
||||||
|
|
||||||
ARENA_DEF(chars, char)
|
ARENA_DEF(chars, char)
|
||||||
ARENA_DEF(ast, Ast)
|
ARENA_DEF(ast, Ast)
|
||||||
@@ -1659,6 +1659,8 @@ typedef enum CmpRes_
|
|||||||
CMP_GT = 1,
|
CMP_GT = 1,
|
||||||
} CmpRes;
|
} CmpRes;
|
||||||
|
|
||||||
|
AttributeType attribute_by_name(Attr *attr);
|
||||||
|
|
||||||
void type_setup(PlatformTarget *target);
|
void type_setup(PlatformTarget *target);
|
||||||
Float float_add(Float op1, Float op2);
|
Float float_add(Float op1, Float op2);
|
||||||
Float float_sub(Float op1, Float op2);
|
Float float_sub(Float op1, Float op2);
|
||||||
@@ -1941,7 +1943,7 @@ bool sema_analyse_ct_assert_stmt(SemaContext *context, Ast *statement);
|
|||||||
bool sema_analyse_statement(SemaContext *context, Ast *statement);
|
bool sema_analyse_statement(SemaContext *context, Ast *statement);
|
||||||
bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type *left_type, Expr *right, bool is_unwrapped_var);
|
bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type *left_type, Expr *right, bool is_unwrapped_var);
|
||||||
|
|
||||||
bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool is_macro, bool failable);
|
bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool failable);
|
||||||
Decl *sema_resolve_symbol_in_current_dynamic_scope(SemaContext *context, const char *symbol);
|
Decl *sema_resolve_symbol_in_current_dynamic_scope(SemaContext *context, const char *symbol);
|
||||||
Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name);
|
Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name);
|
||||||
Decl *unit_resolve_parameterized_symbol(CompilationUnit *unit, NameResolve *name_resolve);
|
Decl *unit_resolve_parameterized_symbol(CompilationUnit *unit, NameResolve *name_resolve);
|
||||||
|
|||||||
@@ -206,11 +206,6 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
|||||||
return expr;
|
return expr;
|
||||||
case EXPR_COMPILER_CONST:
|
case EXPR_COMPILER_CONST:
|
||||||
return expr;
|
return expr;
|
||||||
case EXPR_MACRO_EXPANSION:
|
|
||||||
SCOPE_FIXUP_START
|
|
||||||
MACRO_COPY_EXPR(expr->macro_expansion_expr.inner);
|
|
||||||
SCOPE_FIXUP_END;
|
|
||||||
return expr;
|
|
||||||
case EXPR_DESIGNATOR:
|
case EXPR_DESIGNATOR:
|
||||||
expr->designator_expr.path = macro_copy_designator_list(c, expr->designator_expr.path);
|
expr->designator_expr.path = macro_copy_designator_list(c, expr->designator_expr.path);
|
||||||
MACRO_COPY_EXPR(expr->designator_expr.value);
|
MACRO_COPY_EXPR(expr->designator_expr.value);
|
||||||
|
|||||||
@@ -198,7 +198,6 @@ typedef enum
|
|||||||
EXPR_FORCE_UNWRAP,
|
EXPR_FORCE_UNWRAP,
|
||||||
EXPR_HASH_IDENT,
|
EXPR_HASH_IDENT,
|
||||||
EXPR_MACRO_BLOCK,
|
EXPR_MACRO_BLOCK,
|
||||||
EXPR_MACRO_EXPANSION,
|
|
||||||
EXPR_IDENTIFIER,
|
EXPR_IDENTIFIER,
|
||||||
EXPR_RETVAL,
|
EXPR_RETVAL,
|
||||||
EXPR_FLATPATH,
|
EXPR_FLATPATH,
|
||||||
@@ -411,13 +410,16 @@ typedef enum
|
|||||||
TOKEN_HASH_CONST_IDENT, // #FOOBAR
|
TOKEN_HASH_CONST_IDENT, // #FOOBAR
|
||||||
TOKEN_HASH_TYPE_IDENT, // #Foobar
|
TOKEN_HASH_TYPE_IDENT, // #Foobar
|
||||||
|
|
||||||
|
TOKEN_AT_IDENT, // @macro
|
||||||
|
TOKEN_AT_CONST_IDENT, // @MACRO
|
||||||
|
TOKEN_AT_TYPE_IDENT, // @Macro
|
||||||
|
|
||||||
TOKEN_STRING, // "Teststring"
|
TOKEN_STRING, // "Teststring"
|
||||||
TOKEN_INTEGER, // 123 0x23 0b10010 0o327
|
TOKEN_INTEGER, // 123 0x23 0b10010 0o327
|
||||||
TOKEN_CHAR_LITERAL, // 'a' 'FO' 'BARS' '\u1232'
|
TOKEN_CHAR_LITERAL, // 'a' 'FO' 'BARS' '\u1232'
|
||||||
TOKEN_REAL, // 0x23.2p-2a 43.23e23
|
TOKEN_REAL, // 0x23.2p-2a 43.23e23
|
||||||
TOKEN_BYTES, // Base64 or Hex
|
TOKEN_BYTES, // Base64 or Hex
|
||||||
|
|
||||||
TOKEN_DOC_DIRECTIVE, // Doc Directive
|
|
||||||
TOKEN_DOC_COMMENT, // Doc Comment start
|
TOKEN_DOC_COMMENT, // Doc Comment start
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
@@ -490,14 +492,7 @@ typedef enum
|
|||||||
|
|
||||||
TOKEN_DOCS_START, // /**
|
TOKEN_DOCS_START, // /**
|
||||||
TOKEN_DOCS_END, // */ (may start with an arbitrary number of `*`
|
TOKEN_DOCS_END, // */ (may start with an arbitrary number of `*`
|
||||||
TOKEN_DOCS_ENSURE, // @ensure
|
TOKEN_DOC_DIRECTIVE, // Any doc directive
|
||||||
TOKEN_DOCS_REQUIRE, // @require
|
|
||||||
TOKEN_DOCS_CHECKED, // @checked
|
|
||||||
TOKEN_DOCS_PARAM, // @param
|
|
||||||
TOKEN_DOCS_RETURN, // @return
|
|
||||||
TOKEN_DOCS_OPTRETURN, // @optreturn
|
|
||||||
TOKEN_DOCS_PURE, // @pure
|
|
||||||
|
|
||||||
|
|
||||||
TOKEN_EOF, // \n - SHOULD ALWAYS BE THE LAST TOKEN.
|
TOKEN_EOF, // \n - SHOULD ALWAYS BE THE LAST TOKEN.
|
||||||
|
|
||||||
@@ -669,6 +664,7 @@ typedef enum
|
|||||||
ATTRIBUTE_OVERLAP,
|
ATTRIBUTE_OVERLAP,
|
||||||
ATTRIBUTE_AUTOIMPORT,
|
ATTRIBUTE_AUTOIMPORT,
|
||||||
ATTRIBUTE_OPERATOR,
|
ATTRIBUTE_OPERATOR,
|
||||||
|
ATTRIBUTE_PURE,
|
||||||
ATTRIBUTE_NONE,
|
ATTRIBUTE_NONE,
|
||||||
NUMBER_OF_ATTRIBUTES = ATTRIBUTE_NONE,
|
NUMBER_OF_ATTRIBUTES = ATTRIBUTE_NONE,
|
||||||
} AttributeType;
|
} AttributeType;
|
||||||
|
|||||||
@@ -1160,33 +1160,23 @@ INLINE void skip_to_doc_line_end(Lexer *lexer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool parse_doc_directive(Lexer *lexer)
|
static bool lex_doc_directive(Lexer *lexer)
|
||||||
{
|
{
|
||||||
begin_new_token(lexer);
|
begin_new_token(lexer);
|
||||||
next(lexer);
|
next(lexer);
|
||||||
// Then our keyword
|
// Then our keyword
|
||||||
if (!scan_ident(lexer, TOKEN_IDENT, TOKEN_CONST, TOKEN_TYPE_IDENT, '@'))
|
if (!scan_ident(lexer, TOKEN_AT_IDENT, TOKEN_AT_CONST_IDENT, TOKEN_AT_TYPE_IDENT, '@'))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (lexer->token_type)
|
if (lexer->token_type != TOKEN_AT_IDENT)
|
||||||
{
|
{
|
||||||
case TOKEN_DOCS_ENSURE:
|
add_error_token_at_current(lexer, "A doc directive was expected.");
|
||||||
case TOKEN_DOCS_CHECKED:
|
return false;
|
||||||
case TOKEN_DOCS_REQUIRE:
|
|
||||||
case TOKEN_DOCS_OPTRETURN:
|
|
||||||
case TOKEN_DOCS_PARAM:
|
|
||||||
case TOKEN_DOCS_RETURN:
|
|
||||||
case TOKEN_DOCS_PURE:
|
|
||||||
return true;
|
|
||||||
case TOKEN_IDENT:
|
|
||||||
lexer->token_type = TOKEN_DOC_DIRECTIVE;
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
add_error_token_at_current(lexer, "A doc directive was expected.");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
lexer->token_type = TOKEN_DOC_DIRECTIVE;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool scan_doc_line(Lexer *lexer)
|
static bool scan_doc_line(Lexer *lexer)
|
||||||
@@ -1224,7 +1214,7 @@ RETRY:;
|
|||||||
// If we have '@' [_A-Za-z] then parse the directive
|
// If we have '@' [_A-Za-z] then parse the directive
|
||||||
if (c == '@')
|
if (c == '@')
|
||||||
{
|
{
|
||||||
return parse_doc_directive(lexer);
|
return lex_doc_directive(lexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise scan to the end of the line
|
// Otherwise scan to the end of the line
|
||||||
@@ -1285,6 +1275,10 @@ static bool lexer_scan_token_inner(Lexer *lexer)
|
|||||||
case '\n':
|
case '\n':
|
||||||
return scan_doc_line(lexer);
|
return scan_doc_line(lexer);
|
||||||
case '@':
|
case '@':
|
||||||
|
if (char_is_letter(peek(lexer)))
|
||||||
|
{
|
||||||
|
return scan_ident(lexer, TOKEN_AT_IDENT, TOKEN_AT_CONST_IDENT, TOKEN_AT_TYPE_IDENT, '@');
|
||||||
|
}
|
||||||
return return_token(lexer, TOKEN_AT, "@");
|
return return_token(lexer, TOKEN_AT, "@");
|
||||||
case '\'':
|
case '\'':
|
||||||
return scan_char(lexer);
|
return scan_char(lexer);
|
||||||
|
|||||||
@@ -1347,7 +1347,6 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
|
|||||||
break;
|
break;
|
||||||
case CAST_ENUMLOW:
|
case CAST_ENUMLOW:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
value->value = value->value;
|
|
||||||
break;
|
break;
|
||||||
case CAST_STST:
|
case CAST_STST:
|
||||||
llvm_value_addr(c, value);
|
llvm_value_addr(c, value);
|
||||||
@@ -5546,7 +5545,6 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
|||||||
{
|
{
|
||||||
case NON_RUNTIME_EXPR:
|
case NON_RUNTIME_EXPR:
|
||||||
case EXPR_COND:
|
case EXPR_COND:
|
||||||
case EXPR_MACRO_EXPANSION:
|
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case EXPR_RETVAL:
|
case EXPR_RETVAL:
|
||||||
*value = c->retval;
|
*value = c->retval;
|
||||||
|
|||||||
@@ -345,20 +345,6 @@ bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* macro_expansion ::= '@' non_at_expression
|
|
||||||
*/
|
|
||||||
static Expr *parse_macro_expansion(ParseContext *c, Expr *left)
|
|
||||||
{
|
|
||||||
assert(!left && "Unexpected left hand side");
|
|
||||||
Expr *macro_expression = EXPR_NEW_TOKEN(EXPR_MACRO_EXPANSION);
|
|
||||||
advance_and_verify(c, TOKEN_AT);
|
|
||||||
ASSIGN_EXPR_OR_RET(Expr * inner, parse_precedence(c, PREC_MACRO), poisoned_expr);
|
|
||||||
macro_expression->macro_expansion_expr.inner = inner;
|
|
||||||
assert(inner);
|
|
||||||
RANGE_EXTEND_PREV(macro_expression);
|
|
||||||
return macro_expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -712,32 +698,37 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left)
|
|||||||
{
|
{
|
||||||
if (!parse_attribute(c, &attr)) return poisoned_expr;
|
if (!parse_attribute(c, &attr)) return poisoned_expr;
|
||||||
if (!attr) break;
|
if (!attr) break;
|
||||||
if (attr->name == kw_pure)
|
|
||||||
|
AttributeType attr_type = attribute_by_name(attr);
|
||||||
|
int new_inline = attr_type == ATTRIBUTE_INLINE;
|
||||||
|
switch (attr_type)
|
||||||
{
|
{
|
||||||
if (call->call_expr.attr_pure)
|
case ATTRIBUTE_PURE:
|
||||||
{
|
if (call->call_expr.attr_pure)
|
||||||
SEMA_ERROR(attr, "Repeat of the same attribute is not allowed.");
|
{
|
||||||
|
SEMA_ERROR(attr, "Repeat of the same attribute is not allowed.");
|
||||||
|
return poisoned_expr;
|
||||||
|
}
|
||||||
|
call->call_expr.attr_pure = true;
|
||||||
|
continue;
|
||||||
|
case ATTRIBUTE_INLINE:
|
||||||
|
case ATTRIBUTE_NOINLINE:
|
||||||
|
if (force_inline == new_inline)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(attr, "Repeat of the same attribute is not allowed.");
|
||||||
|
return poisoned_expr;
|
||||||
|
}
|
||||||
|
if (force_inline != -1)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(attr, "@inline and @noinline cannot be combined");
|
||||||
|
return poisoned_expr;
|
||||||
|
}
|
||||||
|
force_inline = new_inline;
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
SEMA_ERROR(attr, "Only '@pure', '@inline' and '@noinline' are valid attributes for calls.");
|
||||||
return poisoned_expr;
|
return poisoned_expr;
|
||||||
}
|
|
||||||
call->call_expr.attr_pure = true;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (attr->name != kw_inline && attr->name != kw_noinline && attr->name != kw_pure)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(attr, "Only '@pure', '@inline' and '@noinline' are valid attributes for calls.");
|
|
||||||
return poisoned_expr;
|
|
||||||
}
|
|
||||||
int new_inline = attr->name == kw_inline;
|
|
||||||
if (new_inline == force_inline)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(attr, "Repeat of the same attribute is not allowed.");
|
|
||||||
return poisoned_expr;
|
|
||||||
}
|
|
||||||
if (force_inline != -1)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(attr, "@inline and @noinline cannot be combined");
|
|
||||||
}
|
|
||||||
force_inline = new_inline;
|
|
||||||
}
|
}
|
||||||
if (force_inline != -1)
|
if (force_inline != -1)
|
||||||
{
|
{
|
||||||
@@ -1029,6 +1020,7 @@ static Expr *parse_identifier_starting_expression(ParseContext *c, Expr *left)
|
|||||||
{
|
{
|
||||||
case TOKEN_IDENT:
|
case TOKEN_IDENT:
|
||||||
case TOKEN_CONST_IDENT:
|
case TOKEN_CONST_IDENT:
|
||||||
|
case TOKEN_AT_IDENT:
|
||||||
{
|
{
|
||||||
Expr *expr = parse_identifier(c, NULL);
|
Expr *expr = parse_identifier(c, NULL);
|
||||||
expr->identifier_expr.path = path;
|
expr->identifier_expr.path = path;
|
||||||
@@ -1752,7 +1744,6 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
|||||||
[TOKEN_INTEGER] = { parse_integer, NULL, PREC_NONE },
|
[TOKEN_INTEGER] = { parse_integer, NULL, PREC_NONE },
|
||||||
[TOKEN_BUILTIN] = { parse_builtin, NULL, PREC_NONE },
|
[TOKEN_BUILTIN] = { parse_builtin, NULL, PREC_NONE },
|
||||||
[TOKEN_CHAR_LITERAL] = { parse_char_lit, NULL, PREC_NONE },
|
[TOKEN_CHAR_LITERAL] = { parse_char_lit, NULL, PREC_NONE },
|
||||||
[TOKEN_AT] = { parse_macro_expansion, NULL, PREC_NONE },
|
|
||||||
[TOKEN_STRING] = { parse_string_literal, NULL, PREC_NONE },
|
[TOKEN_STRING] = { parse_string_literal, NULL, PREC_NONE },
|
||||||
[TOKEN_REAL] = { parse_double, NULL, PREC_NONE },
|
[TOKEN_REAL] = { parse_double, NULL, PREC_NONE },
|
||||||
[TOKEN_OR] = { NULL, parse_binary, PREC_OR },
|
[TOKEN_OR] = { NULL, parse_binary, PREC_OR },
|
||||||
@@ -1776,6 +1767,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
|||||||
[TOKEN_CT_CONST_IDENT] = { parse_ct_ident, NULL, PREC_NONE },
|
[TOKEN_CT_CONST_IDENT] = { parse_ct_ident, NULL, PREC_NONE },
|
||||||
[TOKEN_CT_TYPE_IDENT] = { parse_type_identifier, NULL, PREC_NONE },
|
[TOKEN_CT_TYPE_IDENT] = { parse_type_identifier, NULL, PREC_NONE },
|
||||||
[TOKEN_HASH_IDENT] = { parse_hash_ident, NULL, PREC_NONE },
|
[TOKEN_HASH_IDENT] = { parse_hash_ident, NULL, PREC_NONE },
|
||||||
|
[TOKEN_AT_IDENT] = { parse_identifier, NULL, PREC_NONE },
|
||||||
//[TOKEN_HASH_TYPE_IDENT] = { parse_type_identifier, NULL, PREC_NONE }
|
//[TOKEN_HASH_TYPE_IDENT] = { parse_type_identifier, NULL, PREC_NONE }
|
||||||
|
|
||||||
[TOKEN_CT_SIZEOF] = { parse_ct_sizeof, NULL, PREC_NONE },
|
[TOKEN_CT_SIZEOF] = { parse_ct_sizeof, NULL, PREC_NONE },
|
||||||
|
|||||||
@@ -858,29 +858,26 @@ Decl *parse_var_decl(ParseContext *c)
|
|||||||
|
|
||||||
bool parse_attribute(ParseContext *c, Attr **attribute_ref)
|
bool parse_attribute(ParseContext *c, Attr **attribute_ref)
|
||||||
{
|
{
|
||||||
if (!try_consume(c, TOKEN_AT))
|
|
||||||
{
|
|
||||||
*attribute_ref = NULL;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool had_error;
|
bool had_error;
|
||||||
Path *path = parse_path_prefix(c, &had_error);
|
Path *path = parse_path_prefix(c, &had_error);
|
||||||
if (had_error) return false;
|
if (had_error) return false;
|
||||||
|
if (!tok_is(c, TOKEN_AT_IDENT) && !tok_is(c, TOKEN_AT_TYPE_IDENT))
|
||||||
|
{
|
||||||
|
if (path)
|
||||||
|
{
|
||||||
|
SEMA_ERROR_HERE("Expected an attribute name.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*attribute_ref = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
Attr *attr = CALLOCS(Attr);
|
Attr *attr = CALLOCS(Attr);
|
||||||
|
|
||||||
attr->name = symstr(c);
|
attr->name = symstr(c);
|
||||||
attr->span = c->span;
|
attr->span = c->span;
|
||||||
attr->path = path;
|
attr->path = path;
|
||||||
|
|
||||||
if (tok_is(c, TOKEN_TYPE_IDENT) || tok_is(c, TOKEN_TYPE_IDENT))
|
advance(c);
|
||||||
{
|
|
||||||
advance(c);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TRY_CONSUME_OR_RET(TOKEN_IDENT, "Expected an attribute", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tok_is(c, TOKEN_LPAREN))
|
if (tok_is(c, TOKEN_LPAREN))
|
||||||
{
|
{
|
||||||
@@ -897,11 +894,7 @@ bool parse_attribute(ParseContext *c, Attr **attribute_ref)
|
|||||||
* ;
|
* ;
|
||||||
*
|
*
|
||||||
* attribute
|
* attribute
|
||||||
* : AT IDENT
|
* : path AT_IDENT | AT_TYPE_IDENT ('(' constant_expression ')')?
|
||||||
* | AT path IDENT
|
|
||||||
* | AT IDENT '(' constant_expression ')'
|
|
||||||
* | AT path IDENT '(' constant_expression ')'
|
|
||||||
* ;
|
|
||||||
*
|
*
|
||||||
* @return true if parsing succeeded, false if recovery is needed
|
* @return true if parsing succeeded, false if recovery is needed
|
||||||
*/
|
*/
|
||||||
@@ -1441,10 +1434,9 @@ static bool parse_macro_arguments(ParseContext *c, Visibility visibility, Decl *
|
|||||||
// Do we have trailing block parameters?
|
// Do we have trailing block parameters?
|
||||||
if (try_consume(c, TOKEN_EOS))
|
if (try_consume(c, TOKEN_EOS))
|
||||||
{
|
{
|
||||||
// Consume '@' IDENT
|
// Consume AT_IDENT
|
||||||
TRY_CONSUME_OR_RET(TOKEN_AT, "Expected an ending ')' or a block parameter on the format '@block(...).", false);
|
|
||||||
Decl *body_param = decl_new(DECL_BODYPARAM, symstr(c), c->span, visibility);
|
Decl *body_param = decl_new(DECL_BODYPARAM, symstr(c), c->span, visibility);
|
||||||
if (!consume_ident(c, "variable name")) return false;
|
TRY_CONSUME_OR_RET(TOKEN_AT_IDENT, "Expected an ending ')' or a block parameter on the format '@block(...).", false);
|
||||||
if (try_consume(c, TOKEN_LPAREN))
|
if (try_consume(c, TOKEN_LPAREN))
|
||||||
{
|
{
|
||||||
if (!parse_parameters(c, visibility, &body_param->body_params)) return false;
|
if (!parse_parameters(c, visibility, &body_param->body_params)) return false;
|
||||||
@@ -1694,16 +1686,16 @@ static inline Decl *parse_define(ParseContext *c, Visibility visibility)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool parse_is_func_name(ParseContext *c)
|
static inline bool parse_is_macro_name(ParseContext *c)
|
||||||
{
|
{
|
||||||
return tok_is(c, TOKEN_IDENT) && peek(c) != TOKEN_SCOPE;
|
return (tok_is(c, TOKEN_IDENT) && peek(c) != TOKEN_SCOPE) || tok_is(c, TOKEN_AT_IDENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* func_header ::= type '!'? (type '.')? IDENT
|
* func_header ::= type '!'? (type '.')? (IDENT | MACRO_IDENT)
|
||||||
* macro_header ::= (type '!'?)? (type '.')? IDENT
|
* macro_header ::= (type '!'?)? (type '.')? (IDENT | MACRO_IDENT)
|
||||||
*/
|
*/
|
||||||
static inline bool parse_func_macro_header(ParseContext *c, bool rtype_is_optional,
|
static inline bool parse_func_macro_header(ParseContext *c, bool is_macro,
|
||||||
TypeInfoId *rtype_ref, TypeInfoId *method_type_ref,
|
TypeInfoId *rtype_ref, TypeInfoId *method_type_ref,
|
||||||
const char **name_ref, SourceSpan *name_span)
|
const char **name_ref, SourceSpan *name_span)
|
||||||
{
|
{
|
||||||
@@ -1711,7 +1703,7 @@ static inline bool parse_func_macro_header(ParseContext *c, bool rtype_is_option
|
|||||||
TypeInfo *method_type = NULL;
|
TypeInfo *method_type = NULL;
|
||||||
|
|
||||||
// 1. If we have a macro and see the name, we're done.
|
// 1. If we have a macro and see the name, we're done.
|
||||||
if (rtype_is_optional && parse_is_func_name(c))
|
if (is_macro && parse_is_macro_name(c))
|
||||||
{
|
{
|
||||||
goto RESULT;
|
goto RESULT;
|
||||||
}
|
}
|
||||||
@@ -1720,7 +1712,7 @@ static inline bool parse_func_macro_header(ParseContext *c, bool rtype_is_option
|
|||||||
ASSIGN_TYPE_OR_RET(rtype, parse_failable_type(c), false);
|
ASSIGN_TYPE_OR_RET(rtype, parse_failable_type(c), false);
|
||||||
|
|
||||||
// 4. We might have a type here, if so then we read it.
|
// 4. We might have a type here, if so then we read it.
|
||||||
if (!tok_is(c, TOKEN_DOT) && !parse_is_func_name(c))
|
if (!tok_is(c, TOKEN_DOT) && !parse_is_macro_name(c))
|
||||||
{
|
{
|
||||||
ASSIGN_TYPE_OR_RET(method_type, parse_type(c), false);
|
ASSIGN_TYPE_OR_RET(method_type, parse_type(c), false);
|
||||||
}
|
}
|
||||||
@@ -1732,7 +1724,7 @@ static inline bool parse_func_macro_header(ParseContext *c, bool rtype_is_option
|
|||||||
if (!method_type)
|
if (!method_type)
|
||||||
{
|
{
|
||||||
// 5b. If the rtype is not optional or the return type was a failable, then this is an error.
|
// 5b. If the rtype is not optional or the return type was a failable, then this is an error.
|
||||||
if (!rtype_is_optional || rtype->failable)
|
if (!is_macro || rtype->failable)
|
||||||
{
|
{
|
||||||
SEMA_ERROR_LAST("This looks like you are declaring a method without a return type?");
|
SEMA_ERROR_LAST("This looks like you are declaring a method without a return type?");
|
||||||
return false;
|
return false;
|
||||||
@@ -1750,7 +1742,17 @@ static inline bool parse_func_macro_header(ParseContext *c, bool rtype_is_option
|
|||||||
RESULT:
|
RESULT:
|
||||||
*name_ref = symstr(c);
|
*name_ref = symstr(c);
|
||||||
*name_span = c->span;
|
*name_span = c->span;
|
||||||
TRY_CONSUME_OR_RET(TOKEN_IDENT, "Expected a name here.", false);
|
if (is_macro && c->tok != TOKEN_IDENT && c->tok != TOKEN_AT_IDENT)
|
||||||
|
{
|
||||||
|
sema_error_at(c->span, "Expected a macro name here, e.g. '@someName' or 'someName'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (!is_macro && c->tok != TOKEN_IDENT)
|
||||||
|
{
|
||||||
|
sema_error_at(c->span, "Expected a function name here, e.g. 'someName'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
advance(c);
|
||||||
*rtype_ref = rtype ? type_infoid(rtype) : 0;
|
*rtype_ref = rtype ? type_infoid(rtype) : 0;
|
||||||
*method_type_ref = method_type ? type_infoid(method_type) : 0;
|
*method_type_ref = method_type ? type_infoid(method_type) : 0;
|
||||||
return true;
|
return true;
|
||||||
@@ -1771,12 +1773,10 @@ static inline Decl *parse_macro_declaration(ParseContext *c, Visibility visibili
|
|||||||
TypeInfoId *rtype_ref = &decl->macro_decl.rtype;
|
TypeInfoId *rtype_ref = &decl->macro_decl.rtype;
|
||||||
TypeInfoId *method_type_ref = &decl->macro_decl.type_parent;
|
TypeInfoId *method_type_ref = &decl->macro_decl.type_parent;
|
||||||
if (!parse_func_macro_header(c, true, rtype_ref, method_type_ref, &decl->name, &decl->span)) return poisoned_decl;
|
if (!parse_func_macro_header(c, true, rtype_ref, method_type_ref, &decl->name, &decl->span)) return poisoned_decl;
|
||||||
|
|
||||||
const char *block_parameter = NULL;
|
const char *block_parameter = NULL;
|
||||||
if (!parse_macro_arguments(c, visibility, &decl->macro_decl.parameters, &decl->macro_decl.body_param)) return poisoned_decl;
|
if (!parse_macro_arguments(c, visibility, &decl->macro_decl.parameters, &decl->macro_decl.body_param)) return poisoned_decl;
|
||||||
|
|
||||||
if (!parse_attributes(c, &decl->attributes)) return poisoned_decl;
|
if (!parse_attributes(c, &decl->attributes)) return poisoned_decl;
|
||||||
|
|
||||||
ASSIGN_ASTID_OR_RET(decl->macro_decl.body, parse_stmt(c), poisoned_decl);
|
ASSIGN_ASTID_OR_RET(decl->macro_decl.body, parse_stmt(c), poisoned_decl);
|
||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
@@ -1980,6 +1980,11 @@ static inline Decl *parse_func_definition(ParseContext *c, Visibility visibility
|
|||||||
TypeInfoId *rtype_id_ref = &func->func_decl.function_signature.returntype;
|
TypeInfoId *rtype_id_ref = &func->func_decl.function_signature.returntype;
|
||||||
TypeInfoId *method_type_ref = &func->func_decl.type_parent;
|
TypeInfoId *method_type_ref = &func->func_decl.type_parent;
|
||||||
if (!parse_func_macro_header(c, false, rtype_id_ref, method_type_ref, &func->name, &func->span)) return poisoned_decl;
|
if (!parse_func_macro_header(c, false, rtype_id_ref, method_type_ref, &func->name, &func->span)) return poisoned_decl;
|
||||||
|
if (func->name[0] == '@')
|
||||||
|
{
|
||||||
|
SEMA_ERROR(func, "Function names may not use '@'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!parse_parameter_list(c, visibility, &(func->func_decl.function_signature), is_interface)) return poisoned_decl;
|
if (!parse_parameter_list(c, visibility, &(func->func_decl.function_signature), is_interface)) return poisoned_decl;
|
||||||
if (!parse_attributes(c, &func->attributes)) return poisoned_decl;
|
if (!parse_attributes(c, &func->attributes)) return poisoned_decl;
|
||||||
|
|
||||||
@@ -2230,38 +2235,56 @@ static bool parse_docs(ParseContext *c, AstId *docs_ref)
|
|||||||
// Spin past the lines and line ends
|
// Spin past the lines and line ends
|
||||||
switch (c->tok)
|
switch (c->tok)
|
||||||
{
|
{
|
||||||
case TOKEN_DOCS_PARAM:
|
|
||||||
if (!parse_doc_param(c, &last)) return false;
|
|
||||||
break;
|
|
||||||
case TOKEN_DOCS_RETURN:
|
|
||||||
advance(c);
|
|
||||||
if (!consume(c, TOKEN_STRING, "Expected a string description.")) return false;
|
|
||||||
break;
|
|
||||||
case TOKEN_DOCS_REQUIRE:
|
|
||||||
if (!parse_doc_contract(c, &docs_ref, DOC_DIRECTIVE_REQUIRE)) return false;
|
|
||||||
break;
|
|
||||||
case TOKEN_DOCS_CHECKED:
|
|
||||||
if (!parse_doc_contract(c, &docs_ref, DOC_DIRECTIVE_CHECKED)) return false;
|
|
||||||
break;
|
|
||||||
case TOKEN_DOCS_ENSURE:
|
|
||||||
if (!parse_doc_contract(c, &docs_ref, DOC_DIRECTIVE_ENSURE)) return false;
|
|
||||||
break;
|
|
||||||
case TOKEN_DOCS_OPTRETURN:
|
|
||||||
if (!parse_doc_errors(c, &docs_ref)) return false;
|
|
||||||
break;
|
|
||||||
case TOKEN_DOCS_PURE:
|
|
||||||
{
|
|
||||||
Ast *ast = ast_new_curr(c, AST_DOC_STMT);
|
|
||||||
ast->doc_stmt.kind = DOC_DIRECTIVE_PURE;
|
|
||||||
*docs_ref = astid(ast);
|
|
||||||
docs_ref = &ast->next;
|
|
||||||
advance(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TOKEN_DOC_DIRECTIVE:
|
case TOKEN_DOC_DIRECTIVE:
|
||||||
advance(c);
|
{
|
||||||
// Ignore
|
const char *name = symstr(c);
|
||||||
break;
|
if (name == kw_at_param)
|
||||||
|
{
|
||||||
|
if (!parse_doc_param(c, &last)) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (name == kw_at_return)
|
||||||
|
{
|
||||||
|
advance(c);
|
||||||
|
if (!consume(c, TOKEN_STRING, "Expected a string description.")) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (name == kw_at_require)
|
||||||
|
{
|
||||||
|
if (!parse_doc_contract(c, &docs_ref, DOC_DIRECTIVE_REQUIRE)) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (name == kw_at_checked)
|
||||||
|
{
|
||||||
|
if (!parse_doc_contract(c, &docs_ref, DOC_DIRECTIVE_CHECKED)) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (name == kw_at_ensure)
|
||||||
|
{
|
||||||
|
if (!parse_doc_contract(c, &docs_ref, DOC_DIRECTIVE_ENSURE)) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (name == kw_at_optreturn)
|
||||||
|
{
|
||||||
|
if (!parse_doc_errors(c, &docs_ref)) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (name == kw_at_pure)
|
||||||
|
{
|
||||||
|
Ast *ast = ast_new_curr(c, AST_DOC_STMT);
|
||||||
|
ast->doc_stmt.kind = DOC_DIRECTIVE_PURE;
|
||||||
|
*docs_ref = astid(ast);
|
||||||
|
docs_ref = &ast->next;
|
||||||
|
advance(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
advance(c);
|
||||||
|
// Ignore
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
case TOKEN_DOCS_END:
|
case TOKEN_DOCS_END:
|
||||||
advance(c);
|
advance(c);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -846,7 +846,10 @@ Ast *parse_stmt(ParseContext *c)
|
|||||||
case TOKEN_STATIC: // Static means declaration!
|
case TOKEN_STATIC: // Static means declaration!
|
||||||
case TOKEN_CONST: // Const means declaration!
|
case TOKEN_CONST: // Const means declaration!
|
||||||
return parse_declaration_stmt(c);
|
return parse_declaration_stmt(c);
|
||||||
|
case TOKEN_AT_TYPE_IDENT:
|
||||||
|
case TOKEN_AT_CONST_IDENT:
|
||||||
case TOKEN_AT:
|
case TOKEN_AT:
|
||||||
|
case TOKEN_AT_IDENT:
|
||||||
return parse_expr_stmt(c);
|
return parse_expr_stmt(c);
|
||||||
case TOKEN_RETURN:
|
case TOKEN_RETURN:
|
||||||
{
|
{
|
||||||
@@ -1028,13 +1031,6 @@ Ast *parse_stmt(ParseContext *c)
|
|||||||
SEMA_ERROR_HERE("Reached the end of the file when expecting a statement.");
|
SEMA_ERROR_HERE("Reached the end of the file when expecting a statement.");
|
||||||
return poisoned_ast;
|
return poisoned_ast;
|
||||||
case TOKEN_DOC_DIRECTIVE:
|
case TOKEN_DOC_DIRECTIVE:
|
||||||
case TOKEN_DOCS_ENSURE:
|
|
||||||
case TOKEN_DOCS_REQUIRE:
|
|
||||||
case TOKEN_DOCS_CHECKED:
|
|
||||||
case TOKEN_DOCS_PARAM:
|
|
||||||
case TOKEN_DOCS_RETURN:
|
|
||||||
case TOKEN_DOCS_OPTRETURN:
|
|
||||||
case TOKEN_DOCS_PURE:
|
|
||||||
SEMA_ERROR_HERE("Unexpectedly encountered doc directives.");
|
SEMA_ERROR_HERE("Unexpectedly encountered doc directives.");
|
||||||
return poisoned_ast;
|
return poisoned_ast;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -775,7 +775,6 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
|
|||||||
case EXPR_DESIGNATOR:
|
case EXPR_DESIGNATOR:
|
||||||
case EXPR_EXPR_BLOCK:
|
case EXPR_EXPR_BLOCK:
|
||||||
case EXPR_MACRO_BLOCK:
|
case EXPR_MACRO_BLOCK:
|
||||||
case EXPR_MACRO_EXPANSION:
|
|
||||||
case EXPR_IDENTIFIER:
|
case EXPR_IDENTIFIER:
|
||||||
case EXPR_SLICE_ASSIGN:
|
case EXPR_SLICE_ASSIGN:
|
||||||
case EXPR_SLICE:
|
case EXPR_SLICE:
|
||||||
@@ -930,7 +929,6 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
|
|||||||
case EXPR_DESIGNATOR:
|
case EXPR_DESIGNATOR:
|
||||||
case EXPR_EXPR_BLOCK:
|
case EXPR_EXPR_BLOCK:
|
||||||
case EXPR_MACRO_BLOCK:
|
case EXPR_MACRO_BLOCK:
|
||||||
case EXPR_MACRO_EXPANSION:
|
|
||||||
case EXPR_IDENTIFIER:
|
case EXPR_IDENTIFIER:
|
||||||
case EXPR_SLICE_ASSIGN:
|
case EXPR_SLICE_ASSIGN:
|
||||||
case EXPR_SLICE:
|
case EXPR_SLICE:
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl *
|
|||||||
{
|
{
|
||||||
Attr *attribute = attributes[j];
|
Attr *attribute = attributes[j];
|
||||||
if (!sema_analyse_attribute(context, attribute, ATTR_GLOBAL)) return false;
|
if (!sema_analyse_attribute(context, attribute, ATTR_GLOBAL)) return false;
|
||||||
if (attribute->name == kw_align)
|
if (attribute->name == attribute_list[ATTRIBUTE_ALIGN])
|
||||||
{
|
{
|
||||||
member_alignment = attribute->alignment;
|
member_alignment = attribute->alignment;
|
||||||
// Update total alignment if we have a member that has bigger alignment.
|
// Update total alignment if we have a member that has bigger alignment.
|
||||||
@@ -1075,16 +1075,6 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl)
|
|||||||
return unit_add_method_like(context->unit, type, decl);
|
return unit_add_method_like(context->unit, type, decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline AttributeType attribute_by_name(Attr *attr)
|
|
||||||
{
|
|
||||||
const char *attribute = attr->name;
|
|
||||||
for (unsigned i = 0; i < NUMBER_OF_ATTRIBUTES; i++)
|
|
||||||
{
|
|
||||||
if (attribute_list[i] == attribute) return (AttributeType)i;
|
|
||||||
}
|
|
||||||
return ATTRIBUTE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const char *attribute_domain_to_string(AttributeDomain domain)
|
static const char *attribute_domain_to_string(AttributeDomain domain)
|
||||||
{
|
{
|
||||||
@@ -1151,6 +1141,7 @@ AttributeType sema_analyse_attribute(SemaContext *context, Attr *attr, Attribute
|
|||||||
[ATTRIBUTE_OVERLAP] = ATTR_BITSTRUCT,
|
[ATTRIBUTE_OVERLAP] = ATTR_BITSTRUCT,
|
||||||
[ATTRIBUTE_AUTOIMPORT] = ATTR_MACRO | ATTR_FUNC,
|
[ATTRIBUTE_AUTOIMPORT] = ATTR_MACRO | ATTR_FUNC,
|
||||||
[ATTRIBUTE_OPERATOR] = ATTR_MACRO | ATTR_FUNC,
|
[ATTRIBUTE_OPERATOR] = ATTR_MACRO | ATTR_FUNC,
|
||||||
|
[ATTRIBUTE_PURE] = ATTR_CALL,
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((attribute_domain[type] & domain) != domain)
|
if ((attribute_domain[type] & domain) != domain)
|
||||||
@@ -1669,6 +1660,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
|||||||
decl->macro_decl.unit = context->unit;
|
decl->macro_decl.unit = context->unit;
|
||||||
Decl **parameters = decl->macro_decl.parameters;
|
Decl **parameters = decl->macro_decl.parameters;
|
||||||
unsigned param_count = vec_size(parameters);
|
unsigned param_count = vec_size(parameters);
|
||||||
|
bool is_function_like = true;
|
||||||
for (unsigned i = 0; i < param_count; i++)
|
for (unsigned i = 0; i < param_count; i++)
|
||||||
{
|
{
|
||||||
Decl *param = parameters[i];
|
Decl *param = parameters[i];
|
||||||
@@ -1677,8 +1669,10 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
|||||||
switch (param->var.kind)
|
switch (param->var.kind)
|
||||||
{
|
{
|
||||||
case VARDECL_PARAM_EXPR:
|
case VARDECL_PARAM_EXPR:
|
||||||
case VARDECL_PARAM_CT:
|
|
||||||
case VARDECL_PARAM_REF:
|
case VARDECL_PARAM_REF:
|
||||||
|
is_function_like = false;
|
||||||
|
FALLTHROUGH;
|
||||||
|
case VARDECL_PARAM_CT:
|
||||||
if (is_generic)
|
if (is_generic)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(param, "Only regular parameters and type parameters are allowed for generic functions.");
|
SEMA_ERROR(param, "Only regular parameters and type parameters are allowed for generic functions.");
|
||||||
@@ -1715,6 +1709,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
|||||||
param->resolve_status = RESOLVE_DONE;
|
param->resolve_status = RESOLVE_DONE;
|
||||||
}
|
}
|
||||||
DeclId body_param = decl->macro_decl.body_param;
|
DeclId body_param = decl->macro_decl.body_param;
|
||||||
|
if (body_param) is_function_like = false;
|
||||||
if (is_generic && body_param)
|
if (is_generic && body_param)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(declptr(body_param), "Trailing block syntax is not allowed for generic functions.");
|
SEMA_ERROR(declptr(body_param), "Trailing block syntax is not allowed for generic functions.");
|
||||||
@@ -1756,6 +1751,11 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
|||||||
}
|
}
|
||||||
bool pure = false;
|
bool pure = false;
|
||||||
if (!sema_analyse_doc_header(decl->macro_decl.docs, decl->macro_decl.parameters, body_parameters, &pure)) return decl_poison(decl);
|
if (!sema_analyse_doc_header(decl->macro_decl.docs, decl->macro_decl.parameters, body_parameters, &pure)) return decl_poison(decl);
|
||||||
|
if (decl->name[0] != '@' && !is_function_like)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(decl, "Names of non-function like macros (i.e. a macro with a trailing body, ref or expression parameters, must start with '@'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (decl->macro_decl.type_parent)
|
if (decl->macro_decl.type_parent)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_macro_method(context, decl)) return decl_poison(decl);
|
if (!sema_analyse_macro_method(context, decl)) return decl_poison(decl);
|
||||||
|
|||||||
@@ -452,7 +452,6 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
|||||||
case EXPR_CT_IDENT:
|
case EXPR_CT_IDENT:
|
||||||
case EXPR_FLATPATH:
|
case EXPR_FLATPATH:
|
||||||
case EXPR_COMPOUND_LITERAL:
|
case EXPR_COMPOUND_LITERAL:
|
||||||
case EXPR_MACRO_EXPANSION:
|
|
||||||
case EXPR_COMPILER_CONST:
|
case EXPR_COMPILER_CONST:
|
||||||
case EXPR_POISONED:
|
case EXPR_POISONED:
|
||||||
case EXPR_ARGV_TO_SUBARRAY:
|
case EXPR_ARGV_TO_SUBARRAY:
|
||||||
@@ -885,6 +884,19 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
|
|||||||
|
|
||||||
DEBUG_LOG("Now resolving %s", expr->identifier_expr.ident);
|
DEBUG_LOG("Now resolving %s", expr->identifier_expr.ident);
|
||||||
|
|
||||||
|
DeclId body_param;
|
||||||
|
if (!expr->identifier_expr.path && context->current_macro && (body_param = context->current_macro->macro_decl.body_param))
|
||||||
|
{
|
||||||
|
if (expr->identifier_expr.ident == declptr(body_param)->name)
|
||||||
|
{
|
||||||
|
expr->expr_kind = EXPR_MACRO_BODY_EXPANSION;
|
||||||
|
expr->body_expansion_expr.ast = NULL;
|
||||||
|
expr->body_expansion_expr.declarations = NULL;
|
||||||
|
expr->resolve_status = RESOLVE_NOT_DONE;
|
||||||
|
expr->type = type_void;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Just start with inference
|
// Just start with inference
|
||||||
if (!expr->identifier_expr.path && to)
|
if (!expr->identifier_expr.path && to)
|
||||||
{
|
{
|
||||||
@@ -977,44 +989,6 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sema_expr_analyse_macro_expansion(SemaContext *context, Expr *expr)
|
|
||||||
{
|
|
||||||
Expr *inner = expr->macro_expansion_expr.inner;
|
|
||||||
if (inner->expr_kind == EXPR_IDENTIFIER)
|
|
||||||
{
|
|
||||||
DeclId body_param = context->current_macro ? context->current_macro->macro_decl.body_param : 0;
|
|
||||||
if (body_param && !inner->identifier_expr.path && inner->identifier_expr.ident == declptr(body_param)->name)
|
|
||||||
{
|
|
||||||
expr->expr_kind = EXPR_MACRO_BODY_EXPANSION;
|
|
||||||
expr->body_expansion_expr.ast = NULL;
|
|
||||||
expr->body_expansion_expr.declarations = NULL;
|
|
||||||
expr->resolve_status = RESOLVE_NOT_DONE;
|
|
||||||
expr->type = type_void;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!sema_analyse_expr_lvalue(context, inner)) return false;
|
|
||||||
Decl *decl;
|
|
||||||
switch (inner->expr_kind)
|
|
||||||
{
|
|
||||||
case EXPR_IDENTIFIER:
|
|
||||||
decl = inner->identifier_expr.decl;
|
|
||||||
break;
|
|
||||||
case EXPR_ACCESS:
|
|
||||||
decl = inner->access_expr.ref;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SEMA_ERROR(expr, "Expected a macro identifier here.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (decl->decl_kind != DECL_MACRO)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(inner, "Expected a macro identifier here.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
expr->macro_expansion_expr.decl = decl;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool sema_expr_analyse_ct_identifier(SemaContext *context, Expr *expr)
|
static inline bool sema_expr_analyse_ct_identifier(SemaContext *context, Expr *expr)
|
||||||
{
|
{
|
||||||
@@ -2137,7 +2111,7 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool is_macro, bool failable)
|
bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool failable)
|
||||||
{
|
{
|
||||||
expr->call_expr.is_type_method = struct_var != NULL;
|
expr->call_expr.is_type_method = struct_var != NULL;
|
||||||
if (decl == NULL)
|
if (decl == NULL)
|
||||||
@@ -2147,37 +2121,17 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl
|
|||||||
switch (decl->decl_kind)
|
switch (decl->decl_kind)
|
||||||
{
|
{
|
||||||
case DECL_MACRO:
|
case DECL_MACRO:
|
||||||
if (!is_macro)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(expr, "A macro neeeds to be called with a '@' prefix, please add it.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
expr->call_expr.func_ref = declid(decl);
|
expr->call_expr.func_ref = declid(decl);
|
||||||
expr->call_expr.is_func_ref = true;
|
expr->call_expr.is_func_ref = true;
|
||||||
return sema_expr_analyse_macro_call(context, expr, struct_var, decl, failable);
|
return sema_expr_analyse_macro_call(context, expr, struct_var, decl, failable);
|
||||||
case DECL_VAR:
|
case DECL_VAR:
|
||||||
if (is_macro)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(expr, "A function cannot be called with a '@' prefix, please remove it.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
assert(struct_var == NULL);
|
assert(struct_var == NULL);
|
||||||
return sema_expr_analyse_var_call(context, expr, decl->type->canonical, failable || IS_FAILABLE(decl));
|
return sema_expr_analyse_var_call(context, expr, decl->type->canonical, failable || IS_FAILABLE(decl));
|
||||||
case DECL_FUNC:
|
case DECL_FUNC:
|
||||||
if (is_macro)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(expr, "A function cannot be called with a '@' prefix, please remove it.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
expr->call_expr.func_ref = declid(decl);
|
expr->call_expr.func_ref = declid(decl);
|
||||||
expr->call_expr.is_func_ref = true;
|
expr->call_expr.is_func_ref = true;
|
||||||
return sema_expr_analyse_func_call(context, expr, decl, struct_var, failable);
|
return sema_expr_analyse_func_call(context, expr, decl, struct_var, failable);
|
||||||
case DECL_GENERIC:
|
case DECL_GENERIC:
|
||||||
if (is_macro)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(expr, "A generic function cannot be called with a '@' prefix, please remove it.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
expr->call_expr.func_ref = declid(decl);
|
expr->call_expr.func_ref = declid(decl);
|
||||||
expr->call_expr.is_func_ref = true;
|
expr->call_expr.is_func_ref = true;
|
||||||
return sema_expr_analyse_generic_call(context, expr, struct_var, decl, failable);
|
return sema_expr_analyse_generic_call(context, expr, struct_var, decl, failable);
|
||||||
@@ -2432,7 +2386,6 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr)
|
|||||||
bool failable = func_expr->type && IS_FAILABLE(func_expr);
|
bool failable = func_expr->type && IS_FAILABLE(func_expr);
|
||||||
Decl *decl;
|
Decl *decl;
|
||||||
Expr *struct_var = NULL;
|
Expr *struct_var = NULL;
|
||||||
bool macro = false;
|
|
||||||
switch (func_expr->expr_kind)
|
switch (func_expr->expr_kind)
|
||||||
{
|
{
|
||||||
case EXPR_BUILTIN:
|
case EXPR_BUILTIN:
|
||||||
@@ -2444,15 +2397,10 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr)
|
|||||||
decl = func_expr->access_expr.ref;
|
decl = func_expr->access_expr.ref;
|
||||||
if (decl->decl_kind == DECL_FUNC || decl->decl_kind == DECL_MACRO)
|
if (decl->decl_kind == DECL_FUNC || decl->decl_kind == DECL_MACRO)
|
||||||
{
|
{
|
||||||
macro = decl->decl_kind == DECL_MACRO;
|
if (decl->decl_kind != DECL_MACRO) expr_insert_addr(func_expr->access_expr.parent);
|
||||||
if (!macro) expr_insert_addr(func_expr->access_expr.parent);
|
|
||||||
struct_var = func_expr->access_expr.parent;
|
struct_var = func_expr->access_expr.parent;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EXPR_MACRO_EXPANSION:
|
|
||||||
decl = func_expr->macro_expansion_expr.decl;
|
|
||||||
macro = true;
|
|
||||||
break;
|
|
||||||
case EXPR_TYPEINFO:
|
case EXPR_TYPEINFO:
|
||||||
if (func_expr->type_expr->resolve_status == RESOLVE_DONE)
|
if (func_expr->type_expr->resolve_status == RESOLVE_DONE)
|
||||||
{
|
{
|
||||||
@@ -2477,7 +2425,7 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
decl = decl ? decl_flatten(decl) : NULL;
|
decl = decl ? decl_flatten(decl) : NULL;
|
||||||
return sema_expr_analyse_general_call(context, expr, decl, struct_var, macro, failable);
|
return sema_expr_analyse_general_call(context, expr, decl, struct_var, failable);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sema_deref_array_pointers(Expr *expr)
|
static void sema_deref_array_pointers(Expr *expr)
|
||||||
@@ -2965,18 +2913,6 @@ RETRY:
|
|||||||
// A path is not allowed.
|
// A path is not allowed.
|
||||||
if (child->identifier_expr.path) break;
|
if (child->identifier_expr.path) break;
|
||||||
return child;
|
return child;
|
||||||
case EXPR_MACRO_EXPANSION:
|
|
||||||
child = child->macro_expansion_expr.inner;
|
|
||||||
switch (child->expr_kind)
|
|
||||||
{
|
|
||||||
case EXPR_IDENTIFIER:
|
|
||||||
case EXPR_HASH_IDENT:
|
|
||||||
return sema_expr_resolve_access_child(context, child, missing);
|
|
||||||
default:
|
|
||||||
SEMA_ERROR(child, "Expected a macro name.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EXPR_HASH_IDENT:
|
case EXPR_HASH_IDENT:
|
||||||
{
|
{
|
||||||
Decl *decl = sema_resolve_symbol(context, child->hash_ident_expr.identifier, NULL, child->span);
|
Decl *decl = sema_resolve_symbol(context, child->hash_ident_expr.identifier, NULL, child->span);
|
||||||
@@ -3044,7 +2980,7 @@ static inline void expr_replace_with_enum_array(Expr *enum_array_expr, Decl *enu
|
|||||||
enum_array_expr->resolve_status = RESOLVE_NOT_DONE;
|
enum_array_expr->resolve_status = RESOLVE_NOT_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, TypeInfo *parent, bool was_group, bool is_macro, Expr *identifier)
|
static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, TypeInfo *parent, bool was_group, Expr *identifier)
|
||||||
{
|
{
|
||||||
assert(identifier->expr_kind == EXPR_IDENTIFIER);
|
assert(identifier->expr_kind == EXPR_IDENTIFIER);
|
||||||
|
|
||||||
@@ -3153,13 +3089,6 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 12b. If the member was *not* a macro but was prefixed with `@` then that's an error.
|
|
||||||
if (member->decl_kind != DECL_MACRO && is_macro)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(expr, "'@' should only be placed in front of macro names.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (member->decl_kind == DECL_VAR)
|
if (member->decl_kind == DECL_VAR)
|
||||||
{
|
{
|
||||||
expr->expr_kind = EXPR_TYPEINFO;
|
expr->expr_kind = EXPR_TYPEINFO;
|
||||||
@@ -3178,12 +3107,6 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 12a. If the member was a macro and it isn't prefixed with `@` then that's an error.
|
|
||||||
if (member->decl_kind == DECL_MACRO && !is_macro)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(expr, "Expected '@' before the macro name.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
expr->identifier_expr.ident = name;
|
expr->identifier_expr.ident = name;
|
||||||
expr->expr_kind = EXPR_IDENTIFIER;
|
expr->expr_kind = EXPR_IDENTIFIER;
|
||||||
@@ -3205,7 +3128,6 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr)
|
|||||||
|
|
||||||
// 2. The right hand side may be a @ident or ident
|
// 2. The right hand side may be a @ident or ident
|
||||||
Expr *child = expr->access_expr.child;
|
Expr *child = expr->access_expr.child;
|
||||||
bool is_macro = child->expr_kind == EXPR_MACRO_EXPANSION;
|
|
||||||
|
|
||||||
// 3. Handle xxxxxx.typeid
|
// 3. Handle xxxxxx.typeid
|
||||||
if (child->expr_kind == EXPR_TYPEINFO)
|
if (child->expr_kind == EXPR_TYPEINFO)
|
||||||
@@ -3238,7 +3160,7 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr)
|
|||||||
// 2. If our left-hand side is a type, e.g. MyInt.abc, handle this here.
|
// 2. If our left-hand side is a type, e.g. MyInt.abc, handle this here.
|
||||||
if (parent->expr_kind == EXPR_TYPEINFO)
|
if (parent->expr_kind == EXPR_TYPEINFO)
|
||||||
{
|
{
|
||||||
return sema_expr_analyse_type_access(context, expr, parent->type_expr, was_group, is_macro, identifier);
|
return sema_expr_analyse_type_access(context, expr, parent->type_expr, was_group, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Copy failability
|
// 6. Copy failability
|
||||||
@@ -3263,7 +3185,7 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr)
|
|||||||
Type *flat_type = type_flatten(type);
|
Type *flat_type = type_flatten(type);
|
||||||
const char *kw = identifier->identifier_expr.ident;
|
const char *kw = identifier->identifier_expr.ident;
|
||||||
|
|
||||||
if (!is_macro && kw_type == kw && flat_type->type_kind == TYPE_ANY)
|
if (kw_type == kw && flat_type->type_kind == TYPE_ANY)
|
||||||
{
|
{
|
||||||
expr->expr_kind = EXPR_TYPEOFANY;
|
expr->expr_kind = EXPR_TYPEOFANY;
|
||||||
expr->inner_expr = parent;
|
expr->inner_expr = parent;
|
||||||
@@ -3274,7 +3196,7 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr)
|
|||||||
CHECK_DEEPER:
|
CHECK_DEEPER:
|
||||||
|
|
||||||
// 9. Fix hard coded function `len` on subarrays and arrays
|
// 9. Fix hard coded function `len` on subarrays and arrays
|
||||||
if (!is_macro && kw == kw_len)
|
if (kw == kw_len)
|
||||||
{
|
{
|
||||||
if (flat_type->type_kind == TYPE_SUBARRAY)
|
if (flat_type->type_kind == TYPE_SUBARRAY)
|
||||||
{
|
{
|
||||||
@@ -3292,7 +3214,7 @@ CHECK_DEEPER:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hard coded ptr on subarrays and variant
|
// Hard coded ptr on subarrays and variant
|
||||||
if (!is_macro && kw == kw_ptr)
|
if (kw == kw_ptr)
|
||||||
{
|
{
|
||||||
if (flat_type->type_kind == TYPE_SUBARRAY)
|
if (flat_type->type_kind == TYPE_SUBARRAY)
|
||||||
{
|
{
|
||||||
@@ -3312,7 +3234,7 @@ CHECK_DEEPER:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_macro && kw == kw_ordinal)
|
if (kw == kw_ordinal)
|
||||||
{
|
{
|
||||||
if (type->type_kind == TYPE_ENUM)
|
if (type->type_kind == TYPE_ENUM)
|
||||||
{
|
{
|
||||||
@@ -3366,19 +3288,6 @@ CHECK_DEEPER:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 12a. If the member was a macro and it isn't prefixed with `@` then that's an error.
|
|
||||||
if (member->decl_kind == DECL_MACRO && !is_macro)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(expr, "Expected '@' before the macro name.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// 12b. If the member was *not* a macro but was prefixed with `@` then that's an error.
|
|
||||||
if (member->decl_kind != DECL_MACRO && is_macro)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(expr, "'@' should only be placed in front of macro names.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform bitstruct access to expr_bitaccess.
|
// Transform bitstruct access to expr_bitaccess.
|
||||||
if (member->var.kind == VARDECL_BITMEMBER)
|
if (member->var.kind == VARDECL_BITMEMBER)
|
||||||
{
|
{
|
||||||
@@ -5565,9 +5474,6 @@ static bool sema_take_addr_of(Expr *inner)
|
|||||||
case EXPR_CT_IDENT:
|
case EXPR_CT_IDENT:
|
||||||
SEMA_ERROR(inner, "It's not possible to take the address of a compile time value.");
|
SEMA_ERROR(inner, "It's not possible to take the address of a compile time value.");
|
||||||
return false;
|
return false;
|
||||||
case EXPR_MACRO_EXPANSION:
|
|
||||||
SEMA_ERROR(inner, "It's not possible to take the address of a macro.");
|
|
||||||
return false;
|
|
||||||
case EXPR_IDENTIFIER:
|
case EXPR_IDENTIFIER:
|
||||||
return sema_take_addr_of_ident(inner);
|
return sema_take_addr_of_ident(inner);
|
||||||
case EXPR_UNARY:
|
case EXPR_UNARY:
|
||||||
@@ -6962,8 +6868,6 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
|
|||||||
return sema_expr_analyse_unary(context, expr);
|
return sema_expr_analyse_unary(context, expr);
|
||||||
case EXPR_TYPEID:
|
case EXPR_TYPEID:
|
||||||
return sema_expr_analyse_typeid(context, expr);
|
return sema_expr_analyse_typeid(context, expr);
|
||||||
case EXPR_MACRO_EXPANSION:
|
|
||||||
return sema_expr_analyse_macro_expansion(context, expr);
|
|
||||||
case EXPR_IDENTIFIER:
|
case EXPR_IDENTIFIER:
|
||||||
return sema_expr_analyse_identifier(context, NULL, expr);
|
return sema_expr_analyse_identifier(context, NULL, expr);
|
||||||
case EXPR_CALL:
|
case EXPR_CALL:
|
||||||
@@ -7066,9 +6970,6 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr)
|
|||||||
case EXPR_TYPEINFO:
|
case EXPR_TYPEINFO:
|
||||||
SEMA_ERROR(expr, "A type must be followed by either (...) or '.'.");
|
SEMA_ERROR(expr, "A type must be followed by either (...) or '.'.");
|
||||||
return false;
|
return false;
|
||||||
case EXPR_MACRO_EXPANSION:
|
|
||||||
SEMA_ERROR(expr, "Expected macro followed by (...).", expr->ct_macro_ident_expr.identifier);
|
|
||||||
return expr_poison(expr);
|
|
||||||
case EXPR_CT_IDENT:
|
case EXPR_CT_IDENT:
|
||||||
if (!sema_cast_ct_ident_rvalue(context, expr)) return false;
|
if (!sema_cast_ct_ident_rvalue(context, expr)) return false;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -890,7 +890,7 @@ static Expr *sema_insert_method_macro_call(SemaContext *context, SourceSpan span
|
|||||||
{
|
{
|
||||||
if (parent->type->type_kind != TYPE_POINTER) expr_insert_addr(parent);
|
if (parent->type->type_kind != TYPE_POINTER) expr_insert_addr(parent);
|
||||||
}
|
}
|
||||||
if (!sema_expr_analyse_general_call(context, len_call, method_decl, parent, is_macro, false)) return poisoned_expr;
|
if (!sema_expr_analyse_general_call(context, len_call, method_decl, parent, false)) return poisoned_expr;
|
||||||
len_call->resolve_status = RESOLVE_DONE;
|
len_call->resolve_status = RESOLVE_DONE;
|
||||||
return len_call;
|
return len_call;
|
||||||
}
|
}
|
||||||
@@ -1551,8 +1551,8 @@ static bool sema_analyse_continue_stmt(SemaContext *context, Ast *statement)
|
|||||||
switch (parent->ast_kind)
|
switch (parent->ast_kind)
|
||||||
{
|
{
|
||||||
case AST_FOR_STMT:
|
case AST_FOR_STMT:
|
||||||
// Is this plain "do"?
|
// Break on anything but plain "do"
|
||||||
if (parent->for_stmt.cond || parent->flow.skip_first) break;
|
if (parent->for_stmt.cond || !parent->flow.skip_first) break;
|
||||||
FALLTHROUGH;
|
FALLTHROUGH;
|
||||||
default:
|
default:
|
||||||
SEMA_ERROR(statement, "'continue' may only be used with 'for', 'while' and 'do-while' statements.");
|
SEMA_ERROR(statement, "'continue' may only be used with 'for', 'while' and 'do-while' statements.");
|
||||||
|
|||||||
@@ -74,7 +74,13 @@ const char *kw_check_assign;
|
|||||||
const char *kw_argc;
|
const char *kw_argc;
|
||||||
const char *kw_argv;
|
const char *kw_argv;
|
||||||
const char *kw_mainstub;;
|
const char *kw_mainstub;;
|
||||||
|
const char *kw_at_ensure;
|
||||||
|
const char *kw_at_require;
|
||||||
|
const char *kw_at_pure;
|
||||||
|
const char *kw_at_optreturn;
|
||||||
|
const char *kw_at_param;
|
||||||
|
const char *kw_at_return;
|
||||||
|
const char *kw_at_checked;
|
||||||
|
|
||||||
void symtab_destroy()
|
void symtab_destroy()
|
||||||
{
|
{
|
||||||
@@ -181,27 +187,36 @@ void symtab_init(uint32_t capacity)
|
|||||||
assert(builtin_list[i] && "Missing builtin");
|
assert(builtin_list[i] && "Missing builtin");
|
||||||
}
|
}
|
||||||
|
|
||||||
attribute_list[ATTRIBUTE_INLINE] = kw_inline;
|
type = TOKEN_AT_IDENT;
|
||||||
attribute_list[ATTRIBUTE_NOINLINE] = kw_noinline;
|
kw_at_param = KW_DEF("@param");
|
||||||
attribute_list[ATTRIBUTE_BIGENDIAN] = KW_DEF("bigendian");
|
kw_at_ensure = KW_DEF("@ensure");
|
||||||
attribute_list[ATTRIBUTE_LITTLEENDIAN] = KW_DEF("littleendian");
|
kw_at_optreturn = KW_DEF("@optreturn");
|
||||||
attribute_list[ATTRIBUTE_NORETURN] = KW_DEF("noreturn");
|
kw_at_pure = KW_DEF("@pure");
|
||||||
attribute_list[ATTRIBUTE_SECTION] = KW_DEF("section");
|
kw_at_require = KW_DEF("@require");
|
||||||
attribute_list[ATTRIBUTE_EXTNAME] = KW_DEF("extname");
|
kw_at_checked = KW_DEF("@checked");
|
||||||
attribute_list[ATTRIBUTE_WEAK] = KW_DEF("weak");
|
kw_at_return = KW_DEF("@return");
|
||||||
attribute_list[ATTRIBUTE_ALIGN] = kw_align;
|
attribute_list[ATTRIBUTE_INLINE] = KW_DEF("@inline");
|
||||||
attribute_list[ATTRIBUTE_PACKED] = KW_DEF("packed");
|
attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("@noinline");
|
||||||
attribute_list[ATTRIBUTE_UNUSED] = KW_DEF("unused");
|
attribute_list[ATTRIBUTE_BIGENDIAN] = KW_DEF("@bigendian");
|
||||||
attribute_list[ATTRIBUTE_USED] = KW_DEF("used");
|
attribute_list[ATTRIBUTE_LITTLEENDIAN] = KW_DEF("@littleendian");
|
||||||
attribute_list[ATTRIBUTE_NAKED] = KW_DEF("naked");
|
attribute_list[ATTRIBUTE_NORETURN] = KW_DEF("@noreturn");
|
||||||
attribute_list[ATTRIBUTE_CDECL] = KW_DEF("cdecl");
|
attribute_list[ATTRIBUTE_SECTION] = KW_DEF("@section");
|
||||||
attribute_list[ATTRIBUTE_STDCALL] = KW_DEF("stdcall");
|
attribute_list[ATTRIBUTE_EXTNAME] = KW_DEF("@extname");
|
||||||
attribute_list[ATTRIBUTE_VECCALL] = KW_DEF("veccall");
|
attribute_list[ATTRIBUTE_WEAK] = KW_DEF("@weak");
|
||||||
attribute_list[ATTRIBUTE_REGCALL] = KW_DEF("regcall");
|
attribute_list[ATTRIBUTE_ALIGN] = KW_DEF("@align");
|
||||||
attribute_list[ATTRIBUTE_FASTCALL] = KW_DEF("fastcall");
|
attribute_list[ATTRIBUTE_PACKED] = KW_DEF("@packed");
|
||||||
attribute_list[ATTRIBUTE_OVERLAP] = KW_DEF("overlap");
|
attribute_list[ATTRIBUTE_UNUSED] = KW_DEF("@unused");
|
||||||
attribute_list[ATTRIBUTE_OPERATOR] = KW_DEF("operator");
|
attribute_list[ATTRIBUTE_USED] = KW_DEF("@used");
|
||||||
attribute_list[ATTRIBUTE_AUTOIMPORT] = KW_DEF("autoimport");
|
attribute_list[ATTRIBUTE_NAKED] = KW_DEF("@naked");
|
||||||
|
attribute_list[ATTRIBUTE_CDECL] = KW_DEF("@cdecl");
|
||||||
|
attribute_list[ATTRIBUTE_STDCALL] = KW_DEF("@stdcall");
|
||||||
|
attribute_list[ATTRIBUTE_VECCALL] = KW_DEF("@veccall");
|
||||||
|
attribute_list[ATTRIBUTE_REGCALL] = KW_DEF("@regcall");
|
||||||
|
attribute_list[ATTRIBUTE_FASTCALL] = KW_DEF("@fastcall");
|
||||||
|
attribute_list[ATTRIBUTE_OVERLAP] = KW_DEF("@overlap");
|
||||||
|
attribute_list[ATTRIBUTE_OPERATOR] = KW_DEF("@operator");
|
||||||
|
attribute_list[ATTRIBUTE_PURE] = kw_at_pure;
|
||||||
|
attribute_list[ATTRIBUTE_AUTOIMPORT] = KW_DEF("@autoimport");
|
||||||
|
|
||||||
for (unsigned i = 0; i < NUMBER_OF_ATTRIBUTES; i++)
|
for (unsigned i = 0; i < NUMBER_OF_ATTRIBUTES; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -157,6 +157,13 @@ const char *token_type_to_string(TokenType type)
|
|||||||
case TOKEN_TYPE_IDENT:
|
case TOKEN_TYPE_IDENT:
|
||||||
return "TYPE_IDENT";
|
return "TYPE_IDENT";
|
||||||
|
|
||||||
|
case TOKEN_AT_IDENT:
|
||||||
|
return "MACRO_IDENT";
|
||||||
|
case TOKEN_AT_TYPE_IDENT:
|
||||||
|
return "MACRO_TYPE_IDENT";
|
||||||
|
case TOKEN_AT_CONST_IDENT:
|
||||||
|
return "MACRO_CONST_IDENT";
|
||||||
|
|
||||||
// Asm
|
// Asm
|
||||||
case TOKEN_ASM_STRING:
|
case TOKEN_ASM_STRING:
|
||||||
return "ASM_STRING";
|
return "ASM_STRING";
|
||||||
@@ -318,20 +325,6 @@ const char *token_type_to_string(TokenType type)
|
|||||||
return "/**";
|
return "/**";
|
||||||
case TOKEN_DOCS_END:
|
case TOKEN_DOCS_END:
|
||||||
return "*/";
|
return "*/";
|
||||||
case TOKEN_DOCS_OPTRETURN:
|
|
||||||
return "@optreturn";
|
|
||||||
case TOKEN_DOCS_PARAM:
|
|
||||||
return "@param";
|
|
||||||
case TOKEN_DOCS_RETURN:
|
|
||||||
return "@return";
|
|
||||||
case TOKEN_DOCS_ENSURE:
|
|
||||||
return "@ensure";
|
|
||||||
case TOKEN_DOCS_REQUIRE:
|
|
||||||
return "@require";
|
|
||||||
case TOKEN_DOCS_CHECKED:
|
|
||||||
return "@checked";
|
|
||||||
case TOKEN_DOCS_PURE:
|
|
||||||
return "@pure";
|
|
||||||
case TOKEN_DOC_DIRECTIVE:
|
case TOKEN_DOC_DIRECTIVE:
|
||||||
return "DOC_DIRECTIVE";
|
return "DOC_DIRECTIVE";
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define COMPILER_VERSION "0.2.1"
|
#define COMPILER_VERSION "0.2.2"
|
||||||
@@ -5,13 +5,13 @@ struct St12
|
|||||||
{
|
{
|
||||||
int a @align(16);
|
int a @align(16);
|
||||||
}
|
}
|
||||||
fn St12 f12_0(void) { while (1) {}; @unreachable(); }
|
fn St12 f12_0(void) { while (1) {}; unreachable(); }
|
||||||
fn void f12_1(St12 a0) {}
|
fn void f12_1(St12 a0) {}
|
||||||
|
|
||||||
struct St13_0 { long[3] f0; }
|
struct St13_0 { long[3] f0; }
|
||||||
struct St13_1 { long[2] f0; }
|
struct St13_1 { long[2] f0; }
|
||||||
fn St13_0 f13(int a, int b, int c, int d,
|
fn St13_0 f13(int a, int b, int c, int d,
|
||||||
St13_1 e, int f) { while (1) {}; @unreachable(); }
|
St13_1 e, int f) { while (1) {}; unreachable(); }
|
||||||
|
|
||||||
fn void f14(int a, int b, int c, int d, int e, int f, ichar x) {}
|
fn void f14(int a, int b, int c, int d, int e, int f, ichar x) {}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ fn void test()
|
|||||||
{
|
{
|
||||||
int x = foo();
|
int x = foo();
|
||||||
if (x > 0) return;
|
if (x > 0) return;
|
||||||
@unreachable();
|
unreachable();
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
fn void test()
|
fn void test()
|
||||||
{
|
{
|
||||||
for (int a @align(16) @align(16) = 0 ; a < 10; a++) // #error: Repeat of attribute 'align'
|
for (int a @align(16) @align(16) = 0 ; a < 10; a++) // #error: Repeat of attribute '@align'
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,11 @@ extern fn void printf(char*, ...);
|
|||||||
|
|
||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
printf("%s\n", @getisprime(3));
|
printf("%s\n", getisprime(3));
|
||||||
printf("%s\n", @getisprime(12));
|
printf("%s\n", getisprime(12));
|
||||||
printf("%s\n", @getisprime(4));
|
printf("%s\n", getisprime(4));
|
||||||
printf("%s\n", @getisprime(100));
|
printf("%s\n", getisprime(100));
|
||||||
printf("%s\n", @getisprime(17));
|
printf("%s\n", getisprime(17));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #expect: test.ll
|
/* #expect: test.ll
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ $endswitch;
|
|||||||
|
|
||||||
fn int main()
|
fn int main()
|
||||||
{
|
{
|
||||||
@tester();
|
tester();
|
||||||
@tester();
|
tester();
|
||||||
int i = 1;
|
int i = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ extern fn void printf(char*, ...);
|
|||||||
|
|
||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
printf("%s\n", @get_type(int));
|
printf("%s\n", get_type(int));
|
||||||
printf("%s\n", @get_type(double));
|
printf("%s\n", get_type(double));
|
||||||
printf("%s\n", @get_type(bool));
|
printf("%s\n", get_type(bool));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ macro foo($Foo)
|
|||||||
fn void test1()
|
fn void test1()
|
||||||
{
|
{
|
||||||
var $Bar;
|
var $Bar;
|
||||||
@foo($Bar); // #error: '$Bar' is not defined yet
|
foo($Bar); // #error: '$Bar' is not defined yet
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void test2()
|
fn void test2()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module test;
|
|||||||
import libc;
|
import libc;
|
||||||
import std::io;
|
import std::io;
|
||||||
|
|
||||||
macro timeit(#call)
|
macro @timeit(#call)
|
||||||
{
|
{
|
||||||
long t = (long)libc::clock();
|
long t = (long)libc::clock();
|
||||||
var $Type = $typeof(#call);
|
var $Type = $typeof(#call);
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ macro bitcast($Target, value)
|
|||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
float f = 100;
|
float f = 100;
|
||||||
int i = @bitcast(int, f);
|
int i = bitcast(int, f);
|
||||||
float f2 = @bitcast(float, i);
|
float f2 = bitcast(float, i);
|
||||||
printf("Bitcast %f to %d to %f", f, i, f2);
|
printf("Bitcast %f to %d to %f", f, i, f2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ fn void main()
|
|||||||
foo(1);
|
foo(1);
|
||||||
foo(2);
|
foo(2);
|
||||||
foo(-2);
|
foo(-2);
|
||||||
@foo2(0);
|
foo2(0);
|
||||||
@foo2(1);
|
foo2(1);
|
||||||
@foo2(2);
|
foo2(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #expect: foo.ll
|
/* #expect: foo.ll
|
||||||
|
|||||||
@@ -55,14 +55,14 @@ fn Doc! readDoc(char[] url)
|
|||||||
{
|
{
|
||||||
if (contains(url, "fail")) return ReadError.BAD_READ!;
|
if (contains(url, "fail")) return ReadError.BAD_READ!;
|
||||||
if (contains(url, "head-missing")) return { .head = null };
|
if (contains(url, "head-missing")) return { .head = null };
|
||||||
if (contains(url, "title-missing")) return { @dupe(Head { .title = null })? };
|
if (contains(url, "title-missing")) return { dupe(Head { .title = null })? };
|
||||||
if (contains(url, "title-empty")) return { @dupe(Head { .title = @dupe((char[])"")? })? };
|
if (contains(url, "title-empty")) return { dupe(Head { .title = dupe((char[])"")? })? };
|
||||||
// Not particularly elegant due to missing string functions.
|
// Not particularly elegant due to missing string functions.
|
||||||
int len = libc::snprintf(null, 0, "Title of %.*s", (int)url.len, url.ptr);
|
int len = libc::snprintf(null, 0, "Title of %.*s", (int)url.len, url.ptr);
|
||||||
char* str = mem::alloc(len + 1);
|
char* str = mem::alloc(len + 1);
|
||||||
if (!str) return ReadError.OUT_OF_MEMORY!;
|
if (!str) return ReadError.OUT_OF_MEMORY!;
|
||||||
libc::snprintf(str, len + 1, "Title of %.*s", (int)url.len, url.ptr);
|
libc::snprintf(str, len + 1, "Title of %.*s", (int)url.len, url.ptr);
|
||||||
return { @dupe(Head { .title = @dupe(str[..len - 1])? })? };
|
return { dupe(Head { .title = dupe(str[..len - 1])? })? };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Summary buildSummary(Doc doc)
|
fn Summary buildSummary(Doc doc)
|
||||||
@@ -137,7 +137,7 @@ fn void main()
|
|||||||
libc::printf(`Checking "https://%.*s/":` "\n", (int)url.len, url.ptr);
|
libc::printf(`Checking "https://%.*s/":` "\n", (int)url.len, url.ptr);
|
||||||
Summary summary = readAndBuildSummary(url);
|
Summary summary = readAndBuildSummary(url);
|
||||||
libc::printf(" Summary: ");
|
libc::printf(" Summary: ");
|
||||||
summary.print(@libc::stdout());
|
summary.print(libc::stdout());
|
||||||
libc::printf("\n");
|
libc::printf("\n");
|
||||||
char[] title_sure = summary.title ? *summary.title : "";
|
char[] title_sure = summary.title ? *summary.title : "";
|
||||||
libc::printf(" Title: %.*s\n", (int)title_sure.len, title_sure.ptr);
|
libc::printf(" Title: %.*s\n", (int)title_sure.len, title_sure.ptr);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ macro test()
|
|||||||
|
|
||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
libc::printf("%d\n", @test() ?? 2);
|
libc::printf("%d\n", test() ?? 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #expect: test.ll
|
/* #expect: test.ll
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ macro test()
|
|||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
defer libc::printf("Test1\n");
|
defer libc::printf("Test1\n");
|
||||||
libc::printf("%d\n", @test() ?? 2);
|
libc::printf("%d\n", test() ?? 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #expect: test.ll
|
/* #expect: test.ll
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ macro test()
|
|||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
defer libc::printf("Test1\n");
|
defer libc::printf("Test1\n");
|
||||||
libc::printf("%d\n", @test() ?? 2);
|
libc::printf("%d\n", test() ?? 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #expect: test.ll
|
/* #expect: test.ll
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ macro test()
|
|||||||
|
|
||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
@test() ?? 2; // #error: Cannot find a common type for 'void' and 'int'
|
test() ?? 2; // #error: Cannot find a common type for 'void' and 'int'
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ macro int hello()
|
|||||||
|
|
||||||
fn void test3()
|
fn void test3()
|
||||||
{
|
{
|
||||||
int* x = &@hello(); // #error: To take the address of a temporary value, use '&&' instead of '&'
|
int* x = &hello(); // #error: To take the address of a temporary value, use '&&' instead of '&'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void test3b()
|
fn void test3b()
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ fn void test()
|
|||||||
var $Foo = int;
|
var $Foo = int;
|
||||||
var $Bar = $Foo;
|
var $Bar = $Foo;
|
||||||
$Bar x;
|
$Bar x;
|
||||||
@hello(1);
|
hello(1);
|
||||||
var $foo = 1;
|
var $foo = 1;
|
||||||
$foo;
|
$foo;
|
||||||
FOO;
|
FOO;
|
||||||
|
|||||||
@@ -37,5 +37,5 @@ macro obfuscate(x, $foo)
|
|||||||
|
|
||||||
fn bool test7(uint x)
|
fn bool test7(uint x)
|
||||||
{
|
{
|
||||||
return @obfuscate(x, -1);
|
return obfuscate(x, -1);
|
||||||
}
|
}
|
||||||
@@ -15,10 +15,10 @@ extern fn void printf(char*, ...);
|
|||||||
|
|
||||||
fn int main()
|
fn int main()
|
||||||
{
|
{
|
||||||
int! a = @foo(1);
|
int! a = foo(1);
|
||||||
|
|
||||||
int! b = @foo((a + 3) ?? 2);
|
int! b = foo((a + 3) ?? 2);
|
||||||
int! c = @foo(0);
|
int! c = foo(0);
|
||||||
printf("a = %d\n", a);
|
printf("a = %d\n", a);
|
||||||
printf("b = %d\n", b);
|
printf("b = %d\n", b);
|
||||||
printf("c = %d\n", c);
|
printf("c = %d\n", c);
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ fn int test()
|
|||||||
{
|
{
|
||||||
int a = 2;
|
int a = 2;
|
||||||
int b = 3;
|
int b = 3;
|
||||||
return @foo(&square, 2) + a + b; // 9
|
return foo(&square, 2) + a + b; // 9
|
||||||
// return @foo(square, 2) + a + b;
|
// return foo(square, 2) + a + b;
|
||||||
// Error the symbol "square" cannot be used as an argument.
|
// Error the symbol "square" cannot be used as an argument.
|
||||||
}
|
}
|
||||||
|
|
||||||
// #expect: example.ll
|
/* #expect: example.ll
|
||||||
|
|
||||||
define i32 @example.square(i32 %0) #0 {
|
define i32 @example.square(i32 %0) #0 {
|
||||||
entry:
|
entry:
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ import foo;
|
|||||||
|
|
||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
@testm();
|
testm();
|
||||||
test();
|
test();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void main2()
|
fn void main2()
|
||||||
{
|
{
|
||||||
@testm1(); // #error: Macros from other modules must be prefixed with the module nam
|
testm1(); // #error: Macros from other modules must be prefixed with the module nam
|
||||||
test1(); // #error: Functions from other modules must be prefixed with the module nam
|
test1(); // #error: Functions from other modules must be prefixed with the module nam
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ struct An2
|
|||||||
|
|
||||||
extern fn void printf(char *string);
|
extern fn void printf(char *string);
|
||||||
|
|
||||||
macro void An2.helloWorld(An2 &an2)
|
macro void An2.@helloWorld(An2 &an2)
|
||||||
{
|
{
|
||||||
printf("An2 hello\n");
|
printf("An2 hello\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ struct An2
|
|||||||
|
|
||||||
extern fn void printf(char* string);
|
extern fn void printf(char* string);
|
||||||
|
|
||||||
macro void An2.helloWorld(An2 &an2)
|
macro void An2.@helloWorld(An2 &an2)
|
||||||
{
|
{
|
||||||
printf("An2 hello\n");
|
printf("An2 hello\n");
|
||||||
}
|
}
|
||||||
@@ -44,14 +44,3 @@ fn void test3()
|
|||||||
a.@helloWorld.b; // #error: There is no member or method 'b' on 'void'
|
a.@helloWorld.b; // #error: There is no member or method 'b' on 'void'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void test4()
|
|
||||||
{
|
|
||||||
An1 an;
|
|
||||||
an.x.@y; // #error: '@' should only be placed in front of macro names
|
|
||||||
}
|
|
||||||
|
|
||||||
fn void test5()
|
|
||||||
{
|
|
||||||
An1 an;
|
|
||||||
an.x.@y(); // #error: '@' should only be placed in front of macro names
|
|
||||||
}
|
|
||||||
@@ -9,12 +9,12 @@ module baz;
|
|||||||
import foo;
|
import foo;
|
||||||
import std::io;
|
import std::io;
|
||||||
|
|
||||||
macro void foo::Bar.test(Bar &bar)
|
macro void foo::Bar.@test(Bar &bar)
|
||||||
{
|
{
|
||||||
io::println("Inside of baz::Bar.test");
|
io::println("Inside of baz::Bar.test");
|
||||||
}
|
}
|
||||||
|
|
||||||
macro void Bar.test(Bar &bar) // #error: This macro method is already defined in this module
|
macro void Bar.@test(Bar &bar) // #error: This macro method is already defined in this module
|
||||||
{
|
{
|
||||||
io::println("Inside of baz::Bar.test");
|
io::println("Inside of baz::Bar.test");
|
||||||
}
|
}
|
||||||
@@ -26,6 +26,6 @@ import baz;
|
|||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
Bar bar;
|
Bar bar;
|
||||||
bar.test();
|
bar.@test();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
macro int cofefe(#a)
|
macro int @cofefe(#a)
|
||||||
{
|
{
|
||||||
int y = 0;
|
int y = 0;
|
||||||
return #a + #a;
|
return #a + #a;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
macro foo4(;@body)
|
macro @foo4(;@body)
|
||||||
{
|
{
|
||||||
@body; // #error: must be followed by ()
|
@body; // #error: must be followed by ()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ extern fn void printf(char*,...);
|
|||||||
|
|
||||||
fn int! foo() { return 1; }
|
fn int! foo() { return 1; }
|
||||||
|
|
||||||
macro foo_test(int i; @body())
|
macro @foo_test(int i; @body())
|
||||||
{
|
{
|
||||||
defer printf("%d\n", i);
|
defer printf("%d\n", i);
|
||||||
@body();
|
@body();
|
||||||
@@ -19,7 +19,7 @@ macro foo_defer()
|
|||||||
}
|
}
|
||||||
fn void! main()
|
fn void! main()
|
||||||
{
|
{
|
||||||
@foo_defer();
|
foo_defer();
|
||||||
@foo_test(34) {
|
@foo_test(34) {
|
||||||
defer printf("inside_defer\n");
|
defer printf("inside_defer\n");
|
||||||
};
|
};
|
||||||
|
|||||||
11
test/test_suite/macros/macro_calls_prefix.c3
Normal file
11
test/test_suite/macros/macro_calls_prefix.c3
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
macro foo(a, $b, $Type) {}
|
||||||
|
|
||||||
|
macro @foo2(a, $b, $Type) {}
|
||||||
|
|
||||||
|
macro bar(&x) // #error: non-function
|
||||||
|
{}
|
||||||
|
|
||||||
|
macro baz(#y) {} // #error: non-function
|
||||||
|
|
||||||
|
macro baz2(a; @body()) {} // #error: non-function
|
||||||
|
|
||||||
@@ -8,8 +8,8 @@ macro frab(x)
|
|||||||
|
|
||||||
fn void test2()
|
fn void test2()
|
||||||
{
|
{
|
||||||
@frab(1);
|
frab(1);
|
||||||
@frab(0);
|
frab(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #expect: test.ll
|
/* #expect: test.ll
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ macro foo(y)
|
|||||||
|
|
||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
libc::printf("%d\n", @foo(10));
|
libc::printf("%d\n", foo(10));
|
||||||
}
|
}
|
||||||
@@ -14,8 +14,8 @@ macro int abc(x)
|
|||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
defer printf("On exit\n");
|
defer printf("On exit\n");
|
||||||
@abc(123);
|
abc(123);
|
||||||
@abc(3);
|
abc(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #expect: foo.ll
|
/* #expect: foo.ll
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// #target: macos-x64
|
// #target: macos-x64
|
||||||
module foo;
|
module foo;
|
||||||
macro int cofefe(#a)
|
macro int @cofefe(#a)
|
||||||
{
|
{
|
||||||
int x = 0;
|
int x = 0;
|
||||||
defer printf("Was here\n");
|
defer printf("Was here\n");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
module foo;
|
module foo;
|
||||||
macro int cofefe(a; @body(x))
|
macro int @cofefe(a; @body(x))
|
||||||
{
|
{
|
||||||
@body(a);
|
@body(a);
|
||||||
@body(a);
|
@body(a);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ module baz;
|
|||||||
import bar;
|
import bar;
|
||||||
fn void test()
|
fn void test()
|
||||||
{
|
{
|
||||||
@bar::bar1();
|
bar::bar1();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #expect: baz.ll
|
/* #expect: baz.ll
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ module foo;
|
|||||||
import bar;
|
import bar;
|
||||||
fn void run()
|
fn void run()
|
||||||
{
|
{
|
||||||
@bar::test();
|
bar::test();
|
||||||
}
|
}
|
||||||
|
|
||||||
module bar;
|
module bar;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ macro checker(int x, $i)
|
|||||||
for (int i = 0; i < $indent; i++) printf(" ");
|
for (int i = 0; i < $indent; i++) printf(" ");
|
||||||
printf("Helo %d\n", x);
|
printf("Helo %d\n", x);
|
||||||
$if ($i > 0):
|
$if ($i > 0):
|
||||||
@checker(x, $i - 1);
|
checker(x, $i - 1);
|
||||||
$endif;
|
$endif;
|
||||||
if (x % 2 == 0) break FOO;
|
if (x % 2 == 0) break FOO;
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ macro checker(int x, $i)
|
|||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
int ab = 7;
|
int ab = 7;
|
||||||
@checker(ab, 3);
|
checker(ab, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #expect: test.ll
|
/* #expect: test.ll
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ module foo;
|
|||||||
import bar;
|
import bar;
|
||||||
fn void run()
|
fn void run()
|
||||||
{
|
{
|
||||||
@bar::test();
|
bar::test();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void run2()
|
fn void run2()
|
||||||
{
|
{
|
||||||
@bar::test2();
|
bar::test2();
|
||||||
}
|
}
|
||||||
|
|
||||||
private fn void tester() {}
|
private fn void tester() {}
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ macro int frob()
|
|||||||
|
|
||||||
fn void test1()
|
fn void test1()
|
||||||
{
|
{
|
||||||
@frob();
|
frob();
|
||||||
}
|
}
|
||||||
@@ -14,13 +14,13 @@ fn int Foo.mutate(Foo *foo)
|
|||||||
return 10 * ++foo.x;
|
return 10 * ++foo.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro macro_with_body(foo, &x; @body(x, y))
|
macro @macro_with_body(foo, &x; @body(x, y))
|
||||||
{
|
{
|
||||||
x = foo.x;
|
x = foo.x;
|
||||||
@body(foo.mutate(), x);
|
@body(foo.mutate(), x);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro repeat(int times; @body(x))
|
macro @repeat(int times; @body(x))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < times; i++)
|
for (int i = 0; i < times; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ module test;
|
|||||||
|
|
||||||
extern fn int printf(char *, ...);
|
extern fn int printf(char *, ...);
|
||||||
|
|
||||||
macro foo(x; @body(y))
|
macro @foo(x; @body(y))
|
||||||
{
|
{
|
||||||
@body(x);
|
@body(x);
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ macro foo_no(x)
|
|||||||
|
|
||||||
fn void test2()
|
fn void test2()
|
||||||
{
|
{
|
||||||
@foo_no(10) // #error: This macro does not support trailing statements
|
foo_no(10) // #error: This macro does not support trailing statements
|
||||||
{
|
{
|
||||||
printf("foek");
|
printf("foek");
|
||||||
};
|
};
|
||||||
@@ -40,11 +40,11 @@ fn void test2()
|
|||||||
|
|
||||||
macro foo2(x)
|
macro foo2(x)
|
||||||
{
|
{
|
||||||
@body(x); // #error: 'body' could not be found, did you spell it right?
|
@body(x); // #error: '@body' could not be found, did you spell it right?
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void test4()
|
fn void test4()
|
||||||
{
|
{
|
||||||
@foo2(10);
|
foo2(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ macro foo($Foo)
|
|||||||
define Bar = short;
|
define Bar = short;
|
||||||
fn void test()
|
fn void test()
|
||||||
{
|
{
|
||||||
int x = @foo(int);
|
int x = foo(int);
|
||||||
var $Foo = double;
|
var $Foo = double;
|
||||||
double d = @foo($Foo);
|
double d = foo($Foo);
|
||||||
double d2 = @foo($typeof(d));
|
double d2 = foo($typeof(d));
|
||||||
short z = @foo(Bar);
|
short z = foo(Bar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -53,23 +53,23 @@ fn ulong testFoo(short x)
|
|||||||
{
|
{
|
||||||
Foo z;
|
Foo z;
|
||||||
z.a = x;
|
z.a = x;
|
||||||
return @testbitcast(z, ulong);
|
return testbitcast(z, ulong);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn char[4] test(float x)
|
fn char[4] test(float x)
|
||||||
{
|
{
|
||||||
return @testbitcast(x, char[4]);
|
return testbitcast(x, char[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
float f = 12.353;
|
float f = 12.353;
|
||||||
int i = @testbitcast(f, int);
|
int i = testbitcast(f, int);
|
||||||
float f2 = @testbitcast(i, float);
|
float f2 = testbitcast(i, float);
|
||||||
printf("%f => %d => %f\n", f, i, f2);
|
printf("%f => %d => %f\n", f, i, f2);
|
||||||
double d = 12.353e267;
|
double d = 12.353e267;
|
||||||
ulong l = @testbitcast(d, ulong);
|
ulong l = testbitcast(d, ulong);
|
||||||
double d2 = @testbitcast(d, double);
|
double d2 = testbitcast(d, double);
|
||||||
printf("%e => %llu => %e\n", d, l, d2);
|
printf("%e => %llu => %e\n", d, l, d2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ struct Foo
|
|||||||
|
|
||||||
extern fn void printf(char*, ...);
|
extern fn void printf(char*, ...);
|
||||||
|
|
||||||
macro int* Foo.operator_element_at_ref(Foo &f, int a) @operator(elementref)
|
macro int* Foo.@operator_element_at_ref(Foo &f, int a) @operator(elementref)
|
||||||
{
|
{
|
||||||
return &f.a[a];
|
return &f.a[a];
|
||||||
}
|
}
|
||||||
|
|
||||||
macro int Foo.operator_len(Foo &f) @operator(len)
|
macro int Foo.@operator_len(Foo &f) @operator(len)
|
||||||
{
|
{
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro int Foo.operator_element_at(Foo &f, int a) @operator(elementat)
|
macro int Foo.@operator_element_at(Foo &f, int a) @operator(elementat)
|
||||||
{
|
{
|
||||||
return f.a[a];
|
return f.a[a];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ struct Foo
|
|||||||
int[] x;
|
int[] x;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro int Foo.operator_element_at(Foo &foo, usize index) @operator(elementat)
|
macro int Foo.@operator_element_at(Foo &foo, usize index) @operator(elementat)
|
||||||
{
|
{
|
||||||
return foo.x[index];
|
return foo.x[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
macro usize Foo.operator_len(Foo &foo) @operator(len)
|
macro usize Foo.@operator_len(Foo &foo) @operator(len)
|
||||||
{
|
{
|
||||||
return foo.x.len;
|
return foo.x.len;
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ fn void main()
|
|||||||
|
|
||||||
extern fn int printf(char *fmt, ...);
|
extern fn int printf(char *fmt, ...);
|
||||||
|
|
||||||
// #expect: foo.ll
|
/* #expect: foo.ll
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define void @foo.main() #0 {
|
define void @foo.main() #0 {
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ struct Foo
|
|||||||
int[] x;
|
int[] x;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro int Foo.operator_element_at(Foo &foo, usize index) @operator(elementat)
|
macro int Foo.@operator_element_at(Foo &foo, usize index) @operator(elementat)
|
||||||
{
|
{
|
||||||
return foo.x[index];
|
return foo.x[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
macro usize Foo.operator_len(Foo &foo) @operator(len)
|
macro usize Foo.@operator_len(Foo &foo) @operator(len)
|
||||||
{
|
{
|
||||||
return foo.x.len;
|
return foo.x.len;
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ fn void main()
|
|||||||
|
|
||||||
extern fn int printf(char *fmt, ...);
|
extern fn int printf(char *fmt, ...);
|
||||||
|
|
||||||
// #expect: foo.ll
|
/* #expect: foo.ll
|
||||||
|
|
||||||
define void @foo.main() #0 {
|
define void @foo.main() #0 {
|
||||||
entry:
|
entry:
|
||||||
|
|||||||
Reference in New Issue
Block a user