diff --git a/codegen.c b/codegen.c index 7220d49..552bb77 100644 --- a/codegen.c +++ b/codegen.c @@ -447,72 +447,240 @@ void gen_expr(FILE *fp, ast_node *expr) gen_expr(fp, expr->expr.cast.value); break; case NODE_VAR_DECL: { - int offset; - if (expr->expr.var_decl.type && expr->expr.var_decl.type->expr_type) { - usize var_size = expr->expr.var_decl.type->expr_type->size; - offset = get_var_offset_sized(expr->expr.var_decl.name, - expr->expr.var_decl.name_len, var_size); - } else { - offset = get_var_offset(expr->expr.var_decl.name, expr->expr.var_decl.name_len); + int offset = 0; + type *var_type = expr->expr_type; + if (!var_type && expr->expr.var_decl.type) { + var_type = expr->expr.var_decl.type->expr_type; + } + + bool is_inline_slice = false; + if (var_type && var_type->tag == TYPE_SLICE && expr->expr.var_decl.value && + (expr->expr.var_decl.value->type == NODE_STRUCT_INIT || + expr->expr.var_decl.value->type == NODE_RANGE)) { + is_inline_slice = true; + } + + if (!is_inline_slice) { + if (var_type && var_type->size > 0) { + offset = get_var_offset_sized(expr->expr.var_decl.name, + expr->expr.var_decl.name_len, var_type->size); + } else { + offset = get_var_offset(expr->expr.var_decl.name, expr->expr.var_decl.name_len); + } } if (expr->expr.var_decl.value) { - if (expr->expr.var_decl.value->type == NODE_STRUCT_INIT) { + if (expr->expr.var_decl.value->type == NODE_RANGE && var_type && var_type->tag == TYPE_SLICE) { + ast_node *range = expr->expr.var_decl.value; + if (range->expr.binary.left->type == NODE_INTEGER && + range->expr.binary.right->type == NODE_INTEGER) { + i64 start = range->expr.binary.left->expr.integer; + i64 end = range->expr.binary.right->expr.integer; + i64 count = end - start + 1; + + type *element_type = var_type->data.slice.child; + usize element_size = element_type ? element_type->size : 8; + + usize data_size = count * element_size; + usize aligned_data_size = (data_size + 7) & ~7; + stack_offset += aligned_data_size; + int data_offset = stack_offset; + + stack_offset += 16; + offset = stack_offset; + + char *var_name = strndup(expr->expr.var_decl.name, expr->expr.var_decl.name_len); + shput(variables, var_name, offset); + + for (i64 i = 0; i < count; i++) { + i64 value = start + i; + int element_offset = data_offset - (i * element_size); + fprintf(fp, "mov $%ld, %%rax\n", value); + if (element_size == 4) { + fprintf(fp, "mov %%eax, -%d(%%rbp)\n", element_offset); + } else if (element_size == 2) { + fprintf(fp, "mov %%ax, -%d(%%rbp)\n", element_offset); + } else if (element_size == 1) { + fprintf(fp, "mov %%al, -%d(%%rbp)\n", element_offset); + } else { + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", element_offset); + } + } + + fprintf(fp, "lea -%d(%%rbp), %%rax\n", data_offset); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + fprintf(fp, "mov $%ld, %%rax\n", count); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset - 8); + } + } else if (expr->expr.var_decl.value->type == NODE_STRING && var_type && var_type->tag == TYPE_SLICE) { + ast_node *str = expr->expr.var_decl.value; + usize str_len = str->expr.string.len; + char *str_data = str->expr.string.start; + + usize aligned_data_size = (str_len + 7) & ~7; + stack_offset += aligned_data_size; + int data_offset = stack_offset; + + stack_offset += 16; + offset = stack_offset; + + char *var_name = strndup(expr->expr.var_decl.name, expr->expr.var_decl.name_len); + shput(variables, var_name, offset); + + for (usize i = 0; i < str_len; i++) { + int byte_offset = data_offset - i; + if ((unsigned char)str_data[i] == '\\' && (unsigned char)str_data[i+1] == 'n') { + fprintf(fp, "movb $%d, -%d(%%rbp)\n", (unsigned char)'\n', byte_offset); + i += 1; + } else { + fprintf(fp, "movb $%d, -%d(%%rbp)\n", (unsigned char)str_data[i], byte_offset); + } + } + + fprintf(fp, "lea -%d(%%rbp), %%rax\n", data_offset); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + fprintf(fp, "mov $%lu, %%rax\n", str_len); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset - 8); + } else if (expr->expr.var_decl.value->type == NODE_STRUCT_INIT) { ast_node *member_list = expr->expr.var_decl.value->expr.struct_init.members; ast_node *current = member_list; - type *struct_type = expr->expr_type; - if (!struct_type && expr->expr.var_decl.type) { - struct_type = expr->expr.var_decl.type->expr_type; - } + if (var_type && var_type->tag == TYPE_STRUCT) { + while (current && current->type == NODE_UNIT) { + ast_node *assignment = current->expr.unit_node.expr; + if (assignment && assignment->type == NODE_BINARY && + assignment->expr.binary.operator == OP_ASSIGN) { + ast_node *field = assignment->expr.binary.left; + ast_node *value = assignment->expr.binary.right; - while (current && current->type == NODE_UNIT) { - ast_node *assignment = current->expr.unit_node.expr; - if (assignment && assignment->type == NODE_BINARY && - assignment->expr.binary.operator == OP_ASSIGN) { - ast_node *field = assignment->expr.binary.left; - ast_node *value = assignment->expr.binary.right; + if (field->type == NODE_IDENTIFIER) { + char *field_name = strndup(field->expr.string.start, + field->expr.string.len); - if (field->type == NODE_IDENTIFIER && struct_type && - struct_type->tag == TYPE_STRUCT) { - char *field_name = strndup(field->expr.string.start, - field->expr.string.len); - - member *m = struct_type->data.structure.members; - int field_offset = -1; - while (m) { - if (m->name_len == field->expr.string.len && - strncmp(m->name, field->expr.string.start, m->name_len) == 0) { - field_offset = m->offset; - break; + member *m = var_type->data.structure.members; + int field_offset = -1; + while (m) { + if (m->name_len == field->expr.string.len && + strncmp(m->name, field->expr.string.start, m->name_len) == 0) { + field_offset = m->offset; + break; + } + m = m->next; } - m = m->next; - } - if (field_offset >= 0) { + if (field_offset >= 0) { + gen_expr(fp, value); + + type *field_type = shget(var_type->data.structure.member_types, field_name); + + if (field_type && field_type->size == 4) { + fprintf(fp, "mov %%eax, -%d(%%rbp)\n", offset + field_offset); + } else if (field_type && field_type->size == 2) { + fprintf(fp, "mov %%ax, -%d(%%rbp)\n", offset + field_offset); + } else if (field_type && field_type->size == 1) { + fprintf(fp, "mov %%al, -%d(%%rbp)\n", offset + field_offset); + } else { + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset + field_offset); + } + } + + free(field_name); + } + } + current = current->expr.unit_node.next; + } + } + else if (var_type && (var_type->tag == TYPE_PTR || var_type->tag == TYPE_SLICE)) { + usize element_size = 8; + type *element_type = NULL; + + if (var_type->tag == TYPE_PTR && var_type->data.ptr.child) { + element_type = var_type->data.ptr.child; + element_size = element_type->size; + } else if (var_type->tag == TYPE_SLICE && var_type->data.slice.child) { + element_type = var_type->data.slice.child; + element_size = element_type->size; + } + + int element_count = 0; + ast_node *count_node = current; + while (count_node && count_node->type == NODE_UNIT) { + element_count++; + count_node = count_node->expr.unit_node.next; + } + if (var_type->tag == TYPE_SLICE) { + usize data_size = element_count * element_size; + usize aligned_data_size = (data_size + 7) & ~7; + stack_offset += aligned_data_size; + int data_offset = stack_offset; + stack_offset += 16; + offset = stack_offset; + + char *var_name = strndup(expr->expr.var_decl.name, expr->expr.var_decl.name_len); + shput(variables, var_name, offset); + + int index = 0; + while (current && current->type == NODE_UNIT) { + ast_node *value = current->expr.unit_node.expr; + if (value) { gen_expr(fp, value); - type *field_type = shget(struct_type->data.structure.member_types, field_name); + int element_offset = data_offset - (index * element_size); - if (field_type && field_type->size == 4) { - fprintf(fp, "mov %%eax, -%d(%%rbp)\n", offset + field_offset); - } else if (field_type && field_type->size == 2) { - fprintf(fp, "mov %%ax, -%d(%%rbp)\n", offset + field_offset); - } else if (field_type && field_type->size == 1) { - fprintf(fp, "mov %%al, -%d(%%rbp)\n", offset + field_offset); + if (element_type && element_type->size == 4) { + fprintf(fp, "mov %%eax, -%d(%%rbp)\n", element_offset); + } else if (element_type && element_type->size == 2) { + fprintf(fp, "mov %%ax, -%d(%%rbp)\n", element_offset); + } else if (element_type && element_type->size == 1) { + fprintf(fp, "mov %%al, -%d(%%rbp)\n", element_offset); } else { - fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset + field_offset); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", element_offset); } } + index++; + current = current->expr.unit_node.next; + } - free(field_name); + fprintf(fp, "lea -%d(%%rbp), %%rax\n", data_offset); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + fprintf(fp, "mov $%d, %%rax\n", element_count); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset - 8); + } else { + int index = 0; + while (current && current->type == NODE_UNIT) { + ast_node *value = current->expr.unit_node.expr; + if (value) { + gen_expr(fp, value); + + int element_offset = offset + (index * element_size); + + if (element_type && element_type->size == 4) { + fprintf(fp, "mov %%eax, -%d(%%rbp)\n", element_offset); + } else if (element_type && element_type->size == 2) { + fprintf(fp, "mov %%ax, -%d(%%rbp)\n", element_offset); + } else if (element_type && element_type->size == 1) { + fprintf(fp, "mov %%al, -%d(%%rbp)\n", element_offset); + } else { + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", element_offset); + } + } + index++; + current = current->expr.unit_node.next; } } - current = current->expr.unit_node.next; } } else { gen_expr(fp, expr->expr.var_decl.value); - fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + + // If assigning a slice value, copy the 16-byte structure + if (var_type && var_type->tag == TYPE_SLICE) { + fprintf(fp, "mov (%%rax), %%rcx\n"); // Load ptr field + fprintf(fp, "mov 8(%%rax), %%rdx\n"); // Load len field + fprintf(fp, "mov %%rcx, -%d(%%rbp)\n", offset); // Store ptr + fprintf(fp, "mov %%rdx, -%d(%%rbp)\n", offset - 8); // Store len + } else { + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + } } } break; @@ -598,12 +766,24 @@ void gen_expr(FILE *fp, ast_node *expr) if (base->type == NODE_IDENTIFIER) { int base_offset = get_var_offset(base->expr.string.start, base->expr.string.len); + type *base_type = base->expr_type; - type *struct_type = base->expr_type; + if (base_type && base_type->tag == TYPE_SLICE && member_node->type == NODE_IDENTIFIER) { + char *field_name = strndup(member_node->expr.string.start, member_node->expr.string.len); - if (member_node->type == NODE_IDENTIFIER && struct_type && - struct_type->tag == TYPE_STRUCT) { - member *m = struct_type->data.structure.members; + if (strcmp(field_name, "ptr") == 0) { + fprintf(fp, "mov -%d(%%rbp), %%rax\n", base_offset); + } else if (strcmp(field_name, "len") == 0) { + fprintf(fp, "mov -%d(%%rbp), %%rax\n", base_offset - 8); + } else { + fprintf(fp, "# ERROR: slice field '%s' not found\n", field_name); + } + + free(field_name); + } + else if (member_node->type == NODE_IDENTIFIER && base_type && + base_type->tag == TYPE_STRUCT) { + member *m = base_type->data.structure.members; int field_offset = -1; while (m) { if (m->name_len == member_node->expr.string.len && @@ -620,17 +800,165 @@ void gen_expr(FILE *fp, ast_node *expr) fprintf(fp, "# ERROR: field not found\n"); } } else { - fprintf(fp, "# ERROR: not a struct type\n"); + fprintf(fp, "# ERROR: not a struct or slice type\n"); } } else { fprintf(fp, "# ERROR: complex struct access not implemented\n"); } break; } + case NODE_RANGE: { + if (expr->expr.binary.left->type == NODE_INTEGER && + expr->expr.binary.right->type == NODE_INTEGER) { + i64 start = expr->expr.binary.left->expr.integer; + i64 end = expr->expr.binary.right->expr.integer; + i64 count = end - start + 1; + + usize element_size = 8; + usize data_size = count * element_size; + usize aligned_data_size = (data_size + 7) & ~7; + stack_offset += aligned_data_size; + int data_offset = stack_offset; + + for (i64 i = 0; i < count; i++) { + i64 value = start + i; + int element_offset = data_offset - (i * element_size); + fprintf(fp, "mov $%ld, %%rax\n", value); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", element_offset); + } + + stack_offset += 16; + int slice_offset = stack_offset; + + fprintf(fp, "lea -%d(%%rbp), %%rax\n", data_offset); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", slice_offset); + fprintf(fp, "mov $%ld, %%rax\n", count); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", slice_offset - 8); + + fprintf(fp, "lea -%d(%%rbp), %%rax\n", slice_offset); + } else { + fprintf(fp, "# ERROR: range expression requires constant bounds\n"); + } + break; + } case NODE_STRUCT_INIT: { fprintf(fp, "# ERROR: struct init outside of variable declaration\n"); break; } + case NODE_ARRAY_SUBSCRIPT: { + usize element_size = 8; + type *base_type = expr->expr.subscript.expr->expr_type; + bool is_slice = false; + + if (base_type) { + if (base_type->tag == TYPE_PTR && base_type->data.ptr.child) { + element_size = base_type->data.ptr.child->size; + } else if (base_type->tag == TYPE_SLICE && base_type->data.slice.child) { + element_size = base_type->data.slice.child->size; + is_slice = true; + } + } + + if (expr->expr.subscript.index->type == NODE_RANGE) { + if (expr->expr.subscript.expr->type == NODE_IDENTIFIER) { + int base_offset = get_var_offset(expr->expr.subscript.expr->expr.string.start, + expr->expr.subscript.expr->expr.string.len); + + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", base_offset); + + gen_expr(fp, expr->expr.subscript.index->expr.binary.left); + fprintf(fp, "push %%rax\n"); + + gen_expr(fp, expr->expr.subscript.index->expr.binary.right); + fprintf(fp, "mov %%rax, %%rdx\n"); // rdx = end + fprintf(fp, "pop %%rax\n"); // rax = start + fprintf(fp, "mov %%rdx, %%r8\n"); + fprintf(fp, "sub %%rax, %%r8\n"); + fprintf(fp, "inc %%r8\n"); // r8 = new length + + if (element_size != 1) { + fprintf(fp, "imul $%lu, %%rax\n", element_size); + } + fprintf(fp, "add %%rcx, %%rax\n"); // rax = new ptr + + // Allocate temporary slice struct (16 bytes) + stack_offset += 16; + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", stack_offset); // Store ptr + fprintf(fp, "mov %%r8, -%d(%%rbp)\n", stack_offset - 8); // Store len + fprintf(fp, "lea -%d(%%rbp), %%rax\n", stack_offset); // Return address of temp slice + } + } + else if (expr->expr.subscript.expr->type == NODE_IDENTIFIER && is_slice) { + int base_offset = get_var_offset(expr->expr.subscript.expr->expr.string.start, + expr->expr.subscript.expr->expr.string.len); + + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", base_offset); + + gen_expr(fp, expr->expr.subscript.index); + + if (element_size != 1) { + fprintf(fp, "imul $%lu, %%rax\n", element_size); + } + + fprintf(fp, "add %%rcx, %%rax\n"); + + if (expr->expr_type && expr->expr_type->size == 4) { + fprintf(fp, "movl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 2) { + fprintf(fp, "movzwl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 1) { + fprintf(fp, "movzbl (%%rax), %%eax\n"); + } else { + fprintf(fp, "mov (%%rax), %%rax\n"); + } + } else if (expr->expr.subscript.expr->type == NODE_IDENTIFIER) { + int base_offset = get_var_offset(expr->expr.subscript.expr->expr.string.start, + expr->expr.subscript.expr->expr.string.len); + + gen_expr(fp, expr->expr.subscript.index); + + if (element_size != 1) { + fprintf(fp, "imul $%lu, %%rax\n", element_size); + } + + fprintf(fp, "add $%d, %%rax\n", base_offset); + fprintf(fp, "neg %%rax\n"); + fprintf(fp, "add %%rbp, %%rax\n"); + + if (expr->expr_type && expr->expr_type->size == 4) { + fprintf(fp, "movl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 2) { + fprintf(fp, "movzwl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 1) { + fprintf(fp, "movzbl (%%rax), %%eax\n"); + } else { + fprintf(fp, "mov (%%rax), %%rax\n"); + } + } else { + gen_expr(fp, expr->expr.subscript.expr); + fprintf(fp, "push %%rax\n"); + + gen_expr(fp, expr->expr.subscript.index); + + if (element_size != 1) { + fprintf(fp, "imul $%lu, %%rax\n", element_size); + } + + fprintf(fp, "pop %%rcx\n"); + fprintf(fp, "add %%rcx, %%rax\n"); + + if (expr->expr_type && expr->expr_type->size == 4) { + fprintf(fp, "movl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 2) { + fprintf(fp, "movzwl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 1) { + fprintf(fp, "movzbl (%%rax), %%eax\n"); + } else { + fprintf(fp, "mov (%%rax), %%rax\n"); + } + } + break; + } case NODE_CALL: { const char *arg_regs[] = {"%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"}; @@ -676,6 +1004,10 @@ void gen_expr(FILE *fp, ast_node *expr) void gen_function(FILE *fp, ast_node *fn) { + if (fn->expr.function.is_extern || fn->expr.function.body == NULL) { + return; + } + ast_node *current = fn->expr.function.body; stack_offset = 0; diff --git a/done.txt b/done.txt deleted file mode 100644 index e69de29..0000000 diff --git a/parser.c b/parser.c index 8061fc1..4fd7c65 100644 --- a/parser.c +++ b/parser.c @@ -1089,6 +1089,7 @@ static ast_node *parse_function(parser *p) { ast_node *fn = arena_alloc(p->allocator, sizeof(ast_node)); fn->type = NODE_FUNCTION; + fn->expr.function.is_extern = false; fn->expr.function.type = parse_type(p); fn->expr.function.name = peek(p)->lexeme; fn->expr.function.name_len = peek(p)->lexeme_len; @@ -1097,7 +1098,14 @@ static ast_node *parse_function(parser *p) advance(p); if (match(p, TOKEN_RPAREN)) { - fn->expr.function.body = parse_compound(p);; + // Check if this is an extern declaration (semicolon) or definition (body) + if (match_peek(p, TOKEN_SEMICOLON)) { + // Extern function - no body, just consume semicolon + advance(p); + fn->expr.function.body = NULL; + } else { + fn->expr.function.body = parse_compound(p); + } fn->expr.function.parameters = NULL; fn->expr.function.parameters_len = 0; return fn; @@ -1111,7 +1119,13 @@ static ast_node *parse_function(parser *p) error(p, "expected `,`."); return NULL; } else { - fn->expr.function.body = parse_compound(p); + // Check if this is an extern declaration (semicolon) or definition (body) + if (match_peek(p, TOKEN_SEMICOLON)) { + advance(p); + fn->expr.function.body = NULL; + } else { + fn->expr.function.body = parse_compound(p); + } return fn; } } @@ -1132,7 +1146,14 @@ static ast_node *parse_function(parser *p) prev = current; } - fn->expr.function.body = parse_compound(p); + + // Check if this is an extern declaration (semicolon) or definition (body) + if (match_peek(p, TOKEN_SEMICOLON)) { + advance(p); + fn->expr.function.body = NULL; + } else { + fn->expr.function.body = parse_compound(p); + } return fn; } @@ -1140,6 +1161,13 @@ static ast_node *parse_function(parser *p) static ast_node *parse_statement(parser *p) { token *cur = peek(p); + + /* Check for extern function declaration */ + bool is_extern = false; + if (match(p, TOKEN_EXTERN)) { + is_extern = true; + } + ast_node *type = parse_type(p); if (type && type->type == NODE_STRUCT && type->expr.structure.name_len > 0) { goto skip_struct; @@ -1148,9 +1176,20 @@ static ast_node *parse_statement(parser *p) if (p->tokens->next && p->tokens->next->type == TOKEN_LPAREN) { /* Function definition. */ p->tokens = cur; - return parse_function(p); + if (is_extern) { + advance(p); // Skip TOKEN_EXTERN + } + ast_node *fn = parse_function(p); + if (fn && is_extern) { + fn->expr.function.is_extern = true; + fn->expr.function.body = NULL; + } + return fn; } p->tokens = cur; + if (is_extern) { + advance(p); // Skip TOKEN_EXTERN for non-function case + } /* Variable declaration. */ ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); node->type = NODE_VAR_DECL; diff --git a/parser.h b/parser.h index dced7ec..bbe3d0c 100644 --- a/parser.h +++ b/parser.h @@ -230,6 +230,7 @@ typedef struct _ast_node { usize name_len; struct _ast_node *type; struct _ast_node *body; + bool is_extern; } function; struct { variant *variants; diff --git a/report.txt b/report.txt deleted file mode 100644 index e69de29..0000000 diff --git a/sema.c b/sema.c index f116912..4e87625 100644 --- a/sema.c +++ b/sema.c @@ -152,17 +152,18 @@ static type *get_type(sema *s, ast_node *n) return t; case NODE_PTR_TYPE: t = malloc(sizeof(type)); - t->size = sizeof(usize); t->alignment = sizeof(usize); if (n->expr.ptr_type.flags & PTR_RAW) { t->name = "ptr"; t->tag = TYPE_PTR; + t->size = sizeof(usize); t->data.ptr.child = get_type(s, n->expr.ptr_type.type); t->data.ptr.is_const = (n->expr.ptr_type.flags & PTR_CONST) != 0; t->data.ptr.is_volatile = (n->expr.ptr_type.flags & PTR_VOLATILE) != 0; } else { t->name = "slice"; t->tag = TYPE_SLICE; + t->size = sizeof(usize) * 2; // ptr + len = 16 bytes t->data.slice.child = get_type(s, n->expr.ptr_type.type); t->data.slice.is_const = (n->expr.ptr_type.flags & PTR_CONST) != 0; t->data.slice.is_volatile = (n->expr.ptr_type.flags & PTR_VOLATILE) != 0; @@ -377,8 +378,8 @@ static ast_node *get_def(sema *s, char *name) static type *get_string_type(sema *s, ast_node *node) { type *string_type = arena_alloc(s->allocator, sizeof(type)); - string_type->tag = TYPE_PTR; - string_type->size = sizeof(usize); + string_type->tag = TYPE_SLICE; + string_type->size = sizeof(usize) * 2; // ptr + len = 16 bytes string_type->alignment = sizeof(usize); string_type->name = "slice"; string_type->data.slice.child = shget(type_reg, "u8"); @@ -409,6 +410,33 @@ static type *get_access_type(sema *s, ast_node *node) ast_node *member = node->expr.access.member; char *name_start = member->expr.string.start; usize name_len = member->expr.string.len; + + // Handle slice field access + if (t && t->tag == TYPE_SLICE) { + char *name = intern_string(s, name_start, name_len); + if (strcmp(name, "ptr") == 0) { + // Return pointer to element type + type *ptr_type = arena_alloc(s->allocator, sizeof(type)); + ptr_type->tag = TYPE_PTR; + ptr_type->size = 8; + ptr_type->alignment = 8; + ptr_type->name = "ptr"; + ptr_type->data.ptr.child = t->data.slice.child; + ptr_type->data.ptr.is_const = t->data.slice.is_const; + ptr_type->data.ptr.is_volatile = t->data.slice.is_volatile; + free(name); + return ptr_type; + } else if (strcmp(name, "len") == 0) { + // Return usize type + free(name); + return shget(type_reg, "usize"); + } else { + error(node, "slice doesn't have that field"); + free(name); + return NULL; + } + } + if (!t || (t->tag != TYPE_STRUCT && t->tag != TYPE_UNION)) { error(node, "invalid expression."); return NULL; @@ -557,6 +585,36 @@ static type *get_expression_type(sema *s, ast_node *node) return t; case NODE_ARRAY_SUBSCRIPT: t = get_expression_type(s, node->expr.subscript.expr); + + // Check if this is range subscripting (creates a slice) + if (node->expr.subscript.index && node->expr.subscript.index->type == NODE_RANGE) { + type *element_type = NULL; + switch (t->tag) { + case TYPE_SLICE: + element_type = t->data.slice.child; + break; + case TYPE_PTR: + element_type = t->data.ptr.child; + break; + default: + error(node, "only pointers and slices can be indexed."); + return NULL; + } + + // Return a slice type + type *slice_type = arena_alloc(s->allocator, sizeof(type)); + slice_type->tag = TYPE_SLICE; + slice_type->size = sizeof(usize) * 2; + slice_type->alignment = sizeof(usize); + slice_type->data.slice.child = element_type; + slice_type->data.slice.is_const = false; + slice_type->data.slice.len = 0; + + node->expr_type = slice_type; + return slice_type; + } + + // Regular subscript - return element type switch (t->tag) { case TYPE_SLICE: t = t->data.slice.child; @@ -732,6 +790,18 @@ static void check_statement(sema *s, ast_node *node) break; } if (t->tag == TYPE_STRUCT) { + // Struct initialization with NODE_STRUCT_INIT is allowed + } else if (node->expr.var_decl.value && node->expr.var_decl.value->type == NODE_STRUCT_INIT && + (t->tag == TYPE_SLICE || t->tag == TYPE_PTR)) { + // Array/slice initialization with NODE_STRUCT_INIT is allowed + } else if (node->expr.var_decl.value && node->expr.var_decl.value->type == NODE_RANGE && + t->tag == TYPE_SLICE) { + // Range initialization for slices is allowed + get_expression_type(s, node->expr.var_decl.value); + } else if (node->expr.var_decl.value && node->expr.var_decl.value->type == NODE_STRING && + t->tag == TYPE_SLICE) { + // String literal can be assigned to slice + get_expression_type(s, node->expr.var_decl.value); } else if (!can_cast(get_expression_type(s, node->expr.var_decl.value), t) && !match(t, get_expression_type(s, node->expr.var_decl.value))) { error(node, "type mismatch (decl)."); } @@ -758,15 +828,18 @@ static void check_function(sema *s, ast_node *f) param_node->expr_type = p_type; param_node->address_taken = false; param_node->expr.var_decl.name = t_name; - + shput(current_scope->defs, t_name, param_node); param = param->next; } - ast_node *current = f->expr.function.body; - while (current && current->type == NODE_UNIT) { - check_statement(s, current->expr.unit_node.expr); - current = current->expr.unit_node.next; + // Skip body checking for extern functions + if (!f->expr.function.is_extern && f->expr.function.body) { + ast_node *current = f->expr.function.body; + while (current && current->type == NODE_UNIT) { + check_statement(s, current->expr.unit_node.expr); + current = current->expr.unit_node.next; + } } pop_scope(s); @@ -820,6 +893,7 @@ void sema_init(parser *p, arena *a) register_type(s, "u16", create_integer(s, "u16", 16, false)); register_type(s, "u32", create_integer(s, "u32", 32, false)); register_type(s, "u64", create_integer(s, "u64", 64, false)); + register_type(s, "usize", create_integer(s, "usize", 64, false)); register_type(s, "i8", create_integer(s, "i8", 8, true)); register_type(s, "i16", create_integer(s, "i16", 16, true)); register_type(s, "i32", create_integer(s, "i32", 32, true)); diff --git a/test b/test deleted file mode 100755 index 2fd1a55..0000000 Binary files a/test and /dev/null differ diff --git a/test.l b/test.l index 1aac346..2763f97 100644 --- a/test.l +++ b/test.l @@ -1,10 +1,20 @@ -struct point { - i32 x, - i32 y -} +extern i64 write(i32 fd, *u8 buf, u64 count); +extern void exit(i32 code); +extern *u8 malloc(usize size); i32 main() { - point result = .{ x = 2, y = 1 }; - return (result.y) + 2; + [u8] message = "Hello world!\n"; + *u8 message_heap = malloc(message.len); + [u8] new_message = message_heap[0..13]; + u32 i = 0; + + loop while i < message.len { + new_message[i] = message[i]; + i = i + 1; + } + + write(1, new_message.ptr, new_message.len); + + return 0; } diff --git a/test.s b/test.s deleted file mode 100644 index 9d3b3f4..0000000 --- a/test.s +++ /dev/null @@ -1,20 +0,0 @@ -.section .text -.global main -main: -push %rbp -mov %rsp, %rbp -sub $256, %rsp -mov $2, %rax -mov %eax, -8(%rbp) -mov $1, %rax -mov %eax, -12(%rbp) -mov -12(%rbp), %rax -mov %rax, %rcx -mov $2, %rax -add %rcx, %rax -mov %rbp, %rsp -pop %rbp -ret -mov %rbp, %rsp -pop %rbp -ret diff --git a/test_control b/test_control deleted file mode 100755 index d9550ee..0000000 Binary files a/test_control and /dev/null differ diff --git a/test_control.l b/test_control.l deleted file mode 100644 index d8576a2..0000000 --- a/test_control.l +++ /dev/null @@ -1,23 +0,0 @@ -i32 main() -{ - i32 x = 0; - i32 i = 0; - - // Test while loop with break - while (i < 10) { - i = i + 1; - if (i == 5) { - break; - } - x = x + i; - } - - // Test goto and label - if (x == 10) { - goto skip; - } - x = 999; - - skip: - return x; -} diff --git a/test_simple b/test_simple deleted file mode 100755 index d9550ee..0000000 Binary files a/test_simple and /dev/null differ diff --git a/test_simple.l b/test_simple.l deleted file mode 100644 index 61dc5fb..0000000 --- a/test_simple.l +++ /dev/null @@ -1,13 +0,0 @@ -i32 main() -{ - i32 x = 0; - - while (x < 10) { - x = x + 1; - if (x == 5) { - break; - } - } - - return x; -} diff --git a/todo.cfg b/todo.cfg deleted file mode 100644 index 5e35825..0000000 --- a/todo.cfg +++ /dev/null @@ -1,2 +0,0 @@ -export TODO_DIR="." -export TODO_FILE="$TODO_DIR/todo.txt" diff --git a/todo.txt b/todo.txt deleted file mode 100644 index c023562..0000000 --- a/todo.txt +++ /dev/null @@ -1 +0,0 @@ -implement dominator tree for control flow