Commit 7d22a89eec

Andrew Kelley <superjoe30@gmail.com>
2015-11-24 08:35:23
partial hello world codegen
1 parent 3b4a2af
src/codegen.cpp
@@ -3,10 +3,25 @@
 
 #include <stdio.h>
 
+#include <llvm-c/Core.h>
+
 struct CodeGen {
     AstNode *root;
     HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> fn_decls;
     ZigList<ErrorMsg> errors;
+    LLVMBuilderRef builder;
+    HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> external_fns;
+};
+
+struct ExpressionNode {
+    AstNode *type_node;
+};
+
+struct CodeGenNode {
+    union {
+        LLVMTypeRef type_ref; // for NodeTypeType
+        ExpressionNode expr; // for NodeTypeExpression
+    } data;
 };
 
 CodeGen *create_codegen(AstNode *root) {
@@ -55,31 +70,165 @@ static void analyze_node(CodeGen *g, AstNode *node) {
             analyze_node(g, node->data.param_decl.type);
             break;
         case NodeTypeType:
-            break;
-        case NodeTypePointerType:
+            node->codegen_node = allocate<CodeGenNode>(1);
+            switch (node->data.type.type) {
+                case AstNodeTypeTypePrimitive:
+                    {
+                        Buf *name = &node->data.type.primitive_name;
+                        if (buf_eql_str(name, "u8")) {
+                            node->codegen_node->data.type_ref = LLVMInt8Type();
+                        } else if (buf_eql_str(name, "i32")) {
+                            node->codegen_node->data.type_ref = LLVMInt32Type();
+                        } else {
+                            add_node_error(g, node,
+                                    buf_sprintf("invalid type name: '%s'", buf_ptr(name)));
+                        }
+                        break;
+                    }
+                case AstNodeTypeTypePointer:
+                    {
+                        analyze_node(g, node->data.type.child_type);
+                        node->codegen_node->data.type_ref = LLVMPointerType(
+                                node->data.type.child_type->codegen_node->data.type_ref, 0);
+                        break;
+                    }
+            }
             break;
         case NodeTypeBlock:
+            for (int i = 0; i < node->data.block.statements.length; i += 1) {
+                AstNode *child = node->data.block.statements.at(i);
+                analyze_node(g, child);
+            }
             break;
         case NodeTypeStatement:
-            break;
-        case NodeTypeExpressionStatement:
-            break;
-        case NodeTypeReturnStatement:
+            switch (node->data.statement.type) {
+                case AstNodeStatementTypeExpression:
+                    analyze_node(g, node->data.statement.data.expr.expression);
+                    break;
+                case AstNodeStatementTypeReturn:
+                    analyze_node(g, node->data.statement.data.retrn.expression);
+                    break;
+            }
             break;
         case NodeTypeExpression:
+            switch (node->data.expression.type) {
+                case AstNodeExpressionTypeNumber:
+                    break;
+                case AstNodeExpressionTypeString:
+                    break;
+                case AstNodeExpressionTypeFnCall:
+                    analyze_node(g, node->data.expression.data.fn_call);
+                    break;
+            }
             break;
         case NodeTypeFnCall:
+            for (int i = 0; i < node->data.fn_call.params.length; i += 1) {
+                AstNode *child = node->data.fn_call.params.at(i);
+                analyze_node(g, child);
+            }
             break;
     }
 }
 
+
+/* TODO external fn
+    LLVMTypeRef puts_param_types[] = {LLVMPointerType(LLVMInt8Type(), 0)};
+    LLVMTypeRef puts_type = LLVMFunctionType(LLVMInt32Type(), puts_param_types, 1, 0);
+    LLVMValueRef puts_fn = LLVMAddFunction(mod, "puts", puts_type);
+    LLVMSetLinkage(puts_fn, LLVMExternalLinkage);
+    */
+
 void semantic_analyze(CodeGen *g) {
     // Pass 1.
     analyze_node(g, g->root);
 }
 
