Managing bigint memory
This commit is contained in:
@@ -3,9 +3,17 @@
|
|||||||
// a copy of which can be found in the LICENSE file.
|
// a copy of which can be found in the LICENSE file.
|
||||||
|
|
||||||
struct Token;
|
struct Token;
|
||||||
|
Allocator *bigint_allocator;
|
||||||
global S64 bigint_allocation_count;
|
global S64 bigint_allocation_count;
|
||||||
function void parsing_error(Token *token, const char *str, ...);
|
function void parsing_error(Token *token, const char *str, ...);
|
||||||
#define malloc_arena(x) (bigint_allocation_count++, exp_alloc(&pernament_arena, x))
|
|
||||||
|
#define Set_BigInt_Allocator(x) BigInt_Allocator bigint_allocator(x)
|
||||||
|
struct BigInt_Allocator{
|
||||||
|
BigInt_Allocator(Allocator *allocator){bigint_allocator = allocator;}
|
||||||
|
~BigInt_Allocator(){bigint_allocator = 0;}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define malloc_arena(x) (bigint_allocation_count++, exp_alloc(bigint_allocator, x, AF_ZeroMemory))
|
||||||
#define ALLOC_DIGITS(_digits) (uint64_t *)((_digits) ? malloc_arena(sizeof(uint64_t) * (_digits)) : NULL)
|
#define ALLOC_DIGITS(_digits) (uint64_t *)((_digits) ? malloc_arena(sizeof(uint64_t) * (_digits)) : NULL)
|
||||||
#define FATAL_ERROR(x) parsing_error(0, x)
|
#define FATAL_ERROR(x) parsing_error(0, x)
|
||||||
|
|
||||||
@@ -95,6 +103,33 @@ bigint_mul(const BigInt *a, const BigInt *b){
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function BigInt
|
||||||
|
bigint_add(const BigInt *a, const BigInt *b){
|
||||||
|
BigInt result;
|
||||||
|
bigint_add(&result, a, b);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function BigInt
|
||||||
|
bigint_copy(Allocator *allocator, BigInt *src){
|
||||||
|
BigInt dest = {};
|
||||||
|
if (src->digit_count == 0){
|
||||||
|
bigint_init_unsigned(&dest, 0);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
if(src->digit_count == 1){
|
||||||
|
dest.digit_count = 1;
|
||||||
|
dest.digit = src->digit;
|
||||||
|
dest.is_negative = src->is_negative;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
dest.is_negative = src->is_negative;
|
||||||
|
dest.digit_count = src->digit_count;
|
||||||
|
dest.digits = exp_alloc_array(allocator, uint64_t, dest.digit_count, AF_ZeroMemory);
|
||||||
|
memcpy(dest.digits, src->digits, sizeof(uint64_t) * dest.digit_count);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -671,6 +706,8 @@ bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result)
|
|||||||
|
|
||||||
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2)
|
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2)
|
||||||
{
|
{
|
||||||
|
assert(dest != op1);
|
||||||
|
assert(dest != op2);
|
||||||
if (op1->digit_count == 0)
|
if (op1->digit_count == 0)
|
||||||
{
|
{
|
||||||
return bigint_init_bigint(dest, op2);
|
return bigint_init_bigint(dest, op2);
|
||||||
@@ -893,6 +930,8 @@ static void mul_scalar(BigInt *dest, const BigInt *op, uint64_t scalar)
|
|||||||
|
|
||||||
void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2)
|
void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2)
|
||||||
{
|
{
|
||||||
|
assert(dest != op1);
|
||||||
|
assert(dest != op2);
|
||||||
if (op1->digit_count == 0 || op2->digit_count == 0)
|
if (op1->digit_count == 0 || op2->digit_count == 0)
|
||||||
{
|
{
|
||||||
return bigint_init_unsigned(dest, 0);
|
return bigint_init_unsigned(dest, 0);
|
||||||
@@ -1958,6 +1997,7 @@ void bigint_print(BigInt *bigint, uint64_t base)
|
|||||||
|
|
||||||
const char *bigint_to_error_string(Allocator *allocator, const BigInt *bigint, uint64_t base)
|
const char *bigint_to_error_string(Allocator *allocator, const BigInt *bigint, uint64_t base)
|
||||||
{
|
{
|
||||||
|
Set_BigInt_Allocator(allocator);
|
||||||
if (bigint->digit_count == 0)
|
if (bigint->digit_count == 0)
|
||||||
{
|
{
|
||||||
return "0";
|
return "0";
|
||||||
@@ -2021,6 +2061,7 @@ const char *bigint_to_error_string(Allocator *allocator, const BigInt *bigint, u
|
|||||||
*(current++) = *ptr;
|
*(current++) = *ptr;
|
||||||
}
|
}
|
||||||
*(current++) = '\0';
|
*(current++) = '\0';
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1
main.cpp
1
main.cpp
@@ -108,7 +108,6 @@ For now I don't thing it should be overloadable.
|
|||||||
int main(){
|
int main(){
|
||||||
// test_big_int();
|
// test_big_int();
|
||||||
|
|
||||||
|
|
||||||
test_os_memory();
|
test_os_memory();
|
||||||
thread_ctx_init();
|
thread_ctx_init();
|
||||||
test_unicode();
|
test_unicode();
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ function Ast_Atom *
|
|||||||
ast_int(Token *pos, BigInt val){
|
ast_int(Token *pos, BigInt val){
|
||||||
AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM);
|
AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM);
|
||||||
result->type = untyped_int;
|
result->type = untyped_int;
|
||||||
bigint_init_bigint(&result->big_int_val, &val);
|
result->big_int_val = bigint_copy(pctx->perm, &val);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
new_lex.cpp
23
new_lex.cpp
@@ -125,6 +125,7 @@ struct Lex_Stream{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Lexer{
|
struct Lexer{
|
||||||
|
Allocator *arena;
|
||||||
Lex_Stream stream;
|
Lex_Stream stream;
|
||||||
Array<Token> tokens;
|
Array<Token> tokens;
|
||||||
Intern_Table interns;
|
Intern_Table interns;
|
||||||
@@ -205,17 +206,23 @@ token_error(Token *t, String error_val){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function void
|
function void
|
||||||
lex_parse_u64(Token *t){
|
lex_parse_u64(Lexer *lexer, Token *t){
|
||||||
|
Scratch scratch;
|
||||||
|
Set_BigInt_Allocator(scratch);
|
||||||
|
|
||||||
t->kind = TK_Integer;
|
t->kind = TK_Integer;
|
||||||
BigInt m = bigint_u64(1); // @leak, it accumulates and potentially needs allocation
|
BigInt m = bigint_u64(1); // @leak, it accumulates and potentially needs allocation
|
||||||
BigInt val10 = bigint_u64(10);
|
BigInt val10 = bigint_u64(10);
|
||||||
|
BigInt result = bigint_u64(0);
|
||||||
|
|
||||||
for(S64 i = t->len - 1; i >= 0; --i){
|
for(S64 i = t->len - 1; i >= 0; --i){
|
||||||
BigInt val = bigint_u64(t->str[i] - '0'); // I dont think this is a leak, too small
|
BigInt val = bigint_u64(t->str[i] - '0'); // I dont think this is a leak, too small
|
||||||
BigInt new_val = bigint_mul(&val, &m); // @leak
|
BigInt new_val = bigint_mul(&val, &m); // @leak
|
||||||
bigint_add(&t->int_val, &t->int_val, &new_val);
|
result = bigint_add(&result, &new_val); // @leak
|
||||||
bigint_mul(&m, &m, &val10);
|
m = bigint_mul(&m, &val10); // @leak
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t->int_val = bigint_copy(lexer->arena, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
function void
|
function void
|
||||||
@@ -332,7 +339,10 @@ lex_unwind_indent_stack(Token *t, Lex_Stream *s, Array<Token> *array){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function void
|
function void
|
||||||
lex__stream(Intern_Table *table, Array<Token> *array, Lex_Stream *s){
|
lex__stream(Lexer *lexer, Lex_Stream *s){
|
||||||
|
Intern_Table *table = &lexer->interns;
|
||||||
|
Array<Token> *array = &lexer->tokens;
|
||||||
|
|
||||||
B32 beginning = true;
|
B32 beginning = true;
|
||||||
for(;;){
|
for(;;){
|
||||||
if(lexc(s) == 0 || s->iter >= s->stream.len){
|
if(lexc(s) == 0 || s->iter >= s->stream.len){
|
||||||
@@ -594,7 +604,7 @@ lex__stream(Intern_Table *table, Array<Token> *array, Lex_Stream *s){
|
|||||||
}
|
}
|
||||||
lex_set_len(s, &t);
|
lex_set_len(s, &t);
|
||||||
if(found_dot) lex_parse_f64(&t);
|
if(found_dot) lex_parse_f64(&t);
|
||||||
else lex_parse_u64(&t);
|
else lex_parse_u64(lexer, &t);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -633,6 +643,7 @@ lex__stream(Intern_Table *table, Array<Token> *array, Lex_Stream *s){
|
|||||||
|
|
||||||
function void
|
function void
|
||||||
lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){
|
lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){
|
||||||
|
l->arena = token_string_arena;
|
||||||
l->tokens = array_make<Token>(token_string_arena, 1024*2);
|
l->tokens = array_make<Token>(token_string_arena, 1024*2);
|
||||||
l->interns= intern_table_make(token_string_arena, map_allocator, 1024);
|
l->interns= intern_table_make(token_string_arena, map_allocator, 1024);
|
||||||
}
|
}
|
||||||
@@ -657,7 +668,7 @@ lex_restream(Lexer *lexer, String istream, String file){
|
|||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
lexer->stream.indent_stack.allocator = scratch;
|
lexer->stream.indent_stack.allocator = scratch;
|
||||||
lexer->stream.indent_stack.add(&token_null);
|
lexer->stream.indent_stack.add(&token_null);
|
||||||
lex__stream(&lexer->interns, &lexer->tokens, &lexer->stream);
|
lex__stream(lexer, &lexer->stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Lexer
|
function Lexer
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ unary_test :: ()
|
|||||||
// var := -true
|
// var := -true
|
||||||
// var := +true
|
// var := +true
|
||||||
|
|
||||||
binary_test :: ()
|
binary_test :: (thing: S32 = 1051514424242424242442424242424252525252)
|
||||||
int_val :: 1000
|
int_val :: 1000
|
||||||
add :: int_val + 10 + 2.242 + 124
|
add :: int_val + 10 + 2.242 + 124
|
||||||
mul :: 4 * 2
|
mul :: 4 * 2
|
||||||
@@ -30,10 +30,13 @@ binary_test :: ()
|
|||||||
bit_xor :: 8 ^ 7
|
bit_xor :: 8 ^ 7
|
||||||
character :: 'ó
|
character :: 'ó
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
boolean_equals :: true == false
|
boolean_equals :: true == false
|
||||||
boolean_var: Bool = boolean_equals
|
boolean_var: Bool = boolean_equals
|
||||||
|
|
||||||
cast_value :: cast(4242: S32)
|
cast_value :: 4242 + cast(32: S32) + cast(42: S32)
|
||||||
|
value: S32 = cast_value
|
||||||
|
|
||||||
bvar2 := int_val > 1
|
bvar2 := int_val > 1
|
||||||
if int_val < 1
|
if int_val < 1
|
||||||
|
|||||||
145
typecheck.cpp
145
typecheck.cpp
@@ -72,7 +72,7 @@ value_float(BigInt a){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function void
|
function void
|
||||||
check_value_boundaries(Token *pos, Value *a){
|
check_value_bounds(Token *pos, Value *a){
|
||||||
if(!is_int(a->type)) return;
|
if(!is_int(a->type)) return;
|
||||||
|
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
@@ -101,25 +101,77 @@ convert_untyped(Token *pos, Value a, Ast_Resolved_Type *new_type){
|
|||||||
else parsing_error(pos, "Type mismatch when converting from %s to %s", docname(a.type), docname(new_type));
|
else parsing_error(pos, "Type mismatch when converting from %s to %s", docname(a.type), docname(new_type));
|
||||||
|
|
||||||
a.type = new_type;
|
a.type = new_type;
|
||||||
check_value_boundaries(pos, &a);
|
check_value_bounds(pos, &a);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Type resolution cases
|
||||||
|
|
||||||
|
val := expr
|
||||||
|
convert untyped to typed default
|
||||||
|
check bounds
|
||||||
|
make new symbol
|
||||||
|
|
||||||
|
CONST :: expr
|
||||||
|
make new symbol
|
||||||
|
|
||||||
|
call(default:type = expr)
|
||||||
|
val: type = expr
|
||||||
|
convert untyped to typed based on type
|
||||||
|
make sure expr.type == type
|
||||||
|
check bounds
|
||||||
|
|
||||||
|
expr == expr
|
||||||
|
expr * expr
|
||||||
|
make sure compatible types, floats with ints are ok(convert to float)
|
||||||
|
if only one of them is typed convert the untyped to typed
|
||||||
|
if both types typed make sure they are the same
|
||||||
|
check bounds
|
||||||
|
|
||||||
|
!expr
|
||||||
|
make sure correct type
|
||||||
|
return bool
|
||||||
|
|
||||||
|
call(expr, expr)
|
||||||
|
convert untyped to matching typed
|
||||||
|
check if types match
|
||||||
|
|
||||||
|
cast(expr: type)
|
||||||
|
convert from untyped to typed
|
||||||
|
convert between typed to other typed
|
||||||
|
check if types compatible
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
function void
|
function void
|
||||||
match_values(Value *a, Value *b){
|
match_values(Token *pos, Value *a, Value *b){
|
||||||
// @todo: We want match values to convert when int and float => float
|
if(is_typed(a->type) && is_typed(b->type)){
|
||||||
// but also we want to unify types when one of them is typed and other untyped???
|
if(a->type != b->type){
|
||||||
// Lastly maybe check if typed types are the same
|
parsing_error(pos, "Type mismatch in match_values - left: %s right: %s", docname(a->type), docname(b->type));
|
||||||
if(is_int(a->type) && is_float(b->type))
|
}
|
||||||
|
}
|
||||||
|
if(is_untyped(a->type) && is_typed(b->type)){
|
||||||
|
assert(is_typed(b->type));
|
||||||
|
*a = convert_untyped(pos, *a, b->type);
|
||||||
|
}
|
||||||
|
else if(is_typed(a->type) && is_untyped(b->type)){
|
||||||
|
assert(is_typed(a->type));
|
||||||
|
*b = convert_untyped(pos, *b, a->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(is_int(a->type) && is_float(b->type)){
|
||||||
*a = value_float(a->big_int_val);
|
*a = value_float(a->big_int_val);
|
||||||
else if(is_float(a->type) && is_int(b->type))
|
}
|
||||||
|
else if(is_float(a->type) && is_int(b->type)){
|
||||||
*b = value_float(b->big_int_val);
|
*b = value_float(b->big_int_val);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function Value
|
function Value
|
||||||
compare_values(Token *pos, Token_Kind op, Value a, Value b){
|
compare_values(Token *pos, Token_Kind op, Value a, Value b){
|
||||||
if(!(is_numeric(a.type) && is_numeric(b.type))) parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
|
if(!(is_numeric(a.type) && is_numeric(b.type))) parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
|
||||||
match_values(&a, &b);
|
match_values(pos, &a, &b);
|
||||||
|
|
||||||
B32 result = 0;
|
B32 result = 0;
|
||||||
switch(a.type->kind){
|
switch(a.type->kind){
|
||||||
@@ -164,13 +216,13 @@ compare_values(Token *pos, Token_Kind op, Value a, Value b){
|
|||||||
|
|
||||||
function Value
|
function Value
|
||||||
eval_binary(Token *pos, Token_Kind op, Value a, Value b){
|
eval_binary(Token *pos, Token_Kind op, Value a, Value b){
|
||||||
if(!(is_numeric(a.type) && is_numeric(b.type))) parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
|
|
||||||
match_values(&a, &b);
|
|
||||||
|
|
||||||
if(token_is_compare(op)){
|
if(token_is_compare(op)){
|
||||||
return compare_values(pos, op, a, b);
|
return compare_values(pos, op, a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!(is_numeric(a.type) && is_numeric(b.type))) parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
|
||||||
|
match_values(pos, &a, &b);
|
||||||
|
|
||||||
Value result = {};
|
Value result = {};
|
||||||
result.type = a.type;
|
result.type = a.type;
|
||||||
switch(a.type->kind){
|
switch(a.type->kind){
|
||||||
@@ -285,6 +337,29 @@ try_untyping(Operand *op){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
resolve_var(Token *pos, Operand *expr, Ast_Resolved_Type *type = 0){
|
||||||
|
if(type == expr->type) {
|
||||||
|
assert(expr->type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!type)
|
||||||
|
try_untyping(expr);
|
||||||
|
else if(!expr->type)
|
||||||
|
expr->type = type;
|
||||||
|
else if(is_untyped(expr->type))
|
||||||
|
expr->value = convert_untyped(pos, expr->value, type);
|
||||||
|
|
||||||
|
if(type && expr->type != type){
|
||||||
|
parsing_error(pos, "Assigning but incompatible types, expression: %s expected var type: %s", docname(expr->type), docname(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
type_complete(expr->type);
|
||||||
|
check_value_bounds(pos, &expr->value);
|
||||||
|
assert(expr->type);
|
||||||
|
}
|
||||||
|
|
||||||
#define rewrite_into_const(ast,T,s) _rewrite_into_const(ast,sizeof(T),s)
|
#define rewrite_into_const(ast,T,s) _rewrite_into_const(ast,sizeof(T),s)
|
||||||
function void
|
function void
|
||||||
_rewrite_into_const(Ast *node, U64 ast_size, Value value){
|
_rewrite_into_const(Ast *node, U64 ast_size, Value value){
|
||||||
@@ -395,11 +470,7 @@ resolve_lambda(Ast_Lambda *lambda, Sym *sym = 0){
|
|||||||
For(lambda->args){
|
For(lambda->args){
|
||||||
Ast_Resolved_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL);
|
Ast_Resolved_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL);
|
||||||
Operand default_value = resolve_expr(it->default_value, type);
|
Operand default_value = resolve_expr(it->default_value, type);
|
||||||
|
resolve_var(it->pos, &default_value, type);
|
||||||
if(default_value.type){
|
|
||||||
default_value.value = convert_untyped(it->pos, default_value.value, type);
|
|
||||||
if(default_value.type != type) parsing_error(it->pos, "Default value type and type declaration differ, expected %s got instead %s", docname(type), docname(default_value.type));
|
|
||||||
}
|
|
||||||
|
|
||||||
args.add(type);
|
args.add(type);
|
||||||
}
|
}
|
||||||
@@ -422,6 +493,7 @@ resolve_lambda(Ast_Lambda *lambda, Sym *sym = 0){
|
|||||||
For(lambda->args){
|
For(lambda->args){
|
||||||
S64 i = lambda->args.get_index(&it);
|
S64 i = lambda->args.get_index(&it);
|
||||||
Ast_Resolved_Type *type = args[i];
|
Ast_Resolved_Type *type = args[i];
|
||||||
|
|
||||||
sym_var(it->name, type, it, INSERT_INTO_SCOPE);
|
sym_var(it->name, type, it, INSERT_INTO_SCOPE);
|
||||||
}
|
}
|
||||||
For(lambda->block->stmts){
|
For(lambda->block->stmts){
|
||||||
@@ -671,7 +743,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(original_type != type) assert(expr.type == type);
|
if(original_type != type) assert(expr.type == type);
|
||||||
check_value_boundaries(node->pos, &expr.value);
|
check_value_bounds(node->pos, &expr.value);
|
||||||
return expr;
|
return expr;
|
||||||
BREAK();
|
BREAK();
|
||||||
}
|
}
|
||||||
@@ -713,9 +785,10 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
|
|||||||
assert(node->left->kind == AST_IDENT);
|
assert(node->left->kind == AST_IDENT);
|
||||||
|
|
||||||
Operand right = resolve_expr(node->right);
|
Operand right = resolve_expr(node->right);
|
||||||
try_untyping(&right);
|
resolve_var(node->pos, &right);
|
||||||
|
assert(right.type);
|
||||||
|
|
||||||
Ast_Atom *atom = (Ast_Atom *)node->left;
|
auto atom = (Ast_Atom *)node->left;
|
||||||
sym_var(atom->intern_val, right, node, INSERT_INTO_SCOPE);
|
sym_var(atom->intern_val, right, node, INSERT_INTO_SCOPE);
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -822,29 +895,12 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
|
|||||||
else{
|
else{
|
||||||
Operand left = resolve_expr(node->left);
|
Operand left = resolve_expr(node->left);
|
||||||
Operand right = resolve_expr(node->right);
|
Operand right = resolve_expr(node->right);
|
||||||
if(left.is_const && right.is_const){
|
|
||||||
Value value = eval_binary(node->pos, node->op, left.value, right.value);
|
Value value = eval_binary(node->pos, node->op, left.value, right.value);
|
||||||
|
if(left.is_const && right.is_const){
|
||||||
rewrite_into_const(node, Ast_Binary, value);
|
rewrite_into_const(node, Ast_Binary, value);
|
||||||
result = operand_const_rvalue(value);
|
result = operand_const_rvalue(value);
|
||||||
}
|
}
|
||||||
else{
|
else result = operand_rvalue(left.type);
|
||||||
if(is_untyped(left.type)){
|
|
||||||
assert(is_typed(right.type));
|
|
||||||
left.value = convert_untyped(node->pos, left.value, right.type);
|
|
||||||
}
|
|
||||||
else if(is_untyped(right.type)){
|
|
||||||
assert(is_typed(left.type));
|
|
||||||
right.value = convert_untyped(node->pos, right.value, left.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(left.type != right.type){
|
|
||||||
parsing_error(node->pos, "Type mismatch in binary operation %s - left: %s right: %s", name(node->op), docname(left.type), docname(right.type));
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
result = operand_rvalue(left.type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -907,14 +963,8 @@ resolve_binding(Ast *ast, Sym *sym){
|
|||||||
Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL);
|
Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL);
|
||||||
Operand expr = resolve_expr(node->expr, type);
|
Operand expr = resolve_expr(node->expr, type);
|
||||||
assert(expr.type != 0 || type != 0);
|
assert(expr.type != 0 || type != 0);
|
||||||
|
resolve_var(node->pos, &expr, type);
|
||||||
if(!type) try_untyping(&expr);
|
assert(expr.type);
|
||||||
else if(!expr.type) expr.type = type;
|
|
||||||
else if(type == expr.type);
|
|
||||||
else if(is_untyped(expr.type)) expr.value = convert_untyped(node->pos, expr.value, type);
|
|
||||||
else invalid_codepath;
|
|
||||||
|
|
||||||
type_complete(expr.type);
|
|
||||||
return expr;
|
return expr;
|
||||||
BREAK();
|
BREAK();
|
||||||
}
|
}
|
||||||
@@ -945,7 +995,6 @@ resolve_sym(Sym *sym){
|
|||||||
sym->state = SYM_RESOLVING;
|
sym->state = SYM_RESOLVING;
|
||||||
{
|
{
|
||||||
Operand op = resolve_binding(sym->ast, sym);
|
Operand op = resolve_binding(sym->ast, sym);
|
||||||
sym->type = op.type;
|
|
||||||
sym->value = op.value;
|
sym->value = op.value;
|
||||||
}
|
}
|
||||||
sym->state = SYM_RESOLVED;
|
sym->state = SYM_RESOLVED;
|
||||||
|
|||||||
Reference in New Issue
Block a user