| |
| /* Compiler implementation of the D programming language |
| * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved |
| * written by Walter Bright |
| * http://www.digitalmars.com |
| * Distributed under the Boost Software License, Version 1.0. |
| * http://www.boost.org/LICENSE_1_0.txt |
| * https://github.com/D-Programming-Language/dmd/blob/master/src/mangle.c |
| */ |
| |
| #include "root/dsystem.h" |
| #include "root/root.h" |
| #include "root/aav.h" |
| |
| #include "mangle.h" |
| #include "init.h" |
| #include "declaration.h" |
| #include "aggregate.h" |
| #include "mtype.h" |
| #include "attrib.h" |
| #include "target.h" |
| #include "template.h" |
| #include "id.h" |
| #include "module.h" |
| #include "enum.h" |
| #include "expression.h" |
| #include "utf.h" |
| |
| typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param); |
| int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL); |
| |
| static const char *mangleChar[TMAX]; |
| |
| void initTypeMangle() |
| { |
| mangleChar[Tarray] = "A"; |
| mangleChar[Tsarray] = "G"; |
| mangleChar[Taarray] = "H"; |
| mangleChar[Tpointer] = "P"; |
| mangleChar[Treference] = "R"; |
| mangleChar[Tfunction] = "F"; |
| mangleChar[Tident] = "I"; |
| mangleChar[Tclass] = "C"; |
| mangleChar[Tstruct] = "S"; |
| mangleChar[Tenum] = "E"; |
| mangleChar[Tdelegate] = "D"; |
| |
| mangleChar[Tnone] = "n"; |
| mangleChar[Tvoid] = "v"; |
| mangleChar[Tint8] = "g"; |
| mangleChar[Tuns8] = "h"; |
| mangleChar[Tint16] = "s"; |
| mangleChar[Tuns16] = "t"; |
| mangleChar[Tint32] = "i"; |
| mangleChar[Tuns32] = "k"; |
| mangleChar[Tint64] = "l"; |
| mangleChar[Tuns64] = "m"; |
| mangleChar[Tint128] = "zi"; |
| mangleChar[Tuns128] = "zk"; |
| mangleChar[Tfloat32] = "f"; |
| mangleChar[Tfloat64] = "d"; |
| mangleChar[Tfloat80] = "e"; |
| |
| mangleChar[Timaginary32] = "o"; |
| mangleChar[Timaginary64] = "p"; |
| mangleChar[Timaginary80] = "j"; |
| mangleChar[Tcomplex32] = "q"; |
| mangleChar[Tcomplex64] = "r"; |
| mangleChar[Tcomplex80] = "c"; |
| |
| mangleChar[Tbool] = "b"; |
| mangleChar[Tchar] = "a"; |
| mangleChar[Twchar] = "u"; |
| mangleChar[Tdchar] = "w"; |
| |
| // '@' shouldn't appear anywhere in the deco'd names |
| mangleChar[Tinstance] = "@"; |
| mangleChar[Terror] = "@"; |
| mangleChar[Ttypeof] = "@"; |
| mangleChar[Ttuple] = "B"; |
| mangleChar[Tslice] = "@"; |
| mangleChar[Treturn] = "@"; |
| mangleChar[Tvector] = "@"; |
| mangleChar[Ttraits] = "@"; |
| mangleChar[Tmixin] = "@"; |
| mangleChar[Tnoreturn] = "@"; // becomes 'Nn' |
| |
| mangleChar[Tnull] = "n"; // same as TypeNone |
| |
| for (size_t i = 0; i < TMAX; i++) |
| { |
| if (!mangleChar[i]) |
| fprintf(stderr, "ty = %llu\n", (ulonglong)i); |
| assert(mangleChar[i]); |
| } |
| } |
| |
| /********************************* |
| * Mangling for mod. |
| */ |
| void MODtoDecoBuffer(OutBuffer *buf, MOD mod) |
| { |
| switch (mod) |
| { |
| case 0: |
| break; |
| case MODconst: |
| buf->writeByte('x'); |
| break; |
| case MODimmutable: |
| buf->writeByte('y'); |
| break; |
| case MODshared: |
| buf->writeByte('O'); |
| break; |
| case MODshared | MODconst: |
| buf->writestring("Ox"); |
| break; |
| case MODwild: |
| buf->writestring("Ng"); |
| break; |
| case MODwildconst: |
| buf->writestring("Ngx"); |
| break; |
| case MODshared | MODwild: |
| buf->writestring("ONg"); |
| break; |
| case MODshared | MODwildconst: |
| buf->writestring("ONgx"); |
| break; |
| default: |
| assert(0); |
| } |
| } |
| |
| class Mangler : public Visitor |
| { |
| public: |
| AA *types; |
| AA *idents; |
| OutBuffer *buf; |
| |
| Mangler(OutBuffer *buf) |
| { |
| this->types = NULL; |
| this->idents = NULL; |
| this->buf = buf; |
| } |
| |
| /** |
| * writes a back reference with the relative position encoded with base 26 |
| * using upper case letters for all digits but the last digit which uses |
| * a lower case letter. |
| * The decoder has to look up the referenced position to determine |
| * whether the back reference is an identifier (starts with a digit) |
| * or a type (starts with a letter). |
| * |
| * Params: |
| * pos = relative position to encode |
| */ |
| void writeBackRef(size_t pos) |
| { |
| buf->writeByte('Q'); |
| const size_t base = 26; |
| size_t mul = 1; |
| while (pos >= mul * base) |
| mul *= base; |
| while (mul >= base) |
| { |
| unsigned char dig = (unsigned char)(pos / mul); |
| buf->writeByte('A' + dig); |
| pos -= dig * mul; |
| mul /= base; |
| } |
| buf->writeByte('a' + (unsigned char)pos); |
| } |
| |
| /** |
| * Back references a non-basic type |
| * |
| * The encoded mangling is |
| * 'Q' <relative position of first occurrence of type> |
| * |
| * Params: |
| * t = the type to encode via back referencing |
| * |
| * Returns: |
| * true if the type was found. A back reference has been encoded. |
| * false if the type was not found. The current position is saved for later back references. |
| */ |
| bool backrefType(Type *t) |
| { |
| if (!t->isTypeBasic()) |
| { |
| size_t *p = (size_t *)dmd_aaGet(&types, (void *)t); |
| if (*p) |
| { |
| writeBackRef(buf->length() - *p); |
| return true; |
| } |
| *p = buf->length(); |
| } |
| return false; |
| } |
| |
| /** |
| * Back references a single identifier |
| * |
| * The encoded mangling is |
| * 'Q' <relative position of first occurrence of type> |
| * |
| * Params: |
| * id = the identifier to encode via back referencing |
| * |
| * Returns: |
| * true if the identifier was found. A back reference has been encoded. |
| * false if the identifier was not found. The current position is saved for later back references. |
| */ |
| bool backrefIdentifier(Identifier *id) |
| { |
| size_t *p = (size_t *)dmd_aaGet(&idents, (void *)id); |
| if (*p) |
| { |
| writeBackRef(buf->length() - *p); |
| return true; |
| } |
| *p = buf->length(); |
| return false; |
| } |
| |
| void mangleSymbol(Dsymbol *s) |
| { |
| s->accept(this); |
| } |
| |
| void mangleType(Type *t) |
| { |
| if (!backrefType(t)) |
| t->accept(this); |
| } |
| |
| void mangleIdentifier(Identifier *id, Dsymbol *s) |
| { |
| if (!backrefIdentifier(id)) |
| toBuffer(id->toChars(), s); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| |
| /************************************************** |
| * Type mangling |
| */ |
| |
| void visitWithMask(Type *t, unsigned char modMask) |
| { |
| if (modMask != t->mod) |
| { |
| MODtoDecoBuffer(buf, t->mod); |
| } |
| mangleType(t); |
| } |
| |
| void visit(Type *t) |
| { |
| buf->writestring(mangleChar[t->ty]); |
| } |
| |
| void visit(TypeNext *t) |
| { |
| visit((Type *)t); |
| visitWithMask(t->next, t->mod); |
| } |
| |
| void visit(TypeVector *t) |
| { |
| buf->writestring("Nh"); |
| visitWithMask(t->basetype, t->mod); |
| } |
| |
| void visit(TypeSArray *t) |
| { |
| visit((Type *)t); |
| if (t->dim) |
| buf->print(t->dim->toInteger()); |
| if (t->next) |
| visitWithMask(t->next, t->mod); |
| } |
| |
| void visit(TypeDArray *t) |
| { |
| visit((Type *)t); |
| if (t->next) |
| visitWithMask(t->next, t->mod); |
| } |
| |
| void visit(TypeAArray *t) |
| { |
| visit((Type *)t); |
| visitWithMask(t->index, 0); |
| visitWithMask(t->next, t->mod); |
| } |
| |
| void visit(TypeFunction *t) |
| { |
| //printf("TypeFunction::toDecoBuffer() t = %p %s\n", t, t->toChars()); |
| //static int nest; if (++nest == 50) *(char*)0=0; |
| |
| mangleFuncType(t, t, t->mod, t->next); |
| } |
| |
| void mangleFuncType(TypeFunction *t, TypeFunction *ta, unsigned char modMask, Type *tret) |
| { |
| //printf("mangleFuncType() %s\n", t->toChars()); |
| if (t->inuse && tret) |
| { |
| // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t->toChars()); |
| t->inuse = 2; // flag error to caller |
| return; |
| } |
| t->inuse++; |
| |
| if (modMask != t->mod) |
| MODtoDecoBuffer(buf, t->mod); |
| |
| unsigned char mc; |
| switch (t->linkage) |
| { |
| case LINKd: mc = 'F'; break; |
| case LINKc: mc = 'U'; break; |
| case LINKwindows: mc = 'W'; break; |
| case LINKcpp: mc = 'R'; break; |
| case LINKobjc: mc = 'Y'; break; |
| default: |
| assert(0); |
| } |
| buf->writeByte(mc); |
| |
| if (ta->purity || ta->isnothrow || ta->isnogc || ta->isproperty || ta->isref || ta->trust || ta->isreturn || ta->isscope) |
| { |
| if (ta->purity) |
| buf->writestring("Na"); |
| if (ta->isnothrow) |
| buf->writestring("Nb"); |
| if (ta->isref) |
| buf->writestring("Nc"); |
| if (ta->isproperty) |
| buf->writestring("Nd"); |
| if (ta->isnogc) |
| buf->writestring("Ni"); |
| if (ta->isreturn) |
| buf->writestring("Nj"); |
| if (ta->isscope && !ta->isreturn && !ta->isscopeinferred) |
| buf->writestring("Nl"); |
| switch (ta->trust) |
| { |
| case TRUSTtrusted: |
| buf->writestring("Ne"); |
| break; |
| case TRUSTsafe: |
| buf->writestring("Nf"); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| // Write argument types |
| paramsToDecoBuffer(t->parameterList.parameters); |
| //if (buf->slice().ptr[buf->length() - 1] == '@') halt(); |
| buf->writeByte('Z' - t->parameterList.varargs); // mark end of arg list |
| if (tret != NULL) |
| visitWithMask(tret, 0); |
| |
| t->inuse--; |
| } |
| |
| void visit(TypeIdentifier *t) |
| { |
| visit((Type *)t); |
| const char *name = t->ident->toChars(); |
| size_t len = strlen(name); |
| buf->print(len); |
| buf->writestring(name); |
| } |
| |
| void visit(TypeEnum *t) |
| { |
| visit((Type *)t); |
| mangleSymbol(t->sym); |
| } |
| |
| void visit(TypeStruct *t) |
| { |
| //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", t->toChars(), name); |
| visit((Type *)t); |
| mangleSymbol(t->sym); |
| } |
| |
| void visit(TypeClass *t) |
| { |
| //printf("TypeClass::toDecoBuffer('%s' mod=%x) = '%s'\n", t->toChars(), mod, name); |
| visit((Type *)t); |
| mangleSymbol(t->sym); |
| } |
| |
| void visit(TypeTuple *t) |
| { |
| //printf("TypeTuple::toDecoBuffer() t = %p, %s\n", t, t->toChars()); |
| visit((Type *)t); |
| paramsToDecoBuffer(t->arguments); |
| buf->writeByte('Z'); |
| } |
| |
| void visit(TypeNull *t) |
| { |
| visit((Type *)t); |
| } |
| |
| void visit(TypeNoreturn *) |
| { |
| buf->writestring("Nn"); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| |
| void mangleDecl(Declaration *sthis) |
| { |
| mangleParent(sthis); |
| |
| assert(sthis->ident); |
| mangleIdentifier(sthis->ident, sthis); |
| if (FuncDeclaration *fd = sthis->isFuncDeclaration()) |
| { |
| mangleFunc(fd, false); |
| } |
| else if (sthis->type) |
| { |
| visitWithMask(sthis->type, 0); |
| } |
| else |
| assert(0); |
| } |
| |
| void mangleParent(Dsymbol *s) |
| { |
| Dsymbol *p; |
| if (TemplateInstance *ti = s->isTemplateInstance()) |
| p = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent; |
| else |
| p = s->parent; |
| |
| if (p) |
| { |
| mangleParent(p); |
| TemplateInstance *ti = p->isTemplateInstance(); |
| if (ti && !ti->isTemplateMixin()) |
| { |
| mangleTemplateInstance(ti); |
| } |
| else if (p->getIdent()) |
| { |
| mangleIdentifier(p->ident, s); |
| if (FuncDeclaration *f = p->isFuncDeclaration()) |
| mangleFunc(f, true); |
| } |
| else |
| buf->writeByte('0'); |
| } |
| } |
| |
| void mangleFunc(FuncDeclaration *fd, bool inParent) |
| { |
| //printf("deco = '%s'\n", fd->type->deco ? fd->type->deco : "null"); |
| //printf("fd->type = %s\n", fd->type->toChars()); |
| if (fd->needThis() || fd->isNested()) |
| buf->writeByte('M'); |
| if (inParent) |
| { |
| TypeFunction *tf = (TypeFunction *)fd->type; |
| TypeFunction *tfo = (TypeFunction *)fd->originalType; |
| mangleFuncType(tf, tfo, 0, NULL); |
| } |
| else if (fd->type) |
| { |
| visitWithMask(fd->type, 0); |
| } |
| else |
| { |
| printf("[%s] %s no type\n", fd->loc.toChars(), fd->toChars()); |
| assert(0); // don't mangle function until semantic3 done. |
| } |
| } |
| |
| /************************************************************ |
| * Write length prefixed string to buf. |
| */ |
| void toBuffer(const char *id, Dsymbol *s) |
| { |
| size_t len = strlen(id); |
| if (buf->length() + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone |
| s->error("excessive length %llu for symbol, possible recursive expansion?", buf->length() + len); |
| else |
| { |
| buf->print(len); |
| buf->write(id, len); |
| } |
| } |
| |
| static const char *externallyMangledIdentifier(Declaration *d) |
| { |
| if (!d->parent || d->parent->isModule() || d->linkage == LINKcpp) // if at global scope |
| { |
| switch (d->linkage) |
| { |
| case LINKd: |
| break; |
| case LINKc: |
| case LINKwindows: |
| case LINKobjc: |
| return d->ident->toChars(); |
| case LINKcpp: |
| return target.cpp.toMangle(d); |
| case LINKdefault: |
| d->error("forward declaration"); |
| return d->ident->toChars(); |
| default: |
| fprintf(stderr, "'%s', linkage = %d\n", d->toChars(), d->linkage); |
| assert(0); |
| } |
| } |
| return NULL; |
| } |
| |
| void visit(Declaration *d) |
| { |
| //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", |
| // d, d->toChars(), d->parent ? d->parent->toChars() : "null", d->linkage); |
| if (const char *id = externallyMangledIdentifier(d)) |
| { |
| buf->writestring(id); |
| return; |
| } |
| buf->writestring("_D"); |
| mangleDecl(d); |
| } |
| |
| /****************************************************************************** |
| * Normally FuncDeclaration and FuncAliasDeclaration have overloads. |
| * If and only if there is no overloads, mangle() could return |
| * exact mangled name. |
| * |
| * module test; |
| * void foo(long) {} // _D4test3fooFlZv |
| * void foo(string) {} // _D4test3fooFAyaZv |
| * |
| * // from FuncDeclaration::mangle(). |
| * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo" |
| * // by calling Dsymbol::mangle() |
| * |
| * // from FuncAliasDeclaration::mangle() |
| * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv" |
| * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv" |
| * |
| * If a function has no overloads, .mangleof property still returns exact mangled name. |
| * |
| * void bar() {} |
| * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv" |
| * // by calling FuncDeclaration::mangleExact(). |
| */ |
| void visit(FuncDeclaration *fd) |
| { |
| if (fd->isUnique()) |
| mangleExact(fd); |
| else |
| visit((Dsymbol *)fd); |
| } |
| |
| // ditto |
| void visit(FuncAliasDeclaration *fd) |
| { |
| FuncDeclaration *f = fd->toAliasFunc(); |
| FuncAliasDeclaration *fa = f->isFuncAliasDeclaration(); |
| if (!fd->hasOverloads && !fa) |
| { |
| mangleExact(f); |
| return; |
| } |
| if (fa) |
| { |
| mangleSymbol(fa); |
| return; |
| } |
| visit((Dsymbol *)fd); |
| } |
| |
| void visit(OverDeclaration *od) |
| { |
| if (od->overnext) |
| { |
| visit((Dsymbol *)od); |
| return; |
| } |
| |
| if (FuncDeclaration *fd = od->aliassym->isFuncDeclaration()) |
| { |
| if (!od->hasOverloads || fd->isUnique()) |
| { |
| mangleExact(fd); |
| return; |
| } |
| } |
| if (TemplateDeclaration *td = od->aliassym->isTemplateDeclaration()) |
| { |
| if (!od->hasOverloads || td->overnext == NULL) |
| { |
| mangleSymbol(td); |
| return; |
| } |
| } |
| visit((Dsymbol *)od); |
| } |
| |
| void mangleExact(FuncDeclaration *fd) |
| { |
| assert(!fd->isFuncAliasDeclaration()); |
| |
| if (fd->mangleOverride.length) |
| { |
| buf->writestring(fd->mangleOverride.ptr); |
| return; |
| } |
| |
| if (fd->isMain()) |
| { |
| buf->writestring("_Dmain"); |
| return; |
| } |
| |
| if (fd->isWinMain() || fd->isDllMain() || fd->ident == Id::tls_get_addr) |
| { |
| buf->writestring(fd->ident->toChars()); |
| return; |
| } |
| |
| visit((Declaration *)fd); |
| } |
| |
| void visit(VarDeclaration *vd) |
| { |
| if (vd->mangleOverride.length) |
| { |
| buf->writestring(vd->mangleOverride.ptr); |
| return; |
| } |
| |
| visit((Declaration *)vd); |
| } |
| |
| void visit(AggregateDeclaration *ad) |
| { |
| ClassDeclaration *cd = ad->isClassDeclaration(); |
| Dsymbol *parentsave = ad->parent; |
| if (cd) |
| { |
| /* These are reserved to the compiler, so keep simple |
| * names for them. |
| */ |
| if ((cd->ident == Id::Exception && cd->parent->ident == Id::object) || |
| cd->ident == Id::TypeInfo || |
| cd->ident == Id::TypeInfo_Struct || |
| cd->ident == Id::TypeInfo_Class || |
| cd->ident == Id::TypeInfo_Tuple || |
| cd == ClassDeclaration::object || |
| cd == Type::typeinfoclass || |
| cd == Module::moduleinfo || |
| strncmp(cd->ident->toChars(), "TypeInfo_", 9) == 0) |
| { |
| // Don't mangle parent |
| ad->parent = NULL; |
| } |
| } |
| |
| visit((Dsymbol *)ad); |
| |
| ad->parent = parentsave; |
| } |
| |
| void visit(TemplateInstance *ti) |
| { |
| if (!ti->tempdecl) |
| ti->error("is not defined"); |
| else |
| mangleParent(ti); |
| |
| if (ti->isTemplateMixin() && ti->ident) |
| mangleIdentifier(ti->ident, ti); |
| else |
| mangleTemplateInstance(ti); |
| } |
| |
| void mangleTemplateInstance(TemplateInstance *ti) |
| { |
| TemplateDeclaration *tempdecl = ti->tempdecl->isTemplateDeclaration(); |
| assert(tempdecl); |
| |
| // Use "__U" for the symbols declared inside template constraint. |
| const char T = ti->members ? 'T' : 'U'; |
| buf->printf("__%c", T); |
| mangleIdentifier(tempdecl->ident, tempdecl); |
| |
| Objects *args = ti->tiargs; |
| size_t nparams = tempdecl->parameters->length - (tempdecl->isVariadic() ? 1 : 0); |
| for (size_t i = 0; i < args->length; i++) |
| { |
| RootObject *o = (*args)[i]; |
| Type *ta = isType(o); |
| Expression *ea = isExpression(o); |
| Dsymbol *sa = isDsymbol(o); |
| Tuple *va = isTuple(o); |
| //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); |
| if (i < nparams && (*tempdecl->parameters)[i]->specialization()) |
| buf->writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574 |
| if (ta) |
| { |
| buf->writeByte('T'); |
| visitWithMask(ta, 0); |
| } |
| else if (ea) |
| { |
| // Don't interpret it yet, it might actually be an alias template parameter. |
| // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339. |
| const bool keepLvalue = true; |
| ea = ea->optimize(WANTvalue, keepLvalue); |
| if (ea->op == TOKvar) |
| { |
| sa = ((VarExp *)ea)->var; |
| ea = NULL; |
| goto Lsa; |
| } |
| if (ea->op == TOKthis) |
| { |
| sa = ((ThisExp *)ea)->var; |
| ea = NULL; |
| goto Lsa; |
| } |
| if (ea->op == TOKfunction) |
| { |
| if (((FuncExp *)ea)->td) |
| sa = ((FuncExp *)ea)->td; |
| else |
| sa = ((FuncExp *)ea)->fd; |
| ea = NULL; |
| goto Lsa; |
| } |
| buf->writeByte('V'); |
| if (ea->op == TOKtuple) |
| { |
| ea->error("tuple is not a valid template value argument"); |
| continue; |
| } |
| // Now that we know it is not an alias, we MUST obtain a value |
| unsigned olderr = global.errors; |
| ea = ea->ctfeInterpret(); |
| if (ea->op == TOKerror || olderr != global.errors) |
| continue; |
| |
| /* Use type mangling that matches what it would be for a function parameter |
| */ |
| visitWithMask(ea->type, 0); |
| ea->accept(this); |
| } |
| else if (sa) |
| { |
| Lsa: |
| sa = sa->toAlias(); |
| if (Declaration *d = sa->isDeclaration()) |
| { |
| if (FuncAliasDeclaration *fad = d->isFuncAliasDeclaration()) |
| d = fad->toAliasFunc(); |
| if (d->mangleOverride.length) |
| { |
| buf->writeByte('X'); |
| toBuffer(d->mangleOverride.ptr, d); |
| continue; |
| } |
| if (const char *id = externallyMangledIdentifier(d)) |
| { |
| buf->writeByte('X'); |
| toBuffer(id, d); |
| continue; |
| } |
| if (!d->type || !d->type->deco) |
| { |
| ti->error("forward reference of %s %s", d->kind(), d->toChars()); |
| continue; |
| } |
| } |
| buf->writeByte('S'); |
| mangleSymbol(sa); |
| } |
| else if (va) |
| { |
| assert(i + 1 == args->length); // must be last one |
| args = &va->objects; |
| i = -(size_t)1; |
| } |
| else |
| assert(0); |
| } |
| buf->writeByte('Z'); |
| } |
| |
| void visit(Dsymbol *s) |
| { |
| mangleParent(s); |
| if (s->ident) |
| mangleIdentifier(s->ident, s); |
| else |
| toBuffer(s->toChars(), s); |
| //printf("Dsymbol::mangle() %s = %s\n", s->toChars(), id); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| |
| void visit(Expression *e) |
| { |
| e->error("expression %s is not a valid template value argument", e->toChars()); |
| } |
| |
| void visit(IntegerExp *e) |
| { |
| if ((sinteger_t)e->value < 0) |
| { |
| buf->writeByte('N'); |
| buf->print(-e->value); |
| } |
| else |
| { |
| buf->writeByte('i'); |
| buf->print(e->value); |
| } |
| } |
| |
| void visit(RealExp *e) |
| { |
| buf->writeByte('e'); |
| realToMangleBuffer(e->value); |
| } |
| |
| void realToMangleBuffer(real_t value) |
| { |
| /* Rely on %A to get portable mangling. |
| * Must munge result to get only identifier characters. |
| * |
| * Possible values from %A => mangled result |
| * NAN => NAN |
| * -INF => NINF |
| * INF => INF |
| * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 |
| * 0X1.9P+2 => 19P2 |
| */ |
| |
| if (CTFloat::isNaN(value)) |
| buf->writestring("NAN"); // no -NAN bugs |
| else if (CTFloat::isInfinity(value)) |
| buf->writestring(value < CTFloat::zero ? "NINF" : "INF"); |
| else |
| { |
| const size_t BUFFER_LEN = 36; |
| char buffer[BUFFER_LEN]; |
| size_t n = CTFloat::sprint(buffer, 'A', value); |
| assert(n < BUFFER_LEN); |
| for (size_t i = 0; i < n; i++) |
| { |
| char c = buffer[i]; |
| switch (c) |
| { |
| case '-': |
| buf->writeByte('N'); |
| break; |
| |
| case '+': |
| case 'X': |
| case '.': |
| break; |
| |
| case '0': |
| if (i < 2) |
| break; // skip leading 0X |
| /* fall through */ |
| default: |
| buf->writeByte(c); |
| break; |
| } |
| } |
| } |
| } |
| |
| void visit(ComplexExp *e) |
| { |
| buf->writeByte('c'); |
| realToMangleBuffer(e->toReal()); |
| buf->writeByte('c'); // separate the two |
| realToMangleBuffer(e->toImaginary()); |
| } |
| |
| void visit(NullExp *) |
| { |
| buf->writeByte('n'); |
| } |
| |
| void visit(StringExp *e) |
| { |
| char m; |
| OutBuffer tmp; |
| utf8_t *q; |
| size_t qlen; |
| |
| /* Write string in UTF-8 format |
| */ |
| switch (e->sz) |
| { |
| case 1: |
| m = 'a'; |
| q = (utf8_t *)e->string; |
| qlen = e->len; |
| break; |
| |
| case 2: |
| m = 'w'; |
| for (size_t u = 0; u < e->len; ) |
| { |
| unsigned c; |
| const char *p = utf_decodeWchar((unsigned short *)e->string, e->len, &u, &c); |
| if (p) |
| e->error("%s", p); |
| else |
| tmp.writeUTF8(c); |
| } |
| q = (utf8_t *)tmp.slice().ptr; |
| qlen = tmp.length(); |
| break; |
| |
| case 4: |
| m = 'd'; |
| for (size_t u = 0; u < e->len; u++) |
| { |
| unsigned c = ((unsigned *)e->string)[u]; |
| if (!utf_isValidDchar(c)) |
| e->error("invalid UCS-32 char \\U%08x", c); |
| else |
| tmp.writeUTF8(c); |
| } |
| q = (utf8_t *)tmp.slice().ptr; |
| qlen = tmp.length(); |
| break; |
| |
| default: |
| assert(0); |
| } |
| buf->reserve(1 + 11 + 2 * qlen); |
| buf->writeByte(m); |
| buf->print(qlen); |
| buf->writeByte('_'); // nbytes <= 11 |
| |
| for (utf8_t *p = (utf8_t *)buf->slice().ptr + buf->length(), *pend = p + 2 * qlen; |
| p < pend; p += 2, ++q) |
| { |
| utf8_t hi = *q >> 4 & 0xF; |
| p[0] = (utf8_t)(hi < 10 ? hi + '0' : hi - 10 + 'a'); |
| utf8_t lo = *q & 0xF; |
| p[1] = (utf8_t)(lo < 10 ? lo + '0' : lo - 10 + 'a'); |
| } |
| buf->setsize(buf->length() + 2 * qlen); |
| } |
| |
| void visit(ArrayLiteralExp *e) |
| { |
| size_t dim = e->elements ? e->elements->length : 0; |
| buf->writeByte('A'); |
| buf->print(dim); |
| for (size_t i = 0; i < dim; i++) |
| { |
| e->getElement(i)->accept(this); |
| } |
| } |
| |
| void visit(AssocArrayLiteralExp *e) |
| { |
| size_t dim = e->keys->length; |
| buf->writeByte('A'); |
| buf->print(dim); |
| for (size_t i = 0; i < dim; i++) |
| { |
| (*e->keys)[i]->accept(this); |
| (*e->values)[i]->accept(this); |
| } |
| } |
| |
| void visit(StructLiteralExp *e) |
| { |
| size_t dim = e->elements ? e->elements->length : 0; |
| buf->writeByte('S'); |
| buf->print(dim); |
| for (size_t i = 0; i < dim; i++) |
| { |
| Expression *ex = (*e->elements)[i]; |
| if (ex) |
| ex->accept(this); |
| else |
| buf->writeByte('v'); // 'v' for void |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| |
| void paramsToDecoBuffer(Parameters *parameters) |
| { |
| //printf("Parameter::paramsToDecoBuffer()\n"); |
| Parameter_foreach(parameters, ¶msToDecoBufferDg, (void *)this); |
| } |
| |
| static int paramsToDecoBufferDg(void *ctx, size_t, Parameter *p) |
| { |
| p->accept((Visitor *)ctx); |
| return 0; |
| } |
| |
| void visit(Parameter *p) |
| { |
| if (p->storageClass & STCscope && !(p->storageClass & STCscopeinferred)) |
| buf->writeByte('M'); |
| // 'return inout ref' is the same as 'inout ref' |
| if ((p->storageClass & (STCreturn | STCwild)) == STCreturn) |
| buf->writestring("Nk"); |
| switch (p->storageClass & (STCin | STCout | STCref | STClazy)) |
| { |
| case 0: |
| case STCin: |
| break; |
| case STCout: |
| buf->writeByte('J'); |
| break; |
| case STCref: |
| buf->writeByte('K'); |
| break; |
| case STClazy: |
| buf->writeByte('L'); |
| break; |
| default: |
| assert(0); |
| } |
| visitWithMask(p->type, 0); |
| } |
| }; |
| |
| /****************************************************************************** |
| * Returns exact mangled name of function. |
| */ |
| const char *mangleExact(FuncDeclaration *fd) |
| { |
| if (!fd->mangleString) |
| { |
| OutBuffer buf; |
| Mangler v(&buf); |
| v.mangleExact(fd); |
| fd->mangleString = buf.extractChars(); |
| } |
| return fd->mangleString; |
| } |
| |
| void mangleToBuffer(Type *t, OutBuffer *buf) |
| { |
| Mangler v(buf); |
| v.visitWithMask(t, 0); |
| } |
| |
| void mangleToBuffer(Expression *e, OutBuffer *buf) |
| { |
| Mangler v(buf); |
| e->accept(&v); |
| } |
| |
| void mangleToBuffer(Dsymbol *s, OutBuffer *buf) |
| { |
| Mangler v(buf); |
| s->accept(&v); |
| } |
| |
| void mangleToBuffer(TemplateInstance *ti, OutBuffer *buf) |
| { |
| Mangler v(buf); |
| v.mangleTemplateInstance(ti); |
| } |
| |
| /********************************************** |
| * Convert a string representing a type (the deco) and |
| * return its equivalent Type. |
| * Params: |
| * deco = string containing the deco |
| * Returns: |
| * null for failed to convert |
| * Type for succeeded |
| */ |
| |
| Type *decoToType(const char *deco) |
| { |
| if (!deco) |
| return NULL; |
| |
| //printf("decoToType(): %s\n", deco) |
| if (StringValue *sv = Type::stringtable.lookup(deco, strlen(deco))) |
| { |
| if (sv->ptrvalue) |
| { |
| Type *t = (Type *)sv->ptrvalue; |
| assert(t->deco); |
| return t; |
| } |
| } |
| return NULL; |
| } |