+static LLVMTypeRef to_llvm_type(AstNode *type_node) {
+    assert(type_node->type == NodeTypeType);
+    assert(type_node->codegen_node);
+
+    return type_node->codegen_node->data.type_ref;
+}
+
+static LLVMValueRef gen_fn_call(CodeGen *g, AstNode *fn_call_node) {
+    assert(fn_call_node->type == NodeTypeFnCall);
+
+    zig_panic("TODO support external fn declarations");
+    //LLVMTypeRef fn_type =  LLVMFunctionType(LLVMVoidType(), );
+
+    // resolve function name
+    //LLVMValueRef result = LLVMBuildCall(g->builder, 
+
+
+    //return value;
+}
+
+static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node) {
+    assert(expr_node->type == NodeTypeExpression);
+    switch (expr_node->data.expression.type) {
+        case AstNodeExpressionTypeNumber:
+            zig_panic("TODO number expr");
+            break;
+        case AstNodeExpressionTypeString:
+            zig_panic("TODO string expr");
+            break;
+        case AstNodeExpressionTypeFnCall:
+            return gen_fn_call(g, expr_node->data.expression.data.fn_call);
+    }
+    zig_unreachable();
+}
+
+static void gen_block(CodeGen *g, AstNode *block_node) {
+    assert(block_node->type == NodeTypeBlock);
+
+    for (int i = 0; i < block_node->data.block.statements.length; i += 1) {
+        AstNode *statement_node = block_node->data.block.statements.at(i);
+        assert(statement_node->type == NodeTypeStatement);
+        switch (statement_node->data.statement.type) {
+            case AstNodeStatementTypeReturn:
+                {
+                    AstNode *expr_node = statement_node->data.statement.data.retrn.expression;
+                    LLVMValueRef value = gen_expr(g, expr_node);
+                    LLVMBuildRet(g->builder, value);
+                    break;
+                }
+            case AstNodeStatementTypeExpression:
+                {
+                    AstNode *expr_node = statement_node->data.statement.data.expr.expression;
+                    gen_expr(g, expr_node);
+                    break;
+                }
+        }
+    }
+}
+
 void code_gen(CodeGen *g) {
+    LLVMModuleRef mod = LLVMModuleCreateWithName("ZigModule");
+    g->builder = LLVMCreateBuilder();
+
+
+    for (int fn_decl_i = 0; fn_decl_i < g->root->data.root.fn_decls.length; fn_decl_i += 1) {
+        AstNode *fn_decl_node = g->root->data.root.fn_decls.at(fn_decl_i);
+        AstNodeFnDecl *fn_decl = &fn_decl_node->data.fn_decl;
+
+        LLVMTypeRef ret_type = to_llvm_type(fn_decl->return_type);
+        LLVMTypeRef *param_types = allocate<LLVMTypeRef>(fn_decl->params.length);
+        for (int param_decl_i = 0; param_decl_i < fn_decl->params.length; param_decl_i += 1) {
+            AstNode *param_node = fn_decl->params.at(param_decl_i);
+            assert(param_node->type == NodeTypeParamDecl);
+            AstNode *type_node = param_node->data.param_decl.type;
+            param_types[param_decl_i] = to_llvm_type(type_node);
+        }
+        LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, fn_decl->params.length, 0);
+        LLVMValueRef fn = LLVMAddFunction(mod, buf_ptr(&fn_decl->name), function_type);
+
+        LLVMBasicBlockRef entry = LLVMAppendBasicBlock(fn, "entry");
+        LLVMPositionBuilderAtEnd(g->builder, entry);
+
+        gen_block(g, fn_decl->body);
+    }
 
+    LLVMDumpModule(mod);
 }
 
 ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g) {
src/parser.cpp
@@ -26,16 +26,10 @@ const char *node_type_str(NodeType node_type) {
             return "ParamDecl";
         case NodeTypeType:
             return "Type";
-        case NodeTypePointerType:
-            return "PointerType";
         case NodeTypeBlock:
             return "Block";
         case NodeTypeStatement:
             return "Statement";
-        case NodeTypeExpressionStatement:
-            return "ExpressionStatement";
-        case NodeTypeReturnStatement:
-            return "ReturnStatement";
         case NodeTypeExpression:
             return "Expression";
         case NodeTypeFnCall:
src/parser.hpp
@@ -6,17 +6,15 @@
 #include "tokenizer.hpp"
 
 struct AstNode;
+struct CodeGenNode;
 
 enum NodeType {
     NodeTypeRoot,
     NodeTypeFnDecl,
     NodeTypeParamDecl,
     NodeTypeType,
-    NodeTypePointerType,
     NodeTypeBlock,
     NodeTypeStatement,
-    NodeTypeExpressionStatement,
-    NodeTypeReturnStatement,
     NodeTypeExpression,
     NodeTypeFnCall,
 };
@@ -99,6 +97,7 @@ struct AstNode {
     AstNode *parent;
     int line;
     int column;
+    CodeGenNode *codegen_node;
     union {
         AstNodeRoot root;
         AstNodeFnDecl fn_decl;
test/hello.zig
@@ -1,4 +1,4 @@
-fn main(argc: i32, argv: *mut u8) -> i32 {
+fn main(argc: i32, argv: *mut *mut u8) -> i32 {
     puts("Hello, world!\n");
     return 0;
 }
README.md
@@ -41,7 +41,6 @@ readable, safe, optimal, and concise code to solve any computing problem.
 ## Roadmap
 
  * Hello, world.
-   - Build AST
    - Code Gen
    - Produce .o file.
  * Produce executable file instead of .o file.