Beispiel #1
0
JSBool
Library::Name(JSContext* cx, uintN argc, jsval *vp)
{
  if (argc != 1) {
    JS_ReportError(cx, "libraryName takes one argument");
    return JS_FALSE;
  }

  jsval arg = JS_ARGV(cx, vp)[0];
  JSString* str = NULL;
  if (JSVAL_IS_STRING(arg)) {
    str = JSVAL_TO_STRING(arg);
  }
  else {
    JS_ReportError(cx, "name argument must be a string");
      return JS_FALSE;
  }

  AutoString resultString;
  AppendString(resultString, DLL_PREFIX);
  AppendString(resultString, str);
  AppendString(resultString, DLL_SUFFIX);

  JSString *result = JS_NewUCStringCopyN(cx, resultString.begin(),
                                         resultString.length());
  if (!result)
    return JS_FALSE;

  JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result));
  return JS_TRUE;
}
Beispiel #2
0
bool
Library::Name(JSContext* cx, unsigned argc, Value* vp)
{
  CallArgs args = CallArgsFromVp(argc, vp);
  if (args.length() != 1) {
    JS_ReportErrorASCII(cx, "libraryName takes one argument");
    return false;
  }

  Value arg = args[0];
  JSString* str = nullptr;
  if (arg.isString()) {
    str = arg.toString();
  } else {
    JS_ReportErrorASCII(cx, "name argument must be a string");
    return false;
  }

  AutoString resultString;
  AppendString(resultString, DLL_PREFIX);
  AppendString(resultString, str);
  AppendString(resultString, DLL_SUFFIX);

  JSString* result = JS_NewUCStringCopyN(cx, resultString.begin(),
                                         resultString.length());
  if (!result)
    return false;

  args.rval().setString(result);
  return true;
}
Beispiel #3
0
AString
sp::BuildTypeName(Type *aType, Atom *name, TypeDiagFlags flags)
{
  if (ArrayType *type = aType->asArray()) {
    Vector<ArrayType *> stack;

    Type *cursor = type;
    Type *innermost = nullptr;
    for (;;) {
      if (!cursor->isArray()) {
        innermost = cursor;
        break;
      }
      stack.append(cursor->toArray());
      cursor = cursor->toArray()->contained();
    }

    AutoString builder;
    if (aType->isConst() || !!(flags & TypeDiagFlags::IsConst))
      builder = "const ";

    builder = builder + BuildTypeName(innermost, nullptr, flags & kDiagFlagsInnerMask);

    bool hasFixedLengths = false;
    AutoString brackets;
    for (size_t i = 0; i < stack.length(); i++) {
      if (!stack[i]->hasFixedLength()) {
        brackets = brackets + "[]";
        continue;
      }

      hasFixedLengths = true;
      brackets = brackets + "[" + AutoString(stack[i]->fixedLength()) + "]";
    }

    if (name) {
      if (hasFixedLengths)
        builder = builder + " " + name->chars() + brackets;
      else
        builder = builder + brackets + " " + name->chars();
    } else {
      builder = builder + brackets;
    }
    return AString(builder.ptr());
  }

  AutoString builder;
  if (FunctionType *type = aType->asFunction())
    builder = BuildTypeFromSignature(type->signature(), flags & kDiagFlagsInnerMask);
  else
    builder = GetBaseTypeName(aType);
  if (!!(flags & TypeDiagFlags::IsByRef)) {
    builder = builder + "&";
  }
  if (name)
    builder = builder + " " + name->chars();
  return AString(builder.ptr());
}
Beispiel #4
0
Status pluginGet(int argc, char *argv[])
{
    if (argc != 4)
        return ABC_ERROR(ABC_CC_Error, "usage: ... plugin-get <user> <pass> <plugin> <key>");
    AutoString result;
    ABC_CHECK_OLD(ABC_PluginDataGet(argv[0], argv[1], argv[2], argv[3], &result.get(), &error));
    std::cout << '"' << result.get() << '"' << std::endl;
    return Status();
}
Beispiel #5
0
Status
otpResetGet(int argc, char *argv[])
{
    if (argc != 0)
        return ABC_ERROR(ABC_CC_Error, "usage: ... otp-reset-get");

    AutoString names;
    ABC_CHECK_OLD(ABC_OtpResetGet(&names.get(), &error));
    std::cout << names.get() << std::endl;

    return Status();
}
Beispiel #6
0
Status
otpKeyGet(int argc, char *argv[])
{
    if (argc != 1)
        return ABC_ERROR(ABC_CC_Error, "usage: ... otp-key-get <user>");

    AutoString key;
    ABC_CHECK_OLD(ABC_OtpKeyGet(argv[0], &key.get(), &error));
    std::cout << "key: " << key.get() << std::endl;

    return Status();
}
Beispiel #7
0
bool
Preprocessor::enterFile(TokenKind directive,
                        const SourceLocation &from,
                        const char *file,
                        const char *where)
{
  if (disable_includes_)
    return false;

  AutoString path = searchPaths(file, where);
  if (!path.length()) {
    // Try to append '.inc'.
    size_t len = strlen(file);
    if (len < 4 || strcmp(&file[len - 4], ".inc") != 0) {
      AutoString new_file = AutoString(file) + ".inc";
      path = searchPaths(new_file, where);
    }
  }

  if (!path.length()) {
    if (directive == TOK_M_TRYINCLUDE)
      return true;

    cc_.report(from, rmsg::include_not_found)
      << file;
    return false;
  }

  ReportingContext rc(cc_, from);
  Ref<SourceFile> new_file = cc_.source().open(rc, path.ptr());
  if (!new_file)
    return false;

  LREntry tl = cc_.source().trackFile(from, new_file);
  if (!tl.valid()) {
    // Error was already reported.
    return false;
  }

  if (include_depth_ >= kMaxIncludeDepth) {
    cc_.report(from, rmsg::include_depth_exceeded);
    return false;
  }

  include_depth_++;

  assert(!macro_lexer_ && lexer_);
  lexer_stack_.append(SavedLexer(lexer_, nullptr));
  lexer_ = new Lexer(cc_, *this, lexer_->options(), new_file, tl);
  return true;
}
Beispiel #8
0
static AString
BuildTypeFromSignature(const FunctionSignature *sig, TypeDiagFlags flags)
{
  AutoString base = "function ";
  base = base + BuildTypeFromTypeExpr(sig->returnType(), nullptr, flags & kDiagFlagsInnerMask);
  base = base + "(";

  for (size_t i = 0; i < sig->parameters()->length(); i++) {
    TypeDiagFlags varFlags = flags & kDiagFlagsInnerMask;
    Atom *name = !!(flags & TypeDiagFlags::Names)
                 ? sig->parameters()->at(i)->name()
                 : nullptr;
    if (sig->parameters()->at(i)->sym()->isByRef())
      varFlags |= TypeDiagFlags::IsByRef;
    base = base + BuildTypeFromTypeExpr(sig->parameters()->at(i)->te(), name, varFlags);
    if (i != sig->parameters()->length() - 1)
      base = base + ", ";
  }
  base = base + ")";
  return AString(base.ptr());
}
Beispiel #9
0
  JsonList *toJson(const ParameterList *params) {
    JsonList *list = new (pool_) JsonList();
    for (size_t i = 0; i < params->length(); i++) {
      VarDecl *decl = params->at(i);
      JsonObject *obj = new (pool_) JsonObject();

      obj->add(atom_type_, toJson(decl, false));

      if (decl->name()) {
        obj->add(atom_name_, toJson(decl->name()));
        obj->add(atom_decl_, toJson(decl, true));
      } else {
        obj->add(atom_name_, toJson("..."));

        AutoString builder = BuildTypeName(decl->te(), nullptr, TypeDiagFlags::Names);
        builder = builder + " ...";
        obj->add(atom_decl_, toJson(builder.ptr()));
      }
      list->add(obj);
    }
    return list;
  }
