Managing bigint memory
This commit is contained in:
@@ -3,9 +3,17 @@
|
||||
// a copy of which can be found in the LICENSE file.
|
||||
|
||||
struct Token;
|
||||
Allocator *bigint_allocator;
|
||||
global S64 bigint_allocation_count;
|
||||
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 FATAL_ERROR(x) parsing_error(0, x)
|
||||
|
||||
@@ -95,6 +103,33 @@ bigint_mul(const BigInt *a, const BigInt *b){
|
||||
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)
|
||||
{
|
||||
assert(dest != op1);
|
||||
assert(dest != op2);
|
||||
if (op1->digit_count == 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
assert(dest != op1);
|
||||
assert(dest != op2);
|
||||
if (op1->digit_count == 0 || op2->digit_count == 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)
|
||||
{
|
||||
Set_BigInt_Allocator(allocator);
|
||||
if (bigint->digit_count == 0)
|
||||
{
|
||||
return "0";
|
||||
@@ -2021,6 +2061,7 @@ const char *bigint_to_error_string(Allocator *allocator, const BigInt *bigint, u
|
||||
*(current++) = *ptr;
|
||||
}
|
||||
*(current++) = '\0';
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
1
main.cpp
1
main.cpp
@@ -108,7 +108,6 @@ For now I don't thing it should be overloadable.
|
||||
int main(){
|
||||
// test_big_int();
|
||||
|
||||
|
||||
test_os_memory();
|
||||
thread_ctx_init();
|
||||
test_unicode();
|
||||
|
||||
@@ -319,7 +319,7 @@ function Ast_Atom *
|
||||
ast_int(Token *pos, BigInt val){
|
||||
AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM);
|
||||
result->type = untyped_int;
|
||||
bigint_init_bigint(&result->big_int_val, &val);
|
||||
result->big_int_val = bigint_copy(pctx->perm, &val);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
23
new_lex.cpp
23
new_lex.cpp
@@ -125,6 +125,7 @@ struct Lex_Stream{
|
||||
};
|
||||
|
||||
struct Lexer{
|
||||
Allocator *arena;
|
||||
Lex_Stream stream;
|
||||
Array<Token> tokens;
|
||||
Intern_Table interns;
|
||||
@@ -205,17 +206,23 @@ token_error(Token *t, String error_val){
|
||||
}
|
||||
|
||||
function void
|
||||
lex_parse_u64(Token *t){
|
||||
lex_parse_u64(Lexer *lexer, Token *t){
|
||||
Scratch scratch;
|
||||
Set_BigInt_Allocator(scratch);
|
||||
|
||||
t->kind = TK_Integer;
|
||||
BigInt m = bigint_u64(1); // @leak, it accumulates and potentially needs allocation
|
||||
BigInt val10 = bigint_u64(10);
|
||||
BigInt result = bigint_u64(0);
|
||||
|
||||
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 new_val = bigint_mul(&val, &m); // @leak
|
||||
bigint_add(&t->int_val, &t->int_val, &new_val);
|
||||
bigint_mul(&m, &m, &val10);
|
||||
result = bigint_add(&result, &new_val); // @leak
|
||||
m = bigint_mul(&m, &val10); // @leak
|
||||
}
|
||||
|
||||
t->int_val = bigint_copy(lexer->arena, &result);
|
||||
}
|
||||
|
||||
function void
|
||||
@@ -332,7 +339,10 @@ lex_unwind_indent_stack(Token *t, Lex_Stream *s, Array<Token> *array){
|
||||
}
|
||||
|
||||
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;
|
||||
for(;;){
|
||||
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);
|
||||
if(found_dot) lex_parse_f64(&t);
|
||||
else lex_parse_u64(&t);
|
||||
else lex_parse_u64(lexer, &t);
|
||||
|
||||
} break;
|
||||
|
||||
@@ -633,6 +643,7 @@ lex__stream(Intern_Table *table, Array<Token> *array, Lex_Stream *s){
|
||||
|
||||
function void
|
||||
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->interns= intern_table_make(token_string_arena, map_allocator, 1024);
|
||||
}
|
||||
@@ -657,7 +668,7 @@ lex_restream(Lexer *lexer, String istream, String file){
|
||||
Scratch scratch;
|
||||
lexer->stream.indent_stack.allocator = scratch;
|
||||
lexer->stream.indent_stack.add(&token_null);
|
||||
lex__stream(&lexer->interns, &lexer->tokens, &lexer->stream);
|
||||
lex__stream(lexer, &lexer->stream);
|
||||
}
|
||||
|
||||
function Lexer
|
||||
|
||||
@@ -21,7 +21,7 @@ unary_test :: ()
|
||||
// var := -true
|
||||
// var := +true
|
||||
|
||||
binary_test :: ()
|
||||
binary_test :: (thing: S32 = 1051514424242424242442424242424252525252)
|
||||
int_val :: 1000
|
||||
add :: int_val + 10 + 2.242 + 124
|
||||
mul :: 4 * 2
|
||||
@@ -30,10 +30,13 @@ binary_test :: ()
|
||||
bit_xor :: 8 ^ 7
|
||||
character :: 'ó
|
||||
|
||||
|
||||
|
||||
boolean_equals :: true == false
|
||||
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
|
||||
if int_val < 1
|
||||
|
||||
149
typecheck.cpp
149
typecheck.cpp
@@ -72,7 +72,7 @@ value_float(BigInt a){
|
||||
}
|
||||
|
||||
function void
|
||||
check_value_boundaries(Token *pos, Value *a){
|
||||
check_value_bounds(Token *pos, Value *a){
|
||||
if(!is_int(a->type)) return;
|
||||
|
||||
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));
|
||||
|
||||
a.type = new_type;
|
||||
check_value_boundaries(pos, &a);
|
||||
check_value_bounds(pos, &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
|
||||
match_values(Value *a, Value *b){
|
||||
// @todo: We want match values to convert when int and float => float
|
||||
// but also we want to unify types when one of them is typed and other untyped???
|
||||
// Lastly maybe check if typed types are the same
|
||||
if(is_int(a->type) && is_float(b->type))
|
||||
match_values(Token *pos, Value *a, Value *b){
|
||||
if(is_typed(a->type) && is_typed(b->type)){
|
||||
if(a->type != b->type){
|
||||
parsing_error(pos, "Type mismatch in match_values - left: %s right: %s", docname(a->type), docname(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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
function Value
|
||||
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));
|
||||
match_values(&a, &b);
|
||||
match_values(pos, &a, &b);
|
||||
|
||||
B32 result = 0;
|
||||
switch(a.type->kind){
|
||||
@@ -137,8 +189,8 @@ compare_values(Token *pos, Token_Kind op, Value a, Value b){
|
||||
}break;
|
||||
CASE_BOOL:{
|
||||
switch(op){
|
||||
case TK_Equals: result = a.bool_val == b.bool_val; break;
|
||||
case TK_NotEquals: result = a.bool_val != b.bool_val; break;
|
||||
case TK_Equals: result = a.bool_val == b.bool_val; break;
|
||||
case TK_NotEquals: result = a.bool_val != b.bool_val; break;
|
||||
invalid_default_case;
|
||||
}
|
||||
}break;
|
||||
@@ -164,13 +216,13 @@ compare_values(Token *pos, Token_Kind op, Value a, Value b){
|
||||
|
||||
function Value
|
||||
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)){
|
||||
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 = {};
|
||||
result.type = a.type;
|
||||
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)
|
||||
function void
|
||||
_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){
|
||||
Ast_Resolved_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL);
|
||||
Operand default_value = resolve_expr(it->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));
|
||||
}
|
||||
resolve_var(it->pos, &default_value, type);
|
||||
|
||||
args.add(type);
|
||||
}
|
||||
@@ -422,6 +493,7 @@ resolve_lambda(Ast_Lambda *lambda, Sym *sym = 0){
|
||||
For(lambda->args){
|
||||
S64 i = lambda->args.get_index(&it);
|
||||
Ast_Resolved_Type *type = args[i];
|
||||
|
||||
sym_var(it->name, type, it, INSERT_INTO_SCOPE);
|
||||
}
|
||||
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);
|
||||
check_value_boundaries(node->pos, &expr.value);
|
||||
check_value_bounds(node->pos, &expr.value);
|
||||
return expr;
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -822,29 +895,12 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
|
||||
else{
|
||||
Operand left = resolve_expr(node->left);
|
||||
Operand right = resolve_expr(node->right);
|
||||
Value value = eval_binary(node->pos, node->op, left.value, right.value);
|
||||
if(left.is_const && right.is_const){
|
||||
Value value = eval_binary(node->pos, node->op, left.value, right.value);
|
||||
rewrite_into_const(node, Ast_Binary, value);
|
||||
result = operand_const_rvalue(value);
|
||||
}
|
||||
else{
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
Operand expr = resolve_expr(node->expr, type);
|
||||
assert(expr.type != 0 || type != 0);
|
||||
|
||||
if(!type) try_untyping(&expr);
|
||||
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);
|
||||
resolve_var(node->pos, &expr, type);
|
||||
assert(expr.type);
|
||||
return expr;
|
||||
BREAK();
|
||||
}
|
||||
@@ -945,7 +995,6 @@ resolve_sym(Sym *sym){
|
||||
sym->state = SYM_RESOLVING;
|
||||
{
|
||||
Operand op = resolve_binding(sym->ast, sym);
|
||||
sym->type = op.type;
|
||||
sym->value = op.value;
|
||||
}
|
||||
sym->state = SYM_RESOLVED;
|
||||
|
||||
Reference in New Issue
Block a user