diff --git a/ast/ast/ast_types.h b/ast/ast/ast_types.h index 485572d42..39bd1a553 100644 --- a/ast/ast/ast_types.h +++ b/ast/ast/ast_types.h @@ -69,6 +69,11 @@ struct Type { struct TypeParam* type_param; struct ArrayType* array_type; struct PointerType* pointer_type; + + // '#', stands for anything, + // always has highest native width of the architecture, + // e.g. x86: 8 bytes, avr: 2 bytes + bool is_anytype; }; struct TypeParam { diff --git a/ast/test/test_str_ast.c b/ast/test/test_str_ast.c index 3d5c4eb78..b5beecead 100644 --- a/ast/test/test_str_ast.c +++ b/ast/test/test_str_ast.c @@ -104,7 +104,7 @@ void test_ast_str_expr() { char* s = str_expr(&e); - assert(strcmp(s, "-45*-45") == 0); + assert(strcmp(s, "-45 * -45") == 0); free_un_op_term(u2); free(s); diff --git a/ast/util/copy_ast.c b/ast/util/copy_ast.c index 3b73429cb..b3efdb44a 100644 --- a/ast/util/copy_ast.c +++ b/ast/util/copy_ast.c @@ -179,6 +179,7 @@ struct Type* copy_type(struct Type* t) { res->type_param = NULL; res->array_type = NULL; res->pointer_type = NULL; + res->is_anytype = t->is_anytype; if (t->basic_type != NULL) { res->basic_type = copy_basic_type(t->basic_type); } if (t->type_param != NULL) { res->type_param = copy_type_param(t->type_param); } diff --git a/ast/util/equals_ast.c b/ast/util/equals_ast.c index 454cf3027..6fecf7225 100644 --- a/ast/util/equals_ast.c +++ b/ast/util/equals_ast.c @@ -17,6 +17,10 @@ bool eq_type(struct Type* a, struct Type* b) { if (a->pointer_type != NULL) { return eq_pointertype(a->pointer_type, b->pointer_type); } + if (a->is_anytype && b->is_anytype) { + return true; + } + return false; } diff --git a/ast/util/str_ast.c b/ast/util/str_ast.c index 067ed4ebb..1ebe79c1d 100644 --- a/ast/util/str_ast.c +++ b/ast/util/str_ast.c @@ -293,6 +293,10 @@ char* str_type(struct Type* t) { if (t->pointer_type != NULL) { return str_pointer_type(t->pointer_type); } + if (t->is_anytype) { + return strdup("#"); + } + error("str_type"); return NULL; } @@ -494,7 +498,7 @@ char* str_expr(struct Expr* e) { return NULL; } - uint16_t l = strlen(strTerm1) + strlen(strO) + strlen(strTerm2) + 1; + uint16_t l = strlen(strTerm1) + strlen(strO) + strlen(strTerm2) + 3; char* res = malloc(sizeof(char) * l); @@ -502,7 +506,7 @@ char* str_expr(struct Expr* e) { return NULL; } - sprintf(res, "%s%s%s", strTerm1, strO, strTerm2); + sprintf(res, "%s %s %s", strTerm1, strO, strTerm2); free(strTerm1); @@ -512,6 +516,7 @@ char* str_expr(struct Expr* e) { return res; } +// @returns NULL on error char* str_op(enum OP o) { char* res = malloc(sizeof(char) * 16); @@ -533,8 +538,18 @@ char* str_op(enum OP o) { case OP_OR: str = "|"; break; case OP_XOR: str = "^"; break; + // relational + case OP_EQ: str = "=="; break; + case OP_NEQ: str = "!="; break; + case OP_GE: str = ">="; break; + case OP_GT: str = ">"; break; + case OP_LE: str = "<="; break; + case OP_LT: str = "<"; break; + //should not happen - default: str = "fix str_op"; break; + default: + free(res); + return NULL; } sprintf(res, "%s", str); diff --git a/compiler/main/typechecker/tc_ifstmt.c b/compiler/main/typechecker/tc_ifstmt.c index 3a53bfda9..ecb270930 100644 --- a/compiler/main/typechecker/tc_ifstmt.c +++ b/compiler/main/typechecker/tc_ifstmt.c @@ -35,6 +35,12 @@ bool tc_ifstmt(struct IfStmt* i, struct TCCtx* tcctx) { error_snippet(tcctx, msg, TC_ERR_CONDITION_REQUIRES_BOOL); + char* s2 = str_type(type); + + fprintf(stderr, "actual type: %s\n\n", s2); + + free(s2); + free(msg); return false; diff --git a/compiler/main/typechecker/tc_retstmt.c b/compiler/main/typechecker/tc_retstmt.c index 83a18ce0e..0da25685f 100644 --- a/compiler/main/typechecker/tc_retstmt.c +++ b/compiler/main/typechecker/tc_retstmt.c @@ -11,6 +11,7 @@ //Typechecker Includes #include "_tc.h" +#include "typechecker/type_contains/tc_type_contains.h" #include "typechecker/util/tc_errors.h" #include "typechecker/util/tc_utils.h" #include "tcctx.h" @@ -31,7 +32,7 @@ bool tc_retstmt(struct RetStmt* r, struct TCCtx* tcctx) { if (is_integer_type(returnType) && is_integer_type(returnedType)) { return true; } - if (!eq_type(returnType, returnedType)) { + if (!tc_type_contains(returnType, returnedType)) { char* s1 = str_type(returnType); char* s2 = str_type(returnedType); diff --git a/compiler/main/typechecker/type_contains/tc_pointertype_contains.c b/compiler/main/typechecker/type_contains/tc_pointertype_contains.c index 8e4fa2bd7..3b495b19c 100644 --- a/compiler/main/typechecker/type_contains/tc_pointertype_contains.c +++ b/compiler/main/typechecker/type_contains/tc_pointertype_contains.c @@ -22,5 +22,5 @@ bool tc_pointer_type_contains(struct PointerType* expect, struct Type* actual) { struct PointerType* apt = actual->pointer_type; // pointers of same underlying type can be assigned to each other - return eq_type(expect->element_type, apt->element_type); + return tc_type_contains(expect->element_type, apt->element_type); } diff --git a/compiler/main/typechecker/type_contains/tc_type_contains.c b/compiler/main/typechecker/type_contains/tc_type_contains.c index 9e7baf351..f48a123fb 100644 --- a/compiler/main/typechecker/type_contains/tc_type_contains.c +++ b/compiler/main/typechecker/type_contains/tc_type_contains.c @@ -9,6 +9,10 @@ bool tc_type_contains(struct Type* expect, struct Type* actual) { + if (expect->is_anytype || actual->is_anytype) { + return true; + } + if (expect->pointer_type != NULL) { return tc_pointer_type_contains(expect->pointer_type, actual); diff --git a/compiler/main/typeinference/typeinfer_expr.c b/compiler/main/typeinference/typeinfer_expr.c index 8f4e851b7..ef7a6e8d4 100644 --- a/compiler/main/typeinference/typeinfer_expr.c +++ b/compiler/main/typeinference/typeinfer_expr.c @@ -21,7 +21,7 @@ static struct Type* infer_type_expr_primitive(struct ST* st, struct Expr2Types* static struct Type* infer_type_expr_both_tparam(struct ST* st, struct TypeParam* tp1, enum OP op, struct TypeParam* tp2); -static struct Type* infer_type_expr_ptr_arithmetic(struct ST* st, struct Type* t1, struct Type* t2); +static struct Type* infer_type_expr_ptr_arithmetic(struct ST* st, struct Type* t1, struct Type* t2, enum OP op); static void typeinfer_err_fatal(char* opt_str) { fprintf(stderr, "%s\n", opt_str); @@ -44,10 +44,10 @@ struct Type* infer_type_expr(struct ST* st, struct Expr* expr) { } if (type1->pointer_type) { - return infer_type_expr_ptr_arithmetic(st, type1, type2); + return infer_type_expr_ptr_arithmetic(st, type1, type2, op); } if (type2->pointer_type) { - return infer_type_expr_ptr_arithmetic(st, type2, type1); + return infer_type_expr_ptr_arithmetic(st, type2, type1, op); } struct BasicType* btw1 = type1->basic_type; @@ -82,7 +82,7 @@ struct Type* infer_type_expr(struct ST* st, struct Expr* expr) { return infer_type_expr_primitive(st, &e2t); } -static struct Type* infer_type_expr_ptr_arithmetic(struct ST* st, struct Type* t1, struct Type* t2) { +static struct Type* infer_type_expr_ptr_arithmetic(struct ST* st, struct Type* t1, struct Type* t2, enum OP op) { struct PointerType* pt = t1->pointer_type; @@ -91,10 +91,22 @@ static struct Type* infer_type_expr_ptr_arithmetic(struct ST* st, struct Type* t return NULL; } + if (t2->pointer_type) { + if (op == OP_EQ || op == OP_NEQ || op == OP_GE || op == OP_GT || op == OP_LE || op == OP_LT) { + return typeFromStrPrimitive(st, "bool"); + } + } + if (t2->basic_type && t2->basic_type->simple_type) { - struct SimpleType* st = t2->basic_type->simple_type; + struct SimpleType* stype = t2->basic_type->simple_type; + + if (stype->primitive_type && stype->primitive_type->is_int_type) { + + if (op == OP_EQ || op == OP_NEQ || op == OP_GE || op == OP_GT || op == OP_LE || op == OP_LT) { + + return typeFromStrPrimitive(st, "bool"); + } - if (st->primitive_type && st->primitive_type->is_int_type) { return t1; } } diff --git a/docs/html/grammar.html b/docs/html/grammar.html index 0be27804a..954136fd1 100644 --- a/docs/html/grammar.html +++ b/docs/html/grammar.html @@ -60,7 +60,7 @@

Method

Types

- Type ::= BasicType | TypeParam | ArrayType | PointerType + Type ::= BasicType | TypeParam | ArrayType | PointerType | #

BasicType ::= SimpleType | '(' SubrType ')' @@ -78,7 +78,7 @@

Types

SubrType ::= '(' Type* ')' arrow Type

- StructType ::= uppercase alphanumeric* | "#" + StructType ::= uppercase alphanumeric*

TypeParam ::= "?T" digit diff --git a/examples/stdlib/base/allocator/alloc_0_bytes/alloc_0_bytes.dg b/examples/stdlib/base/allocator/alloc_0_bytes/alloc_0_bytes.dg new file mode 100644 index 000000000..2bced2290 --- /dev/null +++ b/examples/stdlib/base/allocator/alloc_0_bytes/alloc_0_bytes.dg @@ -0,0 +1,13 @@ + +fn main () -> int { + + local *uint8 ptr; + + ptr = malloc(0); + + if ptr != 0 { + return 1; + } + + return 0; +} diff --git a/examples/stdlib/base/allocator/alloc_0_bytes/alloc_0_bytes.exitcode b/examples/stdlib/base/allocator/alloc_0_bytes/alloc_0_bytes.exitcode new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/examples/stdlib/base/allocator/alloc_0_bytes/alloc_0_bytes.exitcode @@ -0,0 +1 @@ +0 diff --git a/examples/stdlib/base/allocator/alloc_0_bytes/alloc_0_bytes.stdlib b/examples/stdlib/base/allocator/alloc_0_bytes/alloc_0_bytes.stdlib new file mode 100644 index 000000000..e69de29bb diff --git a/examples/stdlib/base/allocator/loop_test/loop_test.dg b/examples/stdlib/base/allocator/loop_test/loop_test.dg new file mode 100644 index 000000000..580231e63 --- /dev/null +++ b/examples/stdlib/base/allocator/loop_test/loop_test.dg @@ -0,0 +1,20 @@ + +fn main () -> int { + + // test that the allocations do not exhaus memory + + for i in 0 .. 10000 { + + *uint64 p = malloc(3000); + + if p == 0 { + return 1; + } + + if free(p) != 0 { + return 1; + } + } + + return 0; +} diff --git a/examples/stdlib/base/allocator/loop_test/loop_test.exitcode b/examples/stdlib/base/allocator/loop_test/loop_test.exitcode new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/examples/stdlib/base/allocator/loop_test/loop_test.exitcode @@ -0,0 +1 @@ +0 diff --git a/examples/stdlib/base/allocator/loop_test/loop_test.stdlib b/examples/stdlib/base/allocator/loop_test/loop_test.stdlib new file mode 100644 index 000000000..e69de29bb diff --git a/examples/stdlib/base/allocator/no_overlap/no_overlap.dg b/examples/stdlib/base/allocator/no_overlap/no_overlap.dg new file mode 100644 index 000000000..fa34e7e1d --- /dev/null +++ b/examples/stdlib/base/allocator/no_overlap/no_overlap.dg @@ -0,0 +1,19 @@ + +fn main () -> int { + + *uint64 ptr1 = malloc(30); + *uint64 ptr2 = malloc(30); + + if ((ptr1 + 30) > ptr2 && (ptr1 <= ptr2)){ + return 1; + } + + if ((ptr2 + 30) > ptr1 && (ptr2 <= ptr1)){ + return 1; + } + + free(ptr1); + free(ptr2); + + return 0; +} diff --git a/examples/stdlib/base/allocator/no_overlap/no_overlap.exitcode b/examples/stdlib/base/allocator/no_overlap/no_overlap.exitcode new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/examples/stdlib/base/allocator/no_overlap/no_overlap.exitcode @@ -0,0 +1 @@ +0 diff --git a/examples/stdlib/base/allocator/no_overlap/no_overlap.stdlib b/examples/stdlib/base/allocator/no_overlap/no_overlap.stdlib new file mode 100644 index 000000000..e69de29bb diff --git a/examples/stdlib/base/allocator/realloc_test/realloc_test.dg b/examples/stdlib/base/allocator/realloc_test/realloc_test.dg new file mode 100644 index 000000000..eabae2c33 --- /dev/null +++ b/examples/stdlib/base/allocator/realloc_test/realloc_test.dg @@ -0,0 +1,35 @@ + +fn main () -> int { + + *uint8 p1 = malloc(4096); + + if p1 == 0 { + return 1; + } + + *p1 = 9; + + *uint8 p2 = realloc(p1, 8192); + + if p2 == 0 { + return 2; + } + + if *p2 != 9 { + return 3; + } + + if p1 == p2 { + // it should not re-use that block, it is too small + return 4; + } + + *uint8 p3 = realloc(p2, 4096); + + if p3 != p2 { + // it should re-use the block, it is big enough + return 5; + } + + return 0; +} diff --git a/examples/stdlib/base/allocator/realloc_test/realloc_test.exitcode b/examples/stdlib/base/allocator/realloc_test/realloc_test.exitcode new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/examples/stdlib/base/allocator/realloc_test/realloc_test.exitcode @@ -0,0 +1 @@ +0 diff --git a/examples/stdlib/base/allocator/realloc_test/realloc_test.stdlib b/examples/stdlib/base/allocator/realloc_test/realloc_test.stdlib new file mode 100644 index 000000000..e69de29bb diff --git a/examples/stdlib/base/allocator/use_allocator/use_allocator.dg b/examples/stdlib/base/allocator/use_allocator/use_allocator.dg new file mode 100644 index 000000000..ad1af6f63 --- /dev/null +++ b/examples/stdlib/base/allocator/use_allocator/use_allocator.dg @@ -0,0 +1,34 @@ + +fn main () -> int { + + local *uint8 ptr; + + ptr = malloc(329); + + if ptr == 0 { + return 2; + } + + free(ptr); + + ptr = malloc(8349); + + if ptr == 0 { + return 3; + } + + local *uint8 p; + p = ptr; + + p += 100; + *p = 84; + p += 10; + *p = 92; + p -= 10; + + uint8 res = *p; + + free(ptr); + + return res; +} diff --git a/examples/stdlib/base/allocator/use_allocator/use_allocator.exitcode b/examples/stdlib/base/allocator/use_allocator/use_allocator.exitcode new file mode 100644 index 000000000..871727de1 --- /dev/null +++ b/examples/stdlib/base/allocator/use_allocator/use_allocator.exitcode @@ -0,0 +1 @@ +84 diff --git a/examples/stdlib/base/allocator/use_allocator/use_allocator.stdlib b/examples/stdlib/base/allocator/use_allocator/use_allocator.stdlib new file mode 100644 index 000000000..e69de29bb diff --git a/parser/main/astnodes/types/SimpleType.c b/parser/main/astnodes/types/SimpleType.c index 77bc16dfc..fe07aa3f9 100644 --- a/parser/main/astnodes/types/SimpleType.c +++ b/parser/main/astnodes/types/SimpleType.c @@ -48,8 +48,6 @@ struct SimpleType* makeSimpleType(struct TokenList* tokens) { break; case TYPEID: - case ANYTYPE: - res->struct_type = makeStructType(copy); break; diff --git a/parser/main/astnodes/types/Type.c b/parser/main/astnodes/types/Type.c index a894a0e8e..ff5a8e978 100644 --- a/parser/main/astnodes/types/Type.c +++ b/parser/main/astnodes/types/Type.c @@ -73,6 +73,7 @@ struct Type* makeType2(struct TokenList* tokens) { res->type_param = NULL; res->array_type = NULL; res->pointer_type = NULL; + res->is_anytype = false; struct Token* head = list_head(copy); @@ -89,6 +90,10 @@ struct Type* makeType2(struct TokenList* tokens) { res->type_param = makeTypeParam(copy); if (res->type_param != NULL) { goto end; } break; + case ANYTYPE: + list_consume(copy, 1); + res->is_anytype = true; + goto end; default: res->basic_type = makeBasicType2(copy); if (res->basic_type != NULL) { goto end; } diff --git a/parser/test/astnodes/types/SimpleTypeTest.c b/parser/test/astnodes/types/SimpleTypeTest.c index 43f9d850b..300c6e515 100644 --- a/parser/test/astnodes/types/SimpleTypeTest.c +++ b/parser/test/astnodes/types/SimpleTypeTest.c @@ -8,6 +8,7 @@ #include "types/SimpleType.h" #include "types/BasicType.h" +#include "types/Type.h" #include "token/list/TokenList.h" #include "token/TokenKeys.h" @@ -56,13 +57,14 @@ int simpletype_test_typenode_parsing_anytype() { struct TokenList* list = makeTokenList(); list_add(list, makeToken2(ANYTYPE, "#")); - struct SimpleType* node = makeSimpleType(list); + struct Type* node = makeType2(list); assert(0 == list_size(list)); assert(node != NULL); + assert(node->is_anytype); freeTokenList(list); - free_simple_type(node); + free_type(node); return 1; } diff --git a/stdlib/base/allocator.dg b/stdlib/base/allocator.dg new file mode 100644 index 000000000..f3d15aed9 --- /dev/null +++ b/stdlib/base/allocator.dg @@ -0,0 +1,108 @@ + +// This is a really bad allocator. +// It allocates in multiples of page size. + +fn malloc(uint64 nbytes) -> *# { + + // PROT_READ = 0x1 + // PROT_WRITE = 0x2 + + // MAP_SHARED = 0x1 + // MAP_ANONYMOUS = 0x20 + + if nbytes == 0 { + return 0; + } + + uint64 n = 4096; + uint64 npages = 1; + + while n < nbytes { + n += 4096; + npages++; + } + + local *uint64 ptr; + ptr = mmap(0, n, 0x3, 0x21, -1, 0); + + // preserve number of bytes for calling munmap later + *ptr = n; + + return ptr + 16; +} + +// @returns 0 on success +fn free(*# ptr) -> int { + + *uint64 p = ptr; + + if p == 0 { + return -1; + } + + // obtain the real address + p -= 16; + + uint64 nbytes = *p; + + return munmap(p, nbytes); +} + +fn realloc(*# ptr, uint64 nbytes) -> *# { + + if ptr == 0 { + return malloc(nbytes); + } + + if nbytes == 0 { + free(ptr); + return 0; + } + + *uint64 p = ptr; + p -= 16; + uint64 old_size = *p; + + uint64 n = 4096; + uint64 npages = 1; + while n < nbytes { + n += 4096; + npages++; + } + + if (n <= old_size) { + return ptr; + } + + local *uint64 new_ptr; + new_ptr = malloc(nbytes); + + if new_ptr == 0 { + return 0; + } + + uint64 copy_size = old_size - 16; + if (copy_size > nbytes) { + copy_size = nbytes; + } + + local *# dst; + dst = new_ptr; + local *uint8 src; + src = ptr; + + *uint8 d = dst; + + uint64 i = 0; + while i < copy_size { + *d = *src; + d++; + src++; + i++; + } + + free(ptr); + + return dst; +} +