Beispiel #10
0
HRESULT Helpers::LoadScriptFromFile(LPCSTR filenameToLoad, LPCSTR& contents, UINT* lengthBytesOut /*= nullptr*/, std::string* fullPath /*= nullptr*/, bool shouldMute /*=false */)
{
    static char sHostApplicationPathBuffer[MAX_URI_LENGTH];
    static uint sHostApplicationPathBufferLength = (uint) -1;
    char combinedPathBuffer[MAX_URI_LENGTH];

    HRESULT hr = S_OK;
    BYTE * pRawBytes = nullptr;
    BYTE * pRawBytesFromMap = nullptr;
    UINT lengthBytes = 0;
    contents = nullptr;
    FILE * file = NULL;
    size_t bufferLength = 0;

    LPCSTR filename = fullPath == nullptr ? filenameToLoad : LPCSTR(fullPath->c_str());
    if (sHostApplicationPathBufferLength == (uint)-1)
    {
        // consider incoming filename as the host app and base its' path for others
        sHostApplicationPathBufferLength = GetPathNameLocation(filename);
        if (sHostApplicationPathBufferLength == -1)
        {
            // host app has no path info. (it must be located on current folder!)
            sHostApplicationPathBufferLength = 0;
        }
        else
        {
            sHostApplicationPathBufferLength += 1;
            Assert(sHostApplicationPathBufferLength < MAX_URI_LENGTH);
            // save host app's path and fix the path separator for platform
            pathcpy(sHostApplicationPathBuffer, filename, sHostApplicationPathBufferLength);
        }
        sHostApplicationPathBuffer[sHostApplicationPathBufferLength] = char(0);
    }
    else if (filename[0] != '/' && filename[0] != '\\' && fullPath == nullptr) // make sure it's not a full path
    {
        // concat host path and filename
        uint len = ConcatPath(sHostApplicationPathBuffer, sHostApplicationPathBufferLength,
                   filename, combinedPathBuffer, MAX_URI_LENGTH);

        if (len == (uint)-1)
        {
            hr = E_FAIL;
            goto Error;
        }
        filename = combinedPathBuffer;
    }

    // check if have it registered
    AutoString *data;
    if (SourceMap::Find(filenameToLoad, strlen(filenameToLoad), &data) ||
        SourceMap::Find(filename, strlen(filename), &data))
    {
        pRawBytesFromMap = (BYTE*) data->GetString();
        lengthBytes = (UINT) data->GetLength();
    }
    else
    {
        // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
        // etc.
        if (fopen_s(&file, filename, "rb") != 0)
        {
            if (!HostConfigFlags::flags.MuteHostErrorMsgIsEnabled && !shouldMute)
            {
#ifdef _WIN32
                DWORD lastError = GetLastError();
                char16 wszBuff[MAX_URI_LENGTH];
                fprintf(stderr, "Error in opening file '%s' ", filename);
                wszBuff[0] = 0;
                if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                    nullptr,
                    lastError,
                    0,
                    wszBuff,
                    _countof(wszBuff),
                    nullptr))
                {
                    fwprintf(stderr, _u(": %s"), wszBuff);
                }
                fwprintf(stderr, _u("\n"));
#elif defined(_POSIX_VERSION)
                fprintf(stderr, "Error in opening file: ");
                perror(filename);
#endif
            }

            IfFailGo(E_FAIL);
        }
    }

    if (file != NULL)
    {
        // Determine the file length, in bytes.
        fseek(file, 0, SEEK_END);
        lengthBytes = ftell(file);
        fseek(file, 0, SEEK_SET);
    }

    if (lengthBytes != 0)
    {
        bufferLength = lengthBytes + sizeof(BYTE);
        pRawBytes = (LPBYTE)malloc(bufferLength);
    }
    else
    {
        bufferLength = 1;
        pRawBytes = (LPBYTE)malloc(bufferLength);
    }

    if (nullptr == pRawBytes)
    {
        fwprintf(stderr, _u("out of memory"));
        IfFailGo(E_OUTOFMEMORY);
    }

    if (lengthBytes != 0)
    {
        if (file != NULL)
        {
            //
            // Read the entire content as a binary block.
            //
            size_t readBytes = fread(pRawBytes, sizeof(BYTE), lengthBytes, file);
            if (readBytes < lengthBytes * sizeof(BYTE))
            {
                IfFailGo(E_FAIL);
            }
        }
        else // from module source register
        {
            // Q: module source is on persistent memory. Why do we use the copy instead?
            // A: if we use the same memory twice, ch doesn't know that during FinalizeCallback free.
            // the copy memory will be freed by the finalizer
            Assert(pRawBytesFromMap);
            memcpy_s(pRawBytes, bufferLength, pRawBytesFromMap, lengthBytes);
        }
    }

    if (pRawBytes)
    {
        pRawBytes[lengthBytes] = 0; // Null terminate it. Could be UTF16
    }

    if (file != NULL)
    {
        //
        // Read encoding to make sure it's supported
        //
        // Warning: The UNICODE buffer for parsing is supposed to be provided by the host.
        // This is not a complete read of the encoding. Some encodings like UTF7, UTF1, EBCDIC, SCSU, BOCU could be
        // wrongly classified as ANSI
        //
#pragma warning(push)
        // suppressing prefast warning that "readable size is bufferLength
        // bytes but 2 may be read" as bufferLength is clearly > 2 in the code that follows
#pragma warning(disable:6385)
        C_ASSERT(sizeof(WCHAR) == 2);
        if (bufferLength > 2)
        {
            __analysis_assume(bufferLength > 2);
#pragma prefast(push)
#pragma prefast(disable:6385, "PREfast incorrectly reports this as an out-of-bound access.");
            if ((pRawBytes[0] == 0xFE && pRawBytes[1] == 0xFF) ||
                (pRawBytes[0] == 0xFF && pRawBytes[1] == 0xFE) ||
                (bufferLength > 4 && pRawBytes[0] == 0x00 && pRawBytes[1] == 0x00 &&
                    ((pRawBytes[2] == 0xFE && pRawBytes[3] == 0xFF) ||
                    (pRawBytes[2] == 0xFF && pRawBytes[3] == 0xFE))))

            {
                // unicode unsupported
                fwprintf(stderr, _u("unsupported file encoding. Only ANSI and UTF8 supported"));
                IfFailGo(E_UNEXPECTED);
            }
#pragma prefast(pop)
        }
#pragma warning(pop)
    }

    contents = reinterpret_cast<LPCSTR>(pRawBytes);

