mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix issue with default macro arguments. Test of ?? instead of else. Added libc
This commit is contained in:
committed by
Christoffer Lerno
parent
e4c7dde30b
commit
fb9be722bc
@@ -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)
|
||||
{
|
||||
|
||||
167
resources/lib/std/libc.c3
Normal file
167
resources/lib/std/libc.c3
Normal file
@@ -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
|
||||
@@ -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 },
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -358,6 +358,7 @@ typedef enum
|
||||
TOKEN_PLUS_ASSIGN, // +=
|
||||
TOKEN_PLUSPLUS, // ++
|
||||
TOKEN_RBRAPIPE, // |}
|
||||
TOKEN_QUESTQUEST, // ??
|
||||
TOKEN_SCOPE, // ::
|
||||
TOKEN_SHL, // <<
|
||||
TOKEN_SHR, // >>
|
||||
|
||||
@@ -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, '<'))
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "A233"
|
||||
#define COMPILER_VERSION "A234"
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user