diff --git a/src/build_cfg.c b/src/build_cfg.c index 560a46cc..160d39a0 100644 --- a/src/build_cfg.c +++ b/src/build_cfg.c @@ -253,7 +253,7 @@ static const LocalVariable *build_increment_or_decrement( assert(addr->type->kind == TYPE_POINTER); const Type *t = addr->type->data.valuetype; if (!is_integer_type(t) && !is_pointer_type(t)) - fail_with_error(location, "cannot %s a value of type %s", diff==1?"increment":"decrement", t->name); + fail(location, "cannot %s a value of type %s", diff==1?"increment":"decrement", t->name); const LocalVariable *old_value = add_local_var(st, t); const LocalVariable *new_value = add_local_var(st, t); @@ -836,13 +836,13 @@ static void build_statement(struct State *st, const AstStatement *stmt) case AST_STMT_BREAK: if (!st->breakstack.len) - fail_with_error(stmt->location, "'break' can only be used inside a loop"); + fail(stmt->location, "'break' can only be used inside a loop"); add_jump(st, NULL, End(st->breakstack)[-1], End(st->breakstack)[-1], NULL); break; case AST_STMT_CONTINUE: if (!st->continuestack.len) - fail_with_error(stmt->location, "'continue' can only be used inside a loop"); + fail(stmt->location, "'continue' can only be used inside a loop"); add_jump(st, NULL, End(st->continuestack)[-1], End(st->continuestack)[-1], NULL); break; diff --git a/src/fail.c b/src/fail.c index 33034163..69f6e9f1 100644 --- a/src/fail.c +++ b/src/fail.c @@ -30,7 +30,7 @@ void show_warning(Location location, const char *fmt, ...) va_end(ap); } -noreturn void fail_with_error(Location location, const char *fmt, ...) +noreturn void fail(Location location, const char *fmt, ...) { va_list ap; va_start(ap, fmt); diff --git a/src/jou_compiler.h b/src/jou_compiler.h index fc6f2f61..a8bae5fd 100644 --- a/src/jou_compiler.h +++ b/src/jou_compiler.h @@ -68,15 +68,12 @@ struct Location { #ifdef __GNUC__ void show_warning(Location location, const char *fmt, ...) __attribute__((format(printf,2,3))); - noreturn void fail_with_error(Location location, const char *fmt, ...) __attribute__((format(printf,2,3))); + noreturn void fail(Location location, const char *fmt, ...) __attribute__((format(printf,2,3))); #else void show_warning(Location location, const char *fmt, ...); - noreturn void fail_with_error(Location location, const char *fmt, ...); + noreturn void fail(Location location, const char *fmt, ...); #endif -// TODO: rename the damn function -#define fail(...) fail_with_error(__VA_ARGS__) - struct Token { enum TokenType { TOKEN_SHORT, diff --git a/src/main.c b/src/main.c index 17129562..8589a776 100644 --- a/src/main.c +++ b/src/main.c @@ -189,9 +189,9 @@ static FILE *open_the_file(const char *path, const Location *import_location) FILE *f = fopen(path, "rb"); if (!f) { if (import_location) - fail_with_error(*import_location, "cannot import from \"%s\": %s", path, strerror(errno)); + fail(*import_location, "cannot import from \"%s\": %s", path, strerror(errno)); else - fail_with_error((Location){.filename=path}, "cannot open file: %s", strerror(errno)); + fail((Location){.filename=path}, "cannot open file: %s", strerror(errno)); } return f; } @@ -342,7 +342,7 @@ static void add_imported_symbol(struct FileState *fs, const ExportSymbol *es, As case EXPSYM_GLOBAL_VAR: wat = "global variable"; break; case EXPSYM_TYPE: wat = "type"; break; } - fail_with_error(fs->ast.body.statements[i].location, "a %s named '%s' already exists", wat, es->name); + fail(fs->ast.body.statements[i].location, "a %s named '%s' already exists", wat, es->name); } } @@ -381,12 +381,12 @@ static void add_imported_symbols(struct CompileState *compst) struct FileState *from = find_file(compst, imp->resolved_path); assert(from); if (from == to) { - fail_with_error(imp->location, "the file itself cannot be imported"); + fail(imp->location, "the file itself cannot be imported"); } for (int i = 0; i < seen_before.len; i++) { if (seen_before.ptr[i] == from) { - fail_with_error(imp->location, "file \"%s\" is imported twice", imp->specified_path); + fail(imp->location, "file \"%s\" is imported twice", imp->specified_path); } } Append(&seen_before, from); diff --git a/src/parse.c b/src/parse.c index 5379e3aa..0abe0fc1 100644 --- a/src/parse.c +++ b/src/parse.c @@ -35,7 +35,7 @@ static noreturn void fail_with_parse_error(const Token *token, const char *what_ case TOKEN_DEDENT: strcpy(got, "less indentation"); break; case TOKEN_KEYWORD: snprintf(got, sizeof got, "the '%s' keyword", token->data.name); break; } - fail_with_error(token->location, "expected %s, got %s", what_was_expected_instead, got); + fail(token->location, "expected %s, got %s", what_was_expected_instead, got); } static bool is_keyword(const Token *t, const char *kw) @@ -147,14 +147,14 @@ static AstSignature parse_function_signature(ParserState *ps, bool accept_self) while (!is_operator(ps->tokens, ")")) { if (result.takes_varargs) - fail_with_error(ps->tokens->location, "if '...' is used, it must be the last parameter"); + fail(ps->tokens->location, "if '...' is used, it must be the last parameter"); if (is_operator(ps->tokens, "...")) { result.takes_varargs = true; ps->tokens++; } else if (is_keyword(ps->tokens, "self")) { if (!accept_self) - fail_with_error(ps->tokens->location, "'self' cannot be used here"); + fail(ps->tokens->location, "'self' cannot be used here"); AstNameTypeValue self_arg = { .name="self", .name_location=ps->tokens++->location }; Append(&result.args, self_arg); used_self = true; @@ -162,11 +162,11 @@ static AstSignature parse_function_signature(ParserState *ps, bool accept_self) AstNameTypeValue arg = parse_name_type_value(ps, "an argument name"); if (arg.value) - fail_with_error(arg.value->location, "arguments cannot have default values"); + fail(arg.value->location, "arguments cannot have default values"); for (const AstNameTypeValue *prevarg = result.args.ptr; prevarg < End(result.args); prevarg++) if (!strcmp(prevarg->name, arg.name)) - fail_with_error(arg.name_location, "there are multiple arguments named '%s'", prevarg->name); + fail(arg.name_location, "there are multiple arguments named '%s'", prevarg->name); Append(&result.args, arg); } @@ -182,7 +182,7 @@ static AstSignature parse_function_signature(ParserState *ps, bool accept_self) if (!is_operator(ps->tokens, "->")) { // Special case for common typo: def foo(): if (is_operator(ps->tokens, ":")) { - fail_with_error( + fail( ps->tokens->location, "return type must be specified with '->'," " or with '-> None' if the function doesn't return anything" @@ -193,7 +193,7 @@ static AstSignature parse_function_signature(ParserState *ps, bool accept_self) ps->tokens++; if (!used_self && accept_self) { - fail_with_error( + fail( ps->tokens->location, "missing self, should be 'def %s(self, ...)'", result.name @@ -236,7 +236,7 @@ static AstCall parse_call(ParserState *ps, char openparen, char closeparen, bool for (struct Name *oldname = argnames.ptr; oldname < End(argnames); oldname++) { if (!strcmp(oldname->name, ps->tokens->data.name)) { - fail_with_error( + fail( ps->tokens->location, "multiple values were given for field '%s'", oldname->name); } } @@ -354,7 +354,7 @@ static AstExpression parse_array(ParserState *ps) ps->tokens++; if (is_operator(ps->tokens, "]")) - fail_with_error(ps->tokens->location, "arrays cannot be empty"); + fail(ps->tokens->location, "arrays cannot be empty"); List(AstExpression) items = {0}; do { @@ -456,7 +456,7 @@ static AstExpression parse_elementary_expression(ParserState *ps) ps->tokens++; } else if (is_keyword(ps->tokens, "self")) { if (!ps->is_parsing_method_body) - fail_with_error(ps->tokens->location, "'self' cannot be used here"); + fail(ps->tokens->location, "'self' cannot be used here"); expr.kind = AST_EXPR_GET_VARIABLE; strcpy(expr.data.varname, "self"); ps->tokens++; @@ -608,7 +608,7 @@ static AstExpression parse_expression_with_comparisons(ParserState *ps) if (IsComparator(ps->tokens)) add_to_binop(ps, &result, parse_expression_with_as); if (IsComparator(ps->tokens)) - fail_with_error(ps->tokens->location, "comparisons cannot be chained"); + fail(ps->tokens->location, "comparisons cannot be chained"); #undef IsComparator return result; } @@ -621,7 +621,7 @@ static AstExpression parse_expression_with_not(ParserState *ps) ps->tokens++; } if (is_keyword(ps->tokens, "not")) - fail_with_error(ps->tokens->location, "'not' cannot be repeated"); + fail(ps->tokens->location, "'not' cannot be repeated"); AstExpression result = parse_expression_with_comparisons(ps); if (nottoken) @@ -638,7 +638,7 @@ static AstExpression parse_expression_with_and_or(ParserState *ps) got_and = got_and || is_keyword(ps->tokens, "and"); got_or = got_or || is_keyword(ps->tokens, "or"); if (got_and && got_or) - fail_with_error(ps->tokens->location, "'and' cannot be chained with 'or', you need more parentheses"); + fail(ps->tokens->location, "'and' cannot be chained with 'or', you need more parentheses"); add_to_binop(ps, &result, parse_expression_with_not); } @@ -670,7 +670,7 @@ static void validate_expression_statement(const AstExpression *expr) case AST_EXPR_POST_DECREMENT: break; default: - fail_with_error(expr->location, "not a valid statement"); + fail(expr->location, "not a valid statement"); break; } } @@ -800,7 +800,7 @@ static AstStatement parse_oneline_statement(ParserState *ps) ps->tokens++; result.data.assignment = (AstAssignment){.target=expr, .value=parse_expression(ps)}; if (is_operator(ps->tokens, "=")) - fail_with_error(ps->tokens->location, "only one variable can be assigned at a time"); + fail(ps->tokens->location, "only one variable can be assigned at a time"); } } return result; @@ -829,11 +829,11 @@ static AstFunction parse_funcdef(ParserState *ps, bool is_method) struct AstFunction funcdef = {0}; funcdef.signature = parse_function_signature(ps, is_method); if (!strcmp(funcdef.signature.name, "__init__") && is_method) { - fail_with_error(ps->tokens->location, "Jou does not have a special __init__ method like Python"); + fail(ps->tokens->location, "Jou does not have a special __init__ method like Python"); } if (funcdef.signature.takes_varargs) { // TODO: support "def foo(x: str, ...)" in some way - fail_with_error(ps->tokens->location, "functions with variadic arguments cannot be defined yet"); + fail(ps->tokens->location, "functions with variadic arguments cannot be defined yet"); } assert(!ps->is_parsing_method_body); @@ -865,7 +865,7 @@ static void check_class_for_duplicate_names(const AstClassDef *classdef) for (struct MemberInfo *p1 = infos.ptr; p1 < End(infos); p1++) for (struct MemberInfo *p2 = p1+1; p2 < End(infos); p2++) if (!strcmp(p1->name, p2->name)) - fail_with_error(p2->location, "class %s already has %s named '%s'", classdef->name, p1->kindstr, p1->name); + fail(p2->location, "class %s already has %s named '%s'", classdef->name, p1->kindstr, p1->name); free(infos.ptr); } @@ -893,19 +893,19 @@ static AstClassDef parse_classdef(ParserState *ps) while (ps->tokens->type != TOKEN_DEDENT) { AstNameTypeValue field = parse_name_type_value(ps, "a union member"); if (field.value) - fail_with_error(field.value->location, "union members cannot have default values"); + fail(field.value->location, "union members cannot have default values"); Append(&umember.data.unionfields, field); eat_newline(ps); } ps->tokens++; if (umember.data.unionfields.len < 2) { - fail_with_error(union_keyword_location, "unions must have at least 2 members"); + fail(union_keyword_location, "unions must have at least 2 members"); } Append(&result.members, umember); } else { AstNameTypeValue field = parse_name_type_value(ps, "a method, a field or a union"); if (field.value) - fail_with_error(field.value->location, "class fields cannot have default values"); + fail(field.value->location, "class fields cannot have default values"); Append(&result.members, (AstClassMember){ .kind = AST_CLASSMEMBER_FIELD, .data.field = field, @@ -936,7 +936,7 @@ static AstEnumDef parse_enumdef(ParserState *ps) for (const char **old = membernames.ptr; old < End(membernames); old++) if (!strcmp(*old, ps->tokens->data.name)) - fail_with_error(ps->tokens->location, "the enum has two members named '%s'", ps->tokens->data.name); + fail(ps->tokens->location, "the enum has two members named '%s'", ps->tokens->data.name); Append(&membernames, ps->tokens->data.name); ps->tokens++; @@ -958,14 +958,14 @@ static AstStatement parse_statement(ParserState *ps) AstStatement result = { .location = ps->tokens->location }; if (is_keyword(ps->tokens, "import")) { - fail_with_error(ps->tokens->location, "imports must be in the beginning of the file"); + fail(ps->tokens->location, "imports must be in the beginning of the file"); } else if (is_keyword(ps->tokens, "def")) { ps->tokens++; // skip 'def' keyword result.kind = AST_STMT_FUNCTION; result.data.function.signature = parse_function_signature(ps, false); if (result.data.function.signature.takes_varargs) { // TODO: support "def foo(x: str, ...)" in some way - fail_with_error(ps->tokens->location, "functions with variadic arguments cannot be defined yet"); + fail(ps->tokens->location, "functions with variadic arguments cannot be defined yet"); } result.data.function.body = parse_body(ps); } else if (is_keyword(ps->tokens, "declare")) { @@ -975,7 +975,7 @@ static AstStatement parse_statement(ParserState *ps) result.kind = AST_STMT_DECLARE_GLOBAL_VAR; result.data.vardecl = parse_name_type_value(ps, "a variable name"); if (result.data.vardecl.value) { - fail_with_error( + fail( result.data.vardecl.value->location, "a value cannot be given when declaring a global variable"); } @@ -990,7 +990,7 @@ static AstStatement parse_statement(ParserState *ps) result.data.vardecl = parse_name_type_value(ps, "a variable name"); if (result.data.vardecl.value) { // TODO: make this work - fail_with_error( + fail( result.data.vardecl.value->location, "specifying a value for a global variable is not supported yet"); } @@ -1067,7 +1067,7 @@ static AstImport parse_import(ParserState *ps) part1 = dirname(tmp); part2 = pathtoken->data.string_value; } else { - fail_with_error( + fail( pathtoken->location, "import path must start with 'stdlib/' (standard-library import) or a dot (relative import)"); } diff --git a/src/simplify_cfg.c b/src/simplify_cfg.c index 6a9e455a..ad22b55e 100644 --- a/src/simplify_cfg.c +++ b/src/simplify_cfg.c @@ -535,7 +535,7 @@ static void error_about_missing_return(CfGraph *cfg) "function '%s' doesn't seem to return a value in all cases", cfg->signature.name); } if (s == VS_UNDEFINED) { - fail_with_error( + fail( cfg->signature.returntype_location, "function '%s' must return a value, because it is defined with '-> %s'", cfg->signature.name, cfg->signature.returntype->name); diff --git a/src/tokenize.c b/src/tokenize.c index c744617c..ba9e2907 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -32,20 +32,20 @@ static char read_byte(struct State *st) { c = fgetc(st->f); if (c == EOF && ferror(st->f)) - fail_with_error(st->location, "cannot read file: %s", strerror(errno)); + fail(st->location, "cannot read file: %s", strerror(errno)); // For Windows: \r\n in source file is treated same as \n if (c == '\r') { c = fgetc(st->f); if (c == EOF && ferror(st->f)) - fail_with_error(st->location, "cannot read file: %s", strerror(errno)); + fail(st->location, "cannot read file: %s", strerror(errno)); if (c != '\n') - fail_with_error(st->location, "source file contains a CR byte ('\\r') that isn't a part of a CRLF line ending"); + fail(st->location, "source file contains a CR byte ('\\r') that isn't a part of a CRLF line ending"); } // Use the zero byte to represent end of file. if (c == '\0') - fail_with_error(st->location, "source file contains a zero byte"); // TODO: test this + fail(st->location, "source file contains a zero byte"); // TODO: test this if (c == EOF) { assert(!ferror(st->f)); return '\0'; @@ -88,7 +88,7 @@ static void read_identifier_or_number(struct State *st, char firstbyte, char (*d || (is_number && (c=='.' || (c=='-' && (*dest)[destlen-1]=='e')))) { if (destlen == sizeof *dest - 1) - fail_with_error(st->location, "%s is too long: %.20s...", is_number?"number":"name", *dest); + fail(st->location, "%s is too long: %.20s...", is_number?"number":"name", *dest); (*dest)[destlen++] = c; } else { unread_byte(st, c); @@ -155,7 +155,7 @@ static long long parse_integer(const char *str, Location location, int nbits) valid_digits = "01234567"; } else if (str[0] == '0' && str[1] != '\0') { // wrong syntax like 0777 - fail_with_error(location, "unnecessary zero at start of number"); + fail(location, "unnecessary zero at start of number"); } else { // default decimal umber base = 10; @@ -164,12 +164,12 @@ static long long parse_integer(const char *str, Location location, int nbits) } if (!*digits || strspn(digits, valid_digits) != strlen(digits)) - fail_with_error(location, "invalid number or variable name \"%s\"", str); + fail(location, "invalid number or variable name \"%s\"", str); errno = 0; long long result = strtoll(digits, NULL, base); if (errno == ERANGE || result >> (nbits-1) != 0) - fail_with_error(location, "value does not fit in a signed %d-bit integer", nbits); + fail(location, "value does not fit in a signed %d-bit integer", nbits); return result; } @@ -235,7 +235,7 @@ static char read_hex_escape_byte(struct State *st) char c1 = read_byte(st); char c2 = read_byte(st); if (!isxdigit(c1) || !isxdigit(c2)) - fail_with_error(st->location, "\\x must be followed by two hexadecimal digits (0-9, A-F) to specify a byte"); + fail(st->location, "\\x must be followed by two hexadecimal digits (0-9, A-F) to specify a byte"); char s[] = {c1, c2, '\0'}; return strtol(s, NULL, 16); @@ -273,21 +273,21 @@ static char *read_string(struct State *st, char quote, int *len) case '\'': case '"': if (after_backslash == '"' && quote == '\'') - fail_with_error(st->location, "double quotes shouldn't be escaped in byte literals"); + fail(st->location, "double quotes shouldn't be escaped in byte literals"); if (after_backslash == '\'' && quote == '"') - fail_with_error(st->location, "single quotes shouldn't be escaped in strings"); + fail(st->location, "single quotes shouldn't be escaped in strings"); Append(&result, after_backslash); break; case '0': if (quote == '"') - fail_with_error(st->location, "strings cannot contain zero bytes (\\0), because that is the special end marker byte"); + fail(st->location, "strings cannot contain zero bytes (\\0), because that is the special end marker byte"); Append(&result, '\0'); break; case 'x': { char b = read_hex_escape_byte(st); if (quote == '"' && b == 0) - fail_with_error(st->location, "strings cannot contain zero bytes (\\x00), because that is the special end marker byte"); + fail(st->location, "strings cannot contain zero bytes (\\x00), because that is the special end marker byte"); Append(&result, b); } break; @@ -302,9 +302,9 @@ static char *read_string(struct State *st, char quote, int *len) goto missing_end_quote; default: if ((unsigned char)after_backslash < 0x80 && isprint(after_backslash)) - fail_with_error(st->location, "unknown escape: '\\%c'", after_backslash); + fail(st->location, "unknown escape: '\\%c'", after_backslash); else - fail_with_error(st->location, "unknown '\\' escape"); + fail(st->location, "unknown '\\' escape"); } break; default: @@ -320,9 +320,9 @@ static char *read_string(struct State *st, char quote, int *len) missing_end_quote: if (quote == '"') - fail_with_error(st->location, "missing \" to end the string"); + fail(st->location, "missing \" to end the string"); else - fail_with_error(st->location, "missing ' to end the byte literal"); + fail(st->location, "missing ' to end the byte literal"); } static char read_char_literal(struct State *st) @@ -330,9 +330,9 @@ static char read_char_literal(struct State *st) int len; char *s = read_string(st, '\'', &len); if (len == 0) - fail_with_error(st->location, "a byte literal cannot be empty, maybe use double quotes to instead make a string?"); + fail(st->location, "a byte literal cannot be empty, maybe use double quotes to instead make a string?"); if (len >= 2) - fail_with_error(st->location, "single quotes are for specifying a byte, maybe use double quotes to instead make a string?"); + fail(st->location, "single quotes are for specifying a byte, maybe use double quotes to instead make a string?"); char result = s[0]; free(s); return result; @@ -375,21 +375,21 @@ static const char *read_operator(struct State *st) // These operators are here only to give better error messages if (strcmp(operator, "===") == 0) - fail_with_error(st->location, "use '==' instead of '==='"); + fail(st->location, "use '==' instead of '==='"); if (strcmp(operator, "!==") == 0) - fail_with_error(st->location, "use '!=' instead of '!=='"); + fail(st->location, "use '!=' instead of '!=='"); if (strcmp(operator, "&&") == 0) - fail_with_error(st->location, "use 'and' instead of '&&'"); + fail(st->location, "use 'and' instead of '&&'"); if (strcmp(operator, "||") == 0) - fail_with_error(st->location, "use 'or' instead of '||'"); + fail(st->location, "use 'or' instead of '||'"); if (strcmp(operator, "!") == 0) - fail_with_error(st->location, "use 'not' instead of '!'"); + fail(st->location, "use 'not' instead of '!'"); return *op; } } - fail_with_error(st->location, "there is no '%s' operator", operator); + fail(st->location, "there is no '%s' operator", operator); } @@ -402,12 +402,12 @@ static void handle_parentheses(struct State *st, const struct Token *t) Token opentoken = st->parens[0]; char open = opentoken.data.operator[0]; char close = open2close[(int)open]; - fail_with_error(opentoken.location, "'%c' without a matching '%c'", open, close); + fail(opentoken.location, "'%c' without a matching '%c'", open, close); } if (t->type == TOKEN_OPERATOR && strstr("[{(", t->data.operator)) { if (st->nparens == sizeof(st->parens)/sizeof(st->parens[0])) - fail_with_error(t->location, "too many nested parentheses"); + fail(t->location, "too many nested parentheses"); st->parens[st->nparens++] = *t; } @@ -416,7 +416,7 @@ static void handle_parentheses(struct State *st, const struct Token *t) char open = close2open[(int)close]; if (st->nparens == 0 || st->parens[--st->nparens].data.operator[0] != open) - fail_with_error(t->location, "'%c' without a matching '%c'", close, open); + fail(t->location, "'%c' without a matching '%c'", close, open); } } @@ -442,7 +442,7 @@ static Token read_token(struct State *st) case '\'': t.type = TOKEN_CHAR; t.data.char_value = read_char_literal(st); break; case '"': t.type = TOKEN_STRING; t.data.string_value = read_string(st, '"', NULL); break; case '\t': - fail_with_error(st->location, "Jou files cannot contain tab characters (use 4 spaces for indentation)"); + fail(st->location, "Jou files cannot contain tab characters (use 4 spaces for indentation)"); default: if(is_identifier_or_number_byte(c)) { read_identifier_or_number(st, c, &t.data.name); @@ -476,9 +476,9 @@ static Token read_token(struct State *st) handle_parentheses(st, &t); } else { if ((unsigned char)c < 0x80 && isprint(c)) - fail_with_error(st->location, "unexpected byte '%c' (%#02x)", c, (unsigned char)c); + fail(st->location, "unexpected byte '%c' (%#02x)", c, (unsigned char)c); else - fail_with_error(st->location, "unexpected byte %#02x", (unsigned char)c); + fail(st->location, "unexpected byte %#02x", (unsigned char)c); } break; } @@ -531,7 +531,7 @@ static Token *handle_indentations(const Token *temp_tokens) after_newline.lineno++; if (t->data.indentation_level % 4 != 0) - fail_with_error(after_newline, "indentation must be a multiple of 4 spaces"); + fail(after_newline, "indentation must be a multiple of 4 spaces"); while (level < t->data.indentation_level) { Append(&tokens, (Token){ .location=after_newline, .type=TOKEN_INDENT }); diff --git a/src/typecheck.c b/src/typecheck.c index 473a4f05..ffdc4979 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -115,7 +115,7 @@ ExportSymbol *typecheck_stage1_create_types(FileTypes *ft, const AstFile *ast) const Type *existing = find_type(ft, name); if (existing) - fail_with_error(stmt->location, "%s named '%s' already exists", short_type_description(existing), name); + fail(stmt->location, "%s named '%s' already exists", short_type_description(existing), name); Append(&ft->types, (struct TypeAndUsedPtr){ .type=t, .usedptr=NULL }); Append(&ft->owned_types, t); @@ -139,7 +139,7 @@ int evaluate_array_length(const AstExpression *expr) return (int)expr->data.constant.data.integer.value; } - fail_with_error(expr->location, "cannot evaluate array length at compile time"); + fail(expr->location, "cannot evaluate array length at compile time"); } static bool is_void(const AstType *t) @@ -160,7 +160,7 @@ static bool is_noreturn(const AstType *t) static const Type *type_from_ast(const FileTypes *ft, const AstType *asttype) { if (is_void(asttype) || is_none(asttype) || is_noreturn(asttype)) - fail_with_error(asttype->location, "'%s' cannot be used here because it is not a type", asttype->data.name); + fail(asttype->location, "'%s' cannot be used here because it is not a type", asttype->data.name); const Type *tmp; @@ -182,7 +182,7 @@ static const Type *type_from_ast(const FileTypes *ft, const AstType *asttype) return doubleType; if ((tmp = find_type(ft, asttype->data.name))) return tmp; - fail_with_error(asttype->location, "there is no type named '%s'", asttype->data.name); + fail(asttype->location, "there is no type named '%s'", asttype->data.name); case AST_TYPE_POINTER: if (is_void(asttype->data.valuetype)) @@ -193,7 +193,7 @@ static const Type *type_from_ast(const FileTypes *ft, const AstType *asttype) tmp = type_from_ast(ft, asttype->data.valuetype); int len = evaluate_array_length(asttype->data.array.len); if (len <= 0) - fail_with_error(asttype->data.array.len->location, "array length must be positive"); + fail(asttype->data.array.len->location, "array length must be positive"); return get_array_type(tmp, len); } } @@ -202,7 +202,7 @@ static ExportSymbol handle_global_var(FileTypes *ft, const AstNameTypeValue *var { assert(ft->current_fom_types == NULL); // find_any_var() only finds global vars if (find_any_var(ft, vardecl->name)) - fail_with_error(vardecl->name_location, "a global variable named '%s' already exists", vardecl->name); + fail(vardecl->name_location, "a global variable named '%s' already exists", vardecl->name); assert(!vardecl->value); GlobalVariable *g = calloc(1, sizeof *g); @@ -219,7 +219,7 @@ static ExportSymbol handle_global_var(FileTypes *ft, const AstNameTypeValue *var static Signature handle_signature(FileTypes *ft, const AstSignature *astsig, const Type *self_type) { if (find_function_or_method(ft, self_type, astsig->name)) - fail_with_error(astsig->name_location, "a %s named '%s' already exists", self_type ? "method" : "function", astsig->name); + fail(astsig->name_location, "a %s named '%s' already exists", self_type ? "method" : "function", astsig->name); Signature sig = { .nargs = astsig->args.len, .takes_varargs = astsig->takes_varargs }; safe_strcpy(sig.name, astsig->name); @@ -241,14 +241,14 @@ static Signature handle_signature(FileTypes *ft, const AstSignature *astsig, con if (is_none(&astsig->returntype) || is_noreturn(&astsig->returntype)) sig.returntype = NULL; else if (is_void(&astsig->returntype)) - fail_with_error(astsig->returntype.location, "void is not a valid return type, use '-> None' if the function does not return a value"); + fail(astsig->returntype.location, "void is not a valid return type, use '-> None' if the function does not return a value"); else sig.returntype = type_from_ast(ft, &astsig->returntype); // TODO: validate main() parameters // TODO: test main() taking parameters if (!self_type && !strcmp(sig.name, "main") && sig.returntype != intType) { - fail_with_error(astsig->returntype.location, "the main() function must return int"); + fail(astsig->returntype.location, "the main() function must return int"); } sig.returntype_location = astsig->returntype.location; @@ -463,7 +463,7 @@ static void ensure_can_take_address(const AstExpression *expr, const char *errms } __attribute__((fallthrough)); default: - fail_with_error(expr->location, errmsg_template, short_expression_description(expr)); + fail(expr->location, errmsg_template, short_expression_description(expr)); } } @@ -496,7 +496,7 @@ static noreturn void fail_with_implicit_cast_error( template++; } } - fail_with_error(location, "%.*s", msg.len, msg.ptr); + fail(location, "%.*s", msg.len, msg.ptr); } static bool can_cast_implicitly(const Type *from, const Type *to) @@ -544,7 +544,7 @@ static void do_implicit_cast( { int string_size = strlen(types->expr->data.constant.data.str) + 1; if (to->data.array.len < string_size) { - fail_with_error(location, "a string of %d bytes (including '\\0') does not fit into %s", string_size, to->name); + fail(location, "a string of %d bytes (including '\\0') does not fit into %s", string_size, to->name); } types->implicit_string_to_array_cast = true; } @@ -586,7 +586,7 @@ static void do_explicit_cast(ExpressionTypes *types, const Type *to, Location lo // TODO: pointer-to-int, int-to-pointer ) { - fail_with_error(location, "cannot cast from type %s to %s", from->name, to->name); + fail(location, "cannot cast from type %s to %s", from->name, to->name); } if (from->kind == TYPE_ARRAY && is_pointer_type(to)) @@ -601,11 +601,11 @@ static ExpressionTypes *typecheck_expression_not_void(FileTypes *ft, const AstEx if (!types) { switch(expr->kind) { case AST_EXPR_FUNCTION_CALL: - fail_with_error( + fail( expr->location, "function '%s' does not return a value", expr->data.call.calledname); break; case AST_EXPR_CALL_METHOD: - fail_with_error( + fail( expr->location, "method '%s' does not return a value", expr->data.methodcall.call.calledname); break; default: @@ -671,7 +671,7 @@ static const Type *check_binop( || (got_enums && op != AST_EXPR_EQ && op != AST_EXPR_NE) || (got_pointers && op != AST_EXPR_EQ && op != AST_EXPR_NE && op != AST_EXPR_GT && op != AST_EXPR_GE && op != AST_EXPR_LT && op != AST_EXPR_LE) ) - fail_with_error(location, "wrong types: cannot %s %s and %s", do_what, lhstypes->type->name, rhstypes->type->name); + fail(location, "wrong types: cannot %s %s and %s", do_what, lhstypes->type->name, rhstypes->type->name); const Type *cast_type = NULL; if (got_integers) { @@ -731,7 +731,7 @@ static const Type *check_increment_or_decrement(FileTypes *ft, const AstExpressi ensure_can_take_address(&expr->data.operands[0], bad_expr_fmt); const Type *t = typecheck_expression_not_void(ft, &expr->data.operands[0])->type; if (!is_integer_type(t) && !is_pointer_type(t)) - fail_with_error(expr->location, bad_type_fmt, t->name); + fail(expr->location, bad_type_fmt, t->name); return t; } @@ -739,7 +739,7 @@ static void typecheck_dereferenced_pointer(Location location, const Type *t) { // TODO: improved error message for dereferencing void* if (t->kind != TYPE_POINTER) - fail_with_error(location, "the dereference operator '*' is only for pointers, not for %s", t->name); + fail(location, "the dereference operator '*' is only for pointers, not for %s", t->name); } // ptr[index] @@ -754,14 +754,14 @@ static const Type *typecheck_indexing( ptrtype = types->implicit_cast_type; } else { if (types->type->kind != TYPE_POINTER) - fail_with_error(ptrexpr->location, "value of type %s cannot be indexed", types->type->name); + fail(ptrexpr->location, "value of type %s cannot be indexed", types->type->name); ptrtype = types->type; } assert(ptrtype->kind == TYPE_POINTER); ExpressionTypes *indextypes = typecheck_expression_not_void(ft, indexexpr); if (!is_integer_type(indextypes->type)) { - fail_with_error( + fail( indexexpr->location, "the index inside [...] must be an integer, not %s", indextypes->type->name); @@ -804,11 +804,11 @@ static const Type *typecheck_function_or_method_call(FileTypes *ft, const AstCal const Signature *sig = find_function_or_method(ft, self_type, call->calledname); if (!sig) { if (!self_type) - fail_with_error(location, "function '%s' not found", call->calledname); + fail(location, "function '%s' not found", call->calledname); // If self type is a pointer to a struct that has the method, mention it in the error message if (self_type->kind == TYPE_POINTER && find_method(self_type->data.valuetype, call->calledname)) { - fail_with_error( + fail( location, "the method '%s' is defined on class %s, not on the pointer type %s," " so you need to dereference the pointer first (e.g. by using '->' instead of '.')", @@ -816,12 +816,12 @@ static const Type *typecheck_function_or_method_call(FileTypes *ft, const AstCal } // If it is not a class, explain to the user that there are no methods if (self_type->kind != TYPE_CLASS) { - fail_with_error( + fail( location, "type %s does not have any methods because it is %s, not a class", self_type->name, short_type_description(self_type)); } - fail_with_error(location, "class %s does not have a method named '%s'", + fail(location, "class %s does not have a method named '%s'", self_type->name, call->calledname); } @@ -831,7 +831,7 @@ static const Type *typecheck_function_or_method_call(FileTypes *ft, const AstCal if (self_type) nargs--; if (call->nargs < nargs || (call->nargs > nargs && !sig->takes_varargs)) { - fail_with_error( + fail( location, "%s %s takes %d argument%s, but it was called with %d argument%s", self_type ? "method" : "function", @@ -881,7 +881,7 @@ static const struct ClassField *typecheck_class_field( for (struct ClassField *f = classtype->data.classdata.fields.ptr; f < End(classtype->data.classdata.fields); f++) if (!strcmp(f->name, fieldname)) return f; - fail_with_error(location, "class %s has no field named '%s'", classtype->name, fieldname); + fail(location, "class %s has no field named '%s'", classtype->name, fieldname); } static const Type *typecheck_instantiation(FileTypes *ft, const AstCall *call, Location location) @@ -891,7 +891,7 @@ static const Type *typecheck_instantiation(FileTypes *ft, const AstCall *call, L const Type *t = type_from_ast(ft, &tmp); if (t->kind != TYPE_CLASS) { - fail_with_error(location, + fail(location, "the %s{...} syntax is only for classes, but %s is %s", t->name, t->name, short_type_description(t)); } @@ -911,7 +911,7 @@ static const Type *typecheck_instantiation(FileTypes *ft, const AstCall *call, L for (int i1 = 0; i1 < call->nargs; i1++) { for (int i2 = i1+1; i2 < call->nargs; i2++) { if (specified_fields[i1]->union_id == specified_fields[i2]->union_id) { - fail_with_error( + fail( call->args[i2].location, "fields '%s' and '%s' cannot be set simultaneously because they belong to the same union", specified_fields[i1]->name, specified_fields[i2]->name); @@ -968,7 +968,7 @@ static const Type *cast_array_members_to_a_common_type(Location error_location, AppendStr(&namestr, (*t)->name); AppendStr(&namestr, ", "); } - fail_with_error( + fail( error_location, "array items have different types (%.*s)", namestr.len - 2, namestr.ptr); } @@ -990,14 +990,14 @@ static ExpressionTypes *typecheck_expression(FileTypes *ft, const AstExpression case AST_EXPR_GET_ENUM_MEMBER: result = find_type(ft, expr->data.enummember.enumname); if (!result) - fail_with_error( + fail( expr->location, "there is no type named '%s'", expr->data.enummember.enumname); if (result->kind != TYPE_ENUM) - fail_with_error( + fail( expr->location, "the '::' syntax is only for enums, but %s is %s", expr->data.enummember.enumname, short_type_description(result)); if (!enum_member_exists(result, expr->data.enummember.membername)) - fail_with_error(expr->location, "enum %s has no member named '%s'", + fail(expr->location, "enum %s has no member named '%s'", expr->data.enummember.enumname, expr->data.enummember.membername); break; case AST_EXPR_FUNCTION_CALL: @@ -1027,7 +1027,7 @@ static ExpressionTypes *typecheck_expression(FileTypes *ft, const AstExpression case AST_EXPR_GET_FIELD: temptype = typecheck_expression_not_void(ft, expr->data.classfield.obj)->type; if (temptype->kind != TYPE_CLASS) - fail_with_error( + fail( expr->location, "left side of the '.' operator must be an instance of a class, not %s", temptype->name); @@ -1036,7 +1036,7 @@ static ExpressionTypes *typecheck_expression(FileTypes *ft, const AstExpression case AST_EXPR_DEREF_AND_GET_FIELD: temptype = typecheck_expression_not_void(ft, expr->data.classfield.obj)->type; if (temptype->kind != TYPE_POINTER || temptype->data.valuetype->kind != TYPE_CLASS) - fail_with_error( + fail( expr->location, "left side of the '->' operator must be a pointer to a class, not %s", temptype->name); @@ -1045,7 +1045,7 @@ static ExpressionTypes *typecheck_expression(FileTypes *ft, const AstExpression case AST_EXPR_DEREF_AND_CALL_METHOD: temptype = typecheck_expression_not_void(ft, expr->data.classfield.obj)->type; if (temptype->kind != TYPE_POINTER) - fail_with_error( + fail( expr->location, "left side of the '->' operator must be a pointer, not %s", temptype->name); @@ -1076,7 +1076,7 @@ static ExpressionTypes *typecheck_expression(FileTypes *ft, const AstExpression case AST_EXPR_GET_VARIABLE: result = find_any_var(ft, expr->data.varname); if (!result) - fail_with_error(expr->location, "no variable named '%s'", expr->data.varname); + fail(expr->location, "no variable named '%s'", expr->data.varname); break; case AST_EXPR_DEREFERENCE: temptype = typecheck_expression_not_void(ft, &expr->data.operands[0])->type; @@ -1103,7 +1103,7 @@ static ExpressionTypes *typecheck_expression(FileTypes *ft, const AstExpression case AST_EXPR_NEG: result = typecheck_expression_not_void(ft, &expr->data.operands[0])->type; if (result->kind != TYPE_SIGNED_INTEGER && result->kind != TYPE_FLOATING_POINT) - fail_with_error( + fail( expr->location, "value after '-' must be a float or double or a signed integer, not %s", result->name); @@ -1268,20 +1268,20 @@ static void typecheck_statement(FileTypes *ft, const AstStatement *stmt) case AST_STMT_RETURN: if (ft->current_fom_types->signature.is_noreturn) - fail_with_error( + fail( stmt->location, "function '%s' cannot return because it was defined with '-> noreturn'", ft->current_fom_types->signature.name); const Type *returntype = ft->current_fom_types->signature.returntype; if (stmt->data.returnvalue && !returntype) { - fail_with_error( + fail( stmt->location, "function '%s' cannot return a value because it was defined with '-> None'", ft->current_fom_types->signature.name); } if (returntype && !stmt->data.returnvalue) { - fail_with_error( + fail( stmt->location, "a return value is needed, because the return type of function '%s' is %s", ft->current_fom_types->signature.name, @@ -1301,7 +1301,7 @@ static void typecheck_statement(FileTypes *ft, const AstStatement *stmt) case AST_STMT_DECLARE_LOCAL_VAR: if (find_any_var(ft, stmt->data.vardecl.name)) - fail_with_error(stmt->location, "a variable named '%s' already exists", stmt->data.vardecl.name); + fail(stmt->location, "a variable named '%s' already exists", stmt->data.vardecl.name); const Type *type = type_from_ast(ft, &stmt->data.vardecl.type); add_variable(ft, type, stmt->data.vardecl.name);