Commit c89f77dd8e

Josh Wolfe <thejoshwolfe@gmail.com>
2015-12-03 00:33:06
parsing variable declaration
1 parent ffc2c92
example/expressions/expressions.zig
@@ -0,0 +1,14 @@
+#link("c")
+extern {
+    fn puts(s: *const u8) -> i32;
+    fn exit(code: i32) -> unreachable;
+}
+
+export fn _start() -> unreachable {
+    let a : i32 = 1;
+    let b = 2;
+    let c : i32;
+    // let d; // compile error
+    puts("Hello, world!");
+    exit(a + b);
+}
src/analyze.cpp
@@ -277,6 +277,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
         case NodeTypeType:
         case NodeTypeFnDecl:
         case NodeTypeReturnExpr:
+        case NodeTypeVariableDeclaration:
         case NodeTypeRoot:
         case NodeTypeBlock:
         case NodeTypeBinOpExpr:
@@ -373,6 +374,14 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
                 break;
             }
 
+        case NodeTypeVariableDeclaration:
+            {
+                zig_panic("TODO: analyze variable declaration");
+
+                return_type = g->builtin_types.entry_void;
+                break;
+            }
+
         case NodeTypeBinOpExpr:
             {
                 switch (node->data.bin_op_expr.bin_op) {
@@ -630,6 +639,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
         case NodeTypeType:
         case NodeTypeFnDecl:
         case NodeTypeReturnExpr:
+        case NodeTypeVariableDeclaration:
         case NodeTypeRoot:
         case NodeTypeBlock:
         case NodeTypeBinOpExpr:
src/codegen.cpp
@@ -477,6 +477,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
             return gen_bin_op_expr(g, node);
         case NodeTypeReturnExpr:
             return gen_return_expr(g, node);
+        case NodeTypeVariableDeclaration:
+            zig_panic("TODO: variable declaration code gen");
         case NodeTypeCastExpr:
             return gen_cast_expr(g, node);
         case NodeTypePrefixOpExpr:
src/parser.cpp
@@ -75,6 +75,8 @@ const char *node_type_str(NodeType node_type) {
             return "Directive";
         case NodeTypeReturnExpr:
             return "ReturnExpr";
+        case NodeTypeVariableDeclaration:
+            return "VariableDeclaration";
         case NodeTypeCastExpr:
             return "CastExpr";
         case NodeTypeNumberLiteral:
@@ -178,6 +180,16 @@ void ast_print(AstNode *node, int indent) {
             if (node->data.return_expr.expr)
                 ast_print(node->data.return_expr.expr, indent + 2);
             break;
+        case NodeTypeVariableDeclaration:
+            {
+                Buf *name_buf = &node->data.variable_declaration.symbol;
+                fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf));
+                if (node->data.variable_declaration.type)
+                    ast_print(node->data.variable_declaration.type, indent + 2);
+                if (node->data.variable_declaration.expr)
+                    ast_print(node->data.variable_declaration.expr, indent + 2);
+                break;
+            }
         case NodeTypeExternBlock:
             {
                 fprintf(stderr, "%s\n", node_type_str(node->type));
@@ -1042,6 +1054,45 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
     }
 }
 
+/*
+VariableDeclaration : token(Let) token(Symbole) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
+*/
+static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) {
+    Token *let_tok = &pc->tokens->at(*token_index);
+    if (let_tok->id == TokenIdKeywordLet) {
+        *token_index += 1;
+        AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, let_tok);
+
+        Token *name_token = &pc->tokens->at(*token_index);
+        *token_index += 1;
+        ast_expect_token(pc, name_token, TokenIdSymbol);
+        ast_buf_from_token(pc, name_token, &node->data.variable_declaration.symbol);
+
+        Token *eq_or_colon = &pc->tokens->at(*token_index);
+        *token_index += 1;
+        if (eq_or_colon->id == TokenIdEq) {
+            node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true);
+            return node;
+        } else if (eq_or_colon->id == TokenIdColon) {
+            node->data.variable_declaration.type = ast_parse_type(pc, *token_index, token_index);
+
+            Token *eq_token = &pc->tokens->at(*token_index);
+            if (eq_token->id == TokenIdEq) {
+                *token_index += 1;
+
+                node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true);
+            }
+            return node;
+        } else {
+            ast_invalid_token_error(pc, eq_or_colon);
+        }
+    } else if (mandatory) {
+        ast_invalid_token_error(pc, let_tok);
+    } else {
+        return nullptr;
+    }
+}
+
 /*
 BoolOrExpression : BoolAndExpression token(BoolOr) BoolAndExpression | BoolAndExpression
 */
