Allow returning arrays from functions.
authorDavid Anderson <dvander@alliedmods.net>
Sun Sep 16 22:49:54 2012 -0700 (2012-09-16)
changeset 1919d17f29fe16a
parent 190 dd04fce774cd
child 192 23a804fa1d3e
Allow returning arrays from functions.
src/AST.h
src/Handles.h
src/Parser.cpp
src/SemanticAnalysis.cpp
src/SemanticAnalysis.h
     1.1 --- a/src/AST.h	Sun Sep 16 21:59:26 2012 -0700
     1.2 +++ b/src/AST.h	Sun Sep 16 22:49:54 2012 -0700
     1.3 @@ -779,8 +779,9 @@
     1.4  class FunctionSignature
     1.5  {
     1.6    public:
     1.7 -    FunctionSignature(BoundName *returnType, ParameterList *parameters)
     1.8 +    FunctionSignature(BoundName *returnType, ExpressionList *returnDimensions, ParameterList *parameters)
     1.9        : returnType_(returnType),
    1.10 +        returnDimensions_(returnDimensions),
    1.11          parameters_(parameters)
    1.12      {
    1.13      }
    1.14 @@ -788,12 +789,16 @@
    1.15      BoundName *returnType() const {
    1.16          return returnType_;
    1.17      }
    1.18 +    ExpressionList *returnDimensions() const {
    1.19 +        return returnDimensions_;
    1.20 +    }
    1.21      ParameterList *parameters() const {
    1.22          return parameters_;
    1.23      }
    1.24  
    1.25    private:
    1.26      BoundName *returnType_;
    1.27 +    ExpressionList *returnDimensions_;
    1.28      ParameterList *parameters_;
    1.29  };
    1.30  
     2.1 --- a/src/Handles.h	Sun Sep 16 21:59:26 2012 -0700
     2.2 +++ b/src/Handles.h	Sun Sep 16 22:49:54 2012 -0700
     2.3 @@ -129,6 +129,11 @@
     2.4          return thing_;
     2.5      }
     2.6  
     2.7 +    Local &operator =(const Local &other) {
     2.8 +        thing_ = other.thing_;
     2.9 +        return *this;
    2.10 +    }
    2.11 +
    2.12    private:
    2.13      // Disallow heap allocation.
    2.14      void *operator new(size_t size);
    2.15 @@ -136,7 +141,6 @@
    2.16  
    2.17      // Disallow copy construction.
    2.18      Local(const Local<T> &other);
    2.19 -    Local &operator =(const Local &other);
    2.20  };
    2.21  
    2.22  // A ScopedRoot is a special kind of handle for storing references on the
     3.1 --- a/src/Parser.cpp	Sun Sep 16 21:59:26 2012 -0700
     3.2 +++ b/src/Parser.cpp	Sun Sep 16 22:49:54 2012 -0700
     3.3 @@ -1257,18 +1257,42 @@
     3.4  
     3.5          token = TOK_STOCK;
     3.6      } else {
     3.7 -        if (matchName(returnTag.ref(), TOK_LABEL) && !returnTag)
     3.8 +        if (peek(TOK_LABEL)) {
     3.9 +            if (matchName(returnTag.ref(), TOK_LABEL) && !returnTag)
    3.10 +                return NULL;
    3.11 +        } else if (peek(TOK_NAME)) {
    3.12 +            // Peek for a type that has no :
    3.13 +            returnTag = expectName();
    3.14 +            if (!returnTag)
    3.15 +                return NULL;
    3.16 +        }
    3.17 +    }
    3.18 +
    3.19 +    Local<String> name(zone_);
    3.20 +    ExpressionList *returnDimensions = NULL;
    3.21 +
    3.22 +    bool allowArrayReturns = token != TOK_NATIVE &&
    3.23 +                             token != TOK_PUBLIC &&
    3.24 +                             token != TOK_FORWARD;
    3.25 +
    3.26 +    if (allowArrayReturns && peek(TOK_LBRACKET)) {
    3.27 +        if ((returnDimensions = dimensions()) == NULL)
    3.28              return NULL;
    3.29 +        if ((name = expectName()) == NULL)
    3.30 +            return NULL;
    3.31 +    } else if (peek(TOK_NAME)) {
    3.32 +        if ((name = expectName()) == NULL)
    3.33 +            return NULL;
    3.34 +    } else {
    3.35 +        // We predicted |type name|, but just got |name| instead.
    3.36 +        name = returnTag;
    3.37 +        returnTag = NULL;
    3.38      }
    3.39  
    3.40      BoundName *returnType = NULL;
    3.41      if (returnTag)
    3.42          returnType = bindType(returnTag);
    3.43  
    3.44 -    Local<String> name(zone_, expectName());
    3.45 -    if (!name)
    3.46 -        return NULL;
    3.47 -
    3.48      SourcePosition pos = scanner_.begin();
    3.49  
    3.50      // The function name goes into the outer (global) scope.
    3.51 @@ -1392,7 +1416,7 @@
    3.52  
    3.53      scope_ = scope_->enclosing();
    3.54  
    3.55 -    FunctionSignature signature(returnType, parameters);
    3.56 +    FunctionSignature signature(returnType, returnDimensions, parameters);
    3.57      if (token == TOK_TYPEDEF)
    3.58          return new (pool_) FunctionTypeStatement(pos, type, signature);
    3.59  
    3.60 @@ -1560,6 +1584,17 @@
    3.61      {
    3.62      }
    3.63  
    3.64 +    void dump(const FunctionSignature &sig) {
    3.65 +        prefix();
    3.66 +        fprintf(fp_, "%s", sig.returnType()
    3.67 +                           ? sig.returnType()->name()->chars()
    3.68 +                           : "_");
    3.69 +        if (sig.returnDimensions()) {
    3.70 +            for (size_t i = 0; i < sig.returnDimensions()->length(); i++)
    3.71 +                fprintf(fp_, "[]");
    3.72 +        }
    3.73 +        fprintf(fp_, "()\n");
    3.74 +    }
    3.75      void visit(NameProxy *name) {
    3.76          prefix();
    3.77          fprintf(fp_, "[ NameProxy (%s)%s\n", name->name()->chars(),
    3.78 @@ -1577,11 +1612,15 @@
    3.79      void visit(FunctionTypeStatement *node) {
    3.80          prefix();
    3.81          fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->decl()->name()->chars());
    3.82 +        indent();
    3.83 +        dump(node->signature());
    3.84 +        unindent();
    3.85      }
    3.86      void visit(FunctionStatement *node) {
    3.87          prefix();
    3.88          fprintf(fp_, "[ FunctionStatement (%s)\n", node->fun()->name()->chars());
    3.89          indent();
    3.90 +        dump(node->signature());
    3.91          if (node->body())
    3.92              node->body()->accept(this);
    3.93          unindent();
     4.1 --- a/src/SemanticAnalysis.cpp	Sun Sep 16 21:59:26 2012 -0700
     4.2 +++ b/src/SemanticAnalysis.cpp	Sun Sep 16 22:49:54 2012 -0700
     4.3 @@ -1027,35 +1027,14 @@
     4.4              if (!type)
     4.5                  return false;
     4.6          } else if (parameter->dimensions()) {
     4.7 -            // :TODO: factor in type dimcount
     4.8 -            if (parameter->dimensions()->length() > MAX_ARRAY_DEPTH) {
     4.9 -                cc_.reportError(parameter->variable()->pos(), Message_MaximumArrayDepth);
    4.10 +            type = buildArrayType(type, parameter->dimensions(), parameter->isConst());
    4.11 +            if (!type)
    4.12                  return false;
    4.13 -            }
    4.14  
    4.15 -            if (kind == TOK_NATIVE && parameter->dimensions()->length() > 1) {
    4.16 +            if (kind == TOK_NATIVE && type->levels() > 1) {
    4.17                  cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
    4.18                  return false;
    4.19              }
    4.20 -
    4.21 -            for (size_t i = parameter->dimensions()->length() - 1;
    4.22 -                 i < parameter->dimensions()->length();
    4.23 -                 i--)
    4.24 -            {
    4.25 -                int size = Type::DYNAMIC_ARRAY_SIZE;
    4.26 -                if (Expression *expr = parameter->dimensions()->at(i)) {
    4.27 -                    BoxedPrimitive box;
    4.28 -                    if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
    4.29 -                        cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
    4.30 -                        return false;
    4.31 -                    }
    4.32 -                    size = box.toInt();
    4.33 -                }
    4.34 -
    4.35 -                type = zone_->types()->newArray(type, size, parameter->isConst());
    4.36 -                if (!type)
    4.37 -                    return false;
    4.38 -            }
    4.39          }
    4.40  
    4.41          if (IsScalarString(type)) {
    4.42 @@ -1122,6 +1101,51 @@
    4.43      node->decl()->setType(funtype);
    4.44  }
    4.45  
    4.46 +Type *
    4.47 +SemanticAnalysis::buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst)
    4.48 +{
    4.49 +    Local<Type> arrayType(zone_, type);
    4.50 +
    4.51 +    unsigned dimcount = dimensions->length();
    4.52 +    if (type->isArray())
    4.53 +        dimcount += type->levels();
    4.54 +
    4.55 +    if (dimcount > MAX_ARRAY_DEPTH) {
    4.56 +        cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(),
    4.57 +                        Message_MaximumArrayDepth);
    4.58 +        return false;
    4.59 +    }
    4.60 +
    4.61 +    // Note: constness is sort of bogus. Fix this sometime.
    4.62 +    for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) {
    4.63 +        Expression *expr = dimensions->at(i);
    4.64 +        if (!expr) {
    4.65 +            arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst);
    4.66 +            if (!arrayType)
    4.67 +                return NULL;
    4.68 +
    4.69 +            continue;
    4.70 +        }
    4.71 +
    4.72 +        BoxedPrimitive box;
    4.73 +        if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
    4.74 +            cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
    4.75 +            return NULL;
    4.76 +        }
    4.77 +
    4.78 +        if (box.toInt() <= 0) {
    4.79 +            cc_.reportError(expr->pos(), Message_BadArraySize);
    4.80 +            return NULL;
    4.81 +        }
    4.82 +
    4.83 +        arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst);
    4.84 +        if (!arrayType)
    4.85 +            return NULL;
    4.86 +    }
    4.87 +
    4.88 +    return arrayType;
    4.89 +}
    4.90 +
    4.91  bool
    4.92  SemanticAnalysis::preanalyze(FunctionStatement *node)
    4.93  {
    4.94 @@ -1150,6 +1174,17 @@
    4.95      if (!returnType)
    4.96          return false;
    4.97  
    4.98 +    if (sig.returnDimensions()) {
    4.99 +        returnType = buildArrayType(returnType, sig.returnDimensions(), false);
   4.100 +        if (!returnType)
   4.101 +            return false;
   4.102 +    }
   4.103 +
   4.104 +    if (IsScalarString(returnType)) {
   4.105 +        cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
   4.106 +        return false;
   4.107 +    }
   4.108 +
   4.109      Local<Type> funtype(zone_);
   4.110      if (node->fun()->isNative())
   4.111          funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic());
     5.1 --- a/src/SemanticAnalysis.h	Sun Sep 16 21:59:26 2012 -0700
     5.2 +++ b/src/SemanticAnalysis.h	Sun Sep 16 22:49:54 2012 -0700
     5.3 @@ -182,6 +182,9 @@
     5.4                                  unsigned dimcount,
     5.5                                  unsigned level);
     5.6  
     5.7 +    // Builds an array type used for parameters, returns, or field entries.
     5.8 +    Type *buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst);
     5.9 +
    5.10      Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
    5.11      bool checkArgumentCount(Handle<Type> type, unsigned actual);
    5.12      bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,