diff --git a/CMakeLists.txt b/CMakeLists.txt index 58beca7e5..5d0251cc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,6 @@ add_executable(c3c src/compiler/source_file.c src/compiler/diagnostics.c src/compiler/ast.c - src/compiler/bigint.c src/compiler/bigint.h src/compiler/context.c src/compiler/builtins.c src/compiler/codegen.c src/compiler/const_folding.c src/compiler/enums.h src/compiler/casts.c src/compiler/compiler.h src/compiler/types.c) + src/compiler/bigint.c src/compiler/bigint.h src/compiler/context.c src/compiler/codegen.c src/compiler/expr_analysis.c src/compiler/enums.h src/compiler/casts.c src/compiler/compiler.h src/compiler/types.c) target_compile_options(c3c PRIVATE -Werror -Wall -Wextra -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter) diff --git a/resources/testfragments/compiletest.c3 b/resources/testfragments/compiletest.c3 index ed486e5a1..9832dd24d 100644 --- a/resources/testfragments/compiletest.c3 +++ b/resources/testfragments/compiletest.c3 @@ -12,14 +12,50 @@ struct Bar Foo* fooPtr; } + +func int boo() +{ + bool z = 123 > 3.0; + { + int x = 0; + } + { + int x = 1; + } + int j = 10; + do + { + j = j + 10; + } while (j > 2); + return 1; +} + +func void while_test() +{ + + int a = 10; + while (int b = 37; a > 0) + { + int xy = 1; + } +} + func void test() { - int i = 1; + int a = 10; + while (1) + { + int xy = 1; + } + int eokfe = boo(); + int i = -1; + bool dwf = !2.0; + ushort b = ~cast(byte, 0); int j, k; int l, m = 0; int o = 0, p = 3; - short f = -2; - c_int x = 2; + short f = cast(byte, cast(int,-2)); + //int doek = ~2; return; } diff --git a/resources/testfragments/parsertest.c3 b/resources/testfragments/parsertest.c3 index 1fee37b8c..0073e7ac6 100644 --- a/resources/testfragments/parsertest.c3 +++ b/resources/testfragments/parsertest.c3 @@ -60,6 +60,18 @@ error Errors func Foom test(int a) { + while (int x = 0, int y = 3; int y = foo()) + { + a++; + } + while (int x = 0) + { + a++; + } + while (int x, y = 3; x > 0 && b < 0) + { + a++; + } return 1 + 2; } diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 0e8455463..801616386 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -72,7 +72,7 @@ Expr poisoned_expr = { .expr_kind = EXPR_POISONED, .resolve_status = RESOLVE_DON Type* type_int_max_type(bool is_signed) { - return is_signed ? &type_long : &type_ulong; + return is_signed ? type_long : type_ulong; } /* @@ -99,28 +99,6 @@ Type* type_get_unsigned(Type *type) */ -BinOp bin_op[256] = { - [TOKEN_EQ] = BINOP_ASSIGN, - [TOKEN_STAR] = BINOP_MULT, - [TOKEN_PLUS] = BINOP_ADD, - [TOKEN_MINUS] = BINOP_SUB, - [TOKEN_DIV] = BINOP_DIV, - [TOKEN_MOD] = BINOP_MOD, - [TOKEN_NOT_EQUAL] = BINOP_NE, - [TOKEN_AND] = BINOP_AND, - [TOKEN_OR] = BINOP_OR, - [TOKEN_AMP] = BINOP_BIT_AND, - [TOKEN_BIT_OR] = BINOP_BIT_OR, - [TOKEN_BIT_XOR] = BINOP_BIT_XOR, - [TOKEN_EQEQ] = BINOP_EQ, - [TOKEN_GREATER] = BINOP_GT, - [TOKEN_GREATER_EQ] = BINOP_GE, - [TOKEN_LESS] = BINOP_LT, - [TOKEN_LESS_EQ] = BINOP_LE, - [TOKEN_SHR] = BINOP_SHR, - [TOKEN_SHL] = BINOP_SHL, - [TOKEN_ELVIS] = BINOP_ELVIS -}; AssignOp assign_op[256] = { [TOKEN_EQ] = ASSIGNOP_ASSIGN, @@ -149,10 +127,6 @@ UnaryOp unary_op[256] = { }; -BinOp binop_from_token(TokenType type) -{ - return bin_op[type]; -} AssignOp assignop_from_token(TokenType type) { @@ -168,16 +142,6 @@ TokenType assignop_to_token(AssignOp type) return TOKEN_INVALID_TOKEN; } -TokenType binop_to_token(BinOp type) -{ - for (unsigned i = 0; i < 256; i++) - { - if (bin_op[i] == type) return (TokenType)i; - } - return TOKEN_INVALID_TOKEN; -} - - UnaryOp unaryop_from_token(TokenType type) { return unary_op[type]; @@ -330,16 +294,16 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) } return; case EXPR_BINARY: - fprintf(file, "(binary %s\n", token_type_to_string(binop_to_token(expr->binary_expr.operator))); + fprintf(file, "(binary %s\n", token_type_to_string(expr->binary_expr.operator)); fprint_expr_recursive(file, expr->binary_expr.left, indent + 1); fprint_expr_recursive(file, expr->binary_expr.right, indent + 1); break; case EXPR_UNARY: - fprintf(file, "(unary %s\n", token_type_to_string(unaryop_to_token(expr->unary_expr.operator))); + fprintf(file, "(unary %s\n", token_type_to_string(expr->unary_expr.operator)); fprint_expr_recursive(file, expr->unary_expr.expr, indent + 1); break; case EXPR_POST_UNARY: - fprintf(file, "(postunary %s\n", token_type_to_string(unaryop_to_token(expr->post_expr.operator))); + fprintf(file, "(postunary %s\n", token_type_to_string(expr->post_expr.operator)); fprint_expr_recursive(file, expr->post_expr.expr, indent + 1); break; case EXPR_METHOD_REF: @@ -363,9 +327,9 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) fprintf(file, "(call\n"); fprint_expr_recursive(file, expr->call_expr.function, indent + 1); { - VECEACH(expr->call_expr.parameters, i) + VECEACH(expr->call_expr.arguments, i) { - fprint_expr_recursive(file, expr->call_expr.parameters[i], indent + 1); + fprint_expr_recursive(file, expr->call_expr.arguments[i], indent + 1); } } break; @@ -397,15 +361,6 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) fprint_expr_recursive(file, expr->subscript_expr.expr, indent + 1); fprint_expr_recursive(file, expr->subscript_expr.index, indent + 1); break; - case EXPR_EXPRESSION_LIST: - fprintf(file, "(expressionlist\n"); - { - VECEACH(expr->expression_list, i) - { - fprint_expr_recursive(file, expr->expression_list[i], indent + 1); - } - } - break; case EXPR_TRY: if (!expr->try_expr.else_expr) { @@ -577,6 +532,14 @@ static void fprint_decl_list(FILE *file, Decl **decls, int indent) } } +static void fprint_asts_recursive(FILE *file, Ast **asts, int indent) +{ + VECEACH(asts, i) + { + fprint_ast_recursive(file, asts[i], indent); + } +} + static void fprint_ast_recursive(FILE *file, Ast *ast, int indent) { fprint_indent(file, indent); @@ -590,10 +553,7 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent) } fprintf(file, "(compound\n"); { - VECEACH(ast->compound_stmt.stmts, i) - { - fprint_ast_recursive(file, ast->compound_stmt.stmts[i], indent + 1); - } + fprint_asts_recursive(file, ast->compound_stmt.stmts, indent + 1); } break; case AST_DECLARE_STMT: @@ -614,6 +574,10 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent) fprint_ast_recursive(file, ast->do_stmt.body, indent + 1); fprint_expr_recursive(file, ast->do_stmt.expr, indent + 1); break; + case AST_STMT_LIST: + fprintf(file, "(stmtlist\n"); + fprint_asts_recursive(file, ast->stmt_list, indent + 1); + break; case AST_RETURN_STMT: if (ast->return_stmt.expr) { @@ -638,29 +602,25 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent) case AST_DEFAULT_STMT: fprintf(file, "(default)\n"); return; + case AST_COND_STMT: + fprintf(file, "(cond\n"); + if (ast->cond_stmt.expr) + { + fprint_expr_recursive(file, ast->cond_stmt.expr, indent + 1); + } + else + { + fprint_indent(file, indent); + fprintf(file, "(noexpr)"); + } + fprint_asts_recursive(file, ast->cond_stmt.stmts, indent + 1); + break; case AST_FOR_STMT: fprintf(file, "(for\n"); - if (ast->for_stmt.init) - { - fprint_ast_recursive(file, ast->for_stmt.init, indent + 1); - } - else - { - fprint_indent(file, indent + 1); - fprintf(file, "(noinit)\n"); - } - if (ast->for_stmt.cond) - { - fprint_expr_recursive(file, ast->for_stmt.cond, indent + 1); - } - else - { - fprint_indent(file, indent + 1); - fprintf(file, "(nocond)\n"); - } + fprint_ast_recursive(file, ast->for_stmt.cond, indent + 1); if (ast->for_stmt.incr) { - fprint_expr_recursive(file, ast->for_stmt.incr, indent + 1); + fprint_ast_recursive(file, ast->for_stmt.incr, indent + 1); } else { @@ -678,24 +638,8 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent) fprint_ast_recursive(file, ast->if_stmt.else_body, indent + 1); } break; - case AST_DECL_EXPR_LIST: - fprintf(file, "(declexprlist\n"); - if (ast->decl_expr_list.list_type == DECLEXPR_EXPR) - { - fprint_expr_recursive(file, ast->decl_expr_list.expr, indent + 1); - } - else - { - fprint_decl_recursive(file, ast->decl_expr_list.decl, indent + 1); - } - break; - case AST_COND_STMT: - fprintf(file, "(condstmt\n"); - fprint_decl_recursive(file, ast->cond_stmt.decl, indent + 1); - fprint_ast_recursive(file, ast->cond_stmt.decl_expr, indent + 1); - break; case AST_SWITCH_STMT: - fprintf(file, "(condstmt\n"); + fprintf(file, "(switchstmt\n"); fprint_ast_recursive(file, ast->switch_stmt.cond, indent + 1); fprint_ast_recursive(file, ast->switch_stmt.body, indent + 1); break; diff --git a/src/compiler/builtins.c b/src/compiler/builtins.c deleted file mode 100644 index 12ef44837..000000000 --- a/src/compiler/builtins.c +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "compiler_internal.h" - - - -/* -BuiltinType builtin_common_type[16][16] = { - // err, wptr, nil, bool, char, short, int, long, byte,ushort, int, ulong, float,double, ctint, ctreal - { TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR }, // Error - { TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR }, // void - { TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR }, // wptr - { TERR, TERR, TERR, T_U1, T_I8, T_I16, T_I32, T_I64, T_U8, T_U16, T_U32, T_U64, T_F32, T_F64, T_U1, T_FXX }, // bool - { TERR, TERR, TERR, T_I8, T_I8, T_I16, T_I32, T_I64, T_I8, T_I16, T_I32, T_I64, T_F32, T_F64, T_I8, T_FXX }, // char - { TERR, TERR, TERR, T_I16, T_I16, T_I16, T_I32, T_I64, T_I16, T_I16, T_I32, T_I64, T_F32, T_F64, T_I16, T_FXX }, // short - { TERR, TERR, TERR, T_I32, T_I32, T_I32, T_I32, T_I64, T_I32, T_I32, T_I32, T_I64, T_F32, T_F64, T_I32, T_FXX }, // int - { TERR, TERR, TERR, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_F32, T_F64, T_I64, T_FXX }, // long - { TERR, TERR, TERR, T_U8, T_I8, T_I16, T_I32, T_I64, T_U8, T_U16, T_U32, T_U64, T_F32, T_F64, T_U8, T_FXX }, // byte - { TERR, TERR, TERR, T_U16, T_I16, T_I16, T_I32, T_I64, T_U16, T_U16, T_U32, T_U64, T_F32, T_F64, T_U16, T_FXX }, // ushort - { TERR, TERR, TERR, T_U32, T_I32, T_I32, T_I32, T_I64, T_U32, T_U32, T_U32, T_U64, T_F32, T_F64, T_U32, T_FXX }, // uint - { TERR, TERR, TERR, T_U64, T_I64, T_I64, T_I64, T_I64, T_U64, T_U64, T_U64, T_U64, T_F32, T_F64, T_U64, T_FXX }, // ulong - { TERR, TERR, TERR, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F64, T_F32, T_F32 }, // float - { TERR, TERR, TERR, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64 }, // double - { TERR, TERR, TERR, T_U1, T_I8, T_I16, T_I32, T_I64, T_U8, T_U16, T_U32, T_U64, T_F32, T_F64, T_IXX, T_FXX }, // ctint - { TERR, TERR, TERR, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_F32, T_F64, T_FXX, T_FXX }, // ctreal -}; -void -BuiltinConv BUILTIN_ASSIGN_CONVERSION[16][16] = { - //e v w b c s i l b u u u f d c c - //r o p o h h n o y s i l l o t t - //r i t o a o t n t h n o o u i r - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // error - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // void = - { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // wptr = - { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // bool = - { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, // char = - { 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 }, // short = - { 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0 }, // int = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 }, // long = - { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 }, // byte = - { 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0 }, // ushort = - { 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0 }, // uint = - { 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0 }, // ulong = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, // float = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // double = - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctint - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctfloat -}; - -// x += x -= x /= x *= -bool BUILTIN_ASSIGN_UPDATE_CONVERSION[16][16] = { - //e v w b c s i l b u u u f d c c - //r o p o h h n o y s i l l o t t - //r i t o a o t n t h n o o u i r - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // error - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // void = - { 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // wptr = - { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }, // bool = - { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, // char = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // short = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // int = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // long = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // byte = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // ushort = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // uint = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // ulong = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // float = - { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // double = - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctint - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctfloat -}; -*/ - - -/* -void builtin_convert(ExprConst *value, BuiltinConv conversion, Type *canonical_target) -{ - assert(canonical_target == canonical_target->canonical); - switch (conversion) - { - case C_XXXX: - FATAL_ERROR("Should never be called"); - break; - case C_FPFP: - if (canonical_target->builtin.bitsize == 16) - { - value->f = (float)value->f; - } - if (canonical_target->builtin.bitsize == 32) - { - value->f = (double)value->f; - } - break; - case C_FPSI: - if (value->f < 0) - { - value->integer.i = (uint64_t)(-value->f); - value->type = CONST_NEGATIVE_INT; - } - else - { - value->integer.i = (uint64_t)(-value->f); - value->type = CONST_POSITIVE_INT; - } - break; - case C_FPUI: - assert(value->f >= 0); - value->integer.i = (uint64_t)(value->f); - value->type = CONST_POSITIVE_INT; - break; - case C_SIFP: - case C_UIFP: - value->f = value->integer.i; - if (value->type == CONST_NEGATIVE_INT) value->f = -value->f; - value->type = CONST_FLOAT; - break; - case C_SISI: -// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true); - break; - case C_SIUI: -// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true); - break; - case C_UISI: -// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true); - break; - case C_UIUI: -// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true); - break; - case C_PTXI: -// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true); - break; - case C_XIPT: -// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true); - break; - case C_BOFP: -// value_convert(value, VALUE_TYPE_FLOAT, canonical_target->decl->builtin.bitsize, false, true); - break; - case C_BOSI: -// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true); - break; - case C_BOUI: -// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true); - break; - case C_FPBO: -// value_convert(value, VALUE_TYPE_BOOL, canonical_target->decl->builtin.bitsize, true, true); - break; - case C_XIBO: -// value_convert(value, VALUE_TYPE_BOOL, canonical_target->decl->builtin.bitsize, true, true); - break; - case C_PTBO: -// value_convert(value, VALUE_TYPE_BOOL, canonical_target->decl->builtin.bitsize, true, true); - break; - default: - UNREACHABLE - } -} -*/ - diff --git a/src/compiler/casts.c b/src/compiler/casts.c index f18664c29..a0c3e5d6e 100644 --- a/src/compiler/casts.c +++ b/src/compiler/casts.c @@ -13,6 +13,7 @@ static inline void insert_cast(Expr *expr, CastKind kind, Type *type) *inner = *expr; expr->expr_kind = EXPR_CAST; expr->expr_cast.kind = kind; + expr->expr_cast.expr = inner; expr->type = type; } @@ -33,7 +34,7 @@ static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type) break; } - SEMA_ERROR(expr->loc, "Cannot %s '%s' to '%s'", action, type->name_loc.string, expr->type->name_loc.string); + SEMA_ERROR(expr->loc, "Cannot %s '%s' to '%s'", action, expr->type->name_loc.string, type->name_loc.string); return false; } @@ -80,7 +81,7 @@ static inline bool may_implicitly_cast_ptr_to_ptr(Type *current_type, Type *targ // Neither is void* or have matching bases: // TODO recursively check for ?* or? - if (target_type->base != &type_void && current_type->base != &type_void && target_type->base != current_type->base) return false; + if (target_type->base != type_void && current_type->base != type_void && target_type->base != current_type->base) return false; // Current is not null, or target is nullable? Ok! return target_type->nullable || !current_type->nullable; @@ -240,7 +241,7 @@ static int64_t int_type_min[4] = { INT8_MIN, INT16_MIN, INT32_MIN, INT64_MIN }; bool sisi(Expr* left, Type *canonical, Type *type, CastType cast_type) { Type *left_canonical = left->type->canonical; - bool is_narrowing = left->type->builtin.bytesize < canonical->builtin.bytesize && left_canonical->type_kind != TYPE_IXX; + bool is_narrowing = left_canonical->builtin.bytesize > canonical->builtin.bytesize && left_canonical->type_kind != TYPE_IXX; if (is_narrowing && (cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT)) EXIT_T_MISMATCH(); if (left->expr_kind == EXPR_CONST) @@ -313,7 +314,7 @@ bool sifp(Expr* left, Type *canonical, Type *type, CastType cast_type) if (left->expr_kind == EXPR_CONST) { assert(left->const_expr.type == CONST_INT); - assert(canonical->type_kind >= TYPE_F32 && canonical->type_kind <= TYPE_F64); + assert(canonical->type_kind >= TYPE_F32 && canonical->type_kind <= TYPE_FXX); if (left->const_expr.i > (uint64_t)INT64_MAX) { left->const_expr.f = -((long double)(~left->const_expr.i)); @@ -322,6 +323,7 @@ bool sifp(Expr* left, Type *canonical, Type *type, CastType cast_type) { left->const_expr.f = left->const_expr.i; } + left->const_expr.type = CONST_FLOAT; left->type = type; return true; } @@ -460,15 +462,15 @@ CastFunc BUILTIN_CONVERSION[19][19] = { { &xibo, &sisi, &erro, &sisi, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &erro, &erro, &erro, &erro }, // short { &xibo, &sisi, &sisi, &erro, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &xipt, &erro, &erro, &erro }, // int { &xibo, &sisi, &sisi, &sisi, &erro, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &xipt, &erro, &erro, &erro }, // long - { &xibo, &sisi, &sisi, &sisi, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &xipt, &erro, &erro, &erro }, // cint + { &xibo, &sisi, &sisi, &sisi, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &sifp, &sius, &xipt, &erro, &erro, &erro }, // ixx { &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &erro, &uiui, &uiui, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // byte { &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &erro, &uiui, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // ushort { &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &uiui, &erro, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // uint { &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &uiui, &uiui, &erro, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // ulong - { &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &uiui, &uiui, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // cuint + { &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &uiui, &uiui, &uiui, &erro, &uifp, &uifp, &uifp, &uius, &xipt, &erro, &erro, &erro }, // uxx { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro }, // float { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro, &erro }, // double - { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro }, // cfloat + { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro }, // fxx { &usbo, &ussi, &ussi, &ussi, &ussi, &erro, &usui, &usui, &usui, &usui, &erro, &erro, &erro, &erro, &usus, &erro, &erro, &erro, &erro }, // user { &ptbo, &ptxi, &ptxi, &ptxi, &ptxi, &erro, &ptxi, &ptxi, &ptxi, &ptxi, &erro, &erro, &erro, &erro, &erro, &ptpt, &ptst, &erro, &ptva }, // ptr { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro, &erro }, // str @@ -476,31 +478,80 @@ CastFunc BUILTIN_CONVERSION[19][19] = { { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro, &erro }, // varr }; +Type t_cpy = { .name_loc.string = "cpy" }; +Type t_err = { .name_loc.string = "err" }; + +Type *ARITHMETIC_PROMOTION[19][19] = { +//other bool, char, short, int, long, ctint, byte, ushort, int, ulong, ctuint, float, double, ctreal, user, ptr, str, arr, varr // from: + { &t_u1, &t_i8, &t_i16, &t_i32, &t_i64, &t_u1, &t_u8, &t_u16, &t_u32, &t_u64, &t_u1, &t_f32, &t_f64, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err }, // bool + { &t_i8, &t_i8, &t_i16, &t_i32, &t_i64, &t_i8, &t_i8, &t_i16, &t_i32, &t_i64, &t_i8, &t_f32, &t_f64, &t_err, &t_err, &t_isz, &t_err, &t_err, &t_err }, // char + { &t_i16, &t_i16, &t_i16, &t_i32, &t_i64, &t_i16, &t_i16, &t_i16, &t_i32, &t_i64, &t_i16, &t_f32, &t_f64, &t_err, &t_err, &t_isz, &t_err, &t_err, &t_err }, // short + { &t_i32, &t_i32, &t_i32, &t_i32, &t_i64, &t_i32, &t_i32, &t_i32, &t_i32, &t_i64, &t_i32, &t_f32, &t_f64, &t_err, &t_err, &t_isz, &t_err, &t_err, &t_err }, // int + { &t_i64, &t_i64, &t_i64, &t_i64, &t_i64, &t_i64, &t_i64, &t_i64, &t_i64, &t_i64, &t_i64, &t_f32, &t_f64, &t_err, &t_err, &t_isz, &t_err, &t_err, &t_err }, // long + { &t_u1, &t_i8, &t_i16, &t_i32, &t_i64, &t_ixx, &t_i8, &t_i16, &t_i32, &t_i64, &t_ixx, &t_f32, &t_f64, &t_fxx, &t_err, &t_isz, &t_err, &t_err, &t_err }, // ixx + { &t_u8, &t_i8, &t_i16, &t_i32, &t_i64, &t_uxx, &t_u8, &t_u16, &t_u32, &t_i64, &t_uxx, &t_f32, &t_f64, &t_err, &t_err, &t_usz, &t_err, &t_err, &t_err }, // byte + { &t_u16, &t_i16, &t_i16, &t_i32, &t_i64, &t_uxx, &t_u16, &t_u16, &t_u32, &t_i64, &t_uxx, &t_f32, &t_f64, &t_err, &t_err, &t_usz, &t_err, &t_err, &t_err }, // ushort + { &t_u32, &t_i32, &t_i32, &t_i32, &t_i64, &t_uxx, &t_u32, &t_u32, &t_u32, &t_i64, &t_uxx, &t_f32, &t_f64, &t_err, &t_err, &t_usz, &t_err, &t_err, &t_err }, // uint + { &t_u64, &t_i64, &t_i64, &t_i64, &t_i64, &t_uxx, &t_u64, &t_u64, &t_u64, &t_i64, &t_uxx, &t_f32, &t_f64, &t_err, &t_err, &t_usz, &t_err, &t_err, &t_err }, // ulong + { &t_u1, &t_i8, &t_i16, &t_i32, &t_i64, &t_uxx, &t_u8, &t_u16, &t_u32, &t_u64, &t_uxx, &t_f32, &t_f64, &t_fxx, &t_err, &t_usz, &t_err, &t_err, &t_err }, // uxx + { &t_f32, &t_f32, &t_f32, &t_f32, &t_f32, &t_f32, &t_f32, &t_f32, &t_f32, &t_f32, &t_f32, &t_f32, &t_f64, &t_f32, &t_err, &t_err, &t_err, &t_err, &t_err }, // float + { &t_f64, &t_f64, &t_f64, &t_f64, &t_f64, &t_f64, &t_f64, &t_f64, &t_f64, &t_f64, &t_f64, &t_f64, &t_f64, &t_f64, &t_err, &t_err, &t_err, &t_err, &t_err }, // double + { &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_f32, &t_f64, &t_fxx, &t_err, &t_err, &t_err, &t_err, &t_err }, // fxx + { &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err }, // user + { &t_err, &t_cpy, &t_cpy, &t_cpy, &t_cpy, &t_cpy, &t_cpy, &t_cpy, &t_cpy, &t_cpy, &t_cpy, &t_cpy, &t_err, &t_err, &t_err, &t_cpy, &t_err, &t_err, &t_err }, // ptr + { &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err }, // str + { &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err }, // arr + { &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err, &t_err }, // varr +}; + static inline bool cannot_convert(TypeKind type_kind) { return type_kind <= TYPE_VOID || type_kind >= TYPE_INC_ARRAY; } +bool cast_arithmetic(Expr *expr, Expr *other, const char *action) +{ + Type *canonical = expr->type->canonical; + Type *canonical_to = other->type->canonical; + if (cannot_convert(canonical->type_kind) || cannot_convert(canonical_to->type_kind)) goto ERR; + Type *preferred_type = ARITHMETIC_PROMOTION[canonical->type_kind - TYPE_BOOL][canonical_to->type_kind - TYPE_BOOL]; + if (preferred_type == &t_err) goto ERR; + if (preferred_type == &t_cpy || preferred_type == canonical) return true; + return cast(expr, preferred_type, CAST_TYPE_IMPLICIT); + + ERR: + SEMA_ERROR(expr->loc, "Cannot upcast to resolve '%s' %s '%s'", expr->type->name_loc.string, action, other->type->name_loc.string); + return false; + +} + +bool cast_to_runtime(Expr *expr) +{ + Type *canonical = expr->type->canonical; + switch (canonical->type_kind) + { + case TYPE_IXX: + return cast(expr, type_long, CAST_TYPE_IMPLICIT); + case TYPE_UXX: + return cast(expr, type_ulong, CAST_TYPE_IMPLICIT); + case TYPE_FXX: + return cast(expr, type_double, CAST_TYPE_IMPLICIT); + default: + return true; + } +} + bool cast(Expr *expr, Type *to_type, CastType cast_type) { Type *from_type = expr->type->canonical; Type *canonical = to_type->canonical; + if (from_type == canonical) return true; TypeKind from_kind = from_type->type_kind; TypeKind to_kind = canonical->type_kind; if (cannot_convert(from_kind) || cannot_convert(to_kind)) { - switch (cast_type) - { - case CAST_TYPE_EXPLICIT: - case CAST_TYPE_IMPLICIT: - SEMA_ERROR(expr->loc, "Cannot convert '%s' to '%s'", expr->type->name_loc.start, to_type->name_loc.start); - break; - case CAST_TYPE_IMPLICIT_ASSIGN: - case CAST_TYPE_IMPLICIT_ASSIGN_ADD: - SEMA_ERROR(expr->loc, "Cannot assign '%s' to '%s'", expr->type->name_loc.start, to_type->name_loc.start); - break; - } + sema_type_mismatch(expr, to_type, cast_type); return false; } CastFunc func = BUILTIN_CONVERSION[from_type->type_kind - TYPE_BOOL][to_type->type_kind - TYPE_BOOL]; diff --git a/src/compiler/codegen.c b/src/compiler/codegen.c index 7aa1f8afa..6735265f0 100644 --- a/src/compiler/codegen.c +++ b/src/compiler/codegen.c @@ -7,7 +7,10 @@ #define PRINTF(...) fprintf(context->codegen_output, __VA_ARGS__) #define PRINTTYPE(_t) print_typename(context->codegen_output, _t) +#define INDENT() indent_line(context, indent) + static void codegen_ast(Context *context, Ast *ast, int indent); +static int codegen_emit_expr(Context *context, Expr *expr, int indent); static void print_typename(FILE *file, Type *type) { @@ -100,57 +103,10 @@ static void indent_line(Context *context, int indent) { for (int i = 0; i < indent; i++) { - PRINTF(" "); + PRINTF(" "); } } -static void codegen_expr(Context *context, Expr *expr) -{ - switch (expr->expr_kind) - { - case EXPR_POISONED: - UNREACHABLE; - case EXPR_TRY: - break; - case EXPR_CONST: - break; - case EXPR_BINARY: - break; - case EXPR_CONDITIONAL: - break; - case EXPR_UNARY: - break; - case EXPR_POST_UNARY: - break; - case EXPR_TYPE: - break; - case EXPR_IDENTIFIER: - break; - case EXPR_METHOD_REF: - break; - case EXPR_CALL: - break; - case EXPR_SIZEOF: - break; - case EXPR_SUBSCRIPT: - break; - case EXPR_ACCESS: - break; - case EXPR_STRUCT_VALUE: - break; - case EXPR_STRUCT_INIT_VALUES: - break; - case EXPR_INITIALIZER_LIST: - break; - case EXPR_EXPRESSION_LIST: - break; - case EXPR_DEFERRED_TOKENS: - break; - case EXPR_CAST: - break; - } - TODO -} static inline void codegen_compound_stmt(Context *context, Ast *ast, int indent) { indent_line(context, indent); @@ -169,10 +125,32 @@ static inline void codegen_emit_cast(Context *context, Type *canonical) PRINTF("("); TODO } -static inline void codegen_emit_const_expr(Context *context, Expr *expr) + +static inline int codegen_emit_call_expr(Context *context, Expr *expr, int indent) +{ + // TODO properly + INDENT(); + PRINTTYPE(expr->type); + PRINTF(" _%d = %s();\n", ++context->unique_index, expr->call_expr.function->identifier_expr.decl->name.string); + return context->unique_index; +} + +static inline int codegen_emit_identifier_expr(Context *context, Expr *expr, int indent) +{ + // TODO properly + INDENT(); + PRINTTYPE(expr->type); + Decl *decl = expr->identifier_expr.decl; + PRINTF(" _%d = _%d_%s;\n", ++context->unique_index, decl->var.id, decl->name.string); + return context->unique_index; +} + + +static inline int codegen_emit_const_expr(Context *context, Expr *expr, int indent) { assert(expr->expr_kind == EXPR_CONST); Type *canonical = expr->type->canonical; + INDENT(); switch (canonical->type_kind) { case TYPE_POISONED: @@ -182,48 +160,50 @@ static inline void codegen_emit_const_expr(Context *context, Expr *expr) break; case TYPE_BOOL: assert(expr->const_expr.type == CONST_BOOL); - PRINTF(expr->const_expr.b ? "true" : "false"); - break; + PRINTTYPE(expr->type); + PRINTF(" _%d = %s;\n", ++context->unique_index, expr->const_expr.b ? "true" : "false"); + return context->unique_index; case TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: - assert(expr->const_expr.type == CONST_INT); - PRINTF("(("); - print_typename(context->codegen_output, canonical); - PRINTF(")"); - PRINTF("%lld)", (long long)expr->const_expr.i); - break; case TYPE_IXX: - UNREACHABLE + assert(expr->const_expr.type == CONST_INT); + PRINTTYPE(expr->type); + PRINTF(" _%d = (", ++context->unique_index); + PRINTTYPE(canonical); + PRINTF(")"); + PRINTF("%lld;\n", (long long)expr->const_expr.i); + return context->unique_index; case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: - assert(expr->const_expr.type == CONST_INT); - PRINTF("(("); - print_typename(context->codegen_output, canonical); - PRINTF(")"); - PRINTF("%llu)", expr->const_expr.i); - break; case TYPE_UXX: - UNREACHABLE + assert(expr->const_expr.type == CONST_INT); + PRINTTYPE(expr->type); + PRINTF(" _%d = (", ++context->unique_index); + PRINTTYPE(canonical); + PRINTF(")"); + PRINTF("%llu;\n", expr->const_expr.i); + return context->unique_index; case TYPE_F32: case TYPE_F64: - assert(expr->const_expr.type == CONST_FLOAT); - PRINTF("(("); - print_typename(context->codegen_output, canonical); - PRINTF(")"); - PRINTF("%Lf)", expr->const_expr.f); - break; case TYPE_FXX: - UNREACHABLE + assert(expr->const_expr.type == CONST_FLOAT); + PRINTTYPE(expr->type); + PRINTF(" _%d = (", ++context->unique_index); + PRINTTYPE(canonical); + PRINTF(")"); + PRINTF("%Lf;\n", expr->const_expr.f); + return context->unique_index; case TYPE_POINTER: assert(expr->const_expr.type == CONST_NIL); - PRINTF("(("); - print_typename(context->codegen_output, canonical); - PRINTF("0)"); - break; + PRINTTYPE(expr->type); + PRINTF(" _%d = ((", ++context->unique_index); + PRINTTYPE(canonical); + PRINTF("0);\n"); + return context->unique_index; case TYPE_STRING: TODO case TYPE_ARRAY: @@ -234,33 +214,116 @@ static inline void codegen_emit_const_expr(Context *context, Expr *expr) } } -static inline void codegen_emit_expr(Context *context, Expr *expr) +static inline int codegen_emit_cast_expr(Context *context, Expr *expr, int indent) +{ + int index = codegen_emit_expr(context, expr->expr_cast.expr, indent); + INDENT(); + PRINTTYPE(expr->type); + PRINTF(" _%d = (", ++context->unique_index); + PRINTTYPE(expr->type); + PRINTF(") _%d;\n", index); + return context->unique_index; +} + +static int codegen_emit_simple_binary_expr(Context *context, Expr *expr, int indent) +{ + int l_index = codegen_emit_expr(context, expr->binary_expr.left, indent); + int r_index = codegen_emit_expr(context, expr->binary_expr.right, indent); + INDENT(); + PRINTTYPE(expr->type); + PRINTF(" _%d = _%d %s _%d;\n", ++context->unique_index, l_index, token_type_to_string(expr->binary_expr.operator), r_index); + return context->unique_index; +} + +static int codegen_emit_assign_expr(Context *context, Expr *expr, int indent) +{ + Expr *left = expr->binary_expr.left; + Expr *right = expr->binary_expr.right; + int index = codegen_emit_expr(context, right, indent); + if (expr->binary_expr.left->expr_kind == EXPR_IDENTIFIER) + { + INDENT(); + PRINTF("%s = _%d;\n", left->identifier_expr.identifier.string, index); + return index; + } + else + { + TODO + } +} + +static int codegen_emit_binary_expr(Context *context, Expr *expr, int indent) +{ + switch (expr->binary_expr.operator) + { + case TOKEN_EQ: + return codegen_emit_assign_expr(context, expr, indent); + case TOKEN_PLUS: + case TOKEN_MINUS: + case TOKEN_GREATER: + case TOKEN_GREATER_EQ: + case TOKEN_LESS_EQ: + case TOKEN_LESS: + case TOKEN_EQEQ: + case TOKEN_NOT_EQUAL: + case TOKEN_MOD: + case TOKEN_DIV: + case TOKEN_STAR: + return codegen_emit_simple_binary_expr(context, expr, indent); + case TOKEN_BIT_OR: + case TOKEN_AMP: + case TOKEN_BIT_XOR: + case TOKEN_SHL: + case TOKEN_SHR: + TODO + case TOKEN_MULT_ASSIGN: + case TOKEN_DIV_ASSIGN: + case TOKEN_MINUS_ASSIGN: + case TOKEN_PLUS_ASSIGN: + case TOKEN_MOD_ASSIGN: + case TOKEN_AND_ASSIGN: + case TOKEN_OR_ASSIGN: + case TOKEN_SHR_ASSIGN: + case TOKEN_SHL_ASSIGN: + case TOKEN_BIT_XOR_ASSIGN: + case TOKEN_BIT_OR_ASSIGN: + case TOKEN_BIT_AND_ASSIGN: + case TOKEN_ELVIS: + UNREACHABLE + default: + UNREACHABLE + } +} +static int codegen_emit_expr(Context *context, Expr *expr, int indent) { switch (expr->expr_kind) { case EXPR_CONST: - codegen_emit_const_expr(context, expr); - break; + return codegen_emit_const_expr(context, expr, indent); + case EXPR_CALL: + return codegen_emit_call_expr(context, expr, indent); + case EXPR_IDENTIFIER: + return codegen_emit_identifier_expr(context, expr, indent); + case EXPR_CAST: + return codegen_emit_cast_expr(context, expr, indent); + case EXPR_BINARY: + return codegen_emit_binary_expr(context, expr, indent); default: TODO } } -static inline void codegen_var_decl(Context *context, Decl *decl, int indent) +static inline int codegen_var_decl(Context *context, Decl *decl, int indent) { assert(decl->decl_kind == DECL_VAR); - indent_line(context, indent); - print_typename(context->codegen_output, decl->var.type); - PRINTF(" "); - PRINTF("%s", decl->name.string); - PRINTF(";\n"); - if (!decl->var.init_expr) return; - indent_line(context, indent); - PRINTF("%s = ", decl->name.string); - codegen_emit_expr(context, decl->var.init_expr); - PRINTF(";\n"); + if (!decl->var.init_expr) return -1; + int index = codegen_emit_expr(context, decl->var.init_expr, indent); + INDENT(); + PRINTF("_%d_%s = _%d;\n", decl->var.id, decl->name.string, index); + return index; } + static inline void codegen_declare_stmt(Context *context, Ast *ast, int indent) { Decl *decl = ast->declare_stmt; @@ -277,6 +340,77 @@ static inline void codegen_declare_stmt(Context *context, Ast *ast, int indent) } } +static inline void codegen_emit_for_smt(Context *context, Ast *ast, int indent) +{ + INDENT(); + int loop = ++context->unique_index; + PRINTF("// --- Begin for id:%d ---\n", loop); + Ast **stmts = ast->for_stmt.cond->cond_stmt.stmts; + if (stmts) + { + INDENT(); + PRINTF("// --- Prelude ---\n"); + VECEACH(stmts, i) + { + codegen_ast(context, stmts[i], indent); + } + } + INDENT(); + PRINTF("// --- Loop condition ---\n"); + INDENT(); + PRINTF("_FOR_%d:\n", loop); + if (ast->for_stmt.cond->cond_stmt.expr) + { + int res = codegen_emit_expr(context, ast->for_stmt.cond->cond_stmt.expr, indent); + INDENT(); + PRINTF("if (!_%i) goto _FOR_EXIT_%d;\n", res, loop); + } + INDENT(); + PRINTF("// --- Body ---\n"); + codegen_ast(context, ast->for_stmt.body, indent); + INDENT(); + PRINTF("// --- End ---\n"); + INDENT(); + PRINTF("goto _FOR_%d;\n", loop); + INDENT(); + PRINTF("_FOR_EXIT_%d:;\n", loop); + INDENT(); + PRINTF("// --- End for id:%d --- \n", loop); +} + +static inline void codegen_emit_do_smt(Context *context, Ast *ast, int indent) +{ + INDENT(); + int loop = ++context->unique_index; + PRINTF("// --- Begin do id:%d ---\n", loop); + INDENT(); + PRINTF("_DO_%d_BEGIN:\n", loop); + INDENT(); + PRINTF("// --- Body ---\n"); + codegen_ast(context, ast->do_stmt.body, indent); + INDENT(); + PRINTF("// --- End ---\n"); + INDENT(); + PRINTF("_DO_%d_CONTINUE:\n", loop); + INDENT(); + PRINTF("// --- Loop condition ---\n"); + int res = codegen_emit_expr(context, ast->do_stmt.expr, indent); + INDENT(); + PRINTF("if (_%i) goto _DO_%d_BEGIN;\n", res, loop); + INDENT(); + PRINTF("_DO_%d_EXIT:;\n", loop); + INDENT(); + PRINTF("// --- End do id:%d --- \n", loop); +} + +static inline void codegen_emit_stmt_list(Context *context, Ast *ast, int indent) +{ + VECEACH(ast->stmt_list, i) + { + codegen_ast(context, ast->stmt_list[i], indent); + } +} + static void codegen_ast(Context *context, Ast *ast, int indent) { switch (ast->ast_kind) @@ -309,18 +443,19 @@ static void codegen_ast(Context *context, Ast *ast, int indent) case AST_DECLARE_STMT: codegen_declare_stmt(context, ast, indent); return; - case AST_DECL_EXPR_LIST: - break; case AST_DEFAULT_STMT: break; case AST_DEFER_STMT: break; case AST_DO_STMT: - break; + codegen_emit_do_smt(context, ast, indent); + return; case AST_EXPR_STMT: - break; + codegen_emit_expr(context, ast->expr_stmt, indent); + return; case AST_FOR_STMT: - break; + codegen_emit_for_smt(context, ast, indent); + return; case AST_GOTO_STMT: break; case AST_IF_STMT: @@ -330,15 +465,16 @@ static void codegen_ast(Context *context, Ast *ast, int indent) case AST_NOP_STMT: break; case AST_RETURN_STMT: - indent_line(context, indent); if (ast->return_stmt.expr) { - PRINTF("return "); - codegen_expr(context, ast->return_stmt.expr); + int index = codegen_emit_expr(context, ast->return_stmt.expr, indent); + INDENT(); + PRINTF("return _%d", index); PRINTF(";\n"); } else { + INDENT(); PRINTF("return;\n"); } return; @@ -353,19 +489,61 @@ static void codegen_ast(Context *context, Ast *ast, int indent) case AST_VOLATILE_STMT: break; case AST_WHILE_STMT: - break; + UNREACHABLE case AST_GENERIC_CASE_STMT: break; case AST_GENERIC_DEFAULT_STMT: break; + case AST_STMT_LIST: + codegen_emit_stmt_list(context, ast, indent); + return; } TODO } + +static inline void codegen_func_decl(Context *context, Decl *decl) +{ + if (decl->visibility != VISIBLE_PUBLIC) + { + PRINTF("static "); + } + print_typename(context->codegen_output, decl->func.function_signature.rtype); + PRINTF(" %s__%s()", decl->module->name, decl->name.string); +} + static inline void codegen_func(Context *context, Decl *decl) { - print_typename(context->codegen_output, decl->func.function_signature.rtype); - PRINTF(" %s__%s()\n", decl->module->name, decl->name.string); - codegen_ast(context, decl->func.body, 0); + codegen_func_decl(context, decl); + Ast *const body = decl->func.body; + assert(body->ast_kind == AST_COMPOUND_STMT); + PRINTF("\n{\n"); + Decl **const vars = decl->func.annotations->vars; + Type *type = NULL; + VECEACH(vars, i) + { + Decl *var = vars[i]; + assert(var->decl_kind == DECL_VAR); + Type *current = var->var.type->canonical; + if (type == current) + { + PRINTF(", "); + } + else + { + if (type) PRINTF(";\n"); + indent_line(context, 1); + print_typename(context->codegen_output, var->var.type); + PRINTF(" "); + } + type = current; + PRINTF("_%u_%s", var->var.id, var->name.string); + } + if (type) PRINTF(";\n"); + VECEACH(body->compound_stmt.stmts, i) + { + codegen_ast(context, body->compound_stmt.stmts[i], 1); + } + PRINTF("}\n"); } static void codegen_struct_member(Context *context, Decl *decl, int indent) @@ -405,7 +583,63 @@ static inline void codegen_struct_union(Context *context, Decl *decl) PRINTF("} %s_%s;\n\n", decl->module->name, decl->name.string); } -static inline void codegen_decl(Context *context, Decl *decl) + +static inline void codegen_top_level_func(Context *context, Decl *decl) +{ + codegen_func_decl(context, decl); + PRINTF(";\n"); +} + +static inline void codegen_top_level_struct_union(Context *context, Decl *decl) +{ + const char* type = decl->decl_kind == DECL_UNION ? "union" : "struct"; + PRINTF("typedef %s _%s_%s %s_%s;\n", type, decl->module->name, decl->name.string, decl->module->name, decl->name.string); +} + +static inline void codegen_top_level_decl_header(Context *context, Decl *decl) +{ + switch (decl->decl_kind) + { + case DECL_POISONED: + FATAL_ERROR("Tried to codegen broken code"); + return; + case DECL_FUNC: + codegen_top_level_func(context, decl); + return; + case DECL_VAR: + break; + case DECL_TYPEDEF: + TODO + case DECL_STRUCT: + case DECL_UNION: + codegen_top_level_struct_union(context, decl); + return; + case DECL_ENUM: + TODO + // codegen_top_level_enum(context, decl); + return; + case DECL_ERROR: + TODO + case DECL_MULTI_DECL: + TODO + break; + case DECL_CT_IF: + case DECL_CT_ELSE: + case DECL_CT_ELIF: + case DECL_ENUM_CONSTANT: + case DECL_ARRAY_VALUE: + case DECL_IMPORT: + case DECL_ERROR_CONSTANT: + UNREACHABLE + case DECL_MACRO: + case DECL_GENERIC: + break; + } + TODO + +} + +static inline void codegen_top_level_decl(Context *context, Decl *decl) { switch (decl->decl_kind) { @@ -435,17 +669,16 @@ static inline void codegen_decl(Context *context, Decl *decl) break; case DECL_IMPORT: break; - case DECL_MACRO: - break; + return; case DECL_MULTI_DECL: break; - case DECL_GENERIC: break; case DECL_CT_IF: - break; case DECL_CT_ELSE: - break; case DECL_CT_ELIF: + UNREACHABLE + case DECL_MACRO: + case DECL_GENERIC: break; } TODO @@ -454,6 +687,11 @@ void codegen(Context *context) { VECEACH(context->declarations, i) { - codegen_decl(context, context->declarations[i]); + codegen_top_level_decl_header(context, context->declarations[i]); } + VECEACH(context->declarations, i) + { + codegen_top_level_decl(context, context->declarations[i]); + } + } \ No newline at end of file diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index bb0ee62a7..d6badcb00 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -17,7 +17,6 @@ typedef uint32_t SourceLoc; #define MAX_LOCALS 0xFFFF #define MAX_SCOPE_DEPTH 0xFF - typedef struct _Ast Ast; typedef struct _Decl Decl; typedef struct _Type Type; @@ -140,6 +139,7 @@ typedef struct typedef struct _VarDecl { + unsigned id : 16; VarDeclKind kind : 3; Type *type; Expr *init_expr; @@ -181,12 +181,18 @@ typedef struct Token *throws; } FunctionSignature; +typedef struct +{ + Decl **vars; +} FuncAnnotations; + typedef struct { const char *full_name; Type *struct_parent; FunctionSignature function_signature; - struct _Ast *body; + Ast *body; + FuncAnnotations *annotations; } FuncDecl; typedef struct @@ -283,7 +289,7 @@ typedef struct { Expr *left; Expr *right; - BinOp operator; + TokenType operator; } ExprBinary; typedef struct @@ -296,7 +302,7 @@ typedef struct typedef struct { Expr* expr; - UnaryOp operator; + TokenType operator; } ExprUnary; @@ -320,7 +326,7 @@ typedef struct { bool is_struct_function; Expr *function; - Expr **parameters; + Expr **arguments; } ExprCall; typedef struct @@ -448,17 +454,16 @@ typedef struct typedef struct { - Ast *init; - Expr *cond; - Expr *incr; + Ast *cond; + Ast *incr; Ast *body; } AstForStmt; typedef struct { - Decl *decl; - Ast *decl_expr; + Ast **stmts; + Expr *expr; } AstCondStmt; @@ -544,6 +549,7 @@ typedef struct _Ast AstDeclExprList decl_expr_list; AstGenericCaseStmt generic_case_stmt; struct _Ast* generic_default_stmt; + Ast** stmt_list; }; } Ast; @@ -565,16 +571,19 @@ typedef struct _Module STable public_symbols; } Module; + typedef struct _DynamicScope { - int flags; - int flags_created; + ScopeFlags flags; + ScopeFlags flags_created; unsigned errors; Decl **local_decl_start; Ast *defer_stack_start; Ast *active_defer; + ExitType exit; } DynamicScope; + typedef struct _Context { Token module_name; @@ -591,6 +600,10 @@ typedef struct _Context Decl **last_local; DynamicScope scopes[MAX_SCOPE_DEPTH]; DynamicScope *current_scope; + int unique_index; + Decl *evaluating_macro; + Type *rtype; + int in_volatile_section; } Context; extern Context *current_context; @@ -604,18 +617,25 @@ extern Module poisoned_module; extern Token next_tok; extern Token tok; -extern Type type_bool, type_void, type_string; -extern Type type_half, type_float, type_double, type_quad; -extern Type type_char, type_short, type_int, type_long, type_isize; -extern Type type_byte, type_ushort, type_uint, type_ulong, type_usize; -extern Type type_compint, type_compuint, type_compfloat; -extern Type type_c_short, type_c_int, type_c_long, type_c_longlong; -extern Type type_c_ushort, type_c_uint, type_c_ulong, type_c_ulonglong; +extern Type *type_bool, *type_void, *type_string; +extern Type *type_float, *type_double; +extern Type *type_char, *type_short, *type_int, *type_long, *type_isize; +extern Type *type_byte, *type_ushort, *type_uint, *type_ulong, *type_usize; +extern Type *type_compint, *type_compuint, *type_compfloat; +extern Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong; +extern Type *type_c_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong; + +extern Type t_i8, t_i16, t_i32, t_i64, t_isz, t_ixx; +extern Type t_u1, t_u8, t_u16, t_u32, t_u64, t_usz, t_uxx; +extern Type t_f32, t_f64, t_fxx; +extern Type t_u0, t_str; +extern Type t_cus, t_cui, t_cul, t_cull; +extern Type t_cs, t_ci, t_cl, t_cll; #define AST_NEW(_kind, _token) new_ast(_kind, _token) static inline bool ast_ok(Ast *ast) { return ast == NULL || ast->ast_kind != AST_POISONED; } -static inline void ast_poison(Ast *ast) { ast->ast_kind = AST_POISONED; } +static inline bool ast_poison(Ast *ast) { ast->ast_kind = AST_POISONED; return false; } static inline Ast *new_ast(AstKind kind, Token token) { Ast *ast = malloc_arena(sizeof(Ast)); @@ -677,13 +697,13 @@ static inline ConstType sign_from_type(Type *type) } bool cast(Expr *expr, Type *to_type, CastType cast_type); +bool cast_arithmetic(Expr *expr, Expr *other, const char *action); +bool cast_to_runtime(Expr *expr); void codegen(Context *context); - - - +bool sema_expr_analysis(Context *context, Expr *expr); Context *context_create(File *file); void context_push(Context *context); @@ -692,6 +712,7 @@ bool context_add_import(Context *context, Token module_name, Token alias, Import bool context_set_module_from_filename(Context *context); bool context_set_module(Context *context, Token module_name, Token *generic_parameters); void context_print_ast(Context *context, FILE *file); +Decl *context_find_ident(Context *context, const char *symbol); Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility); Decl *decl_new_user_defined_type(Token name, DeclKind decl_type, Visibility visibility); @@ -709,12 +730,17 @@ void diag_reset(void); void diag_error_range(SourceRange span, const char *message, ...); void diag_verror_range(SourceRange span, const char *message, va_list args); - #define EXPR_NEW_EXPR(_kind, _expr) expr_new(_kind, _expr->loc) #define EXPR_NEW_TOKEN(_kind, _tok) expr_new(_kind, _tok) Expr *expr_new(ExprKind kind, Token start); static inline bool expr_ok(Expr *expr) { return expr == NULL || expr->expr_kind != EXPR_POISONED; } -static inline void expr_poison(Expr *expr) { expr->expr_kind = EXPR_POISONED; expr->resolve_status = RESOLVE_DONE; } +static inline bool expr_poison(Expr *expr) { expr->expr_kind = EXPR_POISONED; expr->resolve_status = RESOLVE_DONE; return false; } +static inline void expr_replace(Expr *expr, Expr *replacement) +{ + Token loc = expr->loc; + *expr = *replacement; + expr->loc = loc; +} void fprint_ast(FILE *file, Ast *ast); void fprint_decl(FILE *file, Decl *dec); @@ -748,12 +774,16 @@ static inline void advance_and_verify(TokenType token_type) advance(); } +Decl *module_find_symbol(Module *module, const char *symbol); + void parse_file(File *file); #define SEMA_ERROR(_tok, ...) sema_error_range(_tok.span, __VA_ARGS__) void sema_init(File *file); void sema_analysis(Context *context); -bool sema_const_fold_binary(Context *context, Expr *expr); + +bool sema_analyse_statement(Context *context, Ast *statement); +bool sema_resolve_type(Context *context, Type *type); void sema_error_at(SourceLoc loc, const char *message, ...); void sema_error_range(SourceRange range, const char *message, ...); void sema_verror_at(SourceLoc loc, const char *message, va_list args); @@ -762,7 +792,6 @@ void sema_error(const char *message, ...); void sema_prev_at_range(SourceRange span, const char *message, ...); void sema_prev_at(SourceLoc loc, const char *message, ...); - File *source_file_load(const char *filename, bool *already_loaded); File *source_file_from_position(SourceLoc loc); @@ -797,14 +826,23 @@ static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_UXX; } static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; } static inline void type_poison(Type *type) { type->type_kind = TYPE_POISONED; type->resolve_status = RESOLVE_DONE; } +static inline bool type_is_integer(Type *type) +{ + assert(type == type->canonical); + return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_UXX; +} + +static inline bool type_is_number(Type *type) +{ + assert(type == type->canonical); + return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_FXX; +} #define TYPE_MODULE_UNRESOLVED(_module, _name) ({ Type *__type = type_new(TYPE_USER_DEFINED); \ __type->name_loc = _name; __type->unresolved.module = _module; __type; }) #define TYPE_UNRESOLVED(_name) ({ Type *__type = type_new(TYPE_USER_DEFINED); __type->name_loc = _name; __type; }) AssignOp assignop_from_token(TokenType type); -BinOp binop_from_token(TokenType type); -TokenType binop_to_token(BinOp type); UnaryOp unaryop_from_token(TokenType type); Decl *struct_find_name(Decl *decl, const char* name); diff --git a/src/compiler/const_folding.c b/src/compiler/const_folding.c deleted file mode 100644 index 30aedfe48..000000000 --- a/src/compiler/const_folding.c +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "compiler_internal.h" - -#define COMP_OP(comp) \ -switch (left->type)\ -{ case CONST_NIL: result->b = 0 comp 0; break;\ -case CONST_BOOL: result->b = left->b comp right->b; break;\ -case CONST_STRING: UNREACHABLE;\ -case CONST_FLOAT: result->b = left->f comp right->f; break;\ -case CONST_INT: result->b = left->i comp right->i; break;\ -default: UNREACHABLE }\ -result->type = CONST_BOOL; expr->expr_kind = EXPR_CONST; expr->type = &type_bool; return true; - -#define BOOL_COMP(comp) \ -switch (left->type)\ -{ case CONST_NIL: result->b = 0 comp 0; break;\ -case CONST_BOOL: result->b = left->b comp right->b; break;\ -case CONST_STRING: UNREACHABLE;\ -case CONST_FLOAT: result->b = (left->f != 0) comp (right->f != 0); break;\ -case CONST_INT: result->b = (left->i != 0) comp (right->i != 0); break;\ -default: break; }\ -result->type = CONST_BOOL; expr->expr_kind = EXPR_CONST; expr->type = &type_bool; return true - -#define BITOP(op)\ -switch (left->type)\ -{ case CONST_NIL: break; \ -case CONST_BOOL: result->b = left->b op right->b; break; \ -case CONST_STRING: case CONST_FLOAT: UNREACHABLE; \ -case CONST_INT: result->b = left->i op right->i; break; \ -default: UNREACHABLE; \ -} break - -#define ARITH(op)\ -switch (left->type)\ -{ case CONST_NIL: case CONST_BOOL: case CONST_STRING: UNREACHABLE; \ -case CONST_FLOAT: result->f = left->f op right->f; break;\ -case CONST_INT: result->i = left->i op right->i; break; \ -default: UNREACHABLE; \ -} break - -bool sema_const_fold_binary(Context *context, Expr *expr) -{ - Expr *left_expr = expr->binary_expr.left; - Expr *right_expr = expr->binary_expr.right; - - if (left_expr->expr_kind != EXPR_CONST || right_expr->expr_kind != EXPR_CONST) return true; - Type *type = left_expr->type->canonical; - assert(type == right_expr->type->canonical); - ExprConst *left = &left_expr->const_expr; - ExprConst *right = &right_expr->const_expr; - ExprConst *result = &expr->const_expr; - switch (expr->binary_expr.operator) - { - case BINOP_ERROR: - case BINOP_ASSIGN: - case BINOP_MULT_ASSIGN: - case BINOP_ADD_ASSIGN: - case BINOP_SUB_ASSIGN: - case BINOP_DIV_ASSIGN: - case BINOP_MOD_ASSIGN: - case BINOP_AND_ASSIGN: - case BINOP_OR_ASSIGN: - case BINOP_BIT_AND_ASSIGN: - case BINOP_BIT_OR_ASSIGN: - case BINOP_BIT_XOR_ASSIGN: - case BINOP_SHR_ASSIGN: - case BINOP_SHL_ASSIGN: - SEMA_ERROR(expr->loc, "Invalid operation '%s' %s '%s.", left_expr->type->name_loc.string, token_type_to_string(binop_to_token(expr->binary_expr.operator)), right_expr->type->name_loc.string); - return false; - case BINOP_MULT: - ARITH(*); - case BINOP_ADD: - ARITH(+); - case BINOP_SUB: - ARITH(-); - case BINOP_DIV: - switch (left->type) - { - case CONST_NIL: - case CONST_BOOL: - case CONST_STRING: - UNREACHABLE; - case CONST_INT: - if (right->i == 0) - { - SEMA_ERROR(expr->binary_expr.right->loc, "Division by zero not allowed."); - return false; - } - result->i = left->i / right->i; - break; - case CONST_FLOAT: - if (right->f == 0) - { - SEMA_ERROR(expr->binary_expr.right->loc, "Division by zero not allowed."); - return false; - } - expr->const_expr.f = left->f / right->f; - expr->const_expr.type = CONST_FLOAT; - break; - } - break; - case BINOP_MOD: - switch (left->type) - { - case CONST_NIL: - case CONST_BOOL: - case CONST_STRING: - case CONST_FLOAT: - UNREACHABLE; - case CONST_INT: - if (right->i == 0) - { - SEMA_ERROR(expr->binary_expr.right->loc, "Cannot do mod by zero."); - return false; - } - result->i = left->i % right->i; - break; - } - break; - case BINOP_AND: - BOOL_COMP(&&); - case BINOP_OR: - BOOL_COMP(||); - case BINOP_BIT_AND: - BITOP(&); - case BINOP_BIT_OR: - BITOP(|); - case BINOP_BIT_XOR: - BITOP(^); - case BINOP_NE: - COMP_OP(!=) - case BINOP_EQ: - COMP_OP(==) - case BINOP_GE: - COMP_OP(>=) - case BINOP_GT: - COMP_OP(>) - case BINOP_LE: - COMP_OP(<=) - case BINOP_LT: - COMP_OP(<) - case BINOP_SHR: - TODO - break; - case BINOP_SHL: - TODO - break; - case BINOP_ELVIS: - TODO - break; - } - expr->type = type; - expr->expr_kind = EXPR_CONST; - return true; -} diff --git a/src/compiler/context.c b/src/compiler/context.c index 654878836..d55103798 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -41,8 +41,6 @@ static inline bool create_module_or_check_name(Context *context, Token module_na bool context_set_module_from_filename(Context *context) { - LOG_FUNC - char buffer[MAX_IDENTIFIER_LENGTH + 1]; int len = filename_to_module(context->file->full_path, buffer); if (!len) @@ -64,7 +62,6 @@ bool context_set_module_from_filename(Context *context) bool context_set_module(Context *context, Token module_name, Token *generic_parameters) { - LOG_FUNC DEBUG_LOG("CONTEXT: Setting module to '%s'.", module_name.string); // Note that we allow the illegal name for now, to be able to parse further. context->module_name = module_name; @@ -96,7 +93,6 @@ void context_register_global_decl(Context *context, Decl *decl) bool context_add_import(Context *context, Token module_name, Token alias, ImportType import_type, Expr** generic_parameters) { - LOG_FUNC DEBUG_LOG("SEMA: Add import of '%s'.", module_name.string); if (!is_all_lower(module_name.string)) { diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 31b39b544..8bfa3c9f7 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -37,25 +37,25 @@ typedef enum AST_CT_ELIF_STMT, AST_CT_ELSE_STMT, AST_DECLARE_STMT, - AST_DECL_EXPR_LIST, AST_DEFAULT_STMT, AST_DEFER_STMT, AST_DO_STMT, AST_EXPR_STMT, AST_FOR_STMT, + AST_GENERIC_CASE_STMT, + AST_GENERIC_DEFAULT_STMT, AST_GOTO_STMT, AST_IF_STMT, AST_LABEL, AST_NOP_STMT, AST_RETURN_STMT, + AST_STMT_LIST, AST_SWITCH_STMT, AST_THROW_STMT, AST_TRY_STMT, AST_NEXT_STMT, AST_VOLATILE_STMT, AST_WHILE_STMT, - AST_GENERIC_CASE_STMT, - AST_GENERIC_DEFAULT_STMT, } AstKind; typedef enum @@ -64,42 +64,7 @@ typedef enum ATTR_UNRESOLVED, } AttrKind; -typedef enum -{ - BINOP_ERROR, - BINOP_ASSIGN, - BINOP_MULT, - BINOP_MULT_ASSIGN, - BINOP_ADD, - BINOP_ADD_ASSIGN, - BINOP_SUB, - BINOP_SUB_ASSIGN, - BINOP_DIV, - BINOP_DIV_ASSIGN, - BINOP_MOD, - BINOP_MOD_ASSIGN, - BINOP_AND, - BINOP_AND_ASSIGN, - BINOP_OR, - BINOP_OR_ASSIGN, - BINOP_BIT_AND, - BINOP_BIT_AND_ASSIGN, - BINOP_BIT_OR, - BINOP_BIT_OR_ASSIGN, - BINOP_BIT_XOR, - BINOP_BIT_XOR_ASSIGN, - BINOP_NE, - BINOP_EQ, - BINOP_GE, - BINOP_GT, - BINOP_LE, - BINOP_LT, - BINOP_SHR, - BINOP_SHR_ASSIGN, - BINOP_SHL, - BINOP_SHL_ASSIGN, - BINOP_ELVIS -} BinOp; + typedef enum { @@ -227,7 +192,6 @@ typedef enum EXPR_STRUCT_INIT_VALUES, EXPR_INITIALIZER_LIST, EXPR_EXPRESSION_LIST, - EXPR_DEFERRED_TOKENS, EXPR_CAST, } ExprKind; @@ -263,7 +227,7 @@ typedef enum NUMBER_TYPE_UNSIGNED_INT, } NumberType; -typedef enum _Precedence +typedef enum { PREC_NONE, PREC_ASSIGNMENT, // =, *=, /=, %=, ... @@ -278,6 +242,14 @@ typedef enum _Precedence PREC_CALL, // . () [] postfix ++/-- } Precedence; +typedef enum +{ + SCOPE_NONE = 0, + SCOPE_BREAK = 1 << 0, + SCOPE_CONTINUE = 1 << 1, + SCOPE_CONTROL = 1 << 2, +} ScopeFlags; + typedef enum { RESOLVE_NOT_DONE = 0, @@ -513,7 +485,6 @@ typedef enum VARDECL_LOCAL = 2, VARDECL_PARAM = 3, VARDECL_MEMBER = 4, - VARDECL_MULTI = 5, } VarDeclKind; typedef enum diff --git a/src/compiler/expr_analysis.c b/src/compiler/expr_analysis.c new file mode 100644 index 000000000..a850ac018 --- /dev/null +++ b/src/compiler/expr_analysis.c @@ -0,0 +1,599 @@ +// Copyright (c) 2019 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "compiler_internal.h" + +typedef bool(*ExprAnalysis)(Context *, Expr*); +typedef bool(*ExprBinopAnalysis)(Context *, Expr*, Expr*, Expr*); +typedef bool(*ExprUnaryAnalysis)(Context *, Expr*, Expr*); + +static ExprBinopAnalysis BINOP_ANALYSIS[TOKEN_EOF]; +static ExprUnaryAnalysis UNARYOP_ANALYSIS[TOKEN_EOF + 1]; +static ExprUnaryAnalysis POSTUNARYOP_ANALYSIS[TOKEN_EOF + 1]; + +static inline bool sema_type_error_on_binop(const char *op, Expr *expr) +{ + SEMA_ERROR(expr->loc, "Cannot perform '%s' %s '%s'.", expr->binary_expr.left->type->name_loc.string, op, expr->binary_expr.right->type->name_loc.string); + return false; +} + + +static inline bool sema_expr_analyse_conditional(Context *context, Expr *expr) +{ + TODO +} + +static inline bool sema_expr_analyse_identifier(Context *context, Expr *expr) +{ + // TODO what about struct functions + if (expr->identifier_expr.module.string) + { + TODO + } + Decl *decl = context_find_ident(context, expr->identifier_expr.identifier.string); + if (decl == NULL) + { + SEMA_ERROR(expr->loc, "Unknown identifier %s.", expr->identifier_expr.identifier.string); + return false; + } + expr->identifier_expr.decl = decl; + expr->type = decl->var.type; + return true; +} + +static inline bool sema_expr_analyse_var_call(Context *context, Expr *expr) { TODO } +static inline bool sema_expr_analyse_macro_call(Context *context, Expr *expr, Decl *macro) +{ + Ast macro_parent; + // TODO handle loops + Decl *stored_macro = context->evaluating_macro; + Type *stored_rtype = context->rtype; + context->evaluating_macro = macro; + context->rtype = macro->macro_decl.rtype; + // Handle escaping macro + bool success = sema_analyse_statement(context, macro->macro_decl.body); + context->evaluating_macro = stored_macro; + context->rtype = stored_rtype; + if (!success) return false; + + TODO + return success; +}; +static inline bool sema_expr_analyse_generic_call(Context *context, Expr *expr) { TODO }; + +static inline bool sema_expr_analyse_func_call(Context *context, Expr *expr, Decl *decl) +{ + if (decl->func.function_signature.throws != NULL) TODO + Expr **args =expr->call_expr.arguments; + Decl **func_params = decl->func.function_signature.params; + unsigned num_args = vec_size(args); + // unsigned num_params = vec_size(func_params); + // TODO handle named parameters, handle default parameters, varargs etc + for (unsigned i = 0; i < num_args; i++) + { + Expr *arg = args[i]; + if (!sema_expr_analysis(context, arg)) return false; + if (!cast(arg, func_params[i]->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; + } + expr->type = decl->func.function_signature.rtype; + return true; +} + +static inline bool sema_expr_analyse_call(Context *context, Expr *expr) +{ + Expr *func_expr = expr->call_expr.function; + if (!sema_expr_analysis(context, func_expr)) return false; + if (func_expr->expr_kind != EXPR_IDENTIFIER) + { + TODO + } + Decl *decl = func_expr->identifier_expr.decl; + switch (decl->decl_kind) + { + case DECL_VAR: + return sema_expr_analyse_var_call(context, expr); + case DECL_FUNC: + return sema_expr_analyse_func_call(context, expr, decl); + case DECL_MACRO: + return sema_expr_analyse_macro_call(context, expr, decl); + case DECL_GENERIC: + return sema_expr_analyse_generic_call(context, expr); + default: + SEMA_ERROR(expr->loc, "The expression cannot be called."); + return false; + break; + } +} + +static inline bool sema_expr_analyse_struct_value(Context *context, Expr *expr) +{ + TODO +} + +static inline bool sema_expr_analyse_struct_init_values(Context *context, Expr *expr) +{ + TODO +} + +static inline bool sema_expr_analyse_subscript(Context *context, Expr *expr) +{ + TODO +} + +static inline bool sema_expr_analyse_access(Context *context, Expr *expr) +{ + TODO +} + +static inline bool sema_expr_analyse_method_ref(Context *context, Expr *expr) +{ + TODO +} + + +static inline bool sema_expr_analyse_initializer_list(Context *context, Expr *expr) +{ + TODO +} + +static inline bool sema_expr_analyse_sizeof(Context *context, Expr *expr) +{ + TODO +} + +static inline bool sema_expr_analyse_cast(Context *context, Expr *expr) +{ + Expr *inner = expr->expr_cast.expr; + if (!sema_resolve_type(context, expr->type)) return false; + if (!sema_expr_analysis(context, inner)) return false; + + if (!cast(inner, expr->type, CAST_TYPE_EXPLICIT)) return false; + + // Overwrite cast. + Token loc = expr->loc; + *expr = *inner; + expr->loc = loc; + + return true; +} + + +static bool sema_expr_analyse_assign(Context *context, Expr *expr, Expr *left, Expr *right) +{ + if (!cast(right, left->type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; + // Check assignable + return true; +} + +static inline bool both_const(Expr *left, Expr *right) +{ + return left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST; +} + +static bool sema_expr_analyse_add(Context *context, Expr *expr, Expr *left, Expr *right) +{ + Type *left_type = left->type->canonical; + Type *right_type = right->type->canonical; + if (left_type->type_kind == TYPE_POINTER) + { + if (!cast_arithmetic(right, left, "+")) return false; + expr->type = left_type; + return true; + } + if (right_type->type_kind == TYPE_POINTER) + { + if (!cast_arithmetic(left, right, "+")) return false; + expr->type = right_type; + return true; + } + if (!cast_arithmetic(left, right, "+")) return false; + if (!cast_arithmetic(right, left, "+")) return false; + + Type *canonical = left->type->canonical; + if (!type_is_number(canonical)) + { + SEMA_ERROR(expr->loc, "Add is not allowed"); + return false; + } + if (both_const(left, right)) + { + switch (left->const_expr.type) + { + case CONST_INT: + expr->const_expr.i = left->const_expr.i + right->const_expr.i; + break; + case CONST_FLOAT: + expr->const_expr.f = left->const_expr.f + right->const_expr.f; + break; + default: + UNREACHABLE + } + expr->expr_kind = EXPR_CONST; + expr->const_expr.type = left->const_expr.type; + } + expr->type = left->type; + return true; +} +static bool sema_expr_analyse_add_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_sub(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_sub_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } + +static bool sema_expr_analyse_mult(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_mult_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_div(Context *context, Expr *expr, Expr *left, Expr *right) +{ + /* + switch (left->type) + { + case CONST_NIL: + case CONST_BOOL: + case CONST_STRING: + UNREACHABLE; + case CONST_INT: + if (right->i == 0) + { + SEMA_ERROR(expr->binary_expr.right->loc, "Division by zero not allowed."); + return false; + } + result->i = left->i / right->i; + break; + case CONST_FLOAT: + if (right->f == 0) + { + SEMA_ERROR(expr->binary_expr.right->loc, "Division by zero not allowed."); + return false; + } + expr->const_expr.f = left->f / right->f; + expr->const_expr.type = CONST_FLOAT; + break; + }*/ + return false; +} + +static bool sema_expr_analyse_div_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_mod(Context *context, Expr *expr, Expr *left, Expr *right) +{ + if (!cast_arithmetic(left, right, "%")) return false; + if (!type_is_integer(right->type->canonical) || !type_is_integer(left->type->canonical)) return sema_type_error_on_binop("%", expr); + + if (right->expr_kind == EXPR_CONST) + { + if (right->const_expr.i == 0) + { + SEMA_ERROR(expr->binary_expr.right->loc, "Cannot perform mod by zero."); + return false; + } + if (left->expr_kind == EXPR_CONST) + { + // TODO negative + expr->const_expr.i = left->const_expr.i / right->const_expr.i; + expr->type = right->type; + expr->expr_kind = EXPR_CONST; + expr->const_expr.type = CONST_INT; + } + } + return true; +} + +static bool sema_expr_analyse_mod_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } + +static bool sema_expr_analyse_bit_and(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_bit_and_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_bit_or(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_bit_or_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_bit_xor(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_bit_xor_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_shr(Context *context, Expr *expr, Expr *left, Expr *right) +{ TODO } +static bool sema_expr_analyse_shr_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_shl(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_shl_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } + +static bool sema_expr_analyse_and(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_and_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_or(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_or_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } + +static bool sema_expr_analyse_eq(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_ne(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_ge(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_gt(Context *context, Expr *expr, Expr *left, Expr *right) +{ + if (!cast_arithmetic(left, right, ">")) return false; + if (!cast_arithmetic(right, left, ">")) return false; + if (both_const(left, right)) + { + switch (left->const_expr.type) + { + case CONST_FLOAT: + expr->const_expr.b = left->const_expr.f > right->const_expr.f; + break; + case CONST_BOOL: + expr->const_expr.b = left->const_expr.b > right->const_expr.b; + break; + case CONST_INT: + expr->const_expr.b = left->const_expr.i > right->const_expr.i; + break; + default: + UNREACHABLE + } + expr->const_expr.type = CONST_BOOL; + expr->expr_kind = EXPR_CONST; + } + if (!cast_to_runtime(left) || !cast_to_runtime(right)) return false; + expr->type = type_bool; + return true; +} +static bool sema_expr_analyse_le(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_lt(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_elvis(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } + + +static bool sema_expr_analyse_deref(Context *context, Expr *expr, Expr *inner) { TODO } +static bool sema_expr_analyse_addr(Context *context, Expr *expr, Expr *inner) { TODO } + +static bool sema_expr_analyse_neg(Context *context, Expr *expr, Expr *inner) +{ + Type *canonical = inner->type->canonical; + if (!builtin_may_negate(canonical)) + { + SEMA_ERROR(expr->loc, "Cannot negate %s.", inner->type->name_loc.string); + return false; + } + if (inner->expr_kind != EXPR_CONST) + { + expr->type = inner->type; + return true; + } + // TODO UXX CAP + expr_replace(expr, inner); + switch (expr->const_expr.type) + { + case CONST_INT: + expr->const_expr.i = ~expr->const_expr.i; + break; + case CONST_FLOAT: + expr->const_expr.f = -expr->const_expr.i; + break; + default: + UNREACHABLE + } + return true; +} +static bool sema_expr_analyse_bit_not(Context *context, Expr *expr, Expr *inner) +{ + Type *canonical = inner->type->canonical; + if (!type_is_integer(canonical) && canonical != type_bool) + { + SEMA_ERROR(expr->loc, "Cannot bit negate %s.", inner->type->name_loc.string); + } + if (inner->expr_kind != EXPR_CONST) + { + expr->type = inner->type; + return true; + } + expr_replace(expr, inner); + // TODO UXX CAP + switch (expr->const_expr.type) + { + case CONST_INT: + expr->const_expr.i = ~expr->const_expr.i; + break; + case CONST_BOOL: + expr->const_expr.b = !expr->const_expr.b; + break; + default: + UNREACHABLE + } + return true; +} +static bool sema_expr_analyse_not(Context *context, Expr *expr, Expr *inner) +{ + if (inner->expr_kind == EXPR_CONST) + { + switch (expr->const_expr.type) + { + case CONST_NIL: + expr->const_expr.b = true; + break; + case CONST_BOOL: + expr->const_expr.b = !inner->const_expr.b; + break; + case CONST_INT: + expr->const_expr.b = inner->const_expr.i == 0; + break; + case CONST_FLOAT: + expr->const_expr.b = inner->const_expr.f == 0; + break; + case CONST_STRING: + expr->const_expr.b = !inner->const_expr.string.len; + break; + } + expr->const_expr.type = CONST_BOOL; + expr->type = type_bool; + expr->expr_kind = EXPR_CONST; + return true; + } + Type *canonical = inner->type->canonical; + switch (canonical->type_kind) + { + case TYPE_POISONED: + case TYPE_IXX: + case TYPE_UXX: + case TYPE_FXX: + case TYPE_INC_ARRAY: + case TYPE_EXPRESSION: + UNREACHABLE + case TYPE_ARRAY: + case TYPE_POINTER: + case TYPE_VARARRAY: + case TYPE_BOOL: + case TYPE_I8: + case TYPE_I16: + case TYPE_I32: + case TYPE_I64: + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + case TYPE_F32: + case TYPE_F64: + return true; + case TYPE_USER_DEFINED: + case TYPE_VOID: + case TYPE_STRING: + SEMA_ERROR(expr->loc, "Cannot use 'not' on %s", inner->type->name_loc.string); + return false; + } + UNREACHABLE +} + +static bool sema_expr_analyse_preinc(Context *context, Expr *expr, Expr *inner) { TODO } +static bool sema_expr_analyse_predec(Context *context, Expr *expr, Expr *inner) { TODO } + +static bool sema_expr_analyse_postinc(Context *context, Expr *expr, Expr *inner) { TODO } +static bool sema_expr_analyse_postdec(Context *context, Expr *expr, Expr *inner) { TODO } + +static inline bool sema_expr_analyse_binary(Context *context, Expr *expr) +{ + assert(expr->resolve_status == RESOLVE_RUNNING); + Expr *left = expr->binary_expr.left; + Expr *right = expr->binary_expr.right; + + if (!sema_expr_analysis(context, left)) return false; + if (!sema_expr_analysis(context, right)) return false; + + return BINOP_ANALYSIS[expr->binary_expr.operator](context, expr, left, right); +} + +static inline bool sema_expr_analyse_unary(Context *context, Expr *expr) +{ + assert(expr->resolve_status == RESOLVE_RUNNING); + Expr *inner = expr->unary_expr.expr; + + if (!sema_expr_analysis(context, inner)) return false; + + return UNARYOP_ANALYSIS[expr->unary_expr.operator](context, expr, inner); +} + +static inline bool sema_expr_analyse_postunary(Context *context, Expr *expr) +{ + assert(expr->resolve_status == RESOLVE_RUNNING); + Expr *inner = expr->post_expr.expr; + + if (!sema_expr_analysis(context, inner)) return false; + + return POSTUNARYOP_ANALYSIS[expr->post_expr.operator](context, expr, inner); +} + +static inline bool sema_expr_analyse_try(Context *context, Expr *expr) +{ + if (!sema_expr_analysis(context, expr->try_expr.expr)) return false; + expr->type = expr->try_expr.expr->type; + if (expr->try_expr.else_expr) + { + if (!sema_expr_analysis(context, expr->try_expr.else_expr)) return false; + if (!cast(expr->try_expr.else_expr, expr->type, CAST_TYPE_IMPLICIT)) return false; + } + // Check errors! + TODO + return true; +} + +static inline bool sema_expr_analyse_type(Context *context, Expr *expr) +{ + TODO + return true; +} + + +static ExprBinopAnalysis BINOP_ANALYSIS[TOKEN_EOF] = { + [TOKEN_EQ] = &sema_expr_analyse_assign, + [TOKEN_STAR] = &sema_expr_analyse_mult, + [TOKEN_MULT_ASSIGN] = &sema_expr_analyse_mult_assign, + [TOKEN_PLUS] = &sema_expr_analyse_add, + [TOKEN_PLUS_ASSIGN] = &sema_expr_analyse_add_assign, + [TOKEN_MINUS] = &sema_expr_analyse_sub, + [TOKEN_MINUS_ASSIGN] = &sema_expr_analyse_sub_assign, + [TOKEN_DIV] = &sema_expr_analyse_div, + [TOKEN_DIV_ASSIGN] = &sema_expr_analyse_div_assign, + [TOKEN_MOD] = &sema_expr_analyse_mod, + [TOKEN_MOD_ASSIGN] = &sema_expr_analyse_mod_assign, + [TOKEN_AND] = &sema_expr_analyse_and, + [TOKEN_AND_ASSIGN] = &sema_expr_analyse_and_assign, + [TOKEN_OR] = &sema_expr_analyse_bit_or, + [TOKEN_OR_ASSIGN] = &sema_expr_analyse_or_assign, + [TOKEN_AMP] = &sema_expr_analyse_bit_and, + [TOKEN_BIT_AND_ASSIGN] = &sema_expr_analyse_bit_and_assign, + [TOKEN_BIT_OR] = &sema_expr_analyse_bit_or, + [TOKEN_BIT_OR_ASSIGN] = &sema_expr_analyse_bit_or_assign, + [TOKEN_BIT_XOR] = &sema_expr_analyse_bit_xor, + [TOKEN_BIT_XOR_ASSIGN] = &sema_expr_analyse_bit_xor_assign, + [TOKEN_NOT_EQUAL] = &sema_expr_analyse_ne, + [TOKEN_EQEQ] = &sema_expr_analyse_eq, + [TOKEN_GREATER_EQ] = &sema_expr_analyse_ge, + [TOKEN_GREATER] = &sema_expr_analyse_gt, + [TOKEN_LESS_EQ] = &sema_expr_analyse_le, + [TOKEN_LESS] = &sema_expr_analyse_lt, + [TOKEN_SHR] = &sema_expr_analyse_shr, + [TOKEN_SHR_ASSIGN] = &sema_expr_analyse_shr_assign, + [TOKEN_SHL] = &sema_expr_analyse_shl, + [TOKEN_SHL_ASSIGN] = &sema_expr_analyse_shl_assign, + [TOKEN_ELVIS] = &sema_expr_analyse_elvis, +}; + + +static ExprUnaryAnalysis UNARYOP_ANALYSIS[TOKEN_EOF + 1] = { + [TOKEN_STAR] = &sema_expr_analyse_deref, + [TOKEN_AMP] = &sema_expr_analyse_addr, + [TOKEN_MINUS] = &sema_expr_analyse_neg, + [TOKEN_BIT_NOT] = &sema_expr_analyse_bit_not, + [TOKEN_NOT] = &sema_expr_analyse_not, + [TOKEN_PLUSPLUS] = &sema_expr_analyse_preinc, + [TOKEN_MINUSMINUS] = &sema_expr_analyse_predec, +}; + +static ExprUnaryAnalysis POSTUNARYOP_ANALYSIS[TOKEN_EOF + 1] = { + [TOKEN_PLUSPLUS] = &sema_expr_analyse_postinc, + [TOKEN_MINUSMINUS] = &sema_expr_analyse_postdec, +}; + + +static ExprAnalysis EXPR_ANALYSIS[EXPR_CAST + 1] = { + [EXPR_TRY] = &sema_expr_analyse_try, + [EXPR_CONST] = NULL, + [EXPR_BINARY] = &sema_expr_analyse_binary, + [EXPR_CONDITIONAL] = &sema_expr_analyse_conditional, + [EXPR_UNARY] = &sema_expr_analyse_unary, + [EXPR_POST_UNARY] = &sema_expr_analyse_postunary, + [EXPR_TYPE] = &sema_expr_analyse_type, + [EXPR_IDENTIFIER] = &sema_expr_analyse_identifier, + [EXPR_METHOD_REF] = &sema_expr_analyse_method_ref, + [EXPR_CALL] = &sema_expr_analyse_call, + [EXPR_SIZEOF] = &sema_expr_analyse_sizeof, + [EXPR_SUBSCRIPT] = &sema_expr_analyse_subscript, + [EXPR_ACCESS] = &sema_expr_analyse_access, + [EXPR_STRUCT_VALUE] = &sema_expr_analyse_struct_value, + [EXPR_STRUCT_INIT_VALUES] = &sema_expr_analyse_struct_init_values, + [EXPR_INITIALIZER_LIST] = &sema_expr_analyse_initializer_list, + [EXPR_CAST] = &sema_expr_analyse_cast, +}; + +bool sema_expr_analysis(Context *context, Expr *expr) +{ + switch (expr->resolve_status) + { + case RESOLVE_NOT_DONE: + expr->resolve_status = RESOLVE_RUNNING; + break; + case RESOLVE_RUNNING: + SEMA_ERROR(expr->loc, "Recursive resolution of expression"); + return expr_poison(expr); + case RESOLVE_DONE: + return expr_ok(expr); + } + if (!EXPR_ANALYSIS[expr->expr_kind](context, expr)) return expr_poison(expr); + expr->resolve_status = RESOLVE_DONE; + return true; +} \ No newline at end of file diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 3136f96d2..34b6bcda0 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -124,7 +124,6 @@ static bool consume_const_name(const char* type) */ static void recover_top_level(void) { - LOG_FUNC advance(); while (tok.type != TOKEN_EOF) { @@ -190,7 +189,6 @@ SEMA_ERROR(tok, "Expected ',' or ')'"); return _res; } } while(0) static Ast* parse_compound_stmt() { - LOG_FUNC CONSUME_OR(TOKEN_LBRACE, &poisoned_ast); Ast *ast = AST_NEW(AST_COMPOUND_STMT, tok); while (!try_consume(TOKEN_RBRACE)) @@ -226,8 +224,6 @@ static Ast* parse_compound_stmt() */ static inline Type *parse_base_type(void) { - LOG_FUNC - if (tok.type == TOKEN_IDENT && next_tok.type == TOKEN_SCOPE) { Type *type = type_new(TYPE_USER_DEFINED); @@ -254,70 +250,70 @@ static inline Type *parse_base_type(void) EXPECT_OR(TOKEN_RPAREN, &poisoned_type); break; case TOKEN_VOID: - type = &type_void; + type = type_void; break; case TOKEN_BOOL: - type = &type_bool; + type = type_bool; break; case TOKEN_BYTE: - type = &type_byte; + type = type_byte; break; case TOKEN_CHAR: - type = &type_char; + type = type_char; break; case TOKEN_DOUBLE: - type = &type_double; + type = type_double; break; case TOKEN_FLOAT: - type = &type_float; + type = type_float; break; case TOKEN_INT: - type = &type_int; + type = type_int; break; case TOKEN_ISIZE: - type = &type_isize; + type = type_isize; break; case TOKEN_LONG: - type = &type_long; + type = type_long; break; case TOKEN_SHORT: - type = &type_short; + type = type_short; break; case TOKEN_UINT: - type = &type_uint; + type = type_uint; break; case TOKEN_ULONG: - type = &type_ulong; + type = type_ulong; break; case TOKEN_USHORT: - type = &type_ushort; + type = type_ushort; break; case TOKEN_USIZE: - type = &type_usize; + type = type_usize; break; case TOKEN_C_SHORT: - type = &type_c_short; + type = type_c_short; break; case TOKEN_C_INT: - type = &type_c_int; + type = type_c_int; break; case TOKEN_C_LONG: - type = &type_c_long; + type = type_c_long; break; case TOKEN_C_LONGLONG: - type = &type_c_longlong; + type = type_c_longlong; break; case TOKEN_C_USHORT: - type = &type_c_ushort; + type = type_c_ushort; break; case TOKEN_C_UINT: - type = &type_c_uint; + type = type_c_uint; break; case TOKEN_C_ULONG: - type = &type_c_ulong; + type = type_c_ulong; break; case TOKEN_C_ULONGLONG: - type = &type_c_ulonglong; + type = type_c_ulonglong; break; default: @@ -341,7 +337,6 @@ static inline Type *parse_base_type(void) */ static inline Type *parse_array_type_index(Type *type) { - LOG_FUNC assert(type_ok(type)); @@ -380,7 +375,6 @@ static inline Type *parse_array_type_index(Type *type) */ static Type *parse_type_expression(void) { - LOG_FUNC Type *type = parse_base_type(); while (type->type_kind != TYPE_POISONED) @@ -552,19 +546,21 @@ static Ast *parse_expr_stmt(void) * : expression * | expression_list ',' expression * ; - * @return Expr * + * @return Ast * */ -static inline Expr *parse_expression_list(void) +static inline Ast *parse_expression_list(void) { - Expr *exp_list = EXPR_NEW_TOKEN(EXPR_EXPRESSION_LIST, tok); - Expr **expressions = NULL; + Ast *statement_list = new_ast(AST_STMT_LIST, tok); + Ast **stmts = NULL; do { - Expr *expr = TRY_EXPR_OR(parse_expr(), &poisoned_expr); - expressions = VECADD(expressions, expr); + Expr *expr = TRY_EXPR_OR(parse_expr(), &poisoned_ast); + Ast *ast = new_ast(AST_EXPR_STMT, expr->loc); + ast->expr_stmt = expr; + stmts = VECADD(stmts, ast); } while (try_consume(TOKEN_COMMA)); - exp_list->expression_list = expressions; - return exp_list; + statement_list->stmt_list = stmts; + return statement_list; } /** @@ -573,42 +569,35 @@ static inline Expr *parse_expression_list(void) * | declaration_list * ; * - * @return Ast* + * @return bool */ -static inline Ast* parse_decl_expr_list(void) +static inline bool parse_decl_expr_list(Ast ***stmt_list) { Expr *expr = NULL; Type *type = NULL; - Ast *decl_expr_list = AST_NEW(AST_DECL_EXPR_LIST, tok); + if (!parse_type_or_expr(&expr, &type)) return false; - if (!parse_type_or_expr(&expr, &type)) return &poisoned_ast; if (expr) { - if (try_consume(TOKEN_COMMA)) + while (1) { - Expr **expressions = NULL; - expressions = VECADD(expressions, expr); - do - { - expr = TRY_EXPR_OR(parse_expr(), &poisoned_ast); - expressions = VECADD(expressions, expr); - } while (try_consume(TOKEN_COMMA)); - Expr *exp_list = EXPR_NEW_EXPR(EXPR_EXPRESSION_LIST, expr); - exp_list->expression_list = expressions; - expr = exp_list; + Ast *stmt = new_ast(AST_EXPR_STMT, expr->loc); + stmt->expr_stmt = expr; + *stmt_list = VECADD(*stmt_list, stmt); + if (!try_consume(TOKEN_COMMA)) break; + expr = TRY_EXPR_OR(parse_expr(), &poisoned_ast); } - - decl_expr_list->decl_expr_list.expr = expr; - decl_expr_list->decl_expr_list.list_type = DECLEXPR_EXPR; - return decl_expr_list; } - - decl_expr_list->decl_expr_list.list_type = DECLEXPR_DECL; - decl_expr_list->decl_expr_list.decl = TRY_DECL_OR(parse_decl_after_type(false, type), &poisoned_ast); - return decl_expr_list; - + else + { + Decl *decl = TRY_DECL_OR(parse_decl_after_type(false, type), &poisoned_ast); + Ast *stmt = new_ast(AST_DECLARE_STMT, decl->name); + stmt->declare_stmt = decl; + *stmt_list = VECADD(*stmt_list, stmt); + } + return true; } /** @@ -621,28 +610,30 @@ static inline Ast* parse_decl_expr_list(void) */ static inline Ast *parse_control_expression() { - Ast *cond = TRY_AST(parse_decl_expr_list()); + Ast *stmt_list = AST_NEW(AST_STMT_LIST, tok); - if (cond->decl_expr_list.list_type == DECLEXPR_EXPR) + Ast ***stmt_ref = &stmt_list->stmt_list; + + if (!parse_decl_expr_list(stmt_ref)) return &poisoned_ast; + + assert(*stmt_ref != NULL); + if (VECLAST(*stmt_ref)->ast_kind == AST_EXPR_STMT) { if (tok.type == TOKEN_EOS) { SEMA_ERROR(tok, "Unexpected ';'."); return &poisoned_ast; } - return cond; + return stmt_list; } if (!try_consume(TOKEN_EOS)) { - return cond; + return stmt_list; } - Decl *decls = cond->decl_expr_list.decl; - cond->ast_kind = AST_COND_STMT; - cond->cond_stmt.decl = decls; - cond->cond_stmt.decl_expr = TRY_AST(parse_decl_expr_list()); - return cond; + if (!parse_decl_expr_list(stmt_ref)) return &poisoned_ast; + return stmt_list; } /** @@ -655,7 +646,6 @@ static inline Ast *parse_control_expression() */ static inline Ast* parse_if_stmt(void) { - LOG_FUNC Ast *if_ast = AST_NEW(AST_IF_STMT, tok); advance_and_verify(TOKEN_IF); CONSUME_OR(TOKEN_LPAREN, &poisoned_ast); @@ -802,12 +792,17 @@ static inline Ast* parse_for_stmt(void) advance_and_verify(TOKEN_FOR); CONSUME_OR(TOKEN_LPAREN, &poisoned_ast); - ast->for_stmt.init = TRY_AST(parse_decl_expr_list()); + Ast *cond = new_ast(AST_COND_STMT, tok); + + if (!parse_decl_expr_list(&cond->cond_stmt.stmts)) return &poisoned_ast; + CONSUME_OR(TOKEN_EOS, &poisoned_ast); if (tok.type != TOKEN_EOS) { - ast->for_stmt.cond = TRY_EXPR_OR(parse_expr(), &poisoned_ast); + cond->cond_stmt.expr = TRY_EXPR_OR(parse_expr(), &poisoned_ast); } + + ast->for_stmt.cond = cond; CONSUME_OR(TOKEN_EOS, &poisoned_ast); if (!try_consume(TOKEN_RPAREN)) @@ -880,7 +875,6 @@ static inline Ast* parse_ct_switch_stmt(void) static inline Ast* parse_ct_else_stmt(void) { - LOG_FUNC Ast *ast = AST_NEW(AST_CT_ELSE_STMT, tok); advance_and_verify(TOKEN_CT_ELSE); ast->ct_elif_stmt.then = TRY_AST(parse_compound_stmt()); @@ -894,7 +888,6 @@ static inline Ast* parse_ct_else_stmt(void) */ static inline Ast *parse_ct_elif_stmt(void) { - LOG_FUNC Ast *ast = AST_NEW(AST_CT_ELIF_STMT, tok); advance_and_verify(TOKEN_CT_ELIF); @@ -924,7 +917,6 @@ static inline Ast *parse_ct_elif_stmt(void) */ static inline Ast* parse_ct_if_stmt(void) { - LOG_FUNC Ast *ast = AST_NEW(AST_CT_IF_STMT, tok); advance_and_verify(TOKEN_CT_IF); ast->ct_if_stmt.expr = TRY_EXPR_OR(parse_paren_expr(), &poisoned_ast); @@ -959,7 +951,6 @@ static inline Ast* parse_ct_each_stmt(void) */ static Ast *parse_return_stmt(void) { - LOG_FUNC advance_and_verify(TOKEN_RETURN); Ast *ast = AST_NEW(AST_RETURN_STMT, tok); @@ -1018,7 +1009,6 @@ bool is_valid_try_statement(TokenType type) static inline Ast *parse_label_stmt(void) { - LOG_FUNC Ast *ast = AST_NEW(AST_LABEL, tok); advance_and_verify(TOKEN_CONST_IDENT); advance_and_verify(TOKEN_COLON); @@ -1132,7 +1122,6 @@ static inline Ast *parse_decl_or_expr_stmt(void) static Ast *parse_stmt(void) { - LOG_FUNC switch (tok.type) { case TOKEN_LBRACE: @@ -1370,7 +1359,6 @@ static Ast *parse_stmt(void) */ static inline bool parse_optional_module_params(Token **tokens) { - LOG_FUNC *tokens = NULL; @@ -1418,7 +1406,6 @@ static inline bool parse_optional_module_params(Token **tokens) */ static inline void parse_module(void) { - LOG_FUNC if (!try_consume(TOKEN_MODULE)) { @@ -1448,81 +1435,7 @@ static inline void parse_module(void) TRY_CONSUME_EOS_OR(); } -/** - * Parse any deferred expression, correctly handling nesting. - * - * @return A non null expression. Poisoned if this fails. - */ -static inline Expr* parse_deferred_expression(void) -{ - LOG_FUNC - Expr *expr = expr_new(EXPR_DEFERRED_TOKENS, next_tok); - int paren = 0; - int brace = 0; - int bracket = 0; - expr->deferred_tokens = NULL; - while (1) - { - switch (next_tok.type) - { - case TOKEN_LPAREN: - paren++; - break; - case TOKEN_LBRACE: - brace++; - break; - case TOKEN_LBRACKET: - bracket++; - break; - case TOKEN_RPAREN: - if (--paren < 0) - { - if (brace > 0 || bracket > 0) - { - sema_error_range(next_tok.span, "I found a mismatched ')' here, did you add one too many?"); - expr->expr_kind = EXPR_POISONED; - } - return expr; - } - break; - case TOKEN_RBRACE: - if (--brace < 0) - { - if (paren > 0 || bracket > 0) - { - sema_error_range(next_tok.span, "I found a mismatched '}' here, did you add one too many?"); - expr->expr_kind = EXPR_POISONED; - } - return expr; - } - break; - case TOKEN_RBRACKET: - if (--bracket < 0) - { - if (paren > 0 || brace > 0) - { - sema_error_range(next_tok.span, "I found a mismatched ']' here, did you add one too many?"); - expr->expr_kind = EXPR_POISONED; - } - return expr; - } - break; - case TOKEN_COMMA: - if (bracket == 0 && brace == 0 && paren == 0) return expr; - break; - case TOKEN_EOF: - case TOKEN_INVALID_TOKEN: - expr->expr_kind = EXPR_POISONED; - return expr; - default: - break; - - } - expr->deferred_tokens = VECADD(expr->deferred_tokens, next_tok); - advance(); - } -} /** * Only call this if the first '(' has been detected. * @@ -1535,7 +1448,6 @@ static inline Expr* parse_deferred_expression(void) */ static inline bool parse_macro_parameter_list(Expr*** result) { - LOG_FUNC TODO advance_and_verify(TOKEN_LPAREN); *result = NULL; @@ -1567,7 +1479,6 @@ static inline bool parse_macro_parameter_list(Expr*** result) */ static inline bool parse_import() { - LOG_FUNC advance_and_verify(TOKEN_IMPORT); @@ -1620,7 +1531,6 @@ static Expr *parse_precedence(Precedence precedence) static inline Expr* parse_expr(void) { - LOG_FUNC Token start = tok; bool found_try = try_consume(TOKEN_TRY); @@ -1654,7 +1564,6 @@ static inline Expr *parse_paren_expr(void) */ static inline void parse_imports(void) { - LOG_FUNC while (tok.type == TOKEN_IMPORT) { @@ -1677,8 +1586,6 @@ static inline Decl *parse_attribute_declaration(Visibility visibility) */ static inline Decl *parse_const_declaration(Visibility visibility) { - LOG_FUNC - advance_and_verify(TOKEN_CONST); Decl *decl = decl_new_var(tok, NULL, VARDECL_CONST, visibility); @@ -1716,7 +1623,6 @@ static inline Decl *parse_const_declaration(Visibility visibility) */ static inline Decl *parse_global_declaration(Visibility visibility) { - LOG_FUNC Type *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); @@ -1749,7 +1655,6 @@ static inline Decl *parse_global_declaration(Visibility visibility) */ static inline bool parse_attributes(Decl *parent_decl) { - LOG_FUNC parent_decl->attributes = NULL; while (tok.type == TOKEN_AT_IDENT || (tok.type == TOKEN_IDENT && next_tok.type == TOKEN_SCOPE)) { @@ -1812,7 +1717,6 @@ static inline bool parse_attributes(Decl *parent_decl) */ bool parse_struct_body(Decl *parent, Decl *visible_parent) { - LOG_FUNC CONSUME_OR(TOKEN_LBRACE, false); @@ -2333,8 +2237,6 @@ static inline Decl *parse_func_definition(Visibility visibility, bool is_interfa */ static inline Decl *parse_error_declaration(Visibility visibility) { - LOG_FUNC - advance_and_verify(TOKEN_ERROR_TYPE); Decl *error_decl = decl_new_user_defined_type(tok, DECL_ERROR, visibility); @@ -2384,8 +2286,6 @@ static inline Decl *parse_error_declaration(Visibility visibility) */ static inline Decl *parse_enum_declaration(Visibility visibility) { - LOG_FUNC - advance_and_verify(TOKEN_ENUM); Decl *decl = decl_new_user_defined_type(tok, DECL_ENUM, visibility); @@ -2400,7 +2300,7 @@ static inline Decl *parse_enum_declaration(Visibility visibility) CONSUME_OR(TOKEN_LBRACE, false); - decl->enums.type = type ? type : &type_int; + decl->enums.type = type ? type : type_int; while (!try_consume(TOKEN_RBRACE)) { Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, tok, decl->visibility); @@ -2435,20 +2335,6 @@ static inline Decl *parse_enum_declaration(Visibility visibility) } -/** - * - */ -static inline void parse_macro_var(void) -{ - LOG_FUNC - - advance_and_verify(TOKEN_CT_IDENT); - Token var_name = tok; - - // TODO use the result - parse_deferred_expression(); - -} static inline bool parse_conditional_top_level(Decl ***decls) @@ -2472,7 +2358,6 @@ static inline bool parse_conditional_top_level(Decl ***decls) static inline Decl *parse_ct_if_top_level(void) { - LOG_FUNC Decl *ct = decl_new(DECL_CT_IF, tok, VISIBLE_LOCAL); advance_and_verify(TOKEN_CT_IF); ct->ct_if_decl.expr = TRY_EXPR_OR(parse_paren_expr(), &poisoned_decl); @@ -2519,8 +2404,6 @@ static inline Decl *parse_ct_if_top_level(void) */ static inline Decl *parse_top_level(void) { - LOG_FUNC - Visibility visibility = VISIBLE_MODULE; switch (tok.type) { @@ -2585,12 +2468,10 @@ static inline Decl *parse_top_level(void) void parse_current(void) { - LOG_FUNC // Prime everything advance(); advance(); parse_module(); parse_imports(); - LOG_FUNC while (tok.type != TOKEN_EOF) { Decl *decl = parse_top_level(); @@ -2607,7 +2488,6 @@ void parse_current(void) void parse_file(File *file) { - LOG_FUNC lexer_add_file_for_lexing(file); Context *context = context_create(file); context_push(context); @@ -2647,7 +2527,7 @@ static Expr *parse_unary_expr(Expr *left) TokenType operator_type = tok.type; Expr *unary = EXPR_NEW_TOKEN(EXPR_UNARY, tok); - unary->unary_expr.operator = unaryop_from_token(operator_type); + unary->unary_expr.operator = operator_type; Precedence rule_precedence = rules[operator_type].precedence; advance(); Expr *right_side = parse_precedence(rule_precedence); @@ -2661,9 +2541,9 @@ static Expr *parse_unary_expr(Expr *left) static Expr *parse_post_unary(Expr *left) { assert(expr_ok(left)); - Expr *unary = EXPR_NEW_EXPR(EXPR_POST_UNARY, left); + Expr *unary = EXPR_NEW_TOKEN(EXPR_POST_UNARY, tok); unary->post_expr.expr = left; - unary->post_expr.operator = unaryop_from_token(tok.type); + unary->post_expr.operator = tok.type; advance(); return unary; } @@ -2702,7 +2582,7 @@ static Expr *parse_binary(Expr *left_side) } Expr *expr = EXPR_NEW_EXPR(EXPR_BINARY, left_side); - expr->binary_expr.operator = binop_from_token(operator_type); + expr->binary_expr.operator = operator_type; expr->binary_expr.left = left_side; expr->binary_expr.right = right_side; return expr; @@ -2723,7 +2603,7 @@ static Expr *parse_call_expr(Expr *left) } Expr *call = EXPR_NEW_EXPR(EXPR_CALL, left); call->call_expr.function = left; - call->call_expr.parameters = params; + call->call_expr.arguments = params; return call; } @@ -2759,7 +2639,7 @@ static Expr *parse_string_literal(Expr *left) assert(!left && "Had left hand side"); Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST, tok); expr_string->resolve_status = RESOLVE_DONE; - expr_string->type = &type_string; + expr_string->type = type_string; advance_and_verify(TOKEN_STRING); char *str = malloc_arena(tok.span.length + 1); @@ -2781,7 +2661,7 @@ static Expr *parse_string_literal(Expr *left) str[len] = '\0'; expr_string->const_expr.string.chars = str; expr_string->const_expr.string.len = len; - expr_string->type = &type_string; + expr_string->type = type_string; expr_string->const_expr.type = CONST_STRING; return expr_string; } @@ -2871,7 +2751,7 @@ static Expr *parse_integer(Expr *left) } expr_int->const_expr.i = i; expr_int->const_expr.type = CONST_INT; - expr_int->type = i > INT64_MAX ? &type_compuint : &type_compint; + expr_int->type = i > INT64_MAX ? type_compuint : type_compint; expr_int->resolve_status = RESOLVE_DONE; advance(); return expr_int; @@ -2892,7 +2772,7 @@ static Expr *parse_double(Expr *left) } advance(); number->const_expr.f = fval; - number->type = &type_compfloat; + number->type = type_compfloat; number->const_expr.type = CONST_FLOAT; number->resolve_status = RESOLVE_DONE; return number; @@ -2903,7 +2783,7 @@ static Expr *parse_bool(Expr *left) assert(!left && "Had left hand side"); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, tok); number->const_expr = (ExprConst) { .b = tok.type == TOKEN_TRUE, .type = CONST_BOOL }; - number->type = &type_bool; + number->type = type_bool; number->resolve_status = RESOLVE_DONE; advance(); return number; @@ -2914,7 +2794,7 @@ static Expr *parse_nil(Expr *left) assert(!left && "Had left hand side"); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, tok); number->const_expr.type = CONST_NIL; - number->type = type_get_canonical_ptr(&type_void); + number->type = type_get_canonical_ptr(type_void); number->resolve_status = RESOLVE_DONE; advance(); return number; diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 2a668eb5c..8cb99a116 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -4,30 +4,15 @@ #include "compiler_internal.h" -static bool sema_resolve_type(Context *context, Type *type); -static bool sema_analyse_expression(Context *context, Expr *expr); - - +typedef bool(*AstAnalysis)(Context *, Ast*); +bool sema_analyse_stmt_list(Context *context, Ast *statement); void sema_init(File *file) { LOG_FUNC } -/** - * Symmetrically promotes one expression by inserting an implicit cast. - * - * @param expr1 - * @param expr2 - * @return false if an implicit cast is not allowed. - */ -static bool type_promote(Expr *expr1, Expr *expr2) -{ - if (expr1->type->canonical == expr2->type->canonical) return true; - TODO -} - /** * Check if a type is contained in another type. * @@ -51,203 +36,6 @@ static bool canonical_type_is_subtype(Type *type, Type *possible_subtype) return canonical_type_is_subtype(type, first_element->var.type->canonical); } -static bool cast_const_type_expression(Expr *expr, Type *type) -{ - Type *canonical = type->canonical; - ExprConst *expr_const = &expr->const_expr; - switch (canonical->type_kind) - { - case TYPE_POISONED: - case TYPE_USER_DEFINED: - case TYPE_EXPRESSION: - case TYPE_INC_ARRAY: - UNREACHABLE; - break; - case TYPE_ARRAY: - TODO - UNREACHABLE - case TYPE_VARARRAY: - TODO - UNREACHABLE; - case TYPE_POINTER: - - TODO - UNREACHABLE; - case TYPE_VOID: - case TYPE_BOOL: - case TYPE_I8: - case TYPE_I16: - case TYPE_I32: - case TYPE_I64: - case TYPE_IXX: - case TYPE_U8: - case TYPE_U16: - case TYPE_U32: - case TYPE_U64: - case TYPE_UXX: - case TYPE_F32: - case TYPE_F64: - case TYPE_FXX: - { - TODO - // BuiltinConv conv = BUILTIN_CONVERSION[expr->type->type_kind - TYPE_VOID][canonical->type_kind - TYPE_VOID]; - // builtin_convert(&expr->const_expr, conv, canonical); - expr->type = type; - return true; - } - case TYPE_STRING: - break; - } - - TODO -} - -static bool expr_insert_cast(Expr *expr, Type *canonical) -{ - assert(canonical == canonical->canonical); - if (expr->expr_kind == EXPR_CONST) return cast_const_type_expression(expr, canonical); - TODO -} - - -typedef enum _AssignCast -{ - ASSIGN_CAST_FAILED, - ASSIGN_CAST_FAILED_ERROR_SHOWN, - ASSIGN_CAST_SKIP, - ASSIGN_CAST, -} AssignCast; - -/** - * Pick the cast to do. - * - * @param expr1 - * @param expr2 - * @return AssignCast - */ -static inline bool type_assign_cast_type(Expr *expr, Type *target_type, bool is_update) -{ - return cast(expr, target_type, CAST_TYPE_IMPLICIT_ASSIGN); - /* - Type *right_type = target_type->canonical; - Type *left_type = expr->type->canonical; - if (right_type == left_type) return true; - - // X = Y where Y is subtype, this is truncation. - if (canonical_type_is_subtype(left_type, right_type)) - { - insert_cast(expr, CAST_TRUNC, target_type); - return true; - } - - // X* = void* - if (right_type == &type_voidptr) - { - if (left_type->type_kind == TYPE_POINTER) - { - insert_cast(expr, CAST_PTRPTR, target_type); - return true; - } - return false; - } - - // void* = X*, void* = X[], void* = X[n], void* = string - if (left_type == &type_voidptr) - { - switch (left_type->type_kind) - { - case TYPE_POINTER: - insert_cast(expr, CAST_PTRPTR, target_type); - return true; - case TYPE_VARARRAY: - insert_cast(expr, CAST_VARRPTR, target_type); - return true; - case TYPE_ARRAY: - insert_cast(expr, CAST_ARRPTR, target_type); - return true; - case TYPE_STRING: - insert_cast(expr, CAST_STRPTR, target_type); - default: - return false; - } - } - - // X* = X[n], X* = X[], X* = Y[], X* = Y[n], X* = Y* if subtype - if (left_type->type_kind == TYPE_POINTER) - { - switch (right_type->type_kind) - { - case TYPE_ARRAY: - insert_cast(expr, CAST_ARRPTR, target_type); - return true; - case TYPE_VARARRAY: - insert_cast(expr, CAST_VARRPTR, target_type); - return true; - case TYPE_POINTER: - if (canonical_type_is_subtype(left_type->base, right_type->base)) return false; - insert_cast(expr, CAST_PTRPTR, target_type); - return true; - case TYPE_STRING: - if (left_type->type_kind == TYPE_I8 || left_type->type_kind == TYPE_U8) - { - insert_cast(expr, CAST_STRPTR, target_type); - return true; - } - return false; - default: - return false; - } - } - - if (!type_is_builtin(left_type->type_kind) || !type_is_builtin(right_type->type_kind)) return false; - - return cast(expr, right_type, target_type, CAST_TYPE_IMPLICIT_ASSIGN);*/ -} - -/** - * Tries to implicitly cast the expression to the recipient type (return, assignment) - * - * @param expr1 - * @param expr2 - * @return false if an implicit cast is not allowed. - */ -static bool type_assign_cast(Expr *expr, Type *type, bool is_update) -{ - assert(type->canonical == type); - if (!type_assign_cast_type(expr, type, is_update)) - { - expr_poison(expr); - return false; - } - return true; -} - -static bool insert_assign_cast_if_needed(Expr *expr, Type *type) -{ - assert(type->canonical == type); - if (expr->type->canonical == type) return true; - if (!type_assign_cast_type(expr, type, false)) - { - expr_poison(expr); - return false; - } - return true; -} - -static bool insert_arith_cast_if_needed(Expr *left, Expr *right, Type *left_type) -{ - Type *right_type = right->type->canonical; - assert(left_type->canonical == left_type); - if (right_type == left_type) return true; - TODO -} - -static bool insert_bool_cast_if_needed(Expr *expr) -{ - Type *canonical = expr->type->canonical; - if (canonical == &type_bool) return true; - TODO -} static void show_shadow_error(Decl *decl, Decl *old) { @@ -255,13 +43,13 @@ static void show_shadow_error(Decl *decl, Decl *old) sema_prev_at_range(old->name.span, "The previous use of '%s' was here.", decl->name.string); } -static inline Decl *module_find_symbol(Module *module, const char *symbol) +Decl *module_find_symbol(Module *module, const char *symbol) { return stable_get(&module->symbols, symbol); } -static Decl *context_find_ident(Context *context, const char *symbol) +Decl *context_find_ident(Context *context, const char *symbol) { Decl **first = &context->locals[0]; Decl **current = context->last_local - 1; @@ -284,14 +72,28 @@ static inline void context_push_scope(Context *context) FATAL_ERROR("Too deeply nested scopes."); } context->current_scope++; + context->current_scope->exit = EXIT_NONE; context->current_scope->local_decl_start = context->last_local; } +static inline void context_push_scope_with_flags(Context *context, ScopeFlags flags) +{ + ScopeFlags previous_flags = context->current_scope->flags; + context_push_scope(context); + context->current_scope->flags = previous_flags | flags; + context->current_scope->flags_created = flags; +} + static inline void context_pop_scope(Context *context) { assert(context->current_scope != &context->scopes[0]); context->last_local = context->current_scope->local_decl_start; + ExitType exit_type = context->current_scope->exit; context->current_scope--; + if (context->current_scope->exit < exit_type) + { + context->current_scope->exit = exit_type; + } } @@ -320,7 +122,7 @@ static bool sema_resolve_array_type(Context *context, Type *type) return true; } -static bool sema_resolve_type(Context *context, Type *type) +bool sema_resolve_type(Context *context, Type *type) { LOG_FUNC @@ -450,65 +252,7 @@ static inline void sema_analyse_struct(Context *context, Decl *decl) DEBUG_LOG("Analysing complete."); } -static bool constant_fold(Context *context, Expr *expr) -{ - if (expr->expr_kind == EXPR_CONST) return true; - switch (expr->expr_kind) - { - case EXPR_POISONED: - return false; - case EXPR_TRY: - if ((unsigned)sema_analyse_expression(context, expr->try_expr.expr) & - (unsigned)(!expr->try_expr.else_expr || sema_analyse_expression(context, expr->try_expr.else_expr))) - { - return true; - } - else - { - expr_poison(expr); - return false; - } - case EXPR_CONST: - return true; - case EXPR_BINARY: - TODO - break; - case EXPR_CONDITIONAL: - break; - case EXPR_UNARY: - break; - case EXPR_POST_UNARY: - if (!sema_analyse_expression(context, expr->post_expr.expr)) - case EXPR_TYPE: - break; - case EXPR_IDENTIFIER: - break; - case EXPR_METHOD_REF: - break; - case EXPR_CALL: - break; - case EXPR_SIZEOF: - break; - case EXPR_SUBSCRIPT: - break; - case EXPR_ACCESS: - break; - case EXPR_STRUCT_VALUE: - break; - case EXPR_STRUCT_INIT_VALUES: - break; - case EXPR_INITIALIZER_LIST: - break; - case EXPR_EXPRESSION_LIST: - break; - case EXPR_DEFERRED_TOKENS: - break; - case EXPR_CAST: - break; - } - TODO - return true; -} + /* static inline void add_integers(ExprConst *result, uint64_t l, bool l_is_negative, uint64_t r, bool r_is_negative) { @@ -530,425 +274,9 @@ static inline void add_integers(ExprConst *result, uint64_t l, bool l_is_negativ } } */ -static inline bool sema_analyse_binary_expr_internal_const(Context *context, Expr *expr) -{ - return constant_fold(context, expr); -} -static inline bool cast_to_common_for_operator(BinOp op, Expr *left, Expr *right) -{ - switch (op) - { - case BINOP_ERROR: - return false; - case BINOP_ASSIGN: - return insert_assign_cast_if_needed(right, left->type->canonical); - case BINOP_MULT: - case BINOP_ADD: - case BINOP_SUB: - case BINOP_DIV: - case BINOP_MOD: - case BINOP_BIT_OR: - case BINOP_BIT_AND: - case BINOP_BIT_XOR: - case BINOP_NE: - case BINOP_EQ: - case BINOP_GE: - case BINOP_GT: - case BINOP_LE: - case BINOP_LT: - return insert_arith_cast_if_needed(left, right, left->type->canonical); - case BINOP_MULT_ASSIGN: - return insert_arith_cast_if_needed(left, right, left->type->canonical); - case BINOP_ADD_ASSIGN: - break; - case BINOP_SUB_ASSIGN: - break; - case BINOP_DIV_ASSIGN: - break; - case BINOP_MOD_ASSIGN: - case BINOP_AND_ASSIGN: - case BINOP_OR_ASSIGN: - break; - case BINOP_AND: - case BINOP_OR: - return insert_bool_cast_if_needed(left) & insert_bool_cast_if_needed(right); - break; - case BINOP_BIT_AND_ASSIGN: - break; - case BINOP_BIT_OR_ASSIGN: - break; - case BINOP_BIT_XOR_ASSIGN: - break; - case BINOP_SHR: - case BINOP_SHL: - TODO - case BINOP_SHR_ASSIGN: - break; - case BINOP_SHL_ASSIGN: - break; - case BINOP_ELVIS: - TODO - } - TODO -} -static inline bool sema_analyse_binary_expr_internal(Context *context, Expr *expr) -{ - assert(expr->resolve_status == RESOLVE_RUNNING); - Expr *left = expr->binary_expr.left; - Expr *right = expr->binary_expr.right; - bool success = sema_analyse_expression(context, left); - success = success && sema_analyse_expression(context, right); - if (!success) - { - expr_poison(expr); - return false; - } - if (!cast_to_common_for_operator(expr->binary_expr.operator, left, right)) - { - expr_poison(expr); - return false; - } - if (left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST) - { - if (!sema_analyse_binary_expr_internal_const(context, expr)) - { - expr_poison(expr); - return false; - } - return true; - } - switch (expr->binary_expr.operator) - { - case BINOP_ERROR: - break; - case BINOP_ASSIGN: - break; - case BINOP_MULT: - break; - case BINOP_MULT_ASSIGN: - break; - case BINOP_ADD: - break; - case BINOP_ADD_ASSIGN: - break; - case BINOP_SUB: - break; - case BINOP_SUB_ASSIGN: - break; - case BINOP_DIV: - break; - case BINOP_DIV_ASSIGN: - break; - case BINOP_MOD: - break; - case BINOP_MOD_ASSIGN: - break; - case BINOP_AND: - break; - case BINOP_AND_ASSIGN: - break; - case BINOP_OR: - break; - case BINOP_OR_ASSIGN: - break; - case BINOP_BIT_AND: - break; - case BINOP_BIT_AND_ASSIGN: - break; - case BINOP_BIT_OR: - break; - case BINOP_BIT_OR_ASSIGN: - break; - case BINOP_BIT_XOR: - break; - case BINOP_BIT_XOR_ASSIGN: - break; - case BINOP_NE: - break; - case BINOP_EQ: - break; - case BINOP_GE: - break; - case BINOP_GT: - break; - case BINOP_LE: - break; - case BINOP_LT: - break; - case BINOP_SHR: - break; - case BINOP_SHR_ASSIGN: - break; - case BINOP_SHL: - break; - case BINOP_SHL_ASSIGN: - break; - case BINOP_ELVIS: - break; - } - TODO -} -static inline bool sema_analyse_unary_expr_internal(Context *context, Expr *expr) -{ - assert(expr->resolve_status == RESOLVE_RUNNING); - Expr *inner = expr->unary_expr.expr; - if (!sema_analyse_expression(context, inner)) - { - expr_poison(expr); - return false; - } - Type *canonical_inner_type = inner->type->canonical; - switch (expr->unary_expr.operator) - { - case UNARYOP_ERROR: - UNREACHABLE; - case UNARYOP_DEREF: - TODO - break; - case UNARYOP_ADDR: - TODO - break; - case UNARYOP_NEG: - if (!type_is_signed(canonical_inner_type) && canonical_inner_type != &type_compuint) - { - bool is_signed = type_is_signed(canonical_inner_type); - bool inneer = canonical_inner_type; - SEMA_ERROR(expr->loc, "Cannot negate %s.", inner->type->name_loc.string); - return false; - } - if (canonical_inner_type == &type_compuint) - { - TODO - } - if (inner->expr_kind == EXPR_CONST) - { - assert(inner->const_expr.type == CONST_INT); - expr->const_expr.type = CONST_INT; - expr->expr_kind = EXPR_CONST; - expr->const_expr.i = ~inner->const_expr.i; - expr->type = inner->type; - return true; - } - return true; - case UNARYOP_BITNEG: - TODO - /* - if (canonical_inner_type->type_kind != TYPE_BUILTIN || !builtin_may_negate(canonical_inner_type)) - { - SEMA_ERROR(expr->loc, "Cannot bit negate %s.", type_to_string(inner->type)); - return false; - }*/ - if (inner->expr_kind == EXPR_CONST) - { - switch (inner->const_expr.type) - { - case CONST_NIL: - case CONST_BOOL: - case CONST_STRING: - case CONST_FLOAT: - UNREACHABLE - case CONST_INT: - - //inner->const_expr.type = CONST_NEGATIVE_INT; - break; - //case CONST_NEGATIVE_INT: - //inner->const_expr.type = CONST_POSITIVE_INT; - break; - TODO - } - } - return true; - case UNARYOP_NOT: - if (inner->expr_kind == EXPR_CONST) - { - switch (inner->const_expr.type) - { - case CONST_NIL: - expr->const_expr.b = true; - break; - case CONST_BOOL: - expr->const_expr.b = !inner->const_expr.b; - break; - case CONST_INT: - expr->const_expr.b = inner->const_expr.i == 0; - break; - case CONST_FLOAT: - expr->const_expr.b = inner->const_expr.f == 0; - break; - case CONST_STRING: - expr->const_expr.b = !inner->const_expr.string.len; - break; - } - expr->const_expr.type = CONST_BOOL; - expr->type = &type_bool; - expr->expr_kind = EXPR_CONST; - return true; - } - switch (canonical_inner_type->type_kind) - { - case TYPE_ARRAY: - case TYPE_POINTER: - case TYPE_VARARRAY: - return true; - default: - SEMA_ERROR(expr->loc, "Cannot use 'not' on %s", inner->type->name_loc.string); - return false; - } - case UNARYOP_INC: - TODO - break; - case UNARYOP_DEC: - TODO - break; - } -} -static inline bool sema_analyse_cast(Context *context, Expr *expr) -{ - Expr *inner = expr->expr_cast.expr; - bool success = sema_analyse_expression(context, inner); - success = sema_resolve_type(context, expr->type) && success; - if (!success) return false; - Type *canonical = expr->type->canonical; - Type *inner_canonical = inner->type->canonical; - if (canonical == inner_canonical) return true; - //BUILTIN_CONVERSION - TODO -} - -static inline bool sema_analyse_expression(Context *context, Expr *expr) -{ - switch (expr->resolve_status) - { - case RESOLVE_NOT_DONE: - expr->resolve_status = RESOLVE_RUNNING; - break; - case RESOLVE_RUNNING: - SEMA_ERROR(expr->loc, "Recursive resolution of expression"); - expr_poison(expr); - return false; - case RESOLVE_DONE: - return expr_ok(expr); - } - switch (expr->expr_kind) - { - case EXPR_POISONED: - UNREACHABLE - case EXPR_TRY: - if (!sema_analyse_expression(context, expr->try_expr.expr)) - { - expr_poison(expr); - return false; - } - if (expr->try_expr.else_expr) - { - if (!sema_analyse_expression(context, expr->try_expr.else_expr)) - { - expr_poison(expr); - return false; - } - if (!type_promote(expr->try_expr.else_expr, expr->try_expr.expr)) - { - expr_poison(expr); - return false; - } - } - expr->type = expr->try_expr.expr->type; - expr->resolve_status = RESOLVE_DONE; - return true; - case EXPR_CONST: - expr->resolve_status = RESOLVE_DONE; - return true; - case EXPR_BINARY: - if (!sema_analyse_binary_expr_internal(context, expr)) - { - expr_poison(expr); - return false; - } - expr->resolve_status = RESOLVE_DONE; - return true; - case EXPR_CONDITIONAL: - TODO - break; - case EXPR_UNARY: - if (!sema_analyse_unary_expr_internal(context, expr)) - { - expr_poison(expr); - return false; - } - expr->resolve_status = RESOLVE_DONE; - return true; - case EXPR_POST_UNARY: - break; - case EXPR_TYPE: - break; - case EXPR_IDENTIFIER: - break; - case EXPR_METHOD_REF: - break; - case EXPR_CALL: - break; - case EXPR_SIZEOF: - break; - case EXPR_SUBSCRIPT: - break; - case EXPR_ACCESS: - break; - case EXPR_STRUCT_VALUE: - break; - case EXPR_STRUCT_INIT_VALUES: - break; - case EXPR_INITIALIZER_LIST: - break; - case EXPR_EXPRESSION_LIST: - break; - case EXPR_DEFERRED_TOKENS: - break; - case EXPR_CAST: - if (!sema_analyse_cast(context, expr)) - { - expr_poison(expr); - return false; - } - return true; - } - { - - } - TODO - return false; -} - -/** - * Convert an expression to a given type using implicit conversion. - * - * @param expr the expression to be implictly converted - * @param type the type to convert to - * @return an expression with cast if needed, or NULL if an error has been sent and the conversion failed. - */ -Expr *expr_implicit_conversion(Expr *expr, Type *type) -{ - TODO - /* - assert(expr->type && expr_ok(expr)); - if (expr->type->type_kind == TYPE_NIL && type->type_kind == TYPE_POINTER) - Type *expr_type = expr->type; - if (type->type_kind == TYPE_POINTER && expr_type->type_kind == TYPE_POINTER) - { - if (expr_type) - if (type->type_kind) - } - Decl *canonical_decl = type->canonical; - if (type->canonical) - if (expr->type->canonical->decl_kind == TYPE_BUILTIN && type->canonical->decl_kind == DECL_BUILTIN) - { - - } - TODO*/ - return NULL; -} static inline bool sema_analyse_function_param(Context *context, Decl *param, bool is_function) { @@ -967,18 +295,13 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo if (param->var.init_expr) { Expr *expr = param->var.init_expr; - if (!sema_analyse_expression(context, expr)) return false; + if (!sema_expr_analysis(context, expr)) return false; if (expr->expr_kind != EXPR_CONST) { SEMA_ERROR(expr->loc, "Only constant expressions may be used as default values."); return false; } - Expr *converted_expr = expr_implicit_conversion(expr, param->var.type); - if (!converted_expr) - { - return false; - } - param->var.init_expr = converted_expr; + if (!cast(expr, param->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; } return true; } @@ -1003,51 +326,66 @@ static inline bool sema_analyse_function_signature(Context *context, FunctionSig return all_ok; } -static bool sema_analyse_statement(Context *context, Ast *parent, Ast *statement); -static inline bool sema_analyse_compound_statement(Context *context, Ast *parent, Ast *compound_statement) +static inline bool sema_analyse_compound_statement_no_scope(Context *context, Ast *compound_statement) { LOG_FUNC bool all_ok = ast_ok(compound_statement); VECEACH(compound_statement->compound_stmt.stmts, i) { - if (!sema_analyse_statement(context, compound_statement, compound_statement->compound_stmt.stmts[i])) + if (!sema_analyse_statement(context, compound_statement->compound_stmt.stmts[i])) { ast_poison(compound_statement->compound_stmt.stmts[i]); all_ok = false; } } + /* if (parent->exit < compound_statement->exit) { parent->exit = compound_statement->exit; - } + }*/ return all_ok; } -static inline bool sema_analyse_return_stmt(Context *context, Ast *parent, Ast *statement) +static inline bool sema_analyse_return_stmt(Context *context, Ast *statement) { LOG_FUNC - parent->exit = EXIT_RETURN; - Type *expected_rtype = context->active_function_for_analysis->func.function_signature.rtype; - if (statement->return_stmt.expr == NULL) + context->current_scope->exit = EXIT_RETURN; + Type *expected_rtype = context->rtype; + Expr *return_expr = statement->return_stmt.expr; + if (return_expr == NULL) { - if (expected_rtype->canonical != &type_void) + if (!expected_rtype) + { + assert(context->evaluating_macro); + context->rtype = type_void; + return true; + } + if (expected_rtype->canonical != type_void) { SEMA_ERROR(statement->token, "Expected to return a result of type %s.", expected_rtype->name_loc.string); return false; } + return true; } - else + if (!sema_expr_analysis(context, return_expr)) return false; + if (!expected_rtype) { - if (!sema_analyse_expression(context, statement->return_stmt.expr)) return false; - Expr *conversion = expr_implicit_conversion(statement->return_stmt.expr, expected_rtype); - if (!conversion) return false; - statement->return_stmt.expr = conversion; + assert(context->evaluating_macro); + context->rtype = type_void; + context->active_function_for_analysis->func.function_signature.rtype = statement->return_stmt.expr->type; + return true; } + if (context->evaluating_macro && expected_rtype->canonical != return_expr->type->canonical) + { + TODO // Fix upcast + } + if (!cast(statement->return_stmt.expr, expected_rtype, CAST_TYPE_IMPLICIT)) return false; return true; } -static inline bool sema_analyse_var_decl(Context *context, Ast *parent, Decl *decl) + +static inline bool sema_analyse_var_decl(Context *context, Decl *decl) { assert(decl->decl_kind == DECL_VAR); if (!sema_resolve_type(context, decl->var.type)) return false; @@ -1055,28 +393,254 @@ static inline bool sema_analyse_var_decl(Context *context, Ast *parent, Decl *de if (other) { show_shadow_error(decl, other); + decl_poison(decl); + decl_poison(other); return false; } - if (context->last_local == &context->locals[MAX_LOCALS - 1]) + Decl *** vars = &context->active_function_for_analysis->func.annotations->vars; + unsigned num_vars = vec_size(*vars); + if (num_vars == MAX_LOCALS - 1 || context->last_local == &context->locals[MAX_LOCALS - 1]) { - FATAL_ERROR("Reached the maximum number of locals"); + SEMA_ERROR(decl->name, "Reached the maximum number of locals."); + return false; } + decl->var.id = num_vars; + *vars = VECADD(*vars, decl); if (decl->var.init_expr) { - sema_analyse_expression(context, decl->var.init_expr); - type_assign_cast(decl->var.init_expr, decl->var.type->canonical, false); + if (!sema_expr_analysis(context, decl->var.init_expr) || + !cast(decl->var.init_expr, decl->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) + { + decl_poison(decl); + return false; + } } context->last_local[0] = decl; context->last_local++; return true; } -static inline bool sema_analyse_multi_decl(Context *context, Ast *parent, Ast *statement) +static inline bool sema_analyse_decl_expr_list(Context *context, Ast *statement) +{ + switch (statement->decl_expr_list.list_type) + { + case DECLEXPR_DECL: + return sema_analyse_var_decl(context, statement->decl_expr_list.decl); + case DECLEXPR_EXPR: + return sema_expr_analysis(context, statement->decl_expr_list.expr); + } + UNREACHABLE +} + + +static inline bool sema_insert_decl_expr_list_in_compound_stmt(Context *context, Ast *compound_statement, Ast *decl_expr_list) +{ + compound_statement->compound_stmt.stmts = VECADD(compound_statement->compound_stmt.stmts, decl_expr_list); + return true; +} + +static inline Ast *convert_expr_to_ast(Expr *expr) +{ + Ast *ast = new_ast(AST_EXPR_STMT, expr->loc); + ast->expr_stmt = expr; + return ast; +} +static inline Expr *convert_decl_to_expr(Context *context, Decl *decl) +{ + assert(decl->decl_kind == DECL_VAR); + assert(decl->decl_kind == VARDECL_LOCAL); + if (!decl->var.init_expr) return NULL; + Expr *assign_expr = expr_new(EXPR_BINARY, decl->name); + assign_expr->resolve_status = RESOLVE_DONE; + Expr *identifier = expr_new(EXPR_IDENTIFIER, decl->name); + identifier->resolve_status = RESOLVE_DONE; + identifier->identifier_expr.identifier = decl->name; + identifier->identifier_expr.decl = decl; + assign_expr->binary_expr.left = identifier; + assign_expr->binary_expr.right = decl->var.init_expr; + assign_expr->binary_expr.operator = TOKEN_EQ; + identifier->type = decl->var.type; + assign_expr->type = decl->var.init_expr->type; + return assign_expr; +} + +static inline bool convert_decl_for_cond(Context *context, Decl *decl, Ast*** stmt_list, Expr** last, bool is_last) +{ + Expr *expr = convert_decl_to_expr(context, decl); + if (!expr) + { + if (is_last) + { + SEMA_ERROR(decl->name, "Expected an initializer for '%s'.", decl->name.string); + return false; + } + // Simply skip declarations if they don't have an initializer, since they're already registered anyway. + return true; + } + if (is_last) + { + *last = expr; + } + else + { + Ast *stmt = convert_expr_to_ast(expr); + *stmt_list = VECADD(*stmt_list, stmt); + } + return true; +} + +static inline bool convert_stmt_for_cond(Context *context, Ast *stmt, Ast*** stmt_list, Expr** last, bool is_last) +{ + if (stmt->ast_kind == AST_EXPR_STMT) + { + if (is_last) + { + *last = stmt->expr_stmt; + return true; + } + *stmt_list = VECADD(*stmt_list, stmt); + return true; + } + assert(stmt->ast_kind == AST_DECLARE_STMT); + Decl *decl = stmt->declare_stmt; + + if (decl->decl_kind != DECL_MULTI_DECL) + { + return convert_decl_for_cond(context, decl, stmt_list, last, is_last); + } + + Decl **decls = decl->multi_decl; + assert(vec_size(decls) > 0); + unsigned last_element = vec_size(decls) - 1; + for (unsigned i = 0; i <= last_element; i++) + { + Decl *sub_decl = decls[i]; + if (!convert_decl_for_cond(context, sub_decl, stmt_list, last, is_last && last_element == i)) return false; + } + return true; +} + +static inline bool decl_or_expr_to_expr_stmt(Context *context, Ast *stmt) +{ + if (stmt->ast_kind == AST_EXPR_STMT) return true; + assert(stmt->ast_kind == AST_DECLARE_STMT); + stmt->ast_kind = AST_EXPR_STMT; + Decl *decl = stmt->declare_stmt; + if (decl->decl_kind == DECL_MULTI_DECL) + { + Expr *list = expr_new(EXPR_EXPRESSION_LIST, stmt->token); + Expr **exprs = NULL; + VECEACH(decl->multi_decl, i) + { + Decl *var = decl->multi_decl[i]; + assert(var->decl_kind == DECL_VAR); + assert(var->decl_kind == VARDECL_LOCAL); + if (var->var.init_expr == NULL) + { + SEMA_ERROR(var->name, "'%s' needs to be assigned.", var->name.string); + return false; + } + Expr *assign_expr = expr_new(EXPR_BINARY, stmt->token); + assign_expr->resolve_status = RESOLVE_DONE; + assign_expr->binary_expr.operator = TOKEN_EQ; + Expr *identifier = expr_new(EXPR_IDENTIFIER, var->name); + identifier->resolve_status = RESOLVE_DONE; + identifier->identifier_expr.decl = var; + identifier->type = var->var.type; + assign_expr->binary_expr.left = identifier; + assign_expr->binary_expr.right = var->var.init_expr; + exprs = VECADD(exprs, assign_expr); + } + list->expression_list = exprs; + stmt->expr_stmt = list; + return true; + } + assert(decl->decl_kind == DECL_VAR); + assert(decl->decl_kind == VARDECL_LOCAL); + if (decl->var.init_expr == NULL) + { + SEMA_ERROR(decl->name, "'%s' needs to be assigned.", decl->name.string); + return false; + } + stmt->expr_stmt = decl->var.init_expr; + return true; +} + +static inline bool sema_flatten_cond(Context *context, Ast *stmt) +{ + assert(stmt->ast_kind == AST_STMT_LIST); + assert(vec_size(stmt->stmt_list) > 0); + + // The common case: + if (vec_size(stmt->stmt_list) == 1 && stmt->stmt_list[0]->ast_kind == AST_EXPR_STMT) + { + Expr *expr = stmt->stmt_list[0]->expr_stmt; + if (!cast(expr, type_bool, CAST_TYPE_IMPLICIT)) return false; + stmt->ast_kind = AST_COND_STMT; + stmt->cond_stmt.expr = expr; + stmt->cond_stmt.stmts = NULL; + return true; + } + Ast **new_list = NULL; + Expr *last = NULL; + + unsigned last_index = vec_size(stmt->stmt_list) - 1; + VECEACH(stmt->stmt_list, i) + { + if (!convert_stmt_for_cond(context, stmt->stmt_list[i], &new_list, &last, last_index == i)) return false; + } + if (!cast(last, type_bool, CAST_TYPE_IMPLICIT)) return false; + stmt->ast_kind = AST_COND_STMT; + stmt->cond_stmt.expr = last; + stmt->cond_stmt.stmts = new_list; + return true; +} + +static inline bool sema_analyse_while_stmt(Context *context, Ast *statement) +{ + LOG_FUNC + Ast *cond = statement->while_stmt.cond; + Ast *body = statement->while_stmt.body; + assert(cond && cond->ast_kind == AST_STMT_LIST); + context_push_scope_with_flags(context, SCOPE_CONTROL); + bool success = sema_analyse_statement(context, cond); + sema_flatten_cond(context, cond); + context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise) + success = success && sema_analyse_statement(context, body); + context_pop_scope(context); + context_pop_scope(context); + if (!success) return false; + statement->ast_kind = AST_FOR_STMT; + statement->for_stmt.cond = cond; + statement->for_stmt.incr = NULL; + statement->for_stmt.body = body; + return success; +} + +static inline bool sema_analyse_do_stmt(Context *context, Ast *statement) +{ + LOG_FUNC + Expr *expr = statement->do_stmt.expr; + Ast *body = statement->do_stmt.body; + bool success; + context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise) + success = sema_analyse_statement(context, body); + context_pop_scope(context); + if (!success) return false; + context_push_scope_with_flags(context, SCOPE_CONTROL); + success = sema_expr_analysis(context, expr); + success = success && cast(expr, type_bool, CAST_TYPE_IMPLICIT); + context_pop_scope(context); + return success; +} + + +static inline bool sema_analyse_multi_decl(Context *context, Ast *statement) { Decl *decl = statement->declare_stmt; VECEACH(statement->declare_stmt->multi_decl, i) { - if (!sema_analyse_var_decl(context, parent, statement->declare_stmt->multi_decl[i])) + if (!sema_analyse_var_decl(context, statement->declare_stmt->multi_decl[i])) { decl_poison(decl); return false; @@ -1085,104 +649,201 @@ static inline bool sema_analyse_multi_decl(Context *context, Ast *parent, Ast *s return true; } -static inline bool sema_analyse_declare_stmt(Context *context, Ast *parent, Ast *statement) +static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement) { Decl *decl = statement->declare_stmt; if (decl->decl_kind == DECL_MULTI_DECL) { - return sema_analyse_multi_decl(context, parent, statement); + return sema_analyse_multi_decl(context, statement); } - return sema_analyse_var_decl(context, parent, decl); + return sema_analyse_var_decl(context, decl); } -static bool sema_analyse_statement(Context *context, Ast *parent, Ast *statement) +static inline bool sema_analyse_expr_stmt(Context *context, Ast *statement) +{ + return sema_expr_analysis(context, statement->expr_stmt); +} + +static inline bool sema_analyse_defer_stmt(Context *context, Ast *statement) +{ + TODO +} + +static inline bool sema_analyse_default_stmt(Context *context, Ast *statement) +{ + TODO +} + +bool sema_analyse_stmt_list(Context *context, Ast *statement) +{ + VECEACH(statement->stmt_list, i) + { + if (!sema_analyse_statement(context, statement->stmt_list[i])) return false; + } + return true; +} + +static inline bool sema_analyse_for_stmt(Context *context, Ast *statement) +{ + context_push_scope_with_flags(context, SCOPE_CONTROL); + + bool success = sema_analyse_statement(context, statement->for_stmt.cond); + success = success && (!statement->for_stmt.incr || sema_analyse_statement(context, statement->for_stmt.incr)); + context_pop_scope(context); + if (!success) return false; + context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise) + success = sema_analyse_statement(context, statement->for_stmt.body); + context_pop_scope(context); + return success; +} + +static inline bool sema_analyse_goto_stmt(Context *context, Ast *statement) +{ + TODO +} + +static inline bool sema_analyse_if_stmt(Context *context, Ast *statement) +{ + TODO +} + +static inline bool sema_analyse_label(Context *context, Ast *statement) +{ + TODO +} + +static inline bool sema_analyse_nop_stmt(Context *context, Ast *statement) +{ + TODO +} + + +static bool sema_analyse_catch_stmt(Context *context, Ast *statement) +{ + TODO +} + +static bool sema_analyse_asm_stmt(Context *context, Ast *statement) +{ + TODO +} + +static bool sema_analyse_attribute(Context *context, Ast *statement) +{ + TODO +} + +static bool sema_analyse_break_stmt(Context *context, Ast *statement) +{ + TODO +} + +static bool sema_analyse_case_stmt(Context *context, Ast *statement) +{ + TODO +} + +static bool sema_analyse_continue_stmt(Context *context, Ast *statement) +{ + TODO +} + +static bool sema_analyse_ct_if_stmt(Context *context, Ast *statement) +{ + TODO +} + +static bool sema_analyse_switch_stmt(Context *context, Ast *statement) +{ + TODO +} + +static bool sema_analyse_try_stmt(Context *context, Ast *statement) +{ + TODO +} + +static bool sema_analyse_throw_stmt(Context *context, Ast *statement) +{ + TODO +} + +static bool sema_analyse_next_stmt(Context *context, Ast *statement) +{ + TODO +} + +static bool sema_analyse_volatile_stmt(Context *context, Ast *statement) +{ + context->in_volatile_section++; + bool result = sema_analyse_statement(context, statement->volatile_stmt); + context->in_volatile_section--; + return result; +} + +static bool sema_analyse_compound_stmt(Context *context, Ast *statement) +{ + context_push_scope(context); + bool success = sema_analyse_compound_statement_no_scope(context, statement); + context_pop_scope(context); + return success; +} + +static AstAnalysis AST_ANALYSIS[AST_WHILE_STMT + 1] = +{ + [AST_ASM_STMT] = &sema_analyse_asm_stmt, + [AST_ATTRIBUTE] = &sema_analyse_attribute, + [AST_BREAK_STMT] = &sema_analyse_break_stmt, + [AST_CASE_STMT] = &sema_analyse_case_stmt, + [AST_CATCH_STMT] = &sema_analyse_catch_stmt, + [AST_COMPOUND_STMT] = &sema_analyse_compound_stmt, + [AST_CONTINUE_STMT] = &sema_analyse_continue_stmt, + [AST_CT_IF_STMT] = &sema_analyse_ct_if_stmt, + [AST_DECLARE_STMT] = &sema_analyse_declare_stmt, + [AST_DEFAULT_STMT] = &sema_analyse_default_stmt, + [AST_DEFER_STMT] = &sema_analyse_defer_stmt, + [AST_DO_STMT] = &sema_analyse_do_stmt, + [AST_EXPR_STMT] = &sema_analyse_expr_stmt, + [AST_FOR_STMT] = &sema_analyse_for_stmt, + [AST_GOTO_STMT] = &sema_analyse_goto_stmt, + [AST_IF_STMT] = &sema_analyse_if_stmt, + [AST_LABEL] = &sema_analyse_label, + [AST_NOP_STMT] = &sema_analyse_nop_stmt, + [AST_RETURN_STMT] = &sema_analyse_return_stmt, + [AST_SWITCH_STMT] = &sema_analyse_switch_stmt, + [AST_TRY_STMT] = &sema_analyse_try_stmt, + [AST_THROW_STMT] = &sema_analyse_throw_stmt, + [AST_NEXT_STMT] = &sema_analyse_next_stmt, + [AST_VOLATILE_STMT] = &sema_analyse_volatile_stmt, + [AST_WHILE_STMT] = &sema_analyse_while_stmt, + [AST_STMT_LIST] = &sema_analyse_stmt_list +}; + +bool sema_analyse_statement(Context *context, Ast *statement) { LOG_FUNC - switch (statement->ast_kind) - { - case AST_POISONED: - break; - case AST_ASM_STMT: - break; - case AST_ATTRIBUTE: - break; - case AST_BREAK_STMT: - break; - case AST_CASE_STMT: - break; - case AST_CATCH_STMT: - break; - case AST_COMPOUND_STMT: - context_push_scope(context); - sema_analyse_compound_statement(context, parent, statement); - context_pop_scope(context); - break; - case AST_COND_STMT: - break; - case AST_CONTINUE_STMT: - break; - case AST_CT_IF_STMT: - break; - case AST_CT_ELIF_STMT: - break; - case AST_CT_ELSE_STMT: - break; - case AST_DECLARE_STMT: - return sema_analyse_declare_stmt(context, parent, statement); - case AST_DECL_EXPR_LIST: - break; - case AST_DEFAULT_STMT: - break; - case AST_DEFER_STMT: - break; - case AST_DO_STMT: - break; - case AST_EXPR_STMT: - break; - case AST_FOR_STMT: - break; - case AST_GOTO_STMT: - break; - case AST_IF_STMT: - break; - case AST_LABEL: - break; - case AST_NOP_STMT: - break; - case AST_RETURN_STMT: - return sema_analyse_return_stmt(context, parent, statement); - case AST_SWITCH_STMT: - break; - case AST_THROW_STMT: - break; - case AST_TRY_STMT: - break; - case AST_NEXT_STMT: - break; - case AST_VOLATILE_STMT: - break; - case AST_WHILE_STMT: - break; - case AST_GENERIC_CASE_STMT: - break; - case AST_GENERIC_DEFAULT_STMT: - break; - } - TODO + if (AST_ANALYSIS[statement->ast_kind](context, statement)) return true; + return ast_poison(statement); } static inline bool sema_analyse_function_body(Context *context, Decl *func) { context->active_function_for_analysis = func; + context->rtype = func->func.function_signature.rtype; context->current_scope = &context->scopes[0]; context->current_scope->local_decl_start = 0; context->last_local = &context->locals[0]; - if (!sema_analyse_compound_statement(context, func->func.body, func->func.body)) return false; - if (func->func.body->exit != EXIT_RETURN && func->func.function_signature.rtype->type_kind != TYPE_ARRAY) + context->unique_index = 0; + context->in_volatile_section = 0; + func->func.annotations = CALLOCS(*func->func.annotations); + context_push_scope(context); + if (!sema_analyse_compound_statement_no_scope(context, func->func.body)) return false; + if (context->current_scope->exit != EXIT_RETURN && func->func.function_signature.rtype->canonical != type_void) { SEMA_ERROR(func->name, "Missing return statement at the end of the function."); return false; } + context_pop_scope(context); return true; } static inline bool sema_analyse_func(Context *context, Decl *decl) @@ -1196,6 +857,21 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) if (!all_ok) decl_poison(decl); return all_ok; } + +static inline bool sema_analyse_macro(Context *context, Decl *decl) +{ + Type *rtype = decl->macro_decl.rtype; + if (decl->macro_decl.rtype && !sema_resolve_type(context, rtype)) return false; + VECEACH(decl->macro_decl.parameters, i) + { + Decl *param = decl->macro_decl.parameters[i]; + assert(param->decl_kind == DECL_VAR); + assert(param->var.kind == VARDECL_PARAM); + if (param->var.type && !sema_resolve_type(context, param->var.type)) return false; + } + return true; +} + static inline void sema_analyse_decl(Context *context, Decl *decl) { LOG_FUNC @@ -1211,6 +887,9 @@ static inline void sema_analyse_decl(Context *context, Decl *decl) case DECL_FUNC: sema_analyse_func(context, decl); break; + case DECL_MACRO: + sema_analyse_macro(context, decl); + break; default: TODO } diff --git a/src/compiler/types.c b/src/compiler/types.c index 8bab3b4c3..448d49cbf 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -4,24 +4,31 @@ #include "compiler_internal.h" -Type type_bool; -Type type_void, type_string; +Type *type_bool, *type_void, *type_string; +Type *type_float, *type_double; +Type *type_char, *type_short, *type_int, *type_long, *type_isize; +Type *type_byte, *type_ushort, *type_uint, *type_ulong, *type_usize; +Type *type_compint, *type_compuint, *type_compfloat; +Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong; +Type *type_c_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong; + +Type t_u0, t_str; +Type t_u1, t_i8, t_i16, t_i32, t_i64, t_ixx; +Type t_u8, t_u16, t_u32, t_u64, t_uxx; +Type t_f32, t_f64, t_fxx; +Type t_usz, t_isz; +Type t_cus, t_cui, t_cul, t_cull; +Type t_cs, t_ci, t_cl, t_cll; -Type type_half, type_float, type_double, type_quad; -Type type_char, type_short, type_int, type_long, type_isize; -Type type_byte, type_ushort, type_uint, type_ulong, type_usize; -Type type_compint, type_compuint, type_compfloat; -Type type_c_short, type_c_int, type_c_long, type_c_longlong; -Type type_c_ushort, type_c_uint, type_c_ulong, type_c_ulonglong; Type *type_signed_int_by_size(int bitsize) { switch (bitsize) { - case 1: return &type_char; - case 2: return &type_short; - case 4: return &type_int; - case 8: return &type_long; + case 1: return type_char; + case 2: return type_short; + case 4: return type_int; + case 8: return type_long; default: FATAL_ERROR("Illegal bitsize %d", bitsize); } } @@ -29,10 +36,10 @@ Type *type_unsigned_int_by_size(int bitsize) { switch (bitsize) { - case 1: return &type_byte; - case 2: return &type_ushort; - case 4: return &type_uint; - case 8: return &type_ulong; + case 1: return type_byte; + case 2: return type_ushort; + case 4: return type_uint; + case 8: return type_ulong; default: FATAL_ERROR("Illegal bitsize %d", bitsize); } } @@ -77,7 +84,7 @@ size_t type_size(Type *canonical) case TYPE_POINTER: case TYPE_VARARRAY: case TYPE_STRING: - return type_isize.canonical->builtin.bytesize; + return t_usz.canonical->builtin.bytesize; case TYPE_ARRAY: return type_size(canonical->base) * canonical->len; } @@ -156,69 +163,71 @@ Type *type_get_canonical_array(Type *arr_type) return canonical; } -static void create_type(const char *name, Type *location, TypeKind kind, unsigned bytesize, unsigned bitsize) +static void create_type(const char *name, Type *location, Type **ptr, TypeKind kind, unsigned bytesize, unsigned bitsize) { *location = (Type) { .type_kind = kind, .resolve_status = RESOLVE_DONE, .builtin.bytesize = bytesize, .builtin.bitsize = bitsize }; location->name_loc.string = name; location->name_loc.span.length = strlen(name); location->canonical = location; + *ptr = location; } -static void type_create_alias(const char *name, Type *location, Type *canonical) +static void type_create_alias(const char *name, Type *location, Type **ptr, Type *canonical) { *location = (Type) { .type_kind = TYPE_USER_DEFINED, .resolve_status = RESOLVE_DONE }; location->name_loc.string = name; location->name_loc.span.length = strlen(name); location->canonical = canonical; + *ptr = location; } void builtin_setup() { - create_type("void", &type_void, TYPE_VOID, 1, 8); + create_type("void", &t_u0, &type_void, TYPE_VOID, 1, 8); + create_type("string", &t_str, &type_string, TYPE_STRING, build_options.pointer_size, build_options.pointer_size * 8); /*TODO * decl_string = (Decl) { .decl_kind = DECL_BUILTIN, .name.string = "string" }; create_type(&decl_string, &type_string); type_string.type_kind = TYPE_STRING; */ -#define DEF_TYPE(_name, _type, _bits) \ -create_type(#_name, &type_ ## _name, _type, (_bits + 7) / 8, _bits); +#define DEF_TYPE(_name, _shortname, _type, _bits) \ +create_type(#_name, &_shortname, &type_ ## _name, _type, (_bits + 7) / 8, _bits); - DEF_TYPE(compint, TYPE_IXX, 64); - DEF_TYPE(compuint, TYPE_UXX, 64); - DEF_TYPE(compfloat, TYPE_FXX, 64); - DEF_TYPE(bool, TYPE_BOOL, 1); + DEF_TYPE(compint, t_ixx, TYPE_IXX, 64); + DEF_TYPE(compuint, t_uxx, TYPE_UXX, 64); + DEF_TYPE(compfloat, t_fxx, TYPE_FXX, 64); + DEF_TYPE(bool, t_u1, TYPE_BOOL, 1); -// DEF_TYPE(half, 2, 16, NUMBER_TYPE_FLOAT, "half", T_F16); - DEF_TYPE(float, TYPE_F32, 32); - DEF_TYPE(double, TYPE_F64, 64); -// DEF_TYPE(quad, 16, 128, NUMBER_TYPE_FLOAT, "long double", T_F128); + DEF_TYPE(float, t_f32, TYPE_F32, 32); + DEF_TYPE(double, t_f64, TYPE_F64, 64); - DEF_TYPE(char, TYPE_I8, 8); - DEF_TYPE(short, TYPE_I16, 16); - DEF_TYPE(int, TYPE_I32, 32); - DEF_TYPE(long, TYPE_I64, 64); + DEF_TYPE(char, t_i8, TYPE_I8, 8); + DEF_TYPE(short, t_i16, TYPE_I16, 16); + DEF_TYPE(int, t_i32, TYPE_I32, 32); + DEF_TYPE(long, t_i64, TYPE_I64, 64); - DEF_TYPE(byte, TYPE_U8, 8); - DEF_TYPE(ushort, TYPE_U16, 16); - DEF_TYPE(uint, TYPE_U32, 32); - DEF_TYPE(ulong, TYPE_U64, 64); + DEF_TYPE(byte, t_u8, TYPE_U8, 8); + DEF_TYPE(ushort, t_u16, TYPE_U16, 16); + DEF_TYPE(uint, t_u32, TYPE_U32, 32); + DEF_TYPE(ulong, t_u64, TYPE_U64, 64); - type_create_alias("usize", &type_usize, type_unsigned_int_by_size(build_options.pointer_size)); - type_create_alias("isize", &type_isize, type_signed_int_by_size(build_options.pointer_size)); + type_create_alias("usize", &t_usz, &type_usize, type_unsigned_int_by_size(build_options.pointer_size)); + type_create_alias("isize", &t_isz, &type_isize, type_signed_int_by_size(build_options.pointer_size)); - type_create_alias("c_ushort", &type_c_ushort, type_unsigned_int_by_size(build_options.cshort_size)); - type_create_alias("c_uint", &type_c_uint, type_unsigned_int_by_size(build_options.cint_size)); - type_create_alias("c_ulong", &type_c_ulong, type_unsigned_int_by_size(build_options.clong_size)); - type_create_alias("c_ulonglong", &type_c_ulonglong, type_unsigned_int_by_size(build_options.clonglong_size)); + type_create_alias("c_ushort", &t_cus, &type_c_ushort, type_unsigned_int_by_size(build_options.cshort_size)); + type_create_alias("c_uint", &t_cui, &type_c_uint, type_unsigned_int_by_size(build_options.cint_size)); + type_create_alias("c_ulong", &t_cul, &type_c_ulong, type_unsigned_int_by_size(build_options.clong_size)); + type_create_alias("c_ulonglong", &t_cull, &type_c_ulonglong, type_unsigned_int_by_size(build_options.clonglong_size)); - type_create_alias("c_short", &type_c_short, type_signed_int_by_size(build_options.cshort_size)); - type_create_alias("c_int", &type_c_int, type_signed_int_by_size(build_options.cint_size)); - type_create_alias("c_long", &type_c_long, type_signed_int_by_size(build_options.clong_size)); - type_create_alias("c_longlong", &type_c_longlong, type_signed_int_by_size(build_options.clonglong_size)); + type_create_alias("c_short", &t_cs, &type_c_short, type_signed_int_by_size(build_options.cshort_size)); + type_create_alias("c_int", &t_ci, &type_c_int, type_signed_int_by_size(build_options.cint_size)); + type_create_alias("c_long", &t_cl, &type_c_long, type_signed_int_by_size(build_options.clong_size)); + type_create_alias("c_longlong", &t_cll, &type_c_longlong, type_signed_int_by_size(build_options.clonglong_size)); #undef DEF_TYPE -} \ No newline at end of file +} + diff --git a/src/utils/lib.h b/src/utils/lib.h index 45d9ddb0e..e509ec332 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -18,6 +18,7 @@ void run_arena_allocator_tests(void); #define MALLOC(mem) malloc_arena(mem) #define MALLOCS(type) malloc_arena(sizeof(type)) +#define CALLOCS(type) ({ void *__x = malloc_arena(sizeof(type)); memset(__x, 0, sizeof(type)); __x; }) static inline bool is_power_of_two(uint64_t x) { @@ -213,7 +214,12 @@ static inline unsigned vec_size(const void*vec) return vec ? (((_VHeader *)vec) - 1)->size : 0; } - +static inline void vec_pop(const void *vec) +{ + assert(vec); + assert(vec_size(vec) > 0); + (((_VHeader *)vec) - 1)->size--; +} static inline void* _expand(void *vec, size_t element_size) { if (vec == NULL)