@@ -1086,19 +1137,23 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma
 }
 
 /*
-NonBlockExpression : BoolOrExpression | ReturnExpression
+NonBlockExpression : ReturnExpression | VariableDeclaration | BoolOrExpression
 */
 static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
     Token *token = &pc->tokens->at(*token_index);
 
-    AstNode *bool_or_expr = ast_parse_bool_or_expr(pc, token_index, false);
-    if (bool_or_expr)
-        return bool_or_expr;
-
     AstNode *return_expr = ast_parse_return_expr(pc, token_index, false);
     if (return_expr)
         return return_expr;
 
+    AstNode *variable_declaration_expr = ast_parse_variable_declaration_expr(pc, token_index, false);
+    if (variable_declaration_expr)
+        return variable_declaration_expr;
+
+    AstNode *bool_or_expr = ast_parse_bool_or_expr(pc, token_index, false);
+    if (bool_or_expr)
+        return bool_or_expr;
+
     if (mandatory)
         ast_invalid_token_error(pc, token);
 
src/parser.hpp
@@ -29,6 +29,7 @@ enum NodeType {
     NodeTypeExternBlock,
     NodeTypeDirective,
     NodeTypeReturnExpr,
+    NodeTypeVariableDeclaration,
     NodeTypeBinOpExpr,
     NodeTypeCastExpr,
     NodeTypeNumberLiteral,
@@ -95,6 +96,13 @@ struct AstNodeReturnExpr {
     AstNode *expr;
 };
 
+struct AstNodeVariableDeclaration {
+    Buf symbol;
+    // one or both of type and expr will be non null
+    AstNode *type;
+    AstNode *expr;
+};
+
 enum BinOpType {
     BinOpTypeInvalid,
     // TODO: include assignment?
@@ -190,6 +198,7 @@ struct AstNode {
         AstNodeParamDecl param_decl;
         AstNodeBlock block;
         AstNodeReturnExpr return_expr;
+        AstNodeVariableDeclaration variable_declaration;
         AstNodeBinOpExpr bin_op_expr;
         AstNodeExternBlock extern_block;
         AstNodeDirective directive;
src/tokenizer.cpp
@@ -165,6 +165,8 @@ static void end_token(Tokenize *t) {
         t->cur_tok->id = TokenIdKeywordFn;
     } else if (mem_eql_str(token_mem, token_len, "return")) {
         t->cur_tok->id = TokenIdKeywordReturn;
+    } else if (mem_eql_str(token_mem, token_len, "let")) {
+        t->cur_tok->id = TokenIdKeywordLet;
     } else if (mem_eql_str(token_mem, token_len, "mut")) {
         t->cur_tok->id = TokenIdKeywordMut;
     } else if (mem_eql_str(token_mem, token_len, "const")) {
@@ -574,6 +576,7 @@ static const char * token_name(Token *token) {
         case TokenIdKeywordConst: return "Const";
         case TokenIdKeywordMut: return "Mut";
         case TokenIdKeywordReturn: return "Return";
+        case TokenIdKeywordLet: return "Let";
         case TokenIdKeywordExtern: return "Extern";
         case TokenIdKeywordUnreachable: return "Unreachable";
         case TokenIdKeywordPub: return "Pub";
src/tokenizer.hpp
@@ -15,6 +15,7 @@ enum TokenId {
     TokenIdSymbol,
     TokenIdKeywordFn,
     TokenIdKeywordReturn,
+    TokenIdKeywordLet,
     TokenIdKeywordMut,
     TokenIdKeywordConst,
     TokenIdKeywordExtern,
README.md
@@ -114,7 +114,7 @@ Statement : NonBlockExpression token(Semicolon) | BlockExpression
 
 Expression : BlockExpression | NonBlockExpression
 
-NonBlockExpression : BoolOrExpression | ReturnExpression
+NonBlockExpression : ReturnExpression | VariableDeclaration | BoolOrExpression
 
 BlockExpression : IfExpression | Block
 
@@ -122,6 +122,8 @@ BoolOrExpression : BoolAndExpression token(BoolOr) BoolAndExpression | BoolAndEx
 
 ReturnExpression : token(Return) option(Expression)
 
+VariableDeclaration : token(Let) token(Symbole) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
+
 IfExpression : token(If) Expression Block option(Else | ElseIf)
 
 ElseIf : token(Else) IfExpression