src/compiler/NameBinding.cpp
changeset 212 443d24cfdf2d
parent 209 5cbec15fadfe
child 217 c22e983b3b6e
     1.1 --- a/src/compiler/NameBinding.cpp	Sat Nov 17 23:13:39 2012 -0800
     1.2 +++ b/src/compiler/NameBinding.cpp	Sun Nov 18 14:53:23 2012 -0800
     1.3 @@ -194,7 +194,8 @@
     1.4              // And we don't necessarily want this to bind.
     1.5          }
     1.6  
     1.7 -        node->initialization()->accept(this);
     1.8 +        if (node->initialization())
     1.9 +            node->initialization()->accept(this);
    1.10      }
    1.11      void visitEnumStatement(EnumStatement *node) {
    1.12          assert(false);
    1.13 @@ -318,7 +319,8 @@
    1.14              node->ifFalse()->accept(this);
    1.15      }
    1.16      void visitIndexExpression(IndexExpression *node) {
    1.17 -        assert(false);
    1.18 +        node->left()->accept(this);
    1.19 +        node->right()->accept(this);
    1.20      }
    1.21      void visitFloatLiteral(FloatLiteral *node) {
    1.22      }
    1.23 @@ -424,6 +426,10 @@
    1.24      return populator.analyze();
    1.25  }
    1.26  
    1.27 +static const int INFER_ARRAY_SIZE = 0;
    1.28 +static const int EVAL_ARRAY_SIZE = -1;
    1.29 +static const int DYNAMIC_ARRAY_SIZE = -2;
    1.30 +
    1.31  class NameBinder : public AstVisitor
    1.32  {
    1.33    public:
    1.34 @@ -487,14 +493,37 @@
    1.35      void visitVariableDeclaration(VariableDeclaration *node) {
    1.36          // Bind the initializer before registering the declaration, so that we
    1.37          // can error on bogus initializers (new x = x).
    1.38 -        node->initialization()->accept(this);
    1.39 +        if (node->initialization())
    1.40 +            node->initialization()->accept(this);
    1.41  
    1.42          Local<Type> type(zone_, bindType(node->type()));
    1.43          if (!type)
    1.44              return;
    1.45  
    1.46 -        if (node->dims()) {
    1.47 -            
    1.48 +        if (node->dims() || type->isArray()) {
    1.49 +            int dims[MAX_ARRAY_DEPTH];
    1.50 +            int levels = evaluateDimensions(node->pos(), type, node->dims(), dims);
    1.51 +            if (levels < 0)
    1.52 +                return;
    1.53 +
    1.54 +            // Do some extra inference based on the initializer, if present.
    1.55 +            Expression *init = node->initialization();
    1.56 +            if (init &&
    1.57 +                init->isArrayLiteral() &&
    1.58 +                init->toArrayLiteral()->isFixed())
    1.59 +            {
    1.60 +                Local<Type> contained(zone_, type->isArray()
    1.61 +                                             ? ArrayType::cast(type)->contained()
    1.62 +                                             : type);
    1.63 +                if (!inferFixedArrayDimensions(init->toArrayLiteral(), contained, dims, levels))
    1.64 +                    return;
    1.65 +            }
    1.66 +
    1.67 +            // If we got extra dimensions, we need to build a new type.
    1.68 +            if (node->dims()) {
    1.69 +                if ((type = buildArrayType(type, dims, node->dims()->length())) == NULL)
    1.70 +                    return;
    1.71 +            }
    1.72          }
    1.73  
    1.74          // If the node already has a symbol (meaning it was a global), then
    1.75 @@ -654,6 +683,109 @@
    1.76      }
    1.77  
    1.78    private:
    1.79 +    int evaluateDimensions(const SourcePosition &pos, Handle<Type> typeArg, ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]) {
    1.80 +        unsigned level = 0;
    1.81 +        Local<Type> type(zone_, typeArg);
    1.82 +        while (type->isArray()) {
    1.83 +            ArrayType *atype = ArrayType::cast(type);
    1.84 +            dims[level] = atype->isFixedLength()
    1.85 +                          ? atype->fixedLength()
    1.86 +                          : DYNAMIC_ARRAY_SIZE;
    1.87 +            type = atype->contained();
    1.88 +            level++;
    1.89 +        }
    1.90 +
    1.91 +        if (!exprs)
    1.92 +            return level;
    1.93 +
    1.94 +        if (level + exprs->length() > MAX_ARRAY_DEPTH) {
    1.95 +            cc_.reportError(pos, Message_MaximumArrayDepth);
    1.96 +            return -1;
    1.97 +        }
    1.98 +
    1.99 +        bool hadEmptySize = false;
   1.100 +        for (size_t i = 0; i < exprs->length(); i++) {
   1.101 +            Expression *expr = exprs->at(i);
   1.102 +            if (!expr) {
   1.103 +                dims[i] = INFER_ARRAY_SIZE;
   1.104 +                hadEmptySize = true;
   1.105 +                continue;
   1.106 +            }
   1.107 +
   1.108 +            BoxedPrimitive box;
   1.109 +            if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
   1.110 +                int size = box.toInt();
   1.111 +                if (size <= 0) {
   1.112 +                    cc_.reportError(expr->pos(), Message_BadArraySize);
   1.113 +                    return false;
   1.114 +                }
   1.115 +
   1.116 +                dims[i] = size;
   1.117 +                continue;
   1.118 +            }
   1.119 +
   1.120 +            if (hadEmptySize) {
   1.121 +                cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
   1.122 +                return false;
   1.123 +            }
   1.124 +
   1.125 +            dims[i] = EVAL_ARRAY_SIZE;
   1.126 +        }
   1.127 +
   1.128 +        return level + exprs->length();
   1.129 +    }
   1.130 +
   1.131 +    // This function computes missing dimension sizes based on a literal
   1.132 +    // initializer. We don't really handle any size rules here; we just
   1.133 +    // do a really dumb inference.
   1.134 +    bool inferFixedArrayDimensions(ArrayLiteral *lit, Handle<Type> contained, int dims[MAX_ARRAY_DEPTH], int levels) {
   1.135 +        for (int i = 0; i < levels; i++) {
   1.136 +            if (dims[i] == EVAL_ARRAY_SIZE || dims[i] == DYNAMIC_ARRAY_SIZE) {
   1.137 +                // The following are invalid:
   1.138 +                //   new x[<expr>] = {...}
   1.139 +                //   new Type:x = {...}  // where Type is a non-fixed array type
   1.140 +                cc_.reportError(lit->pos(), Message_CannotInitializeEvalArray);
   1.141 +                return false;
   1.142 +            }
   1.143 +
   1.144 +            if (dims[i] == INFER_ARRAY_SIZE) {
   1.145 +                // Character arrays are always dynamic when inferred from string literals.
   1.146 +                if (i == levels - 1 && contained->isChar())
   1.147 +                    dims[i] = DYNAMIC_ARRAY_SIZE;
   1.148 +                else
   1.149 +                    dims[i] = lit->expressions()->length();
   1.150 +            }
   1.151 +
   1.152 +            if (i != levels - 1) {
   1.153 +                // Fixed array literals are guaranteed to have at least one expression.
   1.154 +                Expression *next = lit->expressions()->at(0);
   1.155 +                if (!next->isArrayLiteral()) {
   1.156 +                    // Whelp... this array is just malformed. Not the best error message
   1.157 +                    // but whatever.
   1.158 +                    cc_.reportError(next->pos(), Message_ArraySizeCannotBeDetermined);
   1.159 +                    return false;
   1.160 +                }
   1.161 +                lit = next->toArrayLiteral();
   1.162 +            }
   1.163 +        }
   1.164 +
   1.165 +        return true;
   1.166 +    }
   1.167 +
   1.168 +    ArrayType *buildArrayType(Handle<Type> contained, int dims[MAX_ARRAY_DEPTH], size_t postlevels) {
   1.169 +        Local<Type> type(zone_, contained);
   1.170 +        for (size_t i = postlevels - 1; i < postlevels; i--) {
   1.171 +            int size = dims[i] > 0
   1.172 +                       ? dims[i]
   1.173 +                       : ArrayType::DYNAMIC_ARRAY_SIZE;
   1.174 +            
   1.175 +            type = zone_->types()->newArray(contained, size);
   1.176 +            if (!type)
   1.177 +                return NULL;
   1.178 +        }
   1.179 +        return ArrayType::cast(type);
   1.180 +    }
   1.181 +
   1.182      bool fillFunctionType(Handle<FunctionType> fun, const FunctionSignature &sig) {
   1.183          Local<Type> type(zone_);
   1.184          if (!fun->returnType()) {