| author | |
| committer | |
| log | 4bbc074dd7d78f83c57103b22f95967f0936e904 |
| tree | a3ff6adacd0724470e37452a0fa2f32615675f18 |
| parent | 7d22a89eecde6e69323734fa7e8211555231510b |
7 files changed, 348 insertions(+), 93 deletions(-)
README.md+20-12| ... | @@ -72,27 +72,35 @@ zig | C equivalent | Description | ... | @@ -72,27 +72,35 @@ zig | C equivalent | Description |
| 72 | ### Grammar | 72 | ### Grammar |
| 73 | 73 | ||
| 74 | ``` | 74 | ``` |
| 75 | Root : many(FnDecl) token(EOF); | 75 | Root : many(TopLevelDecl) token(EOF) |
| 76 | 76 | ||
| 77 | FnDecl : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) Block; | 77 | TopLevelDecl : FnDef | ExternBlock |
| 78 | 78 | ||
| 79 | ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen); | 79 | ExternBlock : token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace) |
| 80 | 80 | ||
| 81 | ParamDecl : token(Symbol) token(Colon) Type; | 81 | FnProto : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) |
| 82 | 82 | ||
| 83 | Type : token(Symbol) | PointerType; | 83 | FnDecl : FnProto token(Semicolon) |
| 84 | 84 | ||
| 85 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type; | 85 | FnDef : FnProto Block |
| 86 | 86 | ||
| 87 | Block : token(LBrace) many(Statement) token(RBrace); | 87 | ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen) |
| 88 | 88 | ||
| 89 | Statement : ExpressionStatement | ReturnStatement ; | 89 | ParamDecl : token(Symbol) token(Colon) Type |
| 90 | 90 | ||
| 91 | ExpressionStatement : Expression token(Semicolon) ; | 91 | Type : token(Symbol) | PointerType |
| 92 | 92 | ||
| 93 | ReturnStatement : token(Return) Expression token(Semicolon) ; | 93 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type |
| 94 | 94 | ||
| 95 | Expression : token(Number) | token(String) | FnCall ; | 95 | Block : token(LBrace) many(Statement) token(RBrace) |
| 96 | 96 | ||
| 97 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ; | 97 | Statement : ExpressionStatement | ReturnStatement |
| 98 | |||
| 99 | ExpressionStatement : Expression token(Semicolon) | ||
| 100 | |||
| 101 | ReturnStatement : token(Return) Expression token(Semicolon) | ||
| 102 | |||
| 103 | Expression : token(Number) | token(String) | FnCall | ||
| 104 | |||
| 105 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) | ||
| 98 | ``` | 106 | ``` |
src/codegen.cpp+149-56| ... | @@ -5,29 +5,33 @@ | ... | @@ -5,29 +5,33 @@ |
| 5 | 5 | ||
| 6 | #include <llvm-c/Core.h> | 6 | #include <llvm-c/Core.h> |
| 7 | 7 | ||
| 8 | struct FnTableEntry { | ||
| 9 | LLVMValueRef fn_value; | ||
| 10 | AstNode *proto_node; | ||
| 11 | }; | ||
| 12 | |||
| 8 | struct CodeGen { | 13 | struct CodeGen { |
| 14 | LLVMModuleRef mod; | ||
| 9 | AstNode *root; | 15 | AstNode *root; |
| 10 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> fn_decls; | 16 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> fn_defs; |
| 11 | ZigList<ErrorMsg> errors; | 17 | ZigList<ErrorMsg> errors; |
| 12 | LLVMBuilderRef builder; | 18 | LLVMBuilderRef builder; |
| 13 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> external_fns; | 19 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; |
| 14 | }; | 20 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; |
| 15 | |||
| 16 | struct ExpressionNode { | ||
| 17 | AstNode *type_node; | ||
| 18 | }; | 21 | }; |
| 19 | 22 | ||
| 20 | struct CodeGenNode { | 23 | struct CodeGenNode { |
| 21 | union { | 24 | union { |
| 22 | LLVMTypeRef type_ref; // for NodeTypeType | 25 | LLVMTypeRef type_ref; // for NodeTypeType |
| 23 | ExpressionNode expr; // for NodeTypeExpression | ||
| 24 | } data; | 26 | } data; |
| 25 | }; | 27 | }; |
| 26 | 28 | ||
| 27 | CodeGen *create_codegen(AstNode *root) { | 29 | CodeGen *create_codegen(AstNode *root) { |
| 28 | CodeGen *g = allocate<CodeGen>(1); | 30 | CodeGen *g = allocate<CodeGen>(1); |
| 29 | g->root = root; | 31 | g->root = root; |
| 30 | g->fn_decls.init(32); | 32 | g->fn_defs.init(32); |
| 33 | g->fn_table.init(32); | ||
| 34 | g->str_table.init(32); | ||
| 31 | return g; | 35 | return g; |
| 32 | } | 36 | } |
| 33 | 37 | ||
| ... | @@ -41,31 +45,81 @@ static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { | ... | @@ -41,31 +45,81 @@ static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 41 | last_msg->msg = msg; | 45 | last_msg->msg = msg; |
| 42 | } | 46 | } |
| 43 | 47 | ||
| 48 | static LLVMTypeRef to_llvm_type(AstNode *type_node) { | ||
| 49 | assert(type_node->type == NodeTypeType); | ||
| 50 | assert(type_node->codegen_node); | ||
| 51 | |||
| 52 | return type_node->codegen_node->data.type_ref; | ||
| 53 | } | ||
| 54 | |||
| 44 | static void analyze_node(CodeGen *g, AstNode *node) { | 55 | static void analyze_node(CodeGen *g, AstNode *node) { |
| 45 | switch (node->type) { | 56 | switch (node->type) { |
| 46 | case NodeTypeRoot: | 57 | case NodeTypeRoot: |
| 47 | for (int i = 0; i < node->data.root.fn_decls.length; i += 1) { | 58 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { |
| 48 | AstNode *child = node->data.root.fn_decls.at(i); | 59 | AstNode *child = node->data.root.top_level_decls.at(i); |
| 49 | analyze_node(g, child); | 60 | analyze_node(g, child); |
| 50 | } | 61 | } |
| 51 | break; | 62 | break; |
| 52 | case NodeTypeFnDecl: | 63 | case NodeTypeExternBlock: |
| 64 | for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) { | ||
| 65 | AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i); | ||
| 66 | analyze_node(g, fn_decl); | ||
| 67 | |||
| 68 | AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto; | ||
| 69 | Buf *name = &fn_proto->data.fn_proto.name; | ||
| 70 | ZigList<AstNode *> *params = &fn_proto->data.fn_proto.params; | ||
| 71 | |||
| 72 | LLVMTypeRef *fn_param_values = allocate<LLVMTypeRef>(params->length); | ||
| 73 | for (int param_i = 0; param_i < params->length; param_i += 1) { | ||
| 74 | AstNode *param_node = params->at(param_i); | ||
| 75 | assert(param_node->type == NodeTypeParamDecl); | ||
| 76 | AstNode *param_type = param_node->data.param_decl.type; | ||
| 77 | fn_param_values[param_i] = to_llvm_type(param_type); | ||
| 78 | } | ||
| 79 | LLVMTypeRef return_type = to_llvm_type(fn_proto->data.fn_proto.return_type); | ||
| 80 | |||
| 81 | LLVMTypeRef fn_type = LLVMFunctionType(return_type, fn_param_values, params->length, 0); | ||
| 82 | LLVMValueRef fn_val = LLVMAddFunction(g->mod, buf_ptr(name), fn_type); | ||
| 83 | LLVMSetLinkage(fn_val, LLVMExternalLinkage); | ||
| 84 | LLVMSetFunctionCallConv(fn_val, LLVMCCallConv); | ||
| 85 | |||
| 86 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); | ||
| 87 | fn_table_entry->fn_value = fn_val; | ||
| 88 | fn_table_entry->proto_node = fn_proto; | ||
| 89 | g->fn_table.put(name, fn_table_entry); | ||
| 90 | } | ||
| 91 | break; | ||
| 92 | case NodeTypeFnDef: | ||
| 53 | { | 93 | { |
| 54 | auto entry = g->fn_decls.maybe_get(&node->data.fn_decl.name); | 94 | AstNode *proto_node = node->data.fn_def.fn_proto; |
| 95 | assert(proto_node->type = NodeTypeFnProto); | ||
| 96 | Buf *proto_name = &proto_node->data.fn_proto.name; | ||
| 97 | auto entry = g->fn_defs.maybe_get(proto_name); | ||
| 55 | if (entry) { | 98 | if (entry) { |
| 56 | add_node_error(g, node, | 99 | add_node_error(g, node, |
| 57 | buf_sprintf("redefinition of '%s'", buf_ptr(&node->data.fn_decl.name))); | 100 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 58 | } else { | 101 | } else { |
| 59 | g->fn_decls.put(&node->data.fn_decl.name, node); | 102 | g->fn_defs.put(proto_name, node); |
| 60 | for (int i = 0; i < node->data.fn_decl.params.length; i += 1) { | 103 | analyze_node(g, proto_node); |
| 61 | AstNode *child = node->data.fn_decl.params.at(i); | ||
| 62 | analyze_node(g, child); | ||
| 63 | } | ||
| 64 | analyze_node(g, node->data.fn_decl.return_type); | ||
| 65 | analyze_node(g, node->data.fn_decl.body); | ||
| 66 | } | 104 | } |
| 67 | break; | 105 | break; |
| 68 | } | 106 | } |
| 107 | case NodeTypeFnDecl: | ||
| 108 | { | ||
| 109 | AstNode *proto_node = node->data.fn_decl.fn_proto; | ||
| 110 | assert(proto_node->type == NodeTypeFnProto); | ||
| 111 | analyze_node(g, proto_node); | ||
| 112 | break; | ||
| 113 | } | ||
| 114 | case NodeTypeFnProto: | ||
| 115 | { | ||
| 116 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { | ||
| 117 | AstNode *child = node->data.fn_proto.params.at(i); | ||
| 118 | analyze_node(g, child); | ||
| 119 | } | ||
| 120 | analyze_node(g, node->data.fn_proto.return_type); | ||
| 121 | break; | ||
| 122 | } | ||
| 69 | case NodeTypeParamDecl: | 123 | case NodeTypeParamDecl: |
| 70 | analyze_node(g, node->data.param_decl.type); | 124 | analyze_node(g, node->data.param_decl.type); |
| 71 | break; | 125 | break; |
| ... | @@ -131,47 +185,81 @@ static void analyze_node(CodeGen *g, AstNode *node) { | ... | @@ -131,47 +185,81 @@ static void analyze_node(CodeGen *g, AstNode *node) { |
| 131 | } | 185 | } |
| 132 | 186 | ||
| 133 | 187 | ||
| 134 | /* TODO external fn | ||
| 135 | LLVMTypeRef puts_param_types[] = {LLVMPointerType(LLVMInt8Type(), 0)}; | ||
| 136 | LLVMTypeRef puts_type = LLVMFunctionType(LLVMInt32Type(), puts_param_types, 1, 0); | ||
| 137 | LLVMValueRef puts_fn = LLVMAddFunction(mod, "puts", puts_type); | ||
| 138 | LLVMSetLinkage(puts_fn, LLVMExternalLinkage); | ||
| 139 | */ | ||
| 140 | |||
| 141 | void semantic_analyze(CodeGen *g) { | 188 | void semantic_analyze(CodeGen *g) { |
| 189 | g->mod = LLVMModuleCreateWithName("ZigModule"); | ||
| 190 | |||
| 142 | // Pass 1. | 191 | // Pass 1. |
| 143 | analyze_node(g, g->root); | 192 | analyze_node(g, g->root); |
| 144 | } | 193 | } |
| 145 | 194 | ||
| 146 | static LLVMTypeRef to_llvm_type(AstNode *type_node) { | 195 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); |
| 147 | assert(type_node->type == NodeTypeType); | ||
| 148 | assert(type_node->codegen_node); | ||
| 149 | |||
| 150 | return type_node->codegen_node->data.type_ref; | ||
| 151 | } | ||
| 152 | 196 | ||
| 153 | static LLVMValueRef gen_fn_call(CodeGen *g, AstNode *fn_call_node) { | 197 | static LLVMValueRef gen_fn_call(CodeGen *g, AstNode *fn_call_node) { |
| 154 | assert(fn_call_node->type == NodeTypeFnCall); | 198 | assert(fn_call_node->type == NodeTypeFnCall); |
| 155 | 199 | ||
| 156 | zig_panic("TODO support external fn declarations"); | 200 | Buf *name = &fn_call_node->data.fn_call.name; |
| 157 | //LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), ); | ||
| 158 | 201 | ||
| 159 | // resolve function name | 202 | auto entry = g->fn_table.maybe_get(name); |
| 160 | //LLVMValueRef result = LLVMBuildCall(g->builder, | 203 | if (!entry) { |
| 204 | add_node_error(g, fn_call_node, | ||
| 205 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); | ||
| 206 | return LLVMConstNull(LLVMInt32Type()); | ||
| 207 | } | ||
| 208 | FnTableEntry *fn_table_entry = entry->value; | ||
| 209 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); | ||
| 210 | int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length; | ||
| 211 | int actual_param_count = fn_call_node->data.fn_call.params.length; | ||
| 212 | if (expected_param_count != actual_param_count) { | ||
| 213 | add_node_error(g, fn_call_node, | ||
| 214 | buf_sprintf("wrong number of arguments. Expected %d, got %d.", | ||
| 215 | expected_param_count, actual_param_count)); | ||
| 216 | return LLVMConstNull(LLVMInt32Type()); | ||
| 217 | } | ||
| 161 | 218 | ||
| 219 | LLVMValueRef *param_values = allocate<LLVMValueRef>(actual_param_count); | ||
| 220 | for (int i = 0; i < actual_param_count; i += 1) { | ||
| 221 | AstNode *expr_node = fn_call_node->data.fn_call.params.at(i); | ||
| 222 | param_values[i] = gen_expr(g, expr_node); | ||
| 223 | } | ||
| 162 | 224 | ||
| 163 | //return value; | 225 | LLVMValueRef result = LLVMBuildCall(g->builder, fn_table_entry->fn_value, |
| 226 | param_values, actual_param_count, ""); | ||
| 227 | |||
| 228 | return result; | ||
| 229 | } | ||
| 230 | |||
| 231 | static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) { | ||
| 232 | auto entry = g->str_table.maybe_get(str); | ||
| 233 | if (entry) { | ||
| 234 | return entry->value; | ||
| 235 | } | ||
| 236 | LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), false); | ||
| 237 | LLVMValueRef global_value = LLVMAddGlobal(g->mod, LLVMTypeOf(text), ""); | ||
| 238 | LLVMSetLinkage(global_value, LLVMInternalLinkage); | ||
| 239 | LLVMSetInitializer(global_value, text); | ||
| 240 | LLVMSetGlobalConstant(global_value, true); | ||
| 241 | g->str_table.put(str, global_value); | ||
| 242 | |||
| 243 | return global_value; | ||
| 164 | } | 244 | } |
| 165 | 245 | ||
| 166 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node) { | 246 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node) { |
| 167 | assert(expr_node->type == NodeTypeExpression); | 247 | assert(expr_node->type == NodeTypeExpression); |
| 168 | switch (expr_node->data.expression.type) { | 248 | switch (expr_node->data.expression.type) { |
| 169 | case AstNodeExpressionTypeNumber: | 249 | case AstNodeExpressionTypeNumber: |
| 170 | zig_panic("TODO number expr"); | 250 | { |
| 171 | break; | 251 | Buf *number_str = &expr_node->data.expression.data.number; |
| 252 | LLVMTypeRef number_type = LLVMInt32Type(); | ||
| 253 | LLVMValueRef number_val = LLVMConstIntOfStringAndSize(number_type, | ||
| 254 | buf_ptr(number_str), buf_len(number_str), 10); | ||
| 255 | return number_val; | ||
| 256 | } | ||
| 172 | case AstNodeExpressionTypeString: | 257 | case AstNodeExpressionTypeString: |
| 173 | zig_panic("TODO string expr"); | 258 | { |
| 174 | break; | 259 | Buf *str = &expr_node->data.expression.data.string; |
| 260 | fprintf(stderr, "str = '%s'\n", buf_ptr(str)); | ||
| 261 | return find_or_create_string(g, str); | ||
| 262 | } | ||
| 175 | case AstNodeExpressionTypeFnCall: | 263 | case AstNodeExpressionTypeFnCall: |
| 176 | return gen_fn_call(g, expr_node->data.expression.data.fn_call); | 264 | return gen_fn_call(g, expr_node->data.expression.data.fn_call); |
| 177 | } | 265 | } |
| ... | @@ -203,32 +291,37 @@ static void gen_block(CodeGen *g, AstNode *block_node) { | ... | @@ -203,32 +291,37 @@ static void gen_block(CodeGen *g, AstNode *block_node) { |
| 203 | } | 291 | } |
| 204 | 292 | ||
| 205 | void code_gen(CodeGen *g) { | 293 | void code_gen(CodeGen *g) { |
| 206 | LLVMModuleRef mod = LLVMModuleCreateWithName("ZigModule"); | ||
| 207 | g->builder = LLVMCreateBuilder(); | 294 | g->builder = LLVMCreateBuilder(); |
| 208 | 295 | ||
| 296 | auto it = g->fn_defs.entry_iterator(); | ||
| 297 | for (;;) { | ||
| 298 | auto *entry = it.next(); | ||
| 299 | if (!entry) | ||
| 300 | break; | ||
| 209 | 301 | ||
| 210 | for (int fn_decl_i = 0; fn_decl_i < g->root->data.root.fn_decls.length; fn_decl_i += 1) { | 302 | AstNode *fn_def_node = entry->value; |
| 211 | AstNode *fn_decl_node = g->root->data.root.fn_decls.at(fn_decl_i); | 303 | AstNodeFnDef *fn_def = &fn_def_node->data.fn_def; |
| 212 | AstNodeFnDecl *fn_decl = &fn_decl_node->data.fn_decl; | 304 | assert(fn_def->fn_proto->type == NodeTypeFnProto); |
| 305 | AstNodeFnProto *fn_proto = &fn_def->fn_proto->data.fn_proto; | ||
| 213 | 306 | ||
| 214 | LLVMTypeRef ret_type = to_llvm_type(fn_decl->return_type); | 307 | LLVMTypeRef ret_type = to_llvm_type(fn_proto->return_type); |
| 215 | LLVMTypeRef *param_types = allocate<LLVMTypeRef>(fn_decl->params.length); | 308 | LLVMTypeRef *param_types = allocate<LLVMTypeRef>(fn_proto->params.length); |
| 216 | for (int param_decl_i = 0; param_decl_i < fn_decl->params.length; param_decl_i += 1) { | 309 | for (int param_decl_i = 0; param_decl_i < fn_proto->params.length; param_decl_i += 1) { |
| 217 | AstNode *param_node = fn_decl->params.at(param_decl_i); | 310 | AstNode *param_node = fn_proto->params.at(param_decl_i); |
| 218 | assert(param_node->type == NodeTypeParamDecl); | 311 | assert(param_node->type == NodeTypeParamDecl); |
| 219 | AstNode *type_node = param_node->data.param_decl.type; | 312 | AstNode *type_node = param_node->data.param_decl.type; |
| 220 | param_types[param_decl_i] = to_llvm_type(type_node); | 313 | param_types[param_decl_i] = to_llvm_type(type_node); |
| 221 | } | 314 | } |
| 222 | LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, fn_decl->params.length, 0); | 315 | LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, fn_proto->params.length, 0); |
| 223 | LLVMValueRef fn = LLVMAddFunction(mod, buf_ptr(&fn_decl->name), function_type); | 316 | LLVMValueRef fn = LLVMAddFunction(g->mod, buf_ptr(&fn_proto->name), function_type); |
| 224 | 317 | ||
| 225 | LLVMBasicBlockRef entry = LLVMAppendBasicBlock(fn, "entry"); | 318 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn, "entry"); |
| 226 | LLVMPositionBuilderAtEnd(g->builder, entry); | 319 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 227 | 320 | ||
| 228 | gen_block(g, fn_decl->body); | 321 | gen_block(g, fn_def->body); |
| 229 | } | 322 | } |
| 230 | 323 | ||
| 231 | LLVMDumpModule(mod); | 324 | LLVMDumpModule(g->mod); |
| 232 | } | 325 | } |
| 233 | 326 | ||
| 234 | ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g) { | 327 | ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g) { |
src/parser.cpp+151-23| ... | @@ -20,8 +20,12 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -20,8 +20,12 @@ const char *node_type_str(NodeType node_type) { |
| 20 | switch (node_type) { | 20 | switch (node_type) { |
| 21 | case NodeTypeRoot: | 21 | case NodeTypeRoot: |
| 22 | return "Root"; | 22 | return "Root"; |
| 23 | case NodeTypeFnDef: | ||
| 24 | return "FnDef"; | ||
| 23 | case NodeTypeFnDecl: | 25 | case NodeTypeFnDecl: |
| 24 | return "FnDecl"; | 26 | return "FnDecl"; |
| 27 | case NodeTypeFnProto: | ||
| 28 | return "FnProto"; | ||
| 25 | case NodeTypeParamDecl: | 29 | case NodeTypeParamDecl: |
| 26 | return "ParamDecl"; | 30 | return "ParamDecl"; |
| 27 | case NodeTypeType: | 31 | case NodeTypeType: |
| ... | @@ -34,6 +38,8 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -34,6 +38,8 @@ const char *node_type_str(NodeType node_type) { |
| 34 | return "Expression"; | 38 | return "Expression"; |
| 35 | case NodeTypeFnCall: | 39 | case NodeTypeFnCall: |
| 36 | return "FnCall"; | 40 | return "FnCall"; |
| 41 | case NodeTypeExternBlock: | ||
| 42 | return "ExternBlock"; | ||
| 37 | } | 43 | } |
| 38 | zig_unreachable(); | 44 | zig_unreachable(); |
| 39 | } | 45 | } |
| ... | @@ -46,24 +52,30 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -46,24 +52,30 @@ void ast_print(AstNode *node, int indent) { |
| 46 | switch (node->type) { | 52 | switch (node->type) { |
| 47 | case NodeTypeRoot: | 53 | case NodeTypeRoot: |
| 48 | fprintf(stderr, "%s\n", node_type_str(node->type)); | 54 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 49 | for (int i = 0; i < node->data.root.fn_decls.length; i += 1) { | 55 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { |
| 50 | AstNode *child = node->data.root.fn_decls.at(i); | 56 | AstNode *child = node->data.root.top_level_decls.at(i); |
| 51 | ast_print(child, indent + 2); | 57 | ast_print(child, indent + 2); |
| 52 | } | 58 | } |
| 53 | break; | 59 | break; |
| 54 | case NodeTypeFnDecl: | 60 | case NodeTypeFnDef: |
| 61 | { | ||
| 62 | fprintf(stderr, "%s\n", node_type_str(node->type)); | ||
| 63 | AstNode *child = node->data.fn_def.fn_proto; | ||
| 64 | ast_print(child, indent + 2); | ||
| 65 | ast_print(node->data.fn_def.body, indent + 2); | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | case NodeTypeFnProto: | ||
| 55 | { | 69 | { |
| 56 | Buf *name_buf = &node->data.fn_decl.name; | 70 | Buf *name_buf = &node->data.fn_proto.name; |
| 57 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); | 71 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); |
| 58 | 72 | ||
| 59 | for (int i = 0; i < node->data.fn_decl.params.length; i += 1) { | 73 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { |
| 60 | AstNode *child = node->data.fn_decl.params.at(i); | 74 | AstNode *child = node->data.fn_proto.params.at(i); |
| 61 | ast_print(child, indent + 2); | 75 | ast_print(child, indent + 2); |
| 62 | } | 76 | } |
| 63 | 77 | ||
| 64 | ast_print(node->data.fn_decl.return_type, indent + 2); | 78 | ast_print(node->data.fn_proto.return_type, indent + 2); |
| 65 | |||
| 66 | ast_print(node->data.fn_decl.body, indent + 2); | ||
| 67 | 79 | ||
| 68 | break; | 80 | break; |
| 69 | } | 81 | } |
| ... | @@ -115,6 +127,19 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -115,6 +127,19 @@ void ast_print(AstNode *node, int indent) { |
| 115 | break; | 127 | break; |
| 116 | } | 128 | } |
| 117 | break; | 129 | break; |
| 130 | case NodeTypeExternBlock: | ||
| 131 | { | ||
| 132 | fprintf(stderr, "%s\n", node_type_str(node->type)); | ||
| 133 | for (int i = 0; i < node->data.extern_block.fn_decls.length; i += 1) { | ||
| 134 | AstNode *child = node->data.extern_block.fn_decls.at(i); | ||
| 135 | ast_print(child, indent + 2); | ||
| 136 | } | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | case NodeTypeFnDecl: | ||
| 140 | fprintf(stderr, "%s\n", node_type_str(node->type)); | ||
| 141 | ast_print(node->data.fn_decl.fn_proto, indent + 2); | ||
| 142 | break; | ||
| 118 | default: | 143 | default: |
| 119 | fprintf(stderr, "%s\n", node_type_str(node->type)); | 144 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 120 | break; | 145 | break; |
| ... | @@ -135,10 +160,52 @@ static AstNode *ast_create_node(NodeType type, Token *first_token) { | ... | @@ -135,10 +160,52 @@ static AstNode *ast_create_node(NodeType type, Token *first_token) { |
| 135 | return node; | 160 | return node; |
| 136 | } | 161 | } |
| 137 | 162 | ||
| 163 | static AstNode *ast_create_node_with_node(NodeType type, AstNode *other_node) { | ||
| 164 | AstNode *node = allocate<AstNode>(1); | ||
| 165 | node->type = type; | ||
| 166 | node->line = other_node->line; | ||
| 167 | node->column = other_node->column; | ||
| 168 | return node; | ||
| 169 | } | ||
| 170 | |||
| 138 | static void ast_buf_from_token(ParseContext *pc, Token *token, Buf *buf) { | 171 | static void ast_buf_from_token(ParseContext *pc, Token *token, Buf *buf) { |
| 139 | buf_init_from_mem(buf, buf_ptr(pc->buf) + token->start_pos, token->end_pos - token->start_pos); | 172 | buf_init_from_mem(buf, buf_ptr(pc->buf) + token->start_pos, token->end_pos - token->start_pos); |
| 140 | } | 173 | } |
| 141 | 174 | ||
| 175 | static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf) { | ||
| 176 | // skip the double quotes at beginning and end | ||
| 177 | // convert escape sequences | ||
| 178 | bool escape = false; | ||
| 179 | for (int i = token->start_pos; i < token->end_pos - 1; i += 1) { | ||
| 180 | uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i); | ||
| 181 | if (escape) { | ||
| 182 | switch (c) { | ||
| 183 | case '\\': | ||
| 184 | buf_append_char(buf, '\\'); | ||
| 185 | break; | ||
| 186 | case 'r': | ||
| 187 | buf_append_char(buf, '\r'); | ||
| 188 | break; | ||
| 189 | case 'n': | ||
| 190 | buf_append_char(buf, '\n'); | ||
| 191 | break; | ||
| 192 | case 't': | ||
| 193 | buf_append_char(buf, '\t'); | ||
| 194 | break; | ||
| 195 | case '"': | ||
| 196 | buf_append_char(buf, '"'); | ||
| 197 | break; | ||
| 198 | } | ||
| 199 | escape = false; | ||
| 200 | } else if (c == '\\') { | ||
| 201 | escape = true; | ||
| 202 | } else { | ||
| 203 | buf_append_char(buf, c); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | assert(!escape); | ||
| 207 | } | ||
| 208 | |||
| 142 | static void ast_invalid_token_error(ParseContext *pc, Token *token) { | 209 | static void ast_invalid_token_error(ParseContext *pc, Token *token) { |
| 143 | Buf token_value = {0}; | 210 | Buf token_value = {0}; |
| 144 | ast_buf_from_token(pc, token, &token_value); | 211 | ast_buf_from_token(pc, token, &token_value); |
| ... | @@ -304,7 +371,7 @@ static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new | ... | @@ -304,7 +371,7 @@ static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new |
| 304 | token_index += 1; | 371 | token_index += 1; |
| 305 | } else if (token->id == TokenIdStringLiteral) { | 372 | } else if (token->id == TokenIdStringLiteral) { |
| 306 | node->data.expression.type = AstNodeExpressionTypeString; | 373 | node->data.expression.type = AstNodeExpressionTypeString; |
| 307 | ast_buf_from_token(pc, token, &node->data.expression.data.string); | 374 | parse_string_literal(pc, token, &node->data.expression.data.string); |
| 308 | token_index += 1; | 375 | token_index += 1; |
| 309 | } else { | 376 | } else { |
| 310 | ast_invalid_token_error(pc, token); | 377 | ast_invalid_token_error(pc, token); |
| ... | @@ -381,50 +448,111 @@ static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_toke | ... | @@ -381,50 +448,111 @@ static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_toke |
| 381 | } | 448 | } |
| 382 | 449 | ||
| 383 | /* | 450 | /* |
| 384 | FnDecl : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) Block; | 451 | FnProto : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) |
| 385 | */ | 452 | */ |
| 386 | static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) { | 453 | static AstNode *ast_parse_fn_proto(ParseContext *pc, int token_index, int *new_token_index) { |
| 387 | Token *fn_token = &pc->tokens->at(token_index); | 454 | Token *fn_token = &pc->tokens->at(token_index); |
| 388 | token_index += 1; | 455 | token_index += 1; |
| 389 | ast_expect_token(pc, fn_token, TokenIdKeywordFn); | 456 | ast_expect_token(pc, fn_token, TokenIdKeywordFn); |
| 390 | 457 | ||
| 391 | AstNode *node = ast_create_node(NodeTypeFnDecl, fn_token); | 458 | AstNode *node = ast_create_node(NodeTypeFnProto, fn_token); |
| 392 | 459 | ||
| 393 | 460 | ||
| 394 | Token *fn_name = &pc->tokens->at(token_index); | 461 | Token *fn_name = &pc->tokens->at(token_index); |
| 395 | token_index += 1; | 462 | token_index += 1; |
| 396 | ast_expect_token(pc, fn_name, TokenIdSymbol); | 463 | ast_expect_token(pc, fn_name, TokenIdSymbol); |
| 397 | 464 | ||
| 398 | ast_buf_from_token(pc, fn_name, &node->data.fn_decl.name); | 465 | ast_buf_from_token(pc, fn_name, &node->data.fn_proto.name); |
| 399 | 466 | ||
| 400 | 467 | ||
| 401 | ast_parse_param_decl_list(pc, token_index, &token_index, &node->data.fn_decl.params); | 468 | ast_parse_param_decl_list(pc, token_index, &token_index, &node->data.fn_proto.params); |
| 402 | 469 | ||
| 403 | Token *arrow = &pc->tokens->at(token_index); | 470 | Token *arrow = &pc->tokens->at(token_index); |
| 404 | token_index += 1; | 471 | token_index += 1; |
| 405 | if (arrow->id == TokenIdArrow) { | 472 | if (arrow->id == TokenIdArrow) { |
| 406 | node->data.fn_decl.return_type = ast_parse_type(pc, token_index, &token_index); | 473 | node->data.fn_proto.return_type = ast_parse_type(pc, token_index, &token_index); |
| 407 | } else if (arrow->id == TokenIdLBrace) { | 474 | } else if (arrow->id == TokenIdLBrace) { |
| 408 | node->data.fn_decl.return_type = nullptr; | 475 | node->data.fn_proto.return_type = nullptr; |
| 409 | } else { | 476 | } else { |
| 410 | ast_invalid_token_error(pc, arrow); | 477 | ast_invalid_token_error(pc, arrow); |
| 411 | } | 478 | } |
| 412 | 479 | ||
| 413 | node->data.fn_decl.body = ast_parse_block(pc, token_index, &token_index); | 480 | *new_token_index = token_index; |
| 481 | return node; | ||
| 482 | } | ||
| 483 | |||
| 484 | /* | ||
| 485 | FnDef : FnProto Block | ||
| 486 | */ | ||
| 487 | static AstNode *ast_parse_fn_def(ParseContext *pc, int token_index, int *new_token_index) { | ||
| 488 | AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, &token_index); | ||
| 489 | AstNode *node = ast_create_node_with_node(NodeTypeFnDef, fn_proto); | ||
| 490 | |||
| 491 | node->data.fn_def.fn_proto = fn_proto; | ||
| 492 | node->data.fn_def.body = ast_parse_block(pc, token_index, &token_index); | ||
| 493 | |||
| 494 | *new_token_index = token_index; | ||
| 495 | return node; | ||
| 496 | } | ||
| 497 | |||
| 498 | /* | ||
| 499 | FnDecl : FnProto token(Semicolon) | ||
| 500 | */ | ||
| 501 | static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) { | ||
| 502 | AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, &token_index); | ||
| 503 | AstNode *node = ast_create_node_with_node(NodeTypeFnDecl, fn_proto); | ||
| 504 | |||
| 505 | node->data.fn_decl.fn_proto = fn_proto; | ||
| 506 | |||
| 507 | Token *semicolon = &pc->tokens->at(token_index); | ||
| 508 | token_index += 1; | ||
| 509 | ast_expect_token(pc, semicolon, TokenIdSemicolon); | ||
| 414 | 510 | ||
| 415 | *new_token_index = token_index; | 511 | *new_token_index = token_index; |
| 416 | return node; | 512 | return node; |
| 417 | } | 513 | } |
| 418 | 514 | ||
| 515 | /* | ||
| 516 | ExternBlock : token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace) | ||
| 517 | */ | ||
| 518 | static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *new_token_index) { | ||
| 519 | Token *extern_kw = &pc->tokens->at(token_index); | ||
| 520 | token_index += 1; | ||
| 521 | ast_expect_token(pc, extern_kw, TokenIdKeywordExtern); | ||
| 522 | |||
| 523 | AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw); | ||
| 524 | |||
| 525 | Token *l_brace = &pc->tokens->at(token_index); | ||
| 526 | token_index += 1; | ||
| 527 | ast_expect_token(pc, l_brace, TokenIdLBrace); | ||
| 528 | |||
| 529 | for (;;) { | ||
| 530 | Token *token = &pc->tokens->at(token_index); | ||
| 531 | if (token->id == TokenIdRBrace) { | ||
| 532 | token_index += 1; | ||
| 533 | *new_token_index = token_index; | ||
| 534 | return node; | ||
| 535 | } else { | ||
| 536 | AstNode *child = ast_parse_fn_decl(pc, token_index, &token_index); | ||
| 537 | node->data.extern_block.fn_decls.append(child); | ||
| 538 | } | ||
| 539 | } | ||
| 540 | |||
| 541 | |||
| 542 | zig_unreachable(); | ||
| 543 | } | ||
| 419 | 544 | ||
| 420 | static void ast_parse_fn_decl_list(ParseContext *pc, int token_index, ZigList<AstNode *> *fn_decls, | 545 | static void ast_parse_top_level_decls(ParseContext *pc, int token_index, int *new_token_index, |
| 421 | int *new_token_index) | 546 | ZigList<AstNode *> *top_level_decls) |
| 422 | { | 547 | { |
| 423 | for (;;) { | 548 | for (;;) { |
| 424 | Token *token = &pc->tokens->at(token_index); | 549 | Token *token = &pc->tokens->at(token_index); |
| 425 | if (token->id == TokenIdKeywordFn) { | 550 | if (token->id == TokenIdKeywordFn) { |
| 426 | AstNode *fn_decl_node = ast_parse_fn_decl(pc, token_index, &token_index); | 551 | AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, &token_index); |
| 427 | fn_decls->append(fn_decl_node); | 552 | top_level_decls->append(fn_decl_node); |
| 553 | } else if (token->id == TokenIdKeywordExtern) { | ||
| 554 | AstNode *extern_node = ast_parse_extern_block(pc, token_index, &token_index); | ||
| 555 | top_level_decls->append(extern_node); | ||
| 428 | } else { | 556 | } else { |
| 429 | *new_token_index = token_index; | 557 | *new_token_index = token_index; |
| 430 | return; | 558 | return; |
| ... | @@ -440,7 +568,7 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { | ... | @@ -440,7 +568,7 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { |
| 440 | pc.tokens = tokens; | 568 | pc.tokens = tokens; |
| 441 | 569 | ||
| 442 | int new_token_index; | 570 | int new_token_index; |
| 443 | ast_parse_fn_decl_list(&pc, 0, &pc.root->data.root.fn_decls, &new_token_index); | 571 | ast_parse_top_level_decls(&pc, 0, &new_token_index, &pc.root->data.root.top_level_decls); |
| 444 | 572 | ||
| 445 | if (new_token_index != tokens->length - 1) { | 573 | if (new_token_index != tokens->length - 1) { |
| 446 | ast_invalid_token_error(&pc, &tokens->at(new_token_index)); | 574 | ast_invalid_token_error(&pc, &tokens->at(new_token_index)); |
src/parser.hpp+20-2| ... | @@ -10,6 +10,8 @@ struct CodeGenNode; | ... | @@ -10,6 +10,8 @@ struct CodeGenNode; |
| 10 | 10 | ||
| 11 | enum NodeType { | 11 | enum NodeType { |
| 12 | NodeTypeRoot, | 12 | NodeTypeRoot, |
| 13 | NodeTypeFnProto, | ||
| 14 | NodeTypeFnDef, | ||
| 13 | NodeTypeFnDecl, | 15 | NodeTypeFnDecl, |
| 14 | NodeTypeParamDecl, | 16 | NodeTypeParamDecl, |
| 15 | NodeTypeType, | 17 | NodeTypeType, |
| ... | @@ -17,19 +19,28 @@ enum NodeType { | ... | @@ -17,19 +19,28 @@ enum NodeType { |
| 17 | NodeTypeStatement, | 19 | NodeTypeStatement, |
| 18 | NodeTypeExpression, | 20 | NodeTypeExpression, |
| 19 | NodeTypeFnCall, | 21 | NodeTypeFnCall, |
| 22 | NodeTypeExternBlock, | ||
| 20 | }; | 23 | }; |
| 21 | 24 | ||
| 22 | struct AstNodeRoot { | 25 | struct AstNodeRoot { |
| 23 | ZigList<AstNode *> fn_decls; | 26 | ZigList<AstNode *> top_level_decls; |
| 24 | }; | 27 | }; |
| 25 | 28 | ||
| 26 | struct AstNodeFnDecl { | 29 | struct AstNodeFnProto { |
| 27 | Buf name; | 30 | Buf name; |
| 28 | ZigList<AstNode *> params; | 31 | ZigList<AstNode *> params; |
| 29 | AstNode *return_type; | 32 | AstNode *return_type; |
| 33 | }; | ||
| 34 | |||
| 35 | struct AstNodeFnDef { | ||
| 36 | AstNode *fn_proto; | ||
| 30 | AstNode *body; | 37 | AstNode *body; |
| 31 | }; | 38 | }; |
| 32 | 39 | ||
| 40 | struct AstNodeFnDecl { | ||
| 41 | AstNode *fn_proto; | ||
| 42 | }; | ||
| 43 | |||
| 33 | struct AstNodeParamDecl { | 44 | struct AstNodeParamDecl { |
| 34 | Buf name; | 45 | Buf name; |
| 35 | AstNode *type; | 46 | AstNode *type; |
| ... | @@ -92,6 +103,10 @@ struct AstNodeFnCall { | ... | @@ -92,6 +103,10 @@ struct AstNodeFnCall { |
| 92 | ZigList<AstNode *> params; | 103 | ZigList<AstNode *> params; |
| 93 | }; | 104 | }; |
| 94 | 105 | ||
| 106 | struct AstNodeExternBlock { | ||
| 107 | ZigList<AstNode *> fn_decls; | ||
| 108 | }; | ||
| 109 | |||
| 95 | struct AstNode { | 110 | struct AstNode { |
| 96 | enum NodeType type; | 111 | enum NodeType type; |
| 97 | AstNode *parent; | 112 | AstNode *parent; |
| ... | @@ -100,13 +115,16 @@ struct AstNode { | ... | @@ -100,13 +115,16 @@ struct AstNode { |
| 100 | CodeGenNode *codegen_node; | 115 | CodeGenNode *codegen_node; |
| 101 | union { | 116 | union { |
| 102 | AstNodeRoot root; | 117 | AstNodeRoot root; |
| 118 | AstNodeFnDef fn_def; | ||
| 103 | AstNodeFnDecl fn_decl; | 119 | AstNodeFnDecl fn_decl; |
| 120 | AstNodeFnProto fn_proto; | ||
| 104 | AstNodeType type; | 121 | AstNodeType type; |
| 105 | AstNodeParamDecl param_decl; | 122 | AstNodeParamDecl param_decl; |
| 106 | AstNodeBlock block; | 123 | AstNodeBlock block; |
| 107 | AstNodeStatement statement; | 124 | AstNodeStatement statement; |
| 108 | AstNodeExpression expression; | 125 | AstNodeExpression expression; |
| 109 | AstNodeFnCall fn_call; | 126 | AstNodeFnCall fn_call; |
| 127 | AstNodeExternBlock extern_block; | ||
| 110 | } data; | 128 | } data; |
| 111 | }; | 129 | }; |
| 112 | 130 |
src/tokenizer.cpp+3| ... | @@ -150,6 +150,8 @@ static void end_token(Tokenize *t) { | ... | @@ -150,6 +150,8 @@ static void end_token(Tokenize *t) { |
| 150 | t->cur_tok->id = TokenIdKeywordMut; | 150 | t->cur_tok->id = TokenIdKeywordMut; |
| 151 | } else if (mem_eql_str(token_mem, token_len, "const")) { | 151 | } else if (mem_eql_str(token_mem, token_len, "const")) { |
| 152 | t->cur_tok->id = TokenIdKeywordConst; | 152 | t->cur_tok->id = TokenIdKeywordConst; |
| 153 | } else if (mem_eql_str(token_mem, token_len, "extern")) { | ||
| 154 | t->cur_tok->id = TokenIdKeywordExtern; | ||
| 153 | } | 155 | } |
| 154 | 156 | ||
| 155 | t->cur_tok = nullptr; | 157 | t->cur_tok = nullptr; |
| ... | @@ -307,6 +309,7 @@ static const char * token_name(Token *token) { | ... | @@ -307,6 +309,7 @@ static const char * token_name(Token *token) { |
| 307 | case TokenIdKeywordConst: return "Const"; | 309 | case TokenIdKeywordConst: return "Const"; |
| 308 | case TokenIdKeywordMut: return "Mut"; | 310 | case TokenIdKeywordMut: return "Mut"; |
| 309 | case TokenIdKeywordReturn: return "Return"; | 311 | case TokenIdKeywordReturn: return "Return"; |
| 312 | case TokenIdKeywordExtern: return "Extern"; | ||
| 310 | case TokenIdLParen: return "LParen"; | 313 | case TokenIdLParen: return "LParen"; |
| 311 | case TokenIdRParen: return "RParen"; | 314 | case TokenIdRParen: return "RParen"; |
| 312 | case TokenIdComma: return "Comma"; | 315 | case TokenIdComma: return "Comma"; |
src/tokenizer.hpp+1| ... | @@ -17,6 +17,7 @@ enum TokenId { | ... | @@ -17,6 +17,7 @@ enum TokenId { |
| 17 | TokenIdKeywordReturn, | 17 | TokenIdKeywordReturn, |
| 18 | TokenIdKeywordMut, | 18 | TokenIdKeywordMut, |
| 19 | TokenIdKeywordConst, | 19 | TokenIdKeywordConst, |
| 20 | TokenIdKeywordExtern, | ||
| 20 | TokenIdLParen, | 21 | TokenIdLParen, |
| 21 | TokenIdRParen, | 22 | TokenIdRParen, |
| 22 | TokenIdComma, | 23 | TokenIdComma, |
test/hello.zig+4| ... | @@ -1,3 +1,7 @@ | ... | @@ -1,3 +1,7 @@ |
| 1 | extern { | ||
| 2 | fn puts(s: *mut u8) -> i32; | ||
| 3 | } | ||
| 4 | |||
| 1 | fn main(argc: i32, argv: *mut *mut u8) -> i32 { | 5 | fn main(argc: i32, argv: *mut *mut u8) -> i32 { |
| 2 | puts("Hello, world!\n"); | 6 | puts("Hello, world!\n"); |
| 3 | return 0; | 7 | return 0; |