mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Partial codegen
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
599
src/compiler/expr_analysis.c
Normal file
599
src/compiler/expr_analysis.c
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user