getting started on array types

This commit is contained in:
Josh Wolfe 2015-12-07 08:29:19 -07:00
parent 94e61287e7
commit f6eecfe5f4
11 changed files with 116 additions and 21 deletions

View File

@ -144,9 +144,11 @@ ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
ParamDecl : token(Symbol) token(Colon) Type
Type : token(Symbol) | PointerType | token(Unreachable)
Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType
PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type
PointerType : token(Star) (token(Const) | token(Mut)) Type
ArrayType : token(LBracket) Type token(Semicolon) Expression token(RBracket)
Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)

View File

@ -48,18 +48,23 @@ static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node)
}
}
TypeTableEntry *new_type_table_entry() {
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
entry->arrays_by_size.init(2);
return entry;
}
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
TypeTableEntry **parent_pointer = is_const ?
&child_type->pointer_const_parent :
&child_type->pointer_mut_parent;
const char *const_or_mut_str = is_const ? "const" : "mut";
if (*parent_pointer) {
return *parent_pointer;
} else {
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
TypeTableEntry *entry = new_type_table_entry();
entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "*%s %s", const_or_mut_str, buf_ptr(&child_type->name));
buf_appendf(&entry->name, "*%s %s", is_const ? "const" : "mut", buf_ptr(&child_type->name));
entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type,
g->pointer_size_bytes * 8, g->pointer_size_bytes * 8, buf_ptr(&entry->name));
g->type_table.put(&entry->name, entry);
@ -68,6 +73,28 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
}
}
static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, int array_size) {
auto existing_entry = child_type->arrays_by_size.maybe_get(array_size);
if (existing_entry) {
return existing_entry->value;
} else {
TypeTableEntry *entry = new_type_table_entry();
entry->type_ref = LLVMArrayType(child_type->type_ref, array_size);
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "[%s; %ud]", buf_ptr(&child_type->name), array_size);
//entry->di_type = LLVMZigCreateDebugArrayType(g->dbuilder, ..., buf_ptr(&entry->name)); // TODO
g->type_table.put(&entry->name, entry);
child_type->arrays_by_size.put(array_size, entry);
return entry;
}
}
static int parse_int(Buf *number) {
// TODO: think about integer size of array sizes
return atoi(buf_ptr(number));
}
static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeType);
assert(!node->codegen_node);
@ -98,6 +125,28 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const);
return type_node->entry;
}
case AstNodeTypeTypeArray:
{
resolve_type(g, node->data.type.child_type);
TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
if (child_type == g->builtin_types.entry_unreachable) {
add_node_error(g, node,
buf_create_from_str("array of unreachable not allowed"));
}
AstNode *size_node = node->data.type.array_size;
int size; // TODO: think about integer size of array sizes
if (size_node->type != NodeTypeNumberLiteral) {
add_node_error(g, size_node,
buf_create_from_str("array size must be literal number"));
size = -1;
} else {
size = parse_int(&size_node->data.number);
}
type_node->entry = get_array_type(g, child_type, size); // TODO
return type_node->entry;
}
}
zig_unreachable();
}

View File

@ -18,6 +18,7 @@ struct BlockContext;
void semantic_analyze(CodeGen *g);
void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
TypeTableEntry *new_type_table_entry();
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name);

View File

