Commit a11d0aaf62

Andrew Kelley <superjoe30@gmail.com>
2016-01-05 07:37:17
progress toward compile time constant expression evaluation
1 parent 3c55162
src/analyze.cpp
@@ -233,6 +233,30 @@ static TypeTableEntry *get_array_type(CodeGen *g, ImportTableEntry *import,
     }
 }
 
+static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context,
+        AstNode *node, AstNodeNumberLiteral *out_number_literal)
+{
+    switch (node->type) {
+        case NodeTypeNumberLiteral:
+            *out_number_literal = node->data.number_literal;
+            return node->codegen_node->expr_node.type_entry;
+        case NodeTypeBinOpExpr:
+            zig_panic("TODO eval_const_expr bin op expr");
+            break;
+        case NodeTypeSymbol:
+            {
+                VariableTableEntry *var = find_variable(context, &node->data.symbol);
+                assert(var);
+                AstNode *decl_node = var->decl_node;
+                AstNode *expr_node = decl_node->data.variable_declaration.expr;
+                BlockContext *next_context = expr_node->codegen_node->expr_node.block_context;
+                return eval_const_expr(g, next_context, expr_node, out_number_literal);
+            }
+        default:
+            return g->builtin_types.entry_invalid;
+    }
+}
+
 static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry *import, BlockContext *context) {
     assert(node->type == NodeTypeType);
     alloc_codegen_node(node);
@@ -275,14 +299,27 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry
                 }
 
                 AstNode *size_node = node->data.type.array_size;
-                if (size_node->type == NodeTypeNumberLiteral &&
-                    is_num_lit_unsigned(size_node->data.number_literal.kind))
-                {
-                    type_node->entry = get_array_type(g, import, child_type,
-                            size_node->data.number_literal.data.x_uint);
+                TypeTableEntry *size_type = analyze_expression(g, import, context,
+                        g->builtin_types.entry_usize, size_node);
+                if (size_type->id == TypeTableEntryIdInvalid) {
+                    type_node->entry = g->builtin_types.entry_invalid;
+                    return type_node->entry;
+                }
+
+                AstNodeNumberLiteral number_literal;
+                TypeTableEntry *resolved_type = eval_const_expr(g, context, size_node, &number_literal);
+
+                if (resolved_type->id == TypeTableEntryIdInt) {
+                    if (resolved_type->data.integral.is_signed) {
+                        add_node_error(g, size_node,
+                            buf_create_from_str("array size must be unsigned integer"));
+                        type_node->entry = g->builtin_types.entry_invalid;
+                    } else {
+                        type_node->entry = get_array_type(g, import, child_type, number_literal.data.x_uint);
+                    }
                 } else {
                     add_node_error(g, size_node,
-                        buf_create_from_str("array size must be literal unsigned integer"));
+                        buf_create_from_str("unable to resolve constant expression"));
                     type_node->entry = g->builtin_types.entry_invalid;
                 }
                 return type_node->entry;
src/codegen.cpp
@@ -1696,6 +1696,10 @@ static const NumLit num_lit_kinds[] = {
     NumLitU16,
     NumLitU32,
     NumLitU64,
+    NumLitI8,
+    NumLitI16,
+    NumLitI32,
+    NumLitI64,
 };
 
 static void define_builtin_types(CodeGen *g) {
src/parser.cpp
@@ -2750,6 +2750,14 @@ const char *num_lit_str(NumLit num_lit) {
             return "u32";
         case NumLitU64:
             return "u64";
+        case NumLitI8:
+            return "i8";
+        case NumLitI16:
+            return "i16";
+        case NumLitI32:
+            return "i32";
+        case NumLitI64:
+            return "i64";
         case NumLitCount:
             zig_unreachable();
     }
@@ -2761,6 +2769,10 @@ bool is_num_lit_unsigned(NumLit num_lit) {
         case NumLitF32:
         case NumLitF64:
         case NumLitF128:
+        case NumLitI8:
+        case NumLitI16:
+        case NumLitI32:
+        case NumLitI64:
             return false;
         case NumLitU8:
         case NumLitU16:
@@ -2783,6 +2795,10 @@ bool is_num_lit_float(NumLit num_lit) {
         case NumLitU16:
         case NumLitU32:
         case NumLitU64:
+        case NumLitI8:
+        case NumLitI16:
+        case NumLitI32:
+        case NumLitI64:
             return false;
         case NumLitCount:
             zig_unreachable();
@@ -2793,13 +2809,17 @@ bool is_num_lit_float(NumLit num_lit) {
 uint64_t num_lit_bit_count(NumLit num_lit) {
     switch (num_lit) {
         case NumLitU8:
+        case NumLitI8:
             return 8;
         case NumLitU16:
+        case NumLitI16:
             return 16;
         case NumLitU32:
+        case NumLitI32:
         case NumLitF32:
             return 32;
         case NumLitU64:
+        case NumLitI64:
         case NumLitF64:
             return 64;
         case NumLitF128:
src/parser.hpp
@@ -309,6 +309,10 @@ enum NumLit {
     NumLitU16,
     NumLitU32,
     NumLitU64,
+    NumLitI8,
+    NumLitI16,
+    NumLitI32,
+    NumLitI64,
 
     NumLitCount
 };
@@ -322,6 +326,7 @@ struct AstNodeNumberLiteral {
 
     union {
         uint64_t x_uint;
+        int64_t x_int;
         double x_float;
     } data;
 };
test/run_tests.cpp
@@ -777,6 +777,19 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
     return 0;
 }
     )SOURCE", "OK\n");
+
+    add_simple_case("constant expressions", R"SOURCE(
+use "std.zig";
+
+const ARRAY_SIZE : u8 = 20;
+
+pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+    var array : [u8; ARRAY_SIZE];
+    print_u64(#sizeof(#typeof(array)));
+    print_str("\n");
+    return 0;
+}
+    )SOURCE", "20\n");
 }
 
 ////////////////////////////////////////////////////////////////////////////////////