diff --git a/lib/std/io/os/chdir.c3 b/lib/std/io/os/chdir.c3 new file mode 100644 index 000000000..2f3dd4f9d --- /dev/null +++ b/lib/std/io/os/chdir.c3 @@ -0,0 +1,42 @@ +module std::io::os; +import libc; + + +$if (!env::COMPILER_LIBC_AVAILABLE): + +fn void! native_chdir(Path path) +{ + unreachable("'getcwd' not available"); +} + +$elif (env::OS_TYPE == OsType.WIN32): + +macro void! native_chdir(Path path) +{ + @pool() + { + if (files::win32_SetCurrentDirectoryW(path.as_str().to_temp_utf16()!!)) return; + }; + return IoError.GENERAL_ERROR!; +} + +$else: + +extern fn int _chdir(ZString) @extern("chdir"); +macro void! native_chdir(Path p) +{ + if (_chdir((ZString)p.as_str())) + { + switch (libc::errno()) + { + case errno::EACCES: return IoError.NO_PERMISSION!; + case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG!; + case errno::ENOTDIR: return IoError.FILE_NOT_DIR!; + case errno::ENOENT: return IoError.FILE_NOT_FOUND!; + case errno::ELOOP: return IoError.SYMLINK_FAILED!; + default: return IoError.GENERAL_ERROR!; + } + } +} + +$endif; \ No newline at end of file diff --git a/lib/std/io/path.c3 b/lib/std/io/path.c3 index 4ad25d09a..20cac6977 100644 --- a/lib/std/io/path.c3 +++ b/lib/std/io/path.c3 @@ -40,6 +40,7 @@ fn bool is_file(Path path) => os::native_is_file(path.as_str()); fn usz! file_size(Path path) => os::native_file_size(path.as_str()); fn bool exists(Path path) => os::native_file_or_dir_exists(path.as_str()); fn Path! tgetcwd() => getcwd(mem::temp()) @inline; +fn void! chdir(Path path) => os::native_chdir(path) @inline; fn Path! temp_directory(Allocator* using = mem::heap()) => os::native_temp_directory(using); macro bool is_separator(char c, PathEnv path_env = DEFAULT_PATH_ENV) diff --git a/lib/std/os/win32/files.c3 b/lib/std/os/win32/files.c3 index 2e905f682..5b74146a7 100644 --- a/lib/std/os/win32/files.c3 +++ b/lib/std/os/win32/files.c3 @@ -27,6 +27,7 @@ struct Win32_FILE_ATTRIBUTE_DATA extern fn bool win32_GetFileAttributesExW(Win32_LPCWSTR, Win32_GET_FILEEX_INFO_LEVELS, Win32_LPVOID) @extern("GetFileAttributesExW"); extern fn bool win32_PathFileExistsW(Win32_LPCWSTR) @extern("PathFileExistsW"); extern fn Win32_DWORD win32_GetTempPathW(Win32_DWORD nBufferLength, Win32_LPWSTR lpBuffer) @extern("GetTempPathW"); +extern fn bool win32_SetCurrentDirectoryW(Win32_LPCTSTR buffer) @extern("SetCurrentDirectoryW"); /* extern ulong _win32_GetCurrentDirectoryW(ulong, Char16* buffer) @extern("GetCurrentDirectoryW"); diff --git a/src/build/build_options.c b/src/build/build_options.c index 52c6725a5..073de73b9 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -898,6 +898,10 @@ BuildOptions parse_arguments(int argc, const char *argv[]) } FAIL_WITH_ERR("Found the unexpected argument \"%s\".", current_arg); } + if (build_options.command == COMMAND_MISSING) + { + FAIL_WITH_ERR("Missing a compiler command such as 'compile' or 'build'."); + } return build_options; } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 8728c1559..194fae449 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -931,6 +931,24 @@ static inline bool sema_binary_promote_top_down(SemaContext *context, Expr *bina static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *binary, Expr *left, Expr *right) { + // Special handling of f = FOO_BAR + if (right->expr_kind == EXPR_IDENTIFIER && right->identifier_expr.is_const) + { + if (!sema_analyse_expr(context, left)) return false; + if (type_flatten(left->type)->type_kind == TYPE_ENUM) + { + return sema_analyse_inferred_expr(context, left->type, right); + } + } + // Special handling of f = FOO_BAR + if (left->expr_kind == EXPR_IDENTIFIER && left->identifier_expr.is_const) + { + if (!sema_analyse_expr(context, right)) return false; + if (type_flatten(right->type)->type_kind == TYPE_ENUM) + { + return sema_analyse_inferred_expr(context, right->type, left); + } + } if (right->expr_kind == EXPR_INITIALIZER_LIST) { if (!sema_analyse_expr(context, left)) return false; @@ -2103,11 +2121,11 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr) case EXPR_TYPEINFO: if (func_expr->type_expr->resolve_status == RESOLVE_DONE) { - SEMA_ERROR(expr, "A type cannot be followed by (), if you intended a cast, use (type)(expression)."); + SEMA_ERROR(expr, "A type cannot be followed by (), if you intended a cast, use '(type) expression'."); } else { - SEMA_ERROR(expr, "A type cannot be followed by (), did you mean to use {}?"); + SEMA_ERROR(expr, "A type cannot be followed by (), did you mean to use 'type {}'?"); } return false; default: diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index 672842837..7007d8e16 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -528,6 +528,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex if (!to) to = type_untypedlist; assert(to); Type *flattened = type_flatten(to); + bool is_zero_init = expr->expr_kind == EXPR_INITIALIZER_LIST && !vec_size(expr->initializer_list); switch (flattened->type_kind) { case TYPE_UNTYPED_LIST: @@ -541,7 +542,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex return sema_expr_analyse_initializer(context, to, flattened, expr); case TYPE_SUBARRAY: { - if (expr->expr_kind == EXPR_INITIALIZER_LIST && !vec_size(expr->initializer_list)) + if (is_zero_init) { expr->expr_kind = EXPR_CONST; expr->const_expr.const_kind = CONST_POINTER; @@ -561,12 +562,31 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex SEMA_ERROR(expr, "Scaled vectors cannot be initialized using an initializer list, since the length is not known at compile time."); return false; case TYPE_POINTER: + if (is_zero_init) + { + expr_rewrite_to_const_zero(expr, to); + return true; + } SEMA_ERROR(expr, "Pointers cannot be initialized using an initializer list, instead you need to take the address of an array."); return false; + case TYPE_VOID: + case TYPE_POISONED: + case TYPE_FUNC: + case TYPE_TYPEDEF: + case TYPE_OPTIONAL_ANY: + case TYPE_OPTIONAL: + case TYPE_TYPEINFO: + case TYPE_MEMBER: + break; default: + if (is_zero_init) + { + expr_rewrite_to_const_zero(expr, flattened); + expr->type = to; + return true; + } break; } - // Fix error on compound literals SEMA_ERROR(expr, "'%s' cannot use compound literal initialization, did you intend to use a cast?", type_to_error_string(to)); return false; } diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index dcd17b25b..8e3eee321 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -367,7 +367,7 @@ static inline bool sema_analyse_block_exit_stmt(SemaContext *context, Ast *state } else { - if (block_type && block_type != type_void) + if (block_type && type_no_optional(block_type) != type_void) { SEMA_ERROR(statement, "Expected a return value of type %s here.", type_quoted_error_string(block_type)); return false; @@ -966,9 +966,24 @@ static inline bool sema_analyse_cond(SemaContext *context, Expr *expr, CondType } return true; } + // 3a. Check for optional in case of an expression. if (IS_OPTIONAL(last)) { + if (type_no_optional(last->type) == type_void && cast_to_bool) + { + Expr *catch = expr_new_expr(EXPR_CATCH, last); + catch->expr_kind = EXPR_CATCH; + catch->inner_expr = expr_copy(last); + catch->type = type_anyerr; + catch->resolve_status = RESOLVE_DONE; + catch->inner_expr->resolve_status = RESOLVE_DONE; + last->expr_kind = EXPR_UNARY; + last->unary_expr.operator = UNARYOP_NOT; + last->unary_expr.expr = catch; + last->type = type_bool; + return true; + } SEMA_ERROR(last, "The expression may not be an optional, but was %s.", type_quoted_error_string(last->type)); return false; } diff --git a/src/version.h b/src/version.h index c734d6925..03d257220 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.107" \ No newline at end of file +#define COMPILER_VERSION "0.4.108" \ No newline at end of file diff --git a/test/test_suite/cast/cast_parse_fails.c3 b/test/test_suite/cast/cast_parse_fails.c3 index e52fbad02..f807aa354 100644 --- a/test/test_suite/cast/cast_parse_fails.c3 +++ b/test/test_suite/cast/cast_parse_fails.c3 @@ -7,7 +7,7 @@ fn void test2() fn void test3() { - int x = int(32); // #error: A type cannot be followed by (), if you intended a cast, use (type)(expression) + int x = int(32); // #error: A type cannot be followed by (), if you intended a cast, use '(type) expression' } diff --git a/test/test_suite/cast/cast_parse_fails2.c3 b/test/test_suite/cast/cast_parse_fails2.c3 index 020eeb416..883deaee8 100644 --- a/test/test_suite/cast/cast_parse_fails2.c3 +++ b/test/test_suite/cast/cast_parse_fails2.c3 @@ -4,5 +4,5 @@ struct Foo { int a; } fn void test1() { (Foo)({ 32 }); - Foo({ 32 }); // #error: A type cannot be followed by (), if you intended a cast, use (type)(expression) + Foo({ 32 }); // #error: A type cannot be followed by (), if you intended a cast, use '(type) expression' } \ No newline at end of file