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;
+}
+