diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2015-12-08 14:15:34 -0700 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2015-12-08 14:15:34 -0700 |
| commit | 75efc313299af89c69c5f2b4a7c2758753ed36c3 (patch) | |
| tree | 6bee1174842149ad36378a8c241b760af4db77df /src | |
| parent | 2f0e4e9cb26df7a6f6251d0e865d0d964680831e (diff) | |
| download | zig-75efc313299af89c69c5f2b4a7c2758753ed36c3.tar.gz zig-75efc313299af89c69c5f2b4a7c2758753ed36c3.zip | |
add array access syntax
Diffstat (limited to 'src')
| -rw-r--r-- | src/analyze.cpp | 71 | ||||
| -rw-r--r-- | src/analyze.hpp | 211 | ||||
| -rw-r--r-- | src/codegen.cpp | 62 | ||||
| -rw-r--r-- | src/parser.cpp | 58 | ||||
| -rw-r--r-- | src/parser.hpp | 7 | ||||
| -rw-r--r-- | src/semantic_info.hpp | 194 |
6 files changed, 353 insertions, 250 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index c1af7b1557..3351041db9 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6,11 +6,45 @@ */ #include "analyze.hpp" -#include "semantic_info.hpp" #include "error.hpp" #include "zig_llvm.hpp" #include "os.hpp" +static AstNode *first_executing_node(AstNode *node) { + switch (node->type) { + case NodeTypeFnCallExpr: + return first_executing_node(node->data.fn_call_expr.fn_ref_expr); + case NodeTypeRoot: + case NodeTypeRootExportDecl: + case NodeTypeFnProto: + case NodeTypeFnDef: + case NodeTypeFnDecl: + case NodeTypeParamDecl: + case NodeTypeType: + case NodeTypeBlock: + case NodeTypeExternBlock: + case NodeTypeDirective: + case NodeTypeReturnExpr: + case NodeTypeVariableDeclaration: + case NodeTypeBinOpExpr: + case NodeTypeCastExpr: + case NodeTypeNumberLiteral: + case NodeTypeStringLiteral: + case NodeTypeUnreachable: + case NodeTypeSymbol: + case NodeTypePrefixOpExpr: + case NodeTypeArrayAccessExpr: + case NodeTypeUse: + case NodeTypeVoid: + case NodeTypeBoolLiteral: + case NodeTypeIfExpr: + case NodeTypeLabel: + case NodeTypeGoto: + return node; + } + zig_panic("unreachable"); +} + void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { ErrorMsg *err = allocate<ErrorMsg>(1); err->line_start = node->line; @@ -48,9 +82,10 @@ static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) } } -TypeTableEntry *new_type_table_entry() { +TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { TypeTableEntry *entry = allocate<TypeTableEntry>(1); entry->arrays_by_size.init(2); + entry->id = id; return entry; } @@ -61,7 +96,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool if (*parent_pointer) { return *parent_pointer; } else { - TypeTableEntry *entry = new_type_table_entry(); + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer); entry->type_ref = LLVMPointerType(child_type->type_ref, 0); buf_resize(&entry->name, 0); buf_appendf(&entry->name, "*%s %s", is_const ? "const" : "mut", buf_ptr(&child_type->name)); @@ -80,7 +115,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, in if (existing_entry) { return existing_entry->value; } else { - TypeTableEntry *entry = new_type_table_entry(); + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray); entry->type_ref = LLVMArrayType(child_type->type_ref, array_size); buf_resize(&entry->name, 0); buf_appendf(&entry->name, "[%s; %d]", buf_ptr(&child_type->name), array_size); @@ -357,6 +392,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, case NodeTypeBlock: case NodeTypeBinOpExpr: case NodeTypeFnCallExpr: + case NodeTypeArrayAccessExpr: case NodeTypeNumberLiteral: case NodeTypeStringLiteral: case NodeTypeUnreachable: @@ -466,7 +502,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, // ignore void statements once we enter unreachable land. continue; } - add_node_error(g, child, buf_sprintf("unreachable code")); + add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code")); break; } return_type = analyze_expression(g, import, child_context, nullptr, child); @@ -641,14 +677,21 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, case NodeTypeFnCallExpr: { - Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr); + AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; + if (fn_ref_expr->type != NodeTypeSymbol) { + add_node_error(g, node, + buf_sprintf("function pointers not allowed")); + break; + } + + Buf *name = &fn_ref_expr->data.symbol; auto entry = import->fn_table.maybe_get(name); if (!entry) entry = g->fn_table.maybe_get(name); if (!entry) { - add_node_error(g, node, + add_node_error(g, fn_ref_expr, buf_sprintf("undefined function: '%s'", buf_ptr(name))); // still analyze the parameters, even though we don't know what to expect for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { @@ -691,6 +734,19 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, break; } + case NodeTypeArrayAccessExpr: + { + // here we are always reading the array + TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, + node->data.array_access_expr.array_ref_expr); + if (lhs_type->id == TypeTableEntryIdArray) { + zig_panic("TODO"); + } else { + add_node_error(g, node, buf_sprintf("array access of non-array")); + } + + break; + } case NodeTypeNumberLiteral: // TODO: generic literal int type return_type = g->builtin_types.entry_i32; @@ -897,6 +953,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, case NodeTypeBlock: case NodeTypeBinOpExpr: case NodeTypeFnCallExpr: + case NodeTypeArrayAccessExpr: case NodeTypeNumberLiteral: case NodeTypeStringLiteral: case NodeTypeUnreachable: diff --git a/src/analyze.hpp b/src/analyze.hpp index b398d8e22c..c79f2d0f85 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -8,17 +8,216 @@ #ifndef ZIG_ANALYZE_HPP #define ZIG_ANALYZE_HPP -struct CodeGen; -struct AstNode; -struct Buf; +#include "codegen.hpp" +#include "hash_map.hpp" +#include "zig_llvm.hpp" +#include "errmsg.hpp" -struct TypeTableEntry; -struct LocalVariableTableEntry; +struct FnTableEntry; struct BlockContext; +struct TypeTableEntry; + +struct TypeTableEntryPointer { + TypeTableEntry *pointer_child; + bool pointer_is_const; +}; + +struct TypeTableEntryInt { + bool is_signed; +}; + +enum TypeTableEntryId { + TypeTableEntryIdInvalid, + TypeTableEntryIdVoid, + TypeTableEntryIdBool, + TypeTableEntryIdUnreachable, + TypeTableEntryIdInt, + TypeTableEntryIdFloat, + TypeTableEntryIdPointer, + TypeTableEntryIdArray, +}; + +struct TypeTableEntry { + TypeTableEntryId id; + + LLVMTypeRef type_ref; + LLVMZigDIType *di_type; + uint64_t size_in_bits; + uint64_t align_in_bits; + + Buf name; + + union { + TypeTableEntryPointer pointer; + TypeTableEntryInt integral; + } data; + + // 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 { + AstNode *root; + Buf *path; // relative to root_source_dir + LLVMZigDIFile *di_file; + Buf *source_code; + ZigList<int> *line_offsets; + + // reminder: hash tables must be initialized before use + HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; +}; + +struct LabelTableEntry { + AstNode *label_node; + LLVMBasicBlockRef basic_block; + bool used; + bool entered_from_fallthrough; +}; + +struct FnTableEntry { + LLVMValueRef fn_value; + AstNode *proto_node; + AstNode *fn_def_node; + bool is_extern; + bool internal_linkage; + unsigned calling_convention; + ImportTableEntry *import_entry; + + // reminder: hash tables must be initialized before use + HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table; +}; + +struct CodeGen { + LLVMModuleRef module; + ZigList<ErrorMsg*> errors; + LLVMBuilderRef builder; + LLVMZigDIBuilder *dbuilder; + LLVMZigDICompileUnit *compile_unit; + + // reminder: hash tables must be initialized before use + HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; + HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; + HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; + HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; + HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; + + struct { + TypeTableEntry *entry_bool; + TypeTableEntry *entry_u8; + TypeTableEntry *entry_i32; + TypeTableEntry *entry_f32; + TypeTableEntry *entry_string_literal; + TypeTableEntry *entry_void; + TypeTableEntry *entry_unreachable; + TypeTableEntry *entry_invalid; + } builtin_types; + + LLVMTargetDataRef target_data_ref; + unsigned pointer_size_bytes; + bool is_static; + bool strip_debug_symbols; + CodeGenBuildType build_type; + LLVMTargetMachineRef target_machine; + bool is_native_target; + Buf *root_source_dir; + Buf *root_out_name; + + // The function definitions this module includes. There must be a corresponding + // fn_protos entry. + ZigList<FnTableEntry *> fn_defs; + // The function prototypes this module includes. In the case of external declarations, + // there will not be a corresponding fn_defs entry. + ZigList<FnTableEntry *> fn_protos; + + OutType out_type; + FnTableEntry *cur_fn; + LLVMBasicBlockRef cur_basic_block; + BlockContext *cur_block_context; + bool c_stdint_used; + AstNode *root_export_decl; + int version_major; + int version_minor; + int version_patch; + bool verbose; + ErrColor err_color; + ImportTableEntry *root_import; +}; + +struct LocalVariableTableEntry { + Buf name; + TypeTableEntry *type; + LLVMValueRef value_ref; + bool is_const; + bool is_ptr; // if true, value_ref is a pointer + AstNode *decl_node; + LLVMZigDILocalVariable *di_loc_var; + int arg_index; +}; + +struct BlockContext { + AstNode *node; // either NodeTypeFnDef or NodeTypeBlock + BlockContext *root; // always points to the BlockContext with the NodeTypeFnDef + BlockContext *parent; // nullptr when this is the root + HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table; + LLVMZigDIScope *di_scope; +}; + +struct TypeNode { + TypeTableEntry *entry; +}; + +struct FnProtoNode { + FnTableEntry *fn_table_entry; +}; + +struct FnDefNode { + TypeTableEntry *implicit_return_type; + BlockContext *block_context; + bool skip; + // Required to be a pre-order traversal of the AST. (parents must come before children) + ZigList<BlockContext *> all_block_contexts; +}; + +struct ExprNode { + TypeTableEntry *type_entry; + // the context in which this expression is evaluated. + // for blocks, this points to the containing scope, not the block's own scope for its children. + BlockContext *block_context; +}; + +struct AssignNode { + LocalVariableTableEntry *var_entry; +}; + +struct BlockNode { + BlockContext *block_context; +}; + +struct CodeGenNode { + union { + TypeNode type_node; // for NodeTypeType + FnDefNode fn_def_node; // for NodeTypeFnDef + FnProtoNode fn_proto_node; // for NodeTypeFnProto + LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel + AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign + BlockNode block_node; // for NodeTypeBlock + } data; + ExprNode expr_node; // for all the expression nodes +}; + +static inline Buf *hack_get_fn_call_name(CodeGen *g, AstNode *node) { + // Assume that the expression evaluates to a simple name and return the buf + // TODO after type checking works we should be able to remove this hack + assert(node->type == NodeTypeSymbol); + return &node->data.symbol; +} void semantic_analyze(CodeGen *g); void add_node_error(CodeGen *g, AstNode *node, Buf *msg); -TypeTableEntry *new_type_table_entry(); +TypeTableEntry *new_type_table_entry(TypeTableEntryId id); TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name); diff --git a/src/codegen.cpp b/src/codegen.cpp index ecb376f0dc..6c7a84774d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -11,7 +11,6 @@ #include "os.hpp" #include "config.h" #include "error.hpp" -#include "semantic_info.hpp" #include "analyze.hpp" #include "errmsg.hpp" @@ -168,6 +167,12 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { } } +static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) { + assert(node->type == NodeTypeArrayAccessExpr); + + zig_panic("TODO gen arary access"); +} + static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { assert(node->type == NodeTypePrefixOpExpr); assert(node->data.prefix_op_expr.primary_expr); @@ -229,49 +234,55 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { return LLVMBuildShl(g->builder, val1, val2, ""); case BinOpTypeBitShiftRight: add_debug_source_node(g, node); - if (op1_type->is_signed_int) { + if (op1_type->id == TypeTableEntryIdInt) { return LLVMBuildAShr(g->builder, val1, val2, ""); } else { return LLVMBuildLShr(g->builder, val1, val2, ""); } case BinOpTypeAdd: add_debug_source_node(g, node); - if (op1_type->is_float) { + if (op1_type->id == TypeTableEntryIdFloat) { return LLVMBuildFAdd(g->builder, val1, val2, ""); } else { return LLVMBuildNSWAdd(g->builder, val1, val2, ""); } case BinOpTypeSub: add_debug_source_node(g, node); - if (op1_type->is_float) { + if (op1_type->id == TypeTableEntryIdFloat) { return LLVMBuildFSub(g->builder, val1, val2, ""); } else { return LLVMBuildNSWSub(g->builder, val1, val2, ""); } case BinOpTypeMult: add_debug_source_node(g, node); - if (op1_type->is_float) { + if (op1_type->id == TypeTableEntryIdFloat) { return LLVMBuildFMul(g->builder, val1, val2, ""); } else { return LLVMBuildNSWMul(g->builder, val1, val2, ""); } case BinOpTypeDiv: add_debug_source_node(g, node); - if (op1_type->is_float) { + if (op1_type->id == TypeTableEntryIdFloat) { return LLVMBuildFDiv(g->builder, val1, val2, ""); - } else if (op1_type->is_signed_int) { - return LLVMBuildSDiv(g->builder, val1, val2, ""); } else { - return LLVMBuildUDiv(g->builder, val1, val2, ""); + assert(op1_type->id == TypeTableEntryIdInt); + if (op1_type->data.integral.is_signed) { + return LLVMBuildSDiv(g->builder, val1, val2, ""); + } else { + return LLVMBuildUDiv(g->builder, val1, val2, ""); + } } case BinOpTypeMod: add_debug_source_node(g, node); - if (op1_type->is_float) { + if (op1_type->id == TypeTableEntryIdFloat) { return LLVMBuildFRem(g->builder, val1, val2, ""); - } else if (op1_type->is_signed_int) { - return LLVMBuildSRem(g->builder, val1, val2, ""); } else { - return LLVMBuildURem(g->builder, val1, val2, ""); + assert(op1_type->id == TypeTableEntryIdInt); + if (op1_type->data.integral.is_signed) { + return LLVMBuildSRem(g->builder, val1, val2, ""); + } else { + return LLVMBuildURem(g->builder, val1, val2, ""); + } } case BinOpTypeBoolOr: case BinOpTypeBoolAnd: @@ -337,11 +348,13 @@ static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) { assert(op1_type == op2_type); add_debug_source_node(g, node); - if (op1_type->is_float) { + if (op1_type->id == TypeTableEntryIdFloat) { LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op); return LLVMBuildFCmp(g->builder, pred, val1, val2, ""); } else { - LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, op1_type->is_signed_int); + assert(op1_type->id == TypeTableEntryIdInt); + LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, + op1_type->data.integral.is_signed); return LLVMBuildICmp(g->builder, pred, val1, val2, ""); } } @@ -596,6 +609,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { return gen_prefix_op_expr(g, node); case NodeTypeFnCallExpr: return gen_fn_call_expr(g, node); + case NodeTypeArrayAccessExpr: + return gen_array_access_expr(g, node); case NodeTypeUnreachable: add_debug_source_node(g, node); return LLVMBuildUnreachable(g->builder); @@ -865,12 +880,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 = new_type_table_entry(); + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInvalid); buf_init_from_str(&entry->name, "(invalid)"); g->builtin_types.entry_invalid = entry; } { - TypeTableEntry *entry = new_type_table_entry(); + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool); entry->type_ref = LLVMInt1Type(); buf_init_from_str(&entry->name, "bool"); entry->size_in_bits = 1; @@ -882,7 +897,7 @@ static void define_primitive_types(CodeGen *g) { g->builtin_types.entry_bool = entry; } { - TypeTableEntry *entry = new_type_table_entry(); + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); entry->type_ref = LLVMInt8Type(); buf_init_from_str(&entry->name, "u8"); entry->size_in_bits = 8; @@ -895,12 +910,12 @@ 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 = new_type_table_entry(); + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); entry->type_ref = LLVMInt32Type(); buf_init_from_str(&entry->name, "i32"); entry->size_in_bits = 32; entry->align_in_bits = 32; - entry->is_signed_int = true; + entry->data.integral.is_signed = true; entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), entry->size_in_bits, entry->align_in_bits, LLVMZigEncoding_DW_ATE_signed()); @@ -908,12 +923,11 @@ static void define_primitive_types(CodeGen *g) { g->builtin_types.entry_i32 = entry; } { - TypeTableEntry *entry = new_type_table_entry(); + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); entry->type_ref = LLVMFloatType(); buf_init_from_str(&entry->name, "f32"); entry->size_in_bits = 32; entry->align_in_bits = 32; - entry->is_float = true; entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), entry->size_in_bits, entry->align_in_bits, LLVMZigEncoding_DW_ATE_float()); @@ -921,7 +935,7 @@ static void define_primitive_types(CodeGen *g) { g->builtin_types.entry_f32 = entry; } { - TypeTableEntry *entry = new_type_table_entry(); + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid); entry->type_ref = LLVMVoidType(); buf_init_from_str(&entry->name, "void"); entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), @@ -931,7 +945,7 @@ static void define_primitive_types(CodeGen *g) { g->builtin_types.entry_void = entry; } { - TypeTableEntry *entry = new_type_table_entry(); + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable); entry->type_ref = LLVMVoidType(); buf_init_from_str(&entry->name, "unreachable"); entry->di_type = g->builtin_types.entry_void->di_type; diff --git a/src/parser.cpp b/src/parser.cpp index d6f9b96a8d..6aafa8781a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -7,7 +7,7 @@ #include "parser.hpp" #include "errmsg.hpp" -#include "semantic_info.hpp" +#include "analyze.hpp" #include <stdarg.h> #include <stdio.h> @@ -70,6 +70,8 @@ const char *node_type_str(NodeType node_type) { return "BinOpExpr"; case NodeTypeFnCallExpr: return "FnCallExpr"; + case NodeTypeArrayAccessExpr: + return "ArrayAccessExpr"; case NodeTypeExternBlock: return "ExternBlock"; case NodeTypeDirective: @@ -231,6 +233,11 @@ void ast_print(AstNode *node, int indent) { ast_print(child, indent + 2); } break; + case NodeTypeArrayAccessExpr: + fprintf(stderr, "%s\n", node_type_str(node->type)); + ast_print(node->data.array_access_expr.array_ref_expr, indent + 2); + ast_print(node->data.array_access_expr.subscript, indent + 2); + break; case NodeTypeDirective: fprintf(stderr, "%s\n", node_type_str(node->type)); break; @@ -566,10 +573,6 @@ static void ast_parse_param_decl_list(ParseContext *pc, int token_index, int *ne static void ast_parse_fn_call_param_list(ParseContext *pc, int token_index, int *new_token_index, ZigList<AstNode*> *params) { - Token *l_paren = &pc->tokens->at(token_index); - token_index += 1; - ast_expect_token(pc, l_paren, TokenIdLParen); - Token *token = &pc->tokens->at(token_index); if (token->id == TokenIdRParen) { token_index += 1; @@ -680,22 +683,39 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool } /* -FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma)) token(RParen) | PrimaryExpression +SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression) +FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) +ArrayAccessExpression : token(LBracket) Expression token(RBracket) */ -static AstNode *ast_parse_fn_call_expr(ParseContext *pc, int *token_index, bool mandatory) { +static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory); - if (!primary_expr) + if (!primary_expr) { return nullptr; + } - Token *l_paren = &pc->tokens->at(*token_index); - if (l_paren->id != TokenIdLParen) - return primary_expr; + Token *token = &pc->tokens->at(*token_index); + if (token->id == TokenIdLParen) { + *token_index += 1; - AstNode *node = ast_create_node_with_node(pc, NodeTypeFnCallExpr, primary_expr); - node->data.fn_call_expr.fn_ref_expr = primary_expr; - ast_parse_fn_call_param_list(pc, *token_index, token_index, &node->data.fn_call_expr.params); + AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token); + node->data.fn_call_expr.fn_ref_expr = primary_expr; + ast_parse_fn_call_param_list(pc, *token_index, token_index, &node->data.fn_call_expr.params); + return node; + } else if (token->id == TokenIdLBracket) { + *token_index += 1; - return node; + AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, token); + node->data.array_access_expr.array_ref_expr = primary_expr; + node->data.array_access_expr.subscript = ast_parse_expression(pc, token_index, true); + + Token *r_bracket = &pc->tokens->at(*token_index); + *token_index += 1; + ast_expect_token(pc, r_bracket, TokenIdRBracket); + + return node; + } else { + return primary_expr; + } } static PrefixOp tok_to_prefix_op(Token *token) { @@ -725,17 +745,17 @@ static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool man } /* -PrefixOpExpression : PrefixOp FnCallExpression | FnCallExpression +PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression */ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { Token *token = &pc->tokens->at(*token_index); PrefixOp prefix_op = ast_parse_prefix_op(pc, token_index, false); if (prefix_op == PrefixOpInvalid) - return ast_parse_fn_call_expr(pc, token_index, mandatory); + return ast_parse_suffix_op_expr(pc, token_index, mandatory); - AstNode *primary_expr = ast_parse_fn_call_expr(pc, token_index, true); + AstNode *prefix_op_expr = ast_parse_suffix_op_expr(pc, token_index, true); AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token); - node->data.prefix_op_expr.primary_expr = primary_expr; + node->data.prefix_op_expr.primary_expr = prefix_op_expr; node->data.prefix_op_expr.prefix_op = prefix_op; return node; diff --git a/src/parser.hpp b/src/parser.hpp index adac6e7043..0d3723712d 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -38,6 +38,7 @@ enum NodeType { NodeTypeSymbol, NodeTypePrefixOpExpr, NodeTypeFnCallExpr, + NodeTypeArrayAccessExpr, NodeTypeUse, NodeTypeVoid, NodeTypeBoolLiteral, @@ -143,6 +144,11 @@ struct AstNodeFnCallExpr { ZigList<AstNode *> params; }; +struct AstNodeArrayAccessExpr { + AstNode *array_ref_expr; + AstNode *subscript; +}; + struct AstNodeExternBlock { ZigList<AstNode *> *directives; ZigList<AstNode *> fn_decls; @@ -219,6 +225,7 @@ struct AstNode { AstNodeCastExpr cast_expr; AstNodePrefixOpExpr prefix_op_expr; AstNodeFnCallExpr fn_call_expr; + AstNodeArrayAccessExpr array_access_expr; AstNodeUse use; AstNodeIfExpr if_expr; AstNodeLabel label; diff --git a/src/semantic_info.hpp b/src/semantic_info.hpp deleted file mode 100644 index 04039289b6..0000000000 --- a/src/semantic_info.hpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_SEMANTIC_INFO_HPP -#define ZIG_SEMANTIC_INFO_HPP - -#include "codegen.hpp" -#include "hash_map.hpp" -#include "zig_llvm.hpp" -#include "errmsg.hpp" - -struct FnTableEntry; -struct BlockContext; - -struct TypeTableEntry { - LLVMTypeRef type_ref; - LLVMZigDIType *di_type; - uint64_t size_in_bits; - uint64_t align_in_bits; - bool is_signed_int; - bool is_float; - - TypeTableEntry *pointer_child; - 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 { - AstNode *root; - Buf *path; // relative to root_source_dir - LLVMZigDIFile *di_file; - Buf *source_code; - ZigList<int> *line_offsets; - - // reminder: hash tables must be initialized before use - HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; -}; - -struct LabelTableEntry { - AstNode *label_node; - LLVMBasicBlockRef basic_block; - bool used; - bool entered_from_fallthrough; -}; - -struct FnTableEntry { - LLVMValueRef fn_value; - AstNode *proto_node; - AstNode *fn_def_node; - bool is_extern; - bool internal_linkage; - unsigned calling_convention; - ImportTableEntry *import_entry; - - // reminder: hash tables must be initialized before use - HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table; -}; - -struct CodeGen { - LLVMModuleRef module; - ZigList<ErrorMsg*> errors; - LLVMBuilderRef builder; - LLVMZigDIBuilder *dbuilder; - LLVMZigDICompileUnit *compile_unit; - - // reminder: hash tables must be initialized before use - HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; - HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; - HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; - HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; - HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; - - struct { - TypeTableEntry *entry_bool; - TypeTableEntry *entry_u8; - TypeTableEntry *entry_i32; - TypeTableEntry *entry_f32; - TypeTableEntry *entry_string_literal; - TypeTableEntry *entry_void; - TypeTableEntry *entry_unreachable; - TypeTableEntry *entry_invalid; - } builtin_types; - - LLVMTargetDataRef target_data_ref; - unsigned pointer_size_bytes; - bool is_static; - bool strip_debug_symbols; - CodeGenBuildType build_type; - LLVMTargetMachineRef target_machine; - bool is_native_target; - Buf *root_source_dir; - Buf *root_out_name; - - // The function definitions this module includes. There must be a corresponding - // fn_protos entry. - ZigList<FnTableEntry *> fn_defs; - // The function prototypes this module includes. In the case of external declarations, - // there will not be a corresponding fn_defs entry. - ZigList<FnTableEntry *> fn_protos; - - OutType out_type; - FnTableEntry *cur_fn; - LLVMBasicBlockRef cur_basic_block; - BlockContext *cur_block_context; - bool c_stdint_used; - AstNode *root_export_decl; - int version_major; - int version_minor; - int version_patch; - bool verbose; - ErrColor err_color; - ImportTableEntry *root_import; -}; - -struct LocalVariableTableEntry { - Buf name; - TypeTableEntry *type; - LLVMValueRef value_ref; - bool is_const; - bool is_ptr; // if true, value_ref is a pointer - AstNode *decl_node; - LLVMZigDILocalVariable *di_loc_var; - int arg_index; -}; - -struct BlockContext { - AstNode *node; // either NodeTypeFnDef or NodeTypeBlock - BlockContext *root; // always points to the BlockContext with the NodeTypeFnDef - BlockContext *parent; // nullptr when this is the root - HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table; - LLVMZigDIScope *di_scope; -}; - -struct TypeNode { - TypeTableEntry *entry; -}; - -struct FnProtoNode { - FnTableEntry *fn_table_entry; -}; - -struct FnDefNode { - TypeTableEntry *implicit_return_type; - BlockContext *block_context; - bool skip; - // Required to be a pre-order traversal of the AST. (parents must come before children) - ZigList<BlockContext *> all_block_contexts; -}; - -struct ExprNode { - TypeTableEntry *type_entry; - // the context in which this expression is evaluated. - // for blocks, this points to the containing scope, not the block's own scope for its children. - BlockContext *block_context; -}; - -struct AssignNode { - LocalVariableTableEntry *var_entry; -}; - -struct BlockNode { - BlockContext *block_context; -}; - -struct CodeGenNode { - union { - TypeNode type_node; // for NodeTypeType - FnDefNode fn_def_node; // for NodeTypeFnDef - FnProtoNode fn_proto_node; // for NodeTypeFnProto - LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel - AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign - BlockNode block_node; // for NodeTypeBlock - } data; - ExprNode expr_node; // for all the expression nodes -}; - -static inline Buf *hack_get_fn_call_name(CodeGen *g, AstNode *node) { - // Assume that the expression evaluates to a simple name and return the buf - // TODO after type checking works we should be able to remove this hack - assert(node->type == NodeTypeSymbol); - return &node->data.symbol; -} - -#endif |