@ -781,12 +781,12 @@ static void do_code_gen(CodeGen *g) {
static void define_primitive_types(CodeGen *g) {
{
// if this type is anywhere in the AST, we should never hit codegen.
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
TypeTableEntry *entry = new_type_table_entry();
buf_init_from_str(&entry->name, "(invalid)");
g->builtin_types.entry_invalid = entry;
}
{
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
TypeTableEntry *entry = new_type_table_entry();
entry->type_ref = LLVMInt1Type();
buf_init_from_str(&entry->name, "bool");
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 1, 8,
@ -795,7 +795,7 @@ static void define_primitive_types(CodeGen *g) {
g->builtin_types.entry_bool = entry;
}
{
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
TypeTableEntry *entry = new_type_table_entry();
entry->type_ref = LLVMInt8Type();
buf_init_from_str(&entry->name, "u8");
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8,
@ -805,7 +805,7 @@ static void define_primitive_types(CodeGen *g) {
}
g->builtin_types.entry_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
{
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
TypeTableEntry *entry = new_type_table_entry();
entry->type_ref = LLVMInt32Type();
buf_init_from_str(&entry->name, "i32");
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32,
@ -814,7 +814,7 @@ static void define_primitive_types(CodeGen *g) {
g->builtin_types.entry_i32 = entry;
}
{
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
TypeTableEntry *entry = new_type_table_entry();
entry->type_ref = LLVMVoidType();
buf_init_from_str(&entry->name, "void");
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0,
@ -823,7 +823,7 @@ static void define_primitive_types(CodeGen *g) {
g->builtin_types.entry_void = entry;
}
{
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
TypeTableEntry *entry = new_type_table_entry();
entry->type_ref = LLVMVoidType();
buf_init_from_str(&entry->name, "unreachable");
entry->di_type = g->builtin_types.entry_void->di_type;

View File

@ -180,6 +180,13 @@ void ast_print(AstNode *node, int indent) {
ast_print(node->data.type.child_type, indent + 2);
break;
}
case AstNodeTypeTypeArray:
{
fprintf(stderr, "ArrayType\n");
ast_print(node->data.type.child_type, indent + 2);
ast_print(node->data.type.array_size, indent + 2);
break;
}
}
break;
case NodeTypeReturnExpr:
@ -448,8 +455,9 @@ static void ast_parse_directives(ParseContext *pc, int *token_index,
/*
Type : token(Symbol) | PointerType | token(Unreachable)
PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type;
Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType
PointerType : token(Star) (token(Const) | token(Mut)) Type
ArrayType : token(LBracket) Type token(Semicolon) token(Number) token(RBracket)
*/
static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token_index) {
Token *token = &pc->tokens->at(token_index);
@ -463,12 +471,6 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token
} else if (token->id == TokenIdKeywordVoid) {
node->data.type.type = AstNodeTypeTypePrimitive;
buf_init_from_str(&node->data.type.primitive_name, "void");
} else if (token->id == TokenIdKeywordTrue) {
node->data.type.type = AstNodeTypeTypePrimitive;
buf_init_from_str(&node->data.type.primitive_name, "true");
} else if (token->id == TokenIdKeywordFalse) {
node->data.type.type = AstNodeTypeTypePrimitive;
buf_init_from_str(&node->data.type.primitive_name, "false");
} else if (token->id == TokenIdSymbol) {
node->data.type.type = AstNodeTypeTypePrimitive;
ast_buf_from_token(pc, token, &node->data.type.primitive_name);
@ -485,6 +487,20 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token
}
node->data.type.child_type = ast_parse_type(pc, token_index, &token_index);
} else if (token->id == TokenIdLBracket) {
node->data.type.type = AstNodeTypeTypeArray;
node->data.type.child_type = ast_parse_type(pc, token_index, &token_index);
Token *semicolon_token = &pc->tokens->at(token_index);
token_index += 1;
ast_expect_token(pc, semicolon_token, TokenIdSemicolon);
node->data.type.array_size = ast_parse_expression(pc, &token_index, true);
Token *rbracket_token = &pc->tokens->at(token_index);
token_index += 1;
ast_expect_token(pc, rbracket_token, TokenIdRBracket);
} else {
ast_invalid_token_error(pc, token);
}
@ -494,8 +510,7 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token
}
/*
ParamDecl<node> : token(Symbol) token(Colon) Type {
};
ParamDecl : token(Symbol) token(Colon) Type
*/
static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new_token_index) {
Token *param_name = &pc->tokens->at(token_index);

View File

@ -81,12 +81,14 @@ struct AstNodeParamDecl {
enum AstNodeTypeType {
AstNodeTypeTypePrimitive,
AstNodeTypeTypePointer,
AstNodeTypeTypeArray,
};
struct AstNodeType {
AstNodeTypeType type;
Buf primitive_name;
AstNode *child_type;
AstNode *array_size;
bool is_const;
};

View File

@ -23,8 +23,11 @@ struct TypeTableEntry {
bool pointer_is_const;
int user_defined_id;
Buf name;
// use these fields to make sure we don't duplicate type table entries for the same type
TypeTableEntry *pointer_const_parent;
TypeTableEntry *pointer_mut_parent;
HashMap<int, TypeTableEntry *, int_hash, int_eq> arrays_by_size;
};
struct ImportTableEntry {

View File

@ -259,6 +259,14 @@ void tokenize(Buf *buf, Tokenization *out) {
begin_token(&t, TokenIdRBrace);
end_token(&t);
break;
case '[':
begin_token(&t, TokenIdLBracket);
end_token(&t);
break;
case ']':
begin_token(&t, TokenIdRBracket);
end_token(&t);
break;
case ';':
begin_token(&t, TokenIdSemicolon);
end_token(&t);
@ -601,6 +609,8 @@ static const char * token_name(Token *token) {
case TokenIdStar: return "Star";
case TokenIdLBrace: return "LBrace";
case TokenIdRBrace: return "RBrace";
case TokenIdLBracket: return "LBracket";
case TokenIdRBracket: return "RBracket";
case TokenIdStringLiteral: return "StringLiteral";
case TokenIdSemicolon: return "Semicolon";
case TokenIdNumberLiteral: return "NumberLiteral";

View File

@ -36,6 +36,8 @@ enum TokenId {
TokenIdStar,
TokenIdLBrace,
TokenIdRBrace,
TokenIdLBracket,
TokenIdRBracket,
TokenIdStringLiteral,
TokenIdSemicolon,
TokenIdNumberLiteral,

View File

@ -19,3 +19,10 @@ void zig_panic(const char *format, ...) {
va_end(ap);
abort();
}
uint32_t int_hash(int i) {
return *reinterpret_cast<uint32_t*>(&i);
}
bool int_eq(int a, int b) {
return a == b;
}

View File

@ -9,6 +9,7 @@
#define ZIG_UTIL_HPP
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
@ -78,4 +79,7 @@ static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str)
return memcmp(mem, str, mem_len) == 0;
}
uint32_t int_hash(int i);
bool int_eq(int a, int b);
#endif