# HG changeset patch # User David Anderson # Date 1347860994 25200 # Node ID 9d17f29fe16a7d163c0f8e5b262855030b1d12da # Parent dd04fce774cda09d1b86e041b62d3b9b75f48a2f Allow returning arrays from functions. diff -r dd04fce774cd -r 9d17f29fe16a src/AST.h --- a/src/AST.h Sun Sep 16 21:59:26 2012 -0700 +++ b/src/AST.h Sun Sep 16 22:49:54 2012 -0700 @@ -779,8 +779,9 @@ class FunctionSignature { public: - FunctionSignature(BoundName *returnType, ParameterList *parameters) + FunctionSignature(BoundName *returnType, ExpressionList *returnDimensions, ParameterList *parameters) : returnType_(returnType), + returnDimensions_(returnDimensions), parameters_(parameters) { } @@ -788,12 +789,16 @@ BoundName *returnType() const { return returnType_; } + ExpressionList *returnDimensions() const { + return returnDimensions_; + } ParameterList *parameters() const { return parameters_; } private: BoundName *returnType_; + ExpressionList *returnDimensions_; ParameterList *parameters_; }; diff -r dd04fce774cd -r 9d17f29fe16a src/Handles.h --- a/src/Handles.h Sun Sep 16 21:59:26 2012 -0700 +++ b/src/Handles.h Sun Sep 16 22:49:54 2012 -0700 @@ -129,6 +129,11 @@ return thing_; } + Local &operator =(const Local &other) { + thing_ = other.thing_; + return *this; + } + private: // Disallow heap allocation. void *operator new(size_t size); @@ -136,7 +141,6 @@ // Disallow copy construction. Local(const Local &other); - Local &operator =(const Local &other); }; // A ScopedRoot is a special kind of handle for storing references on the diff -r dd04fce774cd -r 9d17f29fe16a src/Parser.cpp --- a/src/Parser.cpp Sun Sep 16 21:59:26 2012 -0700 +++ b/src/Parser.cpp Sun Sep 16 22:49:54 2012 -0700 @@ -1257,18 +1257,42 @@ token = TOK_STOCK; } else { - if (matchName(returnTag.ref(), TOK_LABEL) && !returnTag) + if (peek(TOK_LABEL)) { + if (matchName(returnTag.ref(), TOK_LABEL) && !returnTag) + return NULL; + } else if (peek(TOK_NAME)) { + // Peek for a type that has no : + returnTag = expectName(); + if (!returnTag) + return NULL; + } + } + + Local name(zone_); + ExpressionList *returnDimensions = NULL; + + bool allowArrayReturns = token != TOK_NATIVE && + token != TOK_PUBLIC && + token != TOK_FORWARD; + + if (allowArrayReturns && peek(TOK_LBRACKET)) { + if ((returnDimensions = dimensions()) == NULL) return NULL; + if ((name = expectName()) == NULL) + return NULL; + } else if (peek(TOK_NAME)) { + if ((name = expectName()) == NULL) + return NULL; + } else { + // We predicted |type name|, but just got |name| instead. + name = returnTag; + returnTag = NULL; } BoundName *returnType = NULL; if (returnTag) returnType = bindType(returnTag); - Local name(zone_, expectName()); - if (!name) - return NULL; - SourcePosition pos = scanner_.begin(); // The function name goes into the outer (global) scope. @@ -1392,7 +1416,7 @@ scope_ = scope_->enclosing(); - FunctionSignature signature(returnType, parameters); + FunctionSignature signature(returnType, returnDimensions, parameters); if (token == TOK_TYPEDEF) return new (pool_) FunctionTypeStatement(pos, type, signature); @@ -1560,6 +1584,17 @@ { } + void dump(const FunctionSignature &sig) { + prefix(); + fprintf(fp_, "%s", sig.returnType() + ? sig.returnType()->name()->chars() + : "_"); + if (sig.returnDimensions()) { + for (size_t i = 0; i < sig.returnDimensions()->length(); i++) + fprintf(fp_, "[]"); + } + fprintf(fp_, "()\n"); + } void visit(NameProxy *name) { prefix(); fprintf(fp_, "[ NameProxy (%s)%s\n", name->name()->chars(), @@ -1577,11 +1612,15 @@ void visit(FunctionTypeStatement *node) { prefix(); fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->decl()->name()->chars()); + indent(); + dump(node->signature()); + unindent(); } void visit(FunctionStatement *node) { prefix(); fprintf(fp_, "[ FunctionStatement (%s)\n", node->fun()->name()->chars()); indent(); + dump(node->signature()); if (node->body()) node->body()->accept(this); unindent(); diff -r dd04fce774cd -r 9d17f29fe16a src/SemanticAnalysis.cpp --- a/src/SemanticAnalysis.cpp Sun Sep 16 21:59:26 2012 -0700 +++ b/src/SemanticAnalysis.cpp Sun Sep 16 22:49:54 2012 -0700 @@ -1027,35 +1027,14 @@ if (!type) return false; } else if (parameter->dimensions()) { - // :TODO: factor in type dimcount - if (parameter->dimensions()->length() > MAX_ARRAY_DEPTH) { - cc_.reportError(parameter->variable()->pos(), Message_MaximumArrayDepth); + type = buildArrayType(type, parameter->dimensions(), parameter->isConst()); + if (!type) return false; - } - if (kind == TOK_NATIVE && parameter->dimensions()->length() > 1) { + if (kind == TOK_NATIVE && type->levels() > 1) { cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative); return false; } - - for (size_t i = parameter->dimensions()->length() - 1; - i < parameter->dimensions()->length(); - i--) - { - int size = Type::DYNAMIC_ARRAY_SIZE; - if (Expression *expr = parameter->dimensions()->at(i)) { - BoxedPrimitive box; - if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) { - cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant); - return false; - } - size = box.toInt(); - } - - type = zone_->types()->newArray(type, size, parameter->isConst()); - if (!type) - return false; - } } if (IsScalarString(type)) { @@ -1122,6 +1101,51 @@ node->decl()->setType(funtype); } +Type * +SemanticAnalysis::buildArrayType(Handle type, ExpressionList *dimensions, bool isConst) +{ + Local arrayType(zone_, type); + + unsigned dimcount = dimensions->length(); + if (type->isArray()) + dimcount += type->levels(); + + if (dimcount > MAX_ARRAY_DEPTH) { + cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(), + Message_MaximumArrayDepth); + return false; + } + + // Note: constness is sort of bogus. Fix this sometime. + for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) { + Expression *expr = dimensions->at(i); + if (!expr) { + arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst); + if (!arrayType) + return NULL; + + continue; + } + + BoxedPrimitive box; + if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) { + cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant); + return NULL; + } + + if (box.toInt() <= 0) { + cc_.reportError(expr->pos(), Message_BadArraySize); + return NULL; + } + + arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst); + if (!arrayType) + return NULL; + } + + return arrayType; +} + bool SemanticAnalysis::preanalyze(FunctionStatement *node) { @@ -1150,6 +1174,17 @@ if (!returnType) return false; + if (sig.returnDimensions()) { + returnType = buildArrayType(returnType, sig.returnDimensions(), false); + if (!returnType) + return false; + } + + if (IsScalarString(returnType)) { + cc_.reportError(node->pos(), Message_CannotDeclareStringCell); + return false; + } + Local funtype(zone_); if (node->fun()->isNative()) funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic()); diff -r dd04fce774cd -r 9d17f29fe16a src/SemanticAnalysis.h --- a/src/SemanticAnalysis.h Sun Sep 16 21:59:26 2012 -0700 +++ b/src/SemanticAnalysis.h Sun Sep 16 22:49:54 2012 -0700 @@ -182,6 +182,9 @@ unsigned dimcount, unsigned level); + // Builds an array type used for parameters, returns, or field entries. + Type *buildArrayType(Handle type, ExpressionList *dimensions, bool isConst); + Box *evaluateDefaultParameter(Handle type, Parameter *parameter); bool checkArgumentCount(Handle type, unsigned actual); bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,