aboutsummaryrefslogtreecommitdiff
path: root/src/types.c
diff options
context:
space:
mode:
authorMustafa Quraish <[email protected]>2022-02-02 17:19:15 -0500
committerMustafa Quraish <[email protected]>2022-02-02 17:54:31 -0500
commit55f61417c7d3f6a2f4685e21b7e409ec23b7f41f (patch)
treead5d78d16f3f66046bdac74c2eade63414e55c0c /src/types.c
parentFix examples to include return type on main function (diff)
downloadcup-55f61417c7d3f6a2f4685e21b7e409ec23b7f41f.tar.xz
cup-55f61417c7d3f6a2f4685e21b7e409ec23b7f41f.zip
Move type-related stuff to a separate file
It was getting a bit unwieldy in `parser.c`, and this will potentially help when we start dealing with more complex type-stuff such as casting / conversions / etc.
Diffstat (limited to 'src/types.c')
-rw-r--r--src/types.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/src/types.c b/src/types.c
new file mode 100644
index 0000000..bf855de
--- /dev/null
+++ b/src/types.c
@@ -0,0 +1,186 @@
+#include "parser.h"
+#include "utils.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+
+bool type_equals(Type *a, Type *b)
+{
+ if (a == NULL && b == NULL)
+ return true;
+ if (a == NULL || b == NULL)
+ return false;
+ return a->type == b->type && type_equals(a->ptr, b->ptr);
+}
+
+i64 size_for_type(Type *type)
+{
+ switch (type->type)
+ {
+ case TYPE_INT: return 8;
+ case TYPE_PTR: return 8;
+ default: assert(false && "Unreachable type");
+ }
+}
+
+Type *type_new(DataType type)
+{
+ // For the core types, we don't need to allocate any memory, just
+ // return a pointer to a static instance.
+ static Type type_int = {.type = TYPE_INT, .ptr = NULL};
+ if (type == TYPE_INT) return &type_int;
+
+ Type *self = calloc(sizeof(Type), 1);
+ self->type = type;
+ return self;
+}
+
+static char *data_type_to_str(DataType type)
+{
+ switch (type)
+ {
+ case TYPE_NONE: return "void";
+ case TYPE_INT: return "int";
+ case TYPE_PTR: return "*";
+ default: assert(false && "Unreachable");
+ }
+}
+
+char *type_to_str(Type *type)
+{
+ // FIXME: Handle array types.
+
+ // TODO: This allocates memory and we probably don't want to do that.
+ // TODO: Probably want to increase this size once we have longer types
+ char *str = calloc(sizeof(char), 32);
+ int ptr_count = 0;
+ for (; type->type == TYPE_PTR; type = type->ptr)
+ ptr_count++;
+
+
+ // FIXME: This is inefficient as all hell but this will only really be
+ // used for error reporting.
+ strcat(str, data_type_to_str(type->type));
+ for (int i = 0; i < ptr_count; i++)
+ strcat(str, "*");
+ return str;
+}
+
+Node *handle_unary_expr_types(Node *node, Token *token)
+{
+ Type *old_type = node->unary_expr->expr_type;
+
+ if (node->type == OP_NOT) {
+ node->expr_type = type_new(TYPE_INT);
+ } else if (node->type == OP_ADDROF) {
+ Type *ptr = type_new(TYPE_PTR);
+ ptr->ptr = old_type;
+ node->expr_type = ptr;
+ } else if (node->type == OP_DEREF) {
+ if (old_type->type != TYPE_PTR)
+ die_location(token->loc, "Cannot dereference non-pointer type");
+ node->expr_type = old_type->ptr;
+ } else if (node->type == OP_NEG) {
+ if (old_type->type != TYPE_INT)
+ die_location(token->loc, "Cannot negate non-integer type");
+ node->expr_type = type_new(TYPE_INT);
+ } else {
+ // Default to not changing the type
+ node->expr_type = old_type;
+ }
+ // die_location(token->loc, "Unknown unary expression type in handle_unary_expr_types\n");
+ return node;
+}
+
+Node *handle_binary_expr_types(Node *node, Token *token)
+{
+ Type *left = node->binary.left->expr_type;
+ Type *right = node->binary.right->expr_type;
+
+ switch (node->type)
+ {
+ case OP_PLUS: {
+ if (left->type == TYPE_INT && right->type == TYPE_INT) {
+ node->expr_type = type_new(TYPE_INT);
+ } else if (left->type == TYPE_PTR && right->type == TYPE_INT) {
+ node->expr_type = left;
+ // Pointer arithmetic!
+ Node *mul = Node_new(OP_MUL);
+ mul->binary.left = node->binary.right;
+ mul->binary.right = Node_new(AST_LITERAL);
+ mul->binary.right->literal.type = type_new(TYPE_INT);
+ mul->binary.right->literal.as_int = size_for_type(left->ptr);
+ node->binary.right = mul;
+ } else if (left->type == TYPE_INT && right->type == TYPE_PTR) {
+ node->expr_type = right;
+ // Pointer arithmetic!
+ Node *mul = Node_new(OP_MUL);
+ mul->binary.left = node->binary.left;
+ mul->binary.right = Node_new(AST_LITERAL);
+ mul->binary.right->literal.type = type_new(TYPE_INT);
+ mul->binary.right->literal.as_int = size_for_type(right->ptr);
+ node->binary.left = mul;
+ } else {
+ die_location(token->loc, "Cannot add non-integer types");
+ }
+ } break;
+
+ case OP_MINUS: {
+ if (left->type == TYPE_INT && right->type == TYPE_INT) {
+ node->expr_type = type_new(TYPE_INT);
+ } else if (left->type == TYPE_PTR && right->type == TYPE_INT) {
+ node->expr_type = left;
+ // Pointer arithmetic!
+ Node *mul = Node_new(OP_MUL);
+ mul->binary.left = node->binary.right;
+ mul->binary.right = Node_from_int_literal(size_for_type(left->ptr));
+ node->binary.right = mul;
+ } else if (left->type == TYPE_INT && right->type == TYPE_PTR) {
+ node->expr_type = right;
+ // Pointer arithmetic!
+ Node *mul = Node_new(OP_MUL);
+ mul->binary.left = node->binary.left;
+ mul->binary.right = Node_from_int_literal(size_for_type(right->ptr));
+ node->binary.left = mul;
+ } else if (left->type == TYPE_PTR && right->type == TYPE_PTR) {
+ // TODO: Check for different pointer types
+ node->expr_type = type_new(TYPE_INT);
+ // Divide by size of pointer
+ Node *div = Node_new(OP_DIV);
+ div->binary.left = node;
+ div->binary.right = Node_from_int_literal(size_for_type(left->ptr));
+ div->expr_type = node->expr_type;
+ node = div;
+ } else {
+ die_location(token->loc, "Cannot subtract non-integer types");
+ }
+ } break;
+
+ case OP_DIV:
+ case OP_MOD:
+ case OP_MUL: {
+ if (left->type == TYPE_INT && right->type == TYPE_INT) {
+ node->expr_type = left;
+ } else {
+ die_location(token->loc, "Cannot do operation `%s` non-integer types", node_type_to_str(node->type));
+ }
+ } break;
+
+ case OP_EQ:
+ case OP_NEQ:
+ case OP_LT:
+ case OP_GT:
+ case OP_LEQ:
+ case OP_GEQ:
+ case OP_AND:
+ case OP_OR: {
+ node->expr_type = type_new(TYPE_INT);
+ } break;
+
+ default:
+ die_location(token->loc, "Unknown binary expression type in handle_binary_expr_types\n");
+ }
+ return node;
+}