Error:
    if (SUCCEEDED(hr))
    {
        if (lengthBytesOut)
        {
            *lengthBytesOut = lengthBytes;
        }
    }

    if (file != NULL)
    {
        fclose(file);
    }

    if (pRawBytes && reinterpret_cast<LPCSTR>(pRawBytes) != contents)
    {
        free(pRawBytes);
    }

    return hr;
}
/** Load the PLY mesh. */
bool PiMeshImportPLY::Import(const char * name) {

    // Reset mesh.
    mesh->Reset();

    // Open file.
    PiAutoPtr<PiVirtualFile> vf( PiFileSystem::OpenFile( name ) );
    if( vf == NULL ) {
        piDebug( "*** Cannot open PLY file: '%s'\n", name );
        return false;
    }

    piDebug("--- Loading PLY file '%s'.\n", name );

    PiParser parser;
    parser.StartParseBuffer( vf->GetMem(), vf->GetSize() );

    if( !parser.GetToken( true ) || strCmp(parser.token, "ply") ) {
        piDebug( "*** File '%s' does not appear to be a ply file.\n", name );
        return false;
    }

    PlyHeader head;
    PlyElement * current = NULL;
    LL_Reset( &head.elems, next, prev );


    bool result = false;

    while(true) {

        if( !parser.GetToken( true ) ) {
            piDebug( "*** Unexpected 'end of file' found while reading ply file '%s'.\n", name );
            break;
        }

        if( !strCmp( parser.token, "format" ) ) {
            // 'format' <type> <version>
            if( !parser.GetToken( false ) ) {
                piDebug( "*** Type expected while reading ply file '%s'.\n", name );
                break;
            }

            if( !strCmp( parser.token, "ascii" ) ) head.format = PLY_ASCII;
            else if( !strCmp( parser.token, "binary_big_endian" ) ) head.format = PLY_BINARY_BE;
            else if( !strCmp( parser.token, "binary_little_endian" ) ) head.format = PLY_BINARY_LE;

            if( !parser.GetToken( false ) ) {
                piDebug( "*** Version expected while reading ply file '%s'.\n", name );
                break;
            }

            head.version = 0;
        }
        else if( !strCmp( parser.token, "element" ) ) {
            // 'element' <type> <num>

            current = new PlyElement;
            LL_Reset( current, next, prev );
            LL_AddLast( &head.elems, current, next, prev );
            LL_Reset( &current->props, next, prev );

            if( !parser.GetToken( false ) ) {
                piDebug( "*** Element type expected while reading ply file '%s'.\n", name );
                break;
            }
            current->name = piStrDup( parser.token );
            if( !strCmp( parser.token, "vertex" ) ) current->type = PLET_VERTEX;
            else if( !strCmp( parser.token, "face" ) ) current->type = PLET_FACE;
            else current->type = PLET_OTHER;

            if( !parser.GetToken( false ) ) {
                piDebug( "*** Number of elements expected while reading ply file '%s'.\n", name );
                break;
            }
            current->num = atoi( parser.token );

        }
        else if( !strCmp( parser.token, "property" ) ) {
            // 'property' <type> <name>

            PlyProperty * prop = new PlyProperty;
            LL_Reset( prop, next, prev );
            LL_AddLast( &current->props, prop, next, prev );

            if( !parser.GetToken( false ) ) {
                piDebug( "*** Property type expected while reading ply file '%s'.\n", name );
                break;
            }

            if( !strCmp( parser.token, "list" ) ) {
                prop->mode = PLPM_LIST;
                if( !parser.GetToken( false ) ) {
                    piDebug( "*** Property type expected while reading ply file '%s'.\n", name );
                    break;
                }
                if( !ReadType( parser, (int &)prop->ctype ) ) {
                    piDebug( "*** Unknown property type while reading ply file '%s'.\n", name );
                    break;
                }

                if( !parser.GetToken( false ) ) {
                    piDebug( "*** Property type expected while reading ply file '%s'.\n", name );
                    break;
                }
            }
            else {
                prop->mode = PLPM_SCALAR;
            }

            if( !ReadType( parser, (int &)prop->type ) ) {
                piDebug( "*** Unknown property type while reading ply file '%s'.\n", name );
                break;
            }

            // read name
            if( !parser.GetToken( false ) ) {
                piDebug( "*** Property name expected while reading ply file '%s'.\n", name );
                break;
            }
            prop->name = piStrDup( parser.token );
        }
        else if( !strCmp( parser.token, "comment" ) ) {
            AutoString comment;
            while( parser.GetToken( false ) ) {
                comment.Append(" ");
                comment.Append(parser.token);
            };
            piDebug( "---   Comment:%s\n", comment.GetStr() );
        }
        else if( !strCmp( parser.token, "end_header" ) ) {
            if( parser.NextLine() )
                result = true;
            break;
        }
    };


    if( result == false ) {
        piDebug("***   Load failed.\n");
    }
    else {

        // Analize what we have:
        PlyElement * e;
        for( e = head.elems.next; e != &head.elems; e = e->next ) {
            if( strCmp( e->name, "vertex" ) == 0 ) {
                mesh->SetVertexNum( e->num );
                //pos_array.Resize( e->num );
                //col_array.Resize( e->num );
            }
            else if( strCmp( e->name, "face" ) == 0 ) {
                // Number of faces is not the number of triangles.
                //face_array.Resize( e->num );
            }
        }


        PiMesh::Channel * pos_channel = mesh->GetChannel(mesh->CreateChannel("position", VS_POS, VF_FLOAT, 3));



        uint pos_num = 0;
        Vec2 tmp(0, 0);

        // Extract data.
        for( e = head.elems.next; e != &head.elems; e = e->next ) {

            for( uint i = 0; i < e->num; i++ ) {

                PlyProperty * p;
                for( p = e->props.next; p != &e->props; p = p->next ) {

                    if( p->mode == PLPM_SCALAR ) {
                        float value;
                        ReadFloatValue( parser, head.format, p->type, value );

                        if( strCmp( p->name, "x" ) == 0 ) {
                            tmp.x = value;
                        }
                        else if( strCmp( p->name, "y" ) == 0 ) {
                            tmp.y = value;
                        }
                        else if( strCmp( p->name, "z" ) == 0 ) {
                            pos_channel->data[pos_num++] = Vec4(tmp, value, 1.0f);
                        }
                    }
                    else if( p->mode == PLPM_LIST ) {
                        uint count;
                        ReadIntValue( parser, head.format, p->ctype, count );

                        uint v0, v1, v2;
                        ReadIntValue( parser, head.format, p->type, v0 );
                        ReadIntValue( parser, head.format, p->type, v1 );

                        // conver poly to fan
                        for( uint f = 0; f < count-2; f++ ) {
                            ReadIntValue( parser, head.format, p->type, v2 );
                            mesh->AddFace(v0, v1, v2);
                            v1 = v2;
                        }
                    }
                }
            }
        }

        piDebug("---   Load succeed.\n");
        piDebug( "---   %d vertices\n", mesh->GetVertexNum() );
        piDebug( "---   %d faces\n", mesh->GetFaceNum() );
    }

    // clean header
    PlyElement * e, * enext;
    for( e=head.elems.next; e!=&head.elems; e=enext ) {
        enext = e->next;
        LL_Reset( e, next, prev );

        PlyProperty * p, * pnext;
        for( p=e->props.next; p!=&e->props; p=pnext ) {
            pnext = p->next;
            LL_Reset( p, next, prev );

            mem::free( p->name );
            delete p;
        }

        mem::free( e->name );
        delete e;
    }

    return result;
}
Beispiel #12
0
bool Debugger::CompareOrWriteBaselineFile(LPCSTR fileName)
{
    AutoRestoreContext autoRestoreContext(this->m_context);

    // Pass in undefined for 'this'
    JsValueRef undefinedRef;
    IfJsrtErrorFailLogAndRetFalse(ChakraRTInterface::JsGetUndefinedValue(&undefinedRef));

    JsValueRef result = JS_INVALID_REFERENCE;

    bool testPassed = false;

    if (HostConfigFlags::flags.dbgbaselineIsEnabled)
    {
        this->CallFunction("Verify", &result);
        JsValueRef numberVal;
        IfJsrtErrorFailLogAndRetFalse(ChakraRTInterface::JsConvertValueToNumber(result, &numberVal));
        int val;
        IfJsrtErrorFailLogAndRetFalse(ChakraRTInterface::JsNumberToInt(numberVal, &val));
        testPassed = (val == 0);
    }

    if (!testPassed)
    {
        this->CallFunction("GetOutputJson", &result);

        AutoString baselineData;
        IfJsrtErrorFailLogAndRetFalse(baselineData.Initialize(result));

        char16 baselineFilename[256];
        swprintf_s(baselineFilename, HostConfigFlags::flags.dbgbaselineIsEnabled ? _u("%S.dbg.baseline.rebase") : _u("%S.dbg.baseline"), fileName);

        FILE *file = nullptr;
        if (_wfopen_s(&file, baselineFilename, _u("wt")) != 0)
        {
            return false;
        }

        if (file != nullptr)
        {
            int countWritten = static_cast<int>(fwrite(baselineData.GetString(), sizeof(char), baselineData.GetLength(), file));
            Assert(baselineData.GetLength() <= INT_MAX);
            if (countWritten != (int)baselineData.GetLength())
            {
                Assert(false);
                return false;
            }

            fclose(file);
        }

        if (!HostConfigFlags::flags.dbgbaselineIsEnabled)
        {
            wprintf(_u("No baseline file specified, baseline created at '%s'\n"), baselineFilename);
        }
        else
        {
            Helpers::LogError(_u("Rebase file created at '%s'\n"), baselineFilename);
        }
    }

    return true;
}
Beispiel #13
0
static AString
BuildTypeFromSpecifier(const TypeSpecifier *spec, Atom *name, TypeDiagFlags flags)
{
  AutoString base;
  if (spec->isConst() || !!(flags & TypeDiagFlags::IsConst))
    base = "const ";

  switch (spec->resolver()) {
    case TOK_LABEL:
    {
      // HACK: we should move these atoms into the context.
      const char *chars = spec->proxy()->name()->chars();
      if (strcmp(chars, "Float") == 0)
        base = base + "float";
      else if (strcmp(chars, "String") == 0)
        base = base + "char";
      else if (strcmp(chars, "_") == 0)
        base = base + "int";
      else
        base = base + chars;
      break;
    }
    case TOK_NAME:
      base = base + spec->proxy()->name()->chars();
      break;
    case TOK_IMPLICIT_INT:
      base = base + "int";
      break;
    case TOK_FUNCTION:
      base = base + BuildTypeFromSignature(spec->signature(), flags & kDiagFlagsInnerMask);
      break;
    case TOK_DEFINED:
      base = base + BuildTypeName(spec->getResolvedBase(), nullptr, flags & kDiagFlagsInnerMask);
      break;
    default:
      base = base + TokenNames[spec->resolver()];
      break;
  }

  // We need type analysis to determine the true type, so just make a semi-
  // intelligent guess based on whether or not any rank has a sized dimension.
  bool postDims = (spec->isNewDecl() && spec->hasPostDims()) ||
                  (spec->isOldDecl() && spec->dims());

  if (name && postDims)
    base = base + " " + name->chars();

  for (size_t i = 0; i < spec->rank(); i++) {
    if (Expression *expr = spec->sizeOfRank(i)) {
      if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
        char value[24];
        SafeSprintf(value, sizeof(value), "%d", (int)lit->value());
        base = base + "[" + value + "]";
        continue;
      }
    }

    // Hack. We can do better if it becomes necessary, these types are only
    // for diagnostics.
    base = base + "[]";
  }
  if (name && !postDims) {
    base = base + " ";
    if (spec->isByRef())
      base = base + "&";
    base = base + name->chars();
  } else {
    if (spec->isByRef())
      base = base + "&";
  }

  if (spec->isVariadic())
    base = base + " ...";

  return AString(base.ptr());
}