From 17430361040b08d0f4f679eddd6b09a714be2f59 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 17 Jan 2022 22:16:29 +0100 Subject: [PATCH] Added some File functionality. --- resources/lib/std/hash/adler32.c3 | 1 + resources/lib/std/io.c3 | 145 ++++++++++++++++------- resources/lib/std/libc.c3 | 148 ++++++++++++++++++++++++ src/compiler/llvm_codegen_c_abi_riscv.c | 2 +- src/compiler/parse_global.c | 7 +- 5 files changed, 259 insertions(+), 44 deletions(-) diff --git a/resources/lib/std/hash/adler32.c3 b/resources/lib/std/hash/adler32.c3 index 52f65563c..72b642f78 100644 --- a/resources/lib/std/hash/adler32.c3 +++ b/resources/lib/std/hash/adler32.c3 @@ -1,6 +1,7 @@ // Copyright (c) 2021 Christoffer Lerno. All rights reserved. // Use of this source code is governed by the MIT license // a copy of which can be found in the LICENSE_STDLIB file. + module std::hash::adler32; private const uint ADLER_CONST = 65521; diff --git a/resources/lib/std/io.c3 b/resources/lib/std/io.c3 index c20a93006..f69f66899 100644 --- a/resources/lib/std/io.c3 +++ b/resources/lib/std/io.c3 @@ -5,27 +5,7 @@ module std::io; import std::mem; import libc; -errtype IoError -{ - FILE_NOT_FOUND -} -/* -extern File *stdin @cname(__stdinp); -extern File *stdout @cname(__stdoutp); -extern File *stderr @cname(__stderrp); -*/ -/* -extern func int fputc(int, aliased void*); -extern func void clearerr(aliased void*); -extern func int fclose(aliased void*); -extern func int feof(aliased void*); -extern func int ferror(aliased void*); -extern func int fflush(aliased FILE *); -extern func int fgetc(aliased FILE *); -extern func int fgetpos(FILE *, fpos_t *); -extern func int fseek(void*, long, int); -extern func void* fopen(char *, char *); -*/ + struct File { @@ -59,7 +39,6 @@ fn int println(char *message = "") @inline return _puts(message); } - fn void! File.open(File* file, char[] filename, char[] mode) { char* filename_copy = mem::talloc(filename.len + 1)!!; @@ -74,8 +53,6 @@ fn void! File.open(File* file, char[] filename, char[] mode) if (!file.file) return IoError.FILE_NOT_FOUND!; } -/* - enum Seek { SET = 0, @@ -83,6 +60,110 @@ enum Seek END = 2 } +errtype IoError +{ + FILE_NOT_FOUND, + FILE_NOT_SEEKABLE, + FILE_NOT_VALID, + FILE_INVALID_POSITION, + FILE_OVERFLOW, + FILE_IS_PIPE, + FILE_EOF, + FILE_INCOMPLETE_WRITE, + INTERRUPTED, + UNKNOWN_ERROR, +} + +/** + * @require file.file != null + **/ +fn void! File.seek(File *file, long offset, Seek seekMode = Seek.SET) +{ + if (libc::fseek(file.file, (SeekIndex)(offset), (int)(seekMode))) + { + switch (libc::errno) + { + case EBADF: return IoError.FILE_NOT_SEEKABLE!; + case EINVAL: return IoError.FILE_INVALID_POSITION!; + case EOVERFLOW: return IoError.FILE_OVERFLOW!; + case ESPIPE: return IoError.FILE_IS_PIPE!; + default: return IoError.UNKNOWN_ERROR!; + } + } +} + +/** + * @require file && file.file != null + */ +fn void! File.putc(File *file, char c) +{ + if (!libc::fputc(c, file.file)) return IoError.FILE_EOF!; +} + +/** + * @require file != null + */ +fn void! File.close(File *file) @inline +{ + if (file.file && libc::fclose(file.file)) + { + switch (libc::errno) + { + case ECONNRESET: + case EBADF: return IoError.FILE_NOT_VALID!; + case EINTR: return IoError.INTERRUPTED!; + case EDQUOT: + case EFAULT: + case EAGAIN: + case EFBIG: + case ENETDOWN: + case ENETUNREACH: + case ENOSPC: + case EIO: return IoError.FILE_INCOMPLETE_WRITE!; + default: return IoError.UNKNOWN_ERROR!; + } + } + file.file = null; +} + +/** + * @require file && file.file + */ +fn bool File.eof(File* file) @inline +{ + return libc::feof(file.file) != 0; +} + +/** + * @require file && file.file + */ +fn usize File.read(File* file, void* buffer, usize items, usize element_size = 1) +{ + return libc::fread(buffer, element_size, items, file.file); +} + +/** + * @require file && file.file + */ +fn usize File.write(File* file, void* buffer, usize items, usize element_size = 1) +{ + return libc::fwrite(buffer, element_size, items, file.file); +} + +/** + * @require file && file.file + */ +fn usize! File.println(File* file, char[] string) +{ + usize len = string.len; + if (len != libc::fwrite(string.ptr, 1, len, file.file)) return IoError.UNKNOWN_ERROR!; + if (!libc::putc('\n', file.file)) return IoError.UNKNOWN_ERROR!; + return len + 1; +} + +/* + + error FileError { ulong errno; @@ -94,30 +175,14 @@ func FileError errorFromErrno() } -public func void! File.seek(File *file, long offset, Seek seekMode = Seek.SET) -{ - if (fseek(file->file, offset, (int)(seekMode))) return errorFromErrno()!; -} -public func void! File.putChar(File *file as char c) -{ - if (fputc(c, file->file)) return errorFromErrno()!; -} pubic func void! File.clearerr(File *file) @inline { clearerr(file->file); } -func void File.close(File *file) @inline -{ - if (fclose(file->file)) return errorFromErrno()!; -} -func void File.eof(File *file) @inline -{ - int err = feof(file->file); -} func void File.error(File *file) @inline { diff --git a/resources/lib/std/libc.c3 b/resources/lib/std/libc.c3 index 28222fee0..f3cc12ecd 100644 --- a/resources/lib/std/libc.c3 +++ b/resources/lib/std/libc.c3 @@ -2,6 +2,7 @@ // Use of this source code is governed by the MIT license // a copy of which can be found in the LICENSE_STDLIB file. module libc; +import std::cinterop; // stdlib @@ -22,6 +23,145 @@ struct LongDivResult long rem; } +enum Errno : ErrnoType +{ + EPERM = 1, /* Operation not permitted */ + ENOENT = 2, /* No such file or directory */ + ESRCH = 3, /* No such process */ + EINTR = 4, /* Interrupted system call */ + EIO = 5, /* I/O error */ + ENXIO = 6, /* No such device or address */ + E2BIG = 7, /* Argument list too long */ + ENOEXEC = 8, /* Exec format error */ + EBADF = 9, /* Bad file number */ + ECHILD = 10, /* No child processes */ + EAGAIN = 11, /* Try again */ + ENOMEM = 12, /* Out of memory */ + EACCES = 13, /* Permission denied */ + EFAULT = 14, /* Bad address */ + ENOTBLK = 15, /* Block device required */ + EBUSY = 16, /* Device or resource busy */ + EEXIST = 17, /* File exists */ + EXDEV = 18, /* Cross-device link */ + ENODEV = 19, /* No such device */ + ENOTDIR = 20, /* Not a directory */ + EISDIR = 21, /* Is a directory */ + EINVAL = 22, /* Invalid argument */ + ENFILE = 23, /* File table overflow */ + EMFILE = 24, /* Too many open files */ + ENOTTY = 25, /* Not a typewriter */ + ETXTBSY = 26, /* Text file busy */ + EFBIG = 27, /* File too large */ + ENOSPC = 28, /* No space left on device */ + ESPIPE = 29, /* Illegal seek */ + EROFS = 30, /* Read-only file system */ + EMLINK = 31, /* Too many links */ + EPIPE = 32, /* Broken pipe */ + EDOM = 33, /* Math argument out of domain of func */ + ERANGE = 34, /* Math result not representable */ + EDEADLK = 35, /* Resource deadlock would occur */ + ENAMETOOLONG = 36, /* File name too long */ + ENOLCK = 37, /* No record locks available */ + ENOSYS = 38, /* Function not implemented */ + ENOTEMPTY = 39, /* Directory not empty */ + ELOOP = 40, /* Too many symbolic links encountered */ + + ENOMSG = 42, /* No message of desired type */ + EIDRM = 43, /* Identifier removed */ + ECHRNG = 44, /* Channel number out of range */ + EL2NSYNC = 45, /* Level 2 not synchronized */ + EL3HLT = 46, /* Level 3 halted */ + EL3RST = 47, /* Level 3 reset */ + ELNRNG = 48, /* Link number out of range */ + EUNATCH = 49, /* Protocol driver not attached */ + ENOCSI = 50, /* No CSI structure available */ + EL2HLT = 51, /* Level 2 halted */ + EBADE = 52, /* Invalid exchange */ + EBADR = 53, /* Invalid request descriptor */ + EXFULL = 54, /* Exchange full */ + ENOANO = 55, /* No anode */ + EBADRQC = 56, /* Invalid request code */ + EBADSLT = 57, /* Invalid slot */ + + EBFONT = 59, /* Bad font file format */ + ENOSTR = 60, /* Device not a stream */ + ENODATA = 61, /* No data available */ + ETIME = 62, /* Timer expired */ + ENOSR = 63, /* Out of streams resources */ + ENONET = 64, /* Machine is not on the network */ + ENOPKG = 65, /* Package not installed */ + EREMOTE = 66, /* Object is remote */ + ENOLINK = 67, /* Link has been severed */ + EADV = 68, /* Advertise error */ + ESRMNT = 69, /* Srmount error */ + ECOMM = 70, /* Communication error on send */ + EPROTO = 71, /* Protocol error */ + EMULTIHOP = 72, /* Multihop attempted */ + EDOTDOT = 73, /* RFS specific error */ + EBADMSG = 74, /* Not a data message */ + EOVERFLOW = 75, /* Value too large for defined data type */ + ENOTUNIQ = 76, /* Name not unique on network */ + EBADFD = 77, /* File descriptor in bad state */ + EREMCHG = 78, /* Remote address changed */ + ELIBACC = 79, /* Can not access a needed shared library */ + ELIBBAD = 80, /* Accessing a corrupted shared library */ + ELIBSCN = 81, /* .lib section in a.out corrupted */ + ELIBMAX = 82, /* Attempting to link in too many shared libraries */ + ELIBEXEC = 83, /* Cannot exec a shared library directly */ + EILSEQ = 84, /* Illegal byte sequence */ + ERESTART = 85, /* Interrupted system call should be restarted */ + ESTRPIPE = 86, /* Streams pipe error */ + EUSERS = 87, /* Too many users */ + ENOTSOCK = 88, /* Socket operation on non-socket */ + EDESTADDRREQ = 89, /* Destination address required */ + EMSGSIZE = 90, /* Message too long */ + EPROTOTYPE = 91, /* Protocol wrong type for socket */ + ENOPROTOOPT = 92, /* Protocol not available */ + EPROTONOSUPPORT = 93, /* Protocol not supported */ + ESOCKTNOSUPPORT = 94, /* Socket type not supported */ + EOPNOTSUPP = 95, /* Operation not supported on transport endpoint */ + EPFNOSUPPORT = 96, /* Protocol family not supported */ + EAFNOSUPPORT = 97, /* Address family not supported by protocol */ + EADDRINUSE = 98, /* Address already in use */ + EADDRNOTAVAIL = 99, /* Cannot assign requested address */ + ENETDOWN = 100, /* Network is down */ + ENETUNREACH = 101, /* Network is unreachable */ + ENETRESET = 102, /* Network dropped connection because of reset */ + ECONNABORTED = 103, /* Software caused connection abort */ + ECONNRESET = 104, /* Connection reset by peer */ + ENOBUFS = 105, /* No buffer space available */ + EISCONN = 106, /* Transport endpoint is already connected */ + ENOTCONN = 107, /* Transport endpoint is not connected */ + ESHUTDOWN = 108, /* Cannot send after transport endpoint shutdown */ + ETOOMANYREFS = 109, /* Too many references: cannot splice */ + ETIMEDOUT = 110, /* Connection timed out */ + ECONNREFUSED = 111, /* Connection refused */ + EHOSTDOWN = 112, /* Host is down */ + EHOSTUNREACH = 113, /* No route to host */ + EALREADY = 114, /* Operation already in progress */ + EINPROGRESS = 115, /* Operation now in progress */ + ESTALE = 116, /* Stale NFS file handle */ + EUCLEAN = 117, /* Structure needs cleaning */ + ENOTNAM = 118, /* Not a XENIX named type file */ + ENAVAIL = 119, /* No XENIX semaphores available */ + EISNAM = 120, /* Is a named type file */ + EREMOTEIO = 121, /* Remote I/O error */ + EDQUOT = 122, /* Quota exceeded */ + + ENOMEDIUM = 123, /* No medium found */ + EMEDIUMTYPE = 124, /* Wrong medium type */ + ECANCELED = 125, /* Operation Canceled */ + ENOKEY = 126, /* Required key not available */ + EKEYEXPIRED = 127, /* Key has expired */ + EKEYREVOKED = 128, /* Key has been revoked */ + EKEYREJECTED = 129, /* Key was rejected by service */ + + EOWNERDEAD = 130, /* Owner died */ + ENOTRECOVERABLE = 131, /* State not recoverable */ +} + +extern Errno errno; + define TerminateFunction = fn void(); define CompareFunction = fn int(void*, void*); extern fn double atof(char* str); @@ -93,6 +233,14 @@ const int EOF = -1; const int FOPEN_MAX = 20; const int FILENAME_MAX = 1024; +$if (${C_INT_SIZE} == 64): +define ErrnoType = long; +$elif (${C_INT_SIZE} == 32): +define ErrnoType = int; +$else: +define ErrnoType = short; +$endif; + $if (${C_LONG_SIZE} == 64): define SeekIndex = long; $else: diff --git a/src/compiler/llvm_codegen_c_abi_riscv.c b/src/compiler/llvm_codegen_c_abi_riscv.c index 9dae3601e..a0b079bc9 100644 --- a/src/compiler/llvm_codegen_c_abi_riscv.c +++ b/src/compiler/llvm_codegen_c_abi_riscv.c @@ -283,7 +283,7 @@ void c_abi_func_create_riscv(FunctionPrototype *prototype) // If we have a failable, then the return type is a parameter. if (prototype->ret_by_ref) { - prototype->ret_by_ref_abi_info = riscv_classify_argument_type(type_get_ptr(prototype->ret_by_ref_type), + prototype->ret_by_ref_abi_info = riscv_classify_argument_type(type_get_ptr(type_lowering(prototype->ret_by_ref_type)), true, &arg_gprs_left, &arg_fprs_left); } diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 1104c6d05..b863532f5 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -194,7 +194,7 @@ static inline Decl *parse_ct_case(ParseContext *context) while (1) { TokenType type = context->tok.type; - if (type == TOKEN_CT_DEFAULT || type == TOKEN_CT_CASE || type == TOKEN_LBRACE) break; + if (type == TOKEN_CT_DEFAULT || type == TOKEN_CT_CASE || type == TOKEN_CT_ENDSWITCH) break; ASSIGN_DECL_ELSE(Decl *stmt, parse_top_level_statement(context), poisoned_decl); vec_add(decl->ct_case_decl.body, stmt); } @@ -212,12 +212,13 @@ static inline Decl *parse_ct_switch_top_level(ParseContext *context) Decl *ct = decl_new_ct(DECL_CT_SWITCH, context->prev_tok); ASSIGN_EXPR_ELSE(ct->ct_switch_decl.expr, parse_const_paren_expr(context), poisoned_decl); - CONSUME_OR(TOKEN_LBRACE, poisoned_decl); - while (!try_consume(context, TOKEN_RBRACE)) + CONSUME_OR(TOKEN_COLON, poisoned_decl); + while (!try_consume(context, TOKEN_CT_ENDSWITCH)) { ASSIGN_DECL_ELSE(Decl *result, parse_ct_case(context), poisoned_decl); vec_add(ct->ct_switch_decl.cases, result); } + CONSUME_OR(TOKEN_EOS, poisoned_decl); return ct; }