@ is now part of the name of an attribute or a macro. Macros without '@' must be function-like.

This commit is contained in:
Christoffer Lerno
2022-05-08 15:22:38 +02:00
parent 29a9769651
commit 9691d50a6f
80 changed files with 414 additions and 513 deletions

View File

@@ -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

View File

@@ -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)];
} }

View File

@@ -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;
} }

View File

@@ -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)

View File

@@ -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];
} }

View File

@@ -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

View File

@@ -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
*/ */

View File

@@ -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();
} }

View File

@@ -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);
} }

View File

@@ -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 */

View File

@@ -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++)
{ {

View File

@@ -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);
} }

View File

@@ -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))

View File

@@ -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++)
{ {

View File

@@ -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();
} }
} }

View File

@@ -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++)
{ {

View File

@@ -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);

View File

@@ -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();
} }
} }

View File

@@ -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)
{ {

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 },

View File

@@ -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;

View File

@@ -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;
} }

View File

@@ -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:

View File

@@ -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);

View File

@@ -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;

View File

@@ -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.");

View File

@@ -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++)
{ {

View File

@@ -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";

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.2.1" #define COMPILER_VERSION "0.2.2"

View File

@@ -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) {}

View File

@@ -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++;
} }

View File

@@ -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'
{ {
} }
} }

View File

@@ -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

View File

@@ -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;
} }

View File

@@ -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));
} }

View File

@@ -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()

View File

@@ -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);

View File

@@ -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);
} }

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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'
} }

View File

@@ -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()

View File

@@ -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;

View File

@@ -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);
} }

View File

@@ -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);

View File

@@ -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:

View File

@@ -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
} }

View File

@@ -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");
} }

View File

@@ -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
}

View File

@@ -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();
} }

View File

@@ -1,4 +1,4 @@
macro int cofefe(#a) macro int @cofefe(#a)
{ {
int y = 0; int y = 0;
return #a + #a; return #a + #a;

View File

@@ -1,4 +1,4 @@
macro foo4(;@body) macro @foo4(;@body)
{ {
@body; // #error: must be followed by () @body; // #error: must be followed by ()
} }

View File

@@ -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");
}; };

View 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

View File

@@ -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

View File

@@ -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));
} }

View File

@@ -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

View File

@@ -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");

View File

@@ -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);

View File

@@ -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

View File

@@ -2,7 +2,7 @@ module foo;
import bar; import bar;
fn void run() fn void run()
{ {
@bar::test(); bar::test();
} }
module bar; module bar;

View File

@@ -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

View File

@@ -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() {}

View File

@@ -5,5 +5,5 @@ macro int frob()
fn void test1() fn void test1()
{ {
@frob(); frob();
} }

View File

@@ -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++)
{ {

View File

@@ -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);
} }

View File

@@ -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);
} }

View File

@@ -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);
} }

View File

@@ -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];
} }

View File

@@ -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 {

View File

@@ -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: