diff --git a/resources/lib/std/io.c3 b/resources/lib/std/io.c3 index e92568d84..9764463f4 100644 --- a/resources/lib/std/io.c3 +++ b/resources/lib/std/io.c3 @@ -1,4 +1,6 @@ module std::io; +import std::mem; +import libc; errtype IoError { @@ -54,6 +56,21 @@ func int println(char *message = "") @inline return _puts(message); } + +func void! File.open(File* file, char[] filename, char[] mode) +{ + char* filename_copy = mem::talloc(filename.len + 1)!!; + + char* mode_copy = mem::talloc(mode.len + 1)!!; + + mem::copy(filename_copy, (char*)(filename), filename.len); + mem::copy(mode_copy, (char*)(mode), mode.len); + filename_copy[filename.len] = 0; + mode_copy[filename.len] = 0; + file.file = libc::fopen(filename_copy, mode_copy); + if (!file.file) return IoError.FILE_NOT_FOUND!; +} + /* enum Seek @@ -73,11 +90,6 @@ func FileError errorFromErrno() return FileError { }; } -public func void! File.open(File *file, char *filename, char *mode) -{ - file.file = fopen(filename, mode); - if (!file.file) return errorFromErrno()!; -} public func void! File.seek(File *file, long offset, Seek seekMode = Seek.SET) { diff --git a/resources/lib/std/libc.c3 b/resources/lib/std/libc.c3 new file mode 100644 index 000000000..1e73f7895 --- /dev/null +++ b/resources/lib/std/libc.c3 @@ -0,0 +1,167 @@ +module libc; + +// stdlib + +// Constants need to be per os/arch +const int EXIT_FAILURE = 1; +const int EXIT_SUCCESS = 0; +const int RAND_MAX = 0x7fffffff; + +struct DivResult +{ + int quot; + int rem; +} + +struct LongDivResult +{ + long quot; + long rem; +} + +define TerminateFunction = func void(); +define CompareFunction = func int(void*, void*); +extern func double atof(char* str); +extern func long atol(char* str); +extern func double strtod(char* str, char** endptr); +extern func long strtol(char* str, char** endptr, int base); +extern func ulong stroul(char* str, char** endptr, int base); +extern func void abort(); +extern func void atexit(TerminateFunction f); +extern func void exit(int status); +extern func char* getenv(char* name); +extern func int system(char* str); +extern func void bsearch(void* key, void *base, usize items, usize size, CompareFunction compare); +extern func void qsort(void* base, usize items, usize size, CompareFunction compare); +extern func int abs(int x); +extern func DivResult div(int numer, int denom); +extern func long labs(long x); +extern func LongDivResult ldiv(long number, long denom); +extern func int rand(); +extern func void srand(uint seed); + +// MB functions omitted + +// string +extern func void* memchr(void* str, int c, usize n); +extern func int memcmp(void* str1, void* str2, usize n); +extern func void* memcpy(void* dest, void* src, usize n); +extern func void* memmove(void* dest, void* src, usize n); +extern func void* memset(void* dest, usize n); +extern func char* strcat(char* dest, char* src); +extern func char* strncat(char* dest, char* src, usize n); +extern func char* strchr(char* str, int c); +extern func int strcmp(char* str1, char* str2); +extern func int strncmp(char* str1, char* str2, usize n); +extern func int strcoll(char* str1, char* str2); +extern func char* strcpy(char* dst, char* src); +extern func char* strncpy(char* dst, char* src, usize n); +extern func usize strcspn(char* str1, char* str2); +extern func char* strerror(int errnum); +extern func usize strlen(char* str); +extern func char* strpbrk(char* str1, char* str2); +extern func usize strspn(char* str1, char* str2); +extern func char* strstr(char* haystack, char* needle); +extern func char* strtok(char* str, char* delim); +extern func usize strxfrm(char* dest, char* src, usize n); + +// malloc +extern func void* malloc(usize size); +extern func void* calloc(usize count, usize size); +extern func void* free(void*); +extern func void* realloc(void* ptr, usize size); + +// stdio + +define Fpos = long; +define CFile = void*; + +// The following needs to be set per arch+os +// For now I have simply pulled the defaults from MacOS +const int SEEK_SET = 0; +const int SEEK_CUR = 1; +const int SEEK_END = 2; +const int _IOFBF = 0; // Fully buffered +const int _IOLBF = 1; // Line buffered +const int _IONBF = 2; // Unbuffered +const int BUFSIZ = 1024; +const int EOF = -1; +const int FOPEN_MAX = 20; +const int FILENAME_MAX = 1024; + +extern func int fclose(CFile stream); +extern func void clearerr(CFile stream); +extern func int feof(CFile stream); +extern func int ferror(CFile stream); +extern func int fflush(CFile stream); +extern func int fgetpos(CFile stream, Fpos* pos); +extern func CFile fopen(char* filename, char* mode); +extern func usize fread(void* ptr, usize size, usize nmemb, CFile stream); +extern func CFile freopen(char* filename, char* mode, CFile stream); +extern func int fseek(CFile stream, long offset, int whence); +extern func int fsetpos(CFile stream, Fpos* pos); +extern func long ftell(CFile stream); +extern func usize fwrite(void* ptr, usize size, usize nmemb, CFile stream); +extern func int remove(char* filename); +extern func int rename(char* old_name, char* new_name); +extern func void rewind(CFile stream); +extern func void setbuf(CFile stream, char* buffer); +extern func void setvbuf(CFile stream, char* buffer, int mode, usize size); +extern func CFile tmpnam(char* str); +extern func int fprintf(CFile stream, char* format, ...); +extern func int printf(char* format, ...); +extern func int sprintf(char* str, char* format, ...); +extern func int fscanf(CFile stream, char* format, ...); +extern func int scanf(char* format, ...); +extern func int sscanf(char* str, char* format, ...); +extern func int fgetc(CFile stream); +extern func char* fgets(char* str, int n, CFile stream); +extern func int fputc(int c, CFile stream); +extern func int getc(CFile stream); +extern func int getchar(); +extern func int putc(char c, CFile stream); +extern func int putchar(int c); +extern func int puts(char* str); +extern func int ungetc(int c, CFile stream); +extern func void perror(char* str); + +// vsprintf vprintf not supported + +// time.h + +struct Tm +{ + int tm_sec; /* seconds after the minute [0-60] */ + int tm_min; /* minutes after the hour [0-59] */ + int tm_hour; /* hours since midnight [0-23] */ + int tm_mday; /* day of the month [1-31] */ + int tm_mon; /* months since January [0-11] */ + int tm_year; /* years since 1900 */ + int tm_wday; /* days since Sunday [0-6] */ + int tm_yday; /* days since January 1 [0-365] */ + int tm_isdst; /* Daylight Savings Time flag */ + long tm_gmtoff; /* offset from UTC in seconds */ + char *tm_zone; /* timezone abbreviation */ +} + +// Likely wrong, must be per platform. +const CLOCKS_PER_SEC = 1000000; + +// Time also needs to be per platform +define Time = long; +define Clock = ulong; + +extern func char* asctime(Tm *timeptr); +extern func Clock clock(); +extern func char* ctime(Time *timer); +extern func double difftime(Time time1, Time time2); +extern func Tm* gmtime(Time *timer); +extern func Tm* localtime(Time *timer); +extern func Time mktime(Tm *timeptr); +extern func usize strftime(char* str, usize maxsize, char* format, Tm *timeptr); +extern func Time time(Time *timer); + +// signal +define SignalFunction = func void(int); +extern func SignalFunction signal(int sig, SignalFunction fn); +// Incomplete \ No newline at end of file diff --git a/resources/testfragments/toposort.c3 b/resources/testfragments/toposort.c3 index cdc22fb1e..44fa8dc7f 100644 --- a/resources/testfragments/toposort.c3 +++ b/resources/testfragments/toposort.c3 @@ -23,11 +23,10 @@ struct TopoList } -public func void sort(InputPair[] pairs, uint elements) +func void sort(InputPair[] pairs, uint elements) { - printf(.x = "fe"); InputPair[] result = @array::make(InputPair, pairs.len); - TopoList* top = mem::calloc(TopoList.sizeof, elements); + TopoList* top = @array::make(TopoList, elements); for (int i = 0; i < pairs.len; i++) { InputPair pair = pairs[i]; @@ -71,7 +70,7 @@ public func void sort(InputPair[] pairs, uint elements) } } -public func void main() +func void main() { InputPair[10] pairs = { { 9, 2 }, diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 3fe57ab31..cfad04cbe 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -300,8 +300,8 @@ void compiler_compile(void) vec_add(global_context.sources, strformat("%s/std/mem.c3", global_context.lib_dir)); vec_add(global_context.sources, strformat("%s/std/array.c3", global_context.lib_dir)); vec_add(global_context.sources, strformat("%s/std/math.c3", global_context.lib_dir)); + vec_add(global_context.sources, strformat("%s/std/libc.c3", global_context.lib_dir)); } - bool has_error = false; VECEACH(global_context.sources, i) { diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 5e2965952..88e198714 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -358,6 +358,7 @@ typedef enum TOKEN_PLUS_ASSIGN, // += TOKEN_PLUSPLUS, // ++ TOKEN_RBRAPIPE, // |} + TOKEN_QUESTQUEST, // ?? TOKEN_SCOPE, // :: TOKEN_SHL, // << TOKEN_SHR, // >> diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 9778682d0..06b12c9d3 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -1569,6 +1569,7 @@ static bool lexer_scan_token_inner(Lexer *lexer, LexMode mode) TOKEN_BIT_XOR, "^"); case '?': + if (match(lexer, '?')) return add_token(lexer, TOKEN_QUESTQUEST, "??"); return match(lexer, ':') ? add_token(lexer, TOKEN_ELVIS, "?:") : add_token(lexer, TOKEN_QUESTION, "?"); case '<': if (match(lexer, '<')) diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 34d6dcdf4..ceac89a0b 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -872,7 +872,10 @@ static Expr *parse_bangbang_expr(Context *context, Expr *left) static Expr *parse_else_expr(Context *context, Expr *left) { Expr *else_expr = EXPR_NEW_TOKEN(EXPR_ELSE, context->tok); - advance_and_verify(context, TOKEN_ELSE); + if (!try_consume(context, TOKEN_ELSE)) + { + advance_and_verify(context, TOKEN_QUESTQUEST); + } else_expr->else_expr.expr = left; switch (context->tok.type) { @@ -1371,6 +1374,7 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_ELSE] = { NULL, parse_else_expr, PREC_ELSE }, [TOKEN_QUESTION] = { NULL, parse_ternary_expr, PREC_TERNARY }, + [TOKEN_QUESTQUEST] = { NULL, parse_else_expr, PREC_ELSE}, [TOKEN_ELVIS] = { NULL, parse_ternary_expr, PREC_TERNARY }, [TOKEN_PLUSPLUS] = { parse_unary_expr, parse_post_unary, PREC_CALL }, [TOKEN_MINUSMINUS] = { parse_unary_expr, parse_post_unary, PREC_CALL }, diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 0819ff28f..0e5ed15b7 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -1028,6 +1028,7 @@ Ast *parse_stmt(Context *context) case TOKEN_ALIAS: case TOKEN_AS: case TOKEN_ELSE: + case TOKEN_QUESTQUEST: case TOKEN_ENUM: case TOKEN_FUNC: case TOKEN_GENERIC: diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 2c2e205d4..5a0648f12 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1107,7 +1107,7 @@ static inline bool sema_check_invalid_body_arguments(Context *context, Expr *cal return true; } -static inline bool sema_expand_call_arguments(Context *context, Expr *call, Decl **params, Expr **args, unsigned func_param_count, bool variadic) +static inline bool sema_expand_call_arguments(Context *context, CalledDecl *callee, Expr *call, Decl **params, Expr **args, unsigned func_param_count, bool variadic) { unsigned num_args = vec_size(args); @@ -1197,10 +1197,18 @@ static inline bool sema_expand_call_arguments(Context *context, Expr *call, Decl if (actual_args[i]) continue; // 17b. Set the init expression. - if (params[i]->var.init_expr) + Expr *init_expr = params[i]->var.init_expr; + if (init_expr) { - assert(params[i]->var.init_expr->resolve_status == RESOLVE_DONE); - actual_args[i] = params[i]->var.init_expr; + if (callee->macro) + { + actual_args[i] = copy_expr(init_expr); + } + else + { + assert(init_expr->resolve_status == RESOLVE_DONE); + actual_args[i] = init_expr; + } continue; } @@ -1273,7 +1281,7 @@ static inline bool sema_expr_analyse_call_invocation(Context *context, Expr *cal func_param_count--; } - if (!sema_expand_call_arguments(context, call, params, args, func_param_count, callee.variadic != VARIADIC_NONE)) return false; + if (!sema_expand_call_arguments(context, &callee, call, params, args, func_param_count, callee.variadic != VARIADIC_NONE)) return false; args = call->call_expr.arguments; num_args = vec_size(args); diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index d4f05ecef..8e9dd129b 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -112,6 +112,8 @@ const char *token_type_to_string(TokenType type) return "+="; case TOKEN_PLUSPLUS: return "++"; + case TOKEN_QUESTQUEST: + return "??"; case TOKEN_RBRAPIPE: return "|}"; case TOKEN_SCOPE: diff --git a/src/version.h b/src/version.h index f59962f01..0e00edec7 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "A233" \ No newline at end of file +#define COMPILER_VERSION "A234" \ No newline at end of file diff --git a/test/src/tester.py b/test/src/tester.py index ec8e3b330..45cba6be9 100644 --- a/test/src/tester.py +++ b/test/src/tester.py @@ -170,7 +170,7 @@ class Issues: lines = len(self.sourcefile.content) while self.line < lines: line = self.sourcefile.content[self.line].strip() - if line.startswith("// #"): + if line.startswith("// #") or line.startswith("/* #"): self.parse_header_directive(line) self.line += 1 continue diff --git a/test/test_suite/errors/else_checks.c3t b/test/test_suite/errors/else_checks.c3t index 4e565a43b..156eb3558 100644 --- a/test/test_suite/errors/else_checks.c3t +++ b/test/test_suite/errors/else_checks.c3t @@ -4,13 +4,14 @@ extern func int! testError(); func void test() { - double x = (testError() + testError()) else 100; - double y = (1 << testError()) else 100; - double z = testError() >> 1 else 100; - double w = testError() * testError() else 100; + + double x = (testError() + testError()) ?? 100; + double y = (1 << testError()) ?? 100; + double z = testError() >> 1 ?? 100; + double w = testError() * testError() ?? 100; } -// #expect: else_checks.ll +/* #expect: else_checks.ll ; Function Attrs: nounwind declare i64 @testError(i32*) #0