mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-06 19:06:02 +03:00

VS has different name manglings for classes and structs. With the new extern(C++, class) and extern(C++, struct) declarations, the name mangling algorithm is changed to use a mangling different from the used D entity. A common use case is to map a value type modeled as class in C++ to a struct in D. This is backport of https://github.com/dlang/dmd/pull/5875.
3266 lines
84 KiB
D
3266 lines
84 KiB
D
// Compiler implementation of the D programming language
|
|
// Copyright (c) 1999-2015 by Digital Mars
|
|
// 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
|
|
|
|
module ddmd.hdrgen;
|
|
|
|
import core.stdc.ctype;
|
|
import core.stdc.stdio;
|
|
import core.stdc.string;
|
|
import ddmd.aggregate;
|
|
import ddmd.aliasthis;
|
|
import ddmd.arraytypes;
|
|
import ddmd.attrib;
|
|
import ddmd.complex;
|
|
import ddmd.cond;
|
|
import ddmd.ctfeexpr;
|
|
import ddmd.dclass;
|
|
import ddmd.declaration;
|
|
import ddmd.denum;
|
|
import ddmd.dimport;
|
|
import ddmd.dmodule;
|
|
import ddmd.doc;
|
|
import ddmd.dscope;
|
|
import ddmd.dstruct;
|
|
import ddmd.dsymbol;
|
|
import ddmd.dtemplate;
|
|
import ddmd.dversion;
|
|
import ddmd.expression;
|
|
import ddmd.func;
|
|
import ddmd.globals;
|
|
import ddmd.id;
|
|
import ddmd.identifier;
|
|
import ddmd.init;
|
|
import ddmd.mars;
|
|
import ddmd.mtype;
|
|
import ddmd.nspace;
|
|
import ddmd.parse;
|
|
import ddmd.root.longdouble;
|
|
import ddmd.root.outbuffer;
|
|
import ddmd.root.port;
|
|
import ddmd.root.rootobject;
|
|
import ddmd.statement;
|
|
import ddmd.staticassert;
|
|
import ddmd.target;
|
|
import ddmd.tokens;
|
|
import ddmd.visitor;
|
|
|
|
struct HdrGenState
|
|
{
|
|
bool hdrgen; // true if generating header file
|
|
bool ddoc; // true if generating Ddoc file
|
|
bool fullQual; // fully qualify types when printing
|
|
int tpltMember;
|
|
int autoMember;
|
|
int forStmtInit;
|
|
}
|
|
|
|
enum TEST_EMIT_ALL = 0;
|
|
|
|
extern (C++) void genhdrfile(Module m)
|
|
{
|
|
OutBuffer buf;
|
|
buf.doindent = 1;
|
|
buf.printf("// D import file generated from '%s'", m.srcfile.toChars());
|
|
buf.writenl();
|
|
HdrGenState hgs;
|
|
hgs.hdrgen = true;
|
|
toCBuffer(m, &buf, &hgs);
|
|
// Transfer image to file
|
|
m.hdrfile.setbuffer(buf.data, buf.offset);
|
|
buf.extractData();
|
|
ensurePathToNameExists(Loc(), m.hdrfile.toChars());
|
|
writeFile(m.loc, m.hdrfile);
|
|
}
|
|
|
|
extern (C++) final class PrettyPrintVisitor : Visitor
|
|
{
|
|
alias visit = super.visit;
|
|
public:
|
|
OutBuffer* buf;
|
|
HdrGenState* hgs;
|
|
bool declstring; // set while declaring alias for string,wstring or dstring
|
|
|
|
extern (D) this(OutBuffer* buf, HdrGenState* hgs)
|
|
{
|
|
this.buf = buf;
|
|
this.hgs = hgs;
|
|
}
|
|
|
|
override void visit(Statement s)
|
|
{
|
|
buf.printf("Statement::toCBuffer()");
|
|
buf.writenl();
|
|
assert(0);
|
|
}
|
|
|
|
override void visit(ErrorStatement s)
|
|
{
|
|
buf.printf("__error__");
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(ExpStatement s)
|
|
{
|
|
if (s.exp && s.exp.op == TOKdeclaration)
|
|
{
|
|
// bypass visit(DeclarationExp)
|
|
(cast(DeclarationExp)s.exp).declaration.accept(this);
|
|
return;
|
|
}
|
|
if (s.exp)
|
|
s.exp.accept(this);
|
|
buf.writeByte(';');
|
|
if (!hgs.forStmtInit)
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(CompileStatement s)
|
|
{
|
|
buf.writestring("mixin(");
|
|
s.exp.accept(this);
|
|
buf.writestring(");");
|
|
if (!hgs.forStmtInit)
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(CompoundStatement s)
|
|
{
|
|
foreach (sx; *s.statements)
|
|
{
|
|
if (sx)
|
|
sx.accept(this);
|
|
}
|
|
}
|
|
|
|
override void visit(CompoundDeclarationStatement s)
|
|
{
|
|
bool anywritten = false;
|
|
foreach (sx; *s.statements)
|
|
{
|
|
auto ds = sx ? sx.isExpStatement() : null;
|
|
if (ds && ds.exp.op == TOKdeclaration)
|
|
{
|
|
auto d = (cast(DeclarationExp)ds.exp).declaration;
|
|
assert(d.isDeclaration());
|
|
if (auto v = d.isVarDeclaration())
|
|
visitVarDecl(v, anywritten);
|
|
else
|
|
d.accept(this);
|
|
anywritten = true;
|
|
}
|
|
}
|
|
buf.writeByte(';');
|
|
if (!hgs.forStmtInit)
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(UnrolledLoopStatement s)
|
|
{
|
|
buf.writestring("unrolled {");
|
|
buf.writenl();
|
|
buf.level++;
|
|
foreach (sx; *s.statements)
|
|
{
|
|
if (sx)
|
|
sx.accept(this);
|
|
}
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(ScopeStatement s)
|
|
{
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
if (s.statement)
|
|
s.statement.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(WhileStatement s)
|
|
{
|
|
buf.writestring("while (");
|
|
s.condition.accept(this);
|
|
buf.writeByte(')');
|
|
buf.writenl();
|
|
if (s._body)
|
|
s._body.accept(this);
|
|
}
|
|
|
|
override void visit(DoStatement s)
|
|
{
|
|
buf.writestring("do");
|
|
buf.writenl();
|
|
if (s._body)
|
|
s._body.accept(this);
|
|
buf.writestring("while (");
|
|
s.condition.accept(this);
|
|
buf.writestring(");");
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(ForStatement s)
|
|
{
|
|
buf.writestring("for (");
|
|
if (s._init)
|
|
{
|
|
hgs.forStmtInit++;
|
|
s._init.accept(this);
|
|
hgs.forStmtInit--;
|
|
}
|
|
else
|
|
buf.writeByte(';');
|
|
if (s.condition)
|
|
{
|
|
buf.writeByte(' ');
|
|
s.condition.accept(this);
|
|
}
|
|
buf.writeByte(';');
|
|
if (s.increment)
|
|
{
|
|
buf.writeByte(' ');
|
|
s.increment.accept(this);
|
|
}
|
|
buf.writeByte(')');
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
s._body.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(ForeachStatement s)
|
|
{
|
|
buf.writestring(Token.toChars(s.op));
|
|
buf.writestring(" (");
|
|
foreach (i, p; *s.parameters)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
if (stcToBuffer(buf, p.storageClass))
|
|
buf.writeByte(' ');
|
|
if (p.type)
|
|
typeToBuffer(p.type, p.ident);
|
|
else
|
|
buf.writestring(p.ident.toChars());
|
|
}
|
|
buf.writestring("; ");
|
|
s.aggr.accept(this);
|
|
buf.writeByte(')');
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
if (s._body)
|
|
s._body.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(ForeachRangeStatement s)
|
|
{
|
|
buf.writestring(Token.toChars(s.op));
|
|
buf.writestring(" (");
|
|
if (s.prm.type)
|
|
typeToBuffer(s.prm.type, s.prm.ident);
|
|
else
|
|
buf.writestring(s.prm.ident.toChars());
|
|
buf.writestring("; ");
|
|
s.lwr.accept(this);
|
|
buf.writestring(" .. ");
|
|
s.upr.accept(this);
|
|
buf.writeByte(')');
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
if (s._body)
|
|
s._body.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(IfStatement s)
|
|
{
|
|
buf.writestring("if (");
|
|
if (Parameter p = s.prm)
|
|
{
|
|
StorageClass stc = p.storageClass;
|
|
if (!p.type && !stc)
|
|
stc = STCauto;
|
|
if (stcToBuffer(buf, stc))
|
|
buf.writeByte(' ');
|
|
if (p.type)
|
|
typeToBuffer(p.type, p.ident);
|
|
else
|
|
buf.writestring(p.ident.toChars());
|
|
buf.writestring(" = ");
|
|
}
|
|
s.condition.accept(this);
|
|
buf.writeByte(')');
|
|
buf.writenl();
|
|
if (!s.ifbody.isScopeStatement())
|
|
buf.level++;
|
|
s.ifbody.accept(this);
|
|
if (!s.ifbody.isScopeStatement())
|
|
buf.level--;
|
|
if (s.elsebody)
|
|
{
|
|
buf.writestring("else");
|
|
buf.writenl();
|
|
if (!s.elsebody.isScopeStatement())
|
|
buf.level++;
|
|
s.elsebody.accept(this);
|
|
if (!s.elsebody.isScopeStatement())
|
|
buf.level--;
|
|
}
|
|
}
|
|
|
|
override void visit(ConditionalStatement s)
|
|
{
|
|
s.condition.accept(this);
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
if (s.ifbody)
|
|
s.ifbody.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
if (s.elsebody)
|
|
{
|
|
buf.writestring("else");
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.level++;
|
|
buf.writenl();
|
|
s.elsebody.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
}
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(PragmaStatement s)
|
|
{
|
|
buf.writestring("pragma (");
|
|
buf.writestring(s.ident.toChars());
|
|
if (s.args && s.args.dim)
|
|
{
|
|
buf.writestring(", ");
|
|
argsToBuffer(s.args);
|
|
}
|
|
buf.writeByte(')');
|
|
if (s._body)
|
|
{
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
s._body.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
else
|
|
{
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
}
|
|
|
|
override void visit(StaticAssertStatement s)
|
|
{
|
|
s.sa.accept(this);
|
|
}
|
|
|
|
override void visit(SwitchStatement s)
|
|
{
|
|
buf.writestring(s.isFinal ? "final switch (" : "switch (");
|
|
s.condition.accept(this);
|
|
buf.writeByte(')');
|
|
buf.writenl();
|
|
if (s._body)
|
|
{
|
|
if (!s._body.isScopeStatement())
|
|
{
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
s._body.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
else
|
|
{
|
|
s._body.accept(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
override void visit(CaseStatement s)
|
|
{
|
|
buf.writestring("case ");
|
|
s.exp.accept(this);
|
|
buf.writeByte(':');
|
|
buf.writenl();
|
|
s.statement.accept(this);
|
|
}
|
|
|
|
override void visit(CaseRangeStatement s)
|
|
{
|
|
buf.writestring("case ");
|
|
s.first.accept(this);
|
|
buf.writestring(": .. case ");
|
|
s.last.accept(this);
|
|
buf.writeByte(':');
|
|
buf.writenl();
|
|
s.statement.accept(this);
|
|
}
|
|
|
|
override void visit(DefaultStatement s)
|
|
{
|
|
buf.writestring("default:");
|
|
buf.writenl();
|
|
s.statement.accept(this);
|
|
}
|
|
|
|
override void visit(GotoDefaultStatement s)
|
|
{
|
|
buf.writestring("goto default;");
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(GotoCaseStatement s)
|
|
{
|
|
buf.writestring("goto case");
|
|
if (s.exp)
|
|
{
|
|
buf.writeByte(' ');
|
|
s.exp.accept(this);
|
|
}
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(SwitchErrorStatement s)
|
|
{
|
|
buf.writestring("SwitchErrorStatement::toCBuffer()");
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(ReturnStatement s)
|
|
{
|
|
buf.printf("return ");
|
|
if (s.exp)
|
|
s.exp.accept(this);
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(BreakStatement s)
|
|
{
|
|
buf.writestring("break");
|
|
if (s.ident)
|
|
{
|
|
buf.writeByte(' ');
|
|
buf.writestring(s.ident.toChars());
|
|
}
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(ContinueStatement s)
|
|
{
|
|
buf.writestring("continue");
|
|
if (s.ident)
|
|
{
|
|
buf.writeByte(' ');
|
|
buf.writestring(s.ident.toChars());
|
|
}
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(SynchronizedStatement s)
|
|
{
|
|
buf.writestring("synchronized");
|
|
if (s.exp)
|
|
{
|
|
buf.writeByte('(');
|
|
s.exp.accept(this);
|
|
buf.writeByte(')');
|
|
}
|
|
if (s._body)
|
|
{
|
|
buf.writeByte(' ');
|
|
s._body.accept(this);
|
|
}
|
|
}
|
|
|
|
override void visit(WithStatement s)
|
|
{
|
|
buf.writestring("with (");
|
|
s.exp.accept(this);
|
|
buf.writestring(")");
|
|
buf.writenl();
|
|
if (s._body)
|
|
s._body.accept(this);
|
|
}
|
|
|
|
override void visit(TryCatchStatement s)
|
|
{
|
|
buf.writestring("try");
|
|
buf.writenl();
|
|
if (s._body)
|
|
s._body.accept(this);
|
|
foreach (c; *s.catches)
|
|
{
|
|
visit(c);
|
|
}
|
|
}
|
|
|
|
override void visit(TryFinallyStatement s)
|
|
{
|
|
buf.writestring("try");
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
s._body.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
buf.writestring("finally");
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
s.finalbody.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(OnScopeStatement s)
|
|
{
|
|
buf.writestring(Token.toChars(s.tok));
|
|
buf.writeByte(' ');
|
|
s.statement.accept(this);
|
|
}
|
|
|
|
override void visit(ThrowStatement s)
|
|
{
|
|
buf.printf("throw ");
|
|
s.exp.accept(this);
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(DebugStatement s)
|
|
{
|
|
if (s.statement)
|
|
{
|
|
s.statement.accept(this);
|
|
}
|
|
}
|
|
|
|
override void visit(GotoStatement s)
|
|
{
|
|
buf.writestring("goto ");
|
|
buf.writestring(s.ident.toChars());
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(LabelStatement s)
|
|
{
|
|
buf.writestring(s.ident.toChars());
|
|
buf.writeByte(':');
|
|
buf.writenl();
|
|
if (s.statement)
|
|
s.statement.accept(this);
|
|
}
|
|
|
|
override void visit(AsmStatement s)
|
|
{
|
|
buf.writestring("asm { ");
|
|
Token* t = s.tokens;
|
|
buf.level++;
|
|
while (t)
|
|
{
|
|
buf.writestring(t.toChars());
|
|
if (t.next &&
|
|
t.value != TOKmin &&
|
|
t.value != TOKcomma && t.next.value != TOKcomma &&
|
|
t.value != TOKlbracket && t.next.value != TOKlbracket &&
|
|
t.next.value != TOKrbracket &&
|
|
t.value != TOKlparen && t.next.value != TOKlparen &&
|
|
t.next.value != TOKrparen &&
|
|
t.value != TOKdot && t.next.value != TOKdot)
|
|
{
|
|
buf.writeByte(' ');
|
|
}
|
|
t = t.next;
|
|
}
|
|
buf.level--;
|
|
buf.writestring("; }");
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(ImportStatement s)
|
|
{
|
|
foreach (imp; *s.imports)
|
|
{
|
|
imp.accept(this);
|
|
}
|
|
}
|
|
|
|
void visit(Catch c)
|
|
{
|
|
buf.writestring("catch");
|
|
if (c.type)
|
|
{
|
|
buf.writeByte('(');
|
|
typeToBuffer(c.type, c.ident);
|
|
buf.writeByte(')');
|
|
}
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
if (c.handler)
|
|
c.handler.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
/**************************************************
|
|
* An entry point to pretty-print type.
|
|
*/
|
|
void typeToBuffer(Type t, Identifier ident)
|
|
{
|
|
if (t.ty == Tfunction)
|
|
{
|
|
visitFuncIdentWithPrefix(cast(TypeFunction)t, ident, null, true);
|
|
return;
|
|
}
|
|
visitWithMask(t, 0);
|
|
if (ident)
|
|
{
|
|
buf.writeByte(' ');
|
|
buf.writestring(ident.toChars());
|
|
}
|
|
}
|
|
|
|
void visitWithMask(Type t, ubyte modMask)
|
|
{
|
|
// Tuples and functions don't use the type constructor syntax
|
|
if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple)
|
|
{
|
|
t.accept(this);
|
|
}
|
|
else
|
|
{
|
|
ubyte m = t.mod & ~(t.mod & modMask);
|
|
if (m & MODshared)
|
|
{
|
|
MODtoBuffer(buf, MODshared);
|
|
buf.writeByte('(');
|
|
}
|
|
if (m & MODwild)
|
|
{
|
|
MODtoBuffer(buf, MODwild);
|
|
buf.writeByte('(');
|
|
}
|
|
if (m & (MODconst | MODimmutable))
|
|
{
|
|
MODtoBuffer(buf, m & (MODconst | MODimmutable));
|
|
buf.writeByte('(');
|
|
}
|
|
t.accept(this);
|
|
if (m & (MODconst | MODimmutable))
|
|
buf.writeByte(')');
|
|
if (m & MODwild)
|
|
buf.writeByte(')');
|
|
if (m & MODshared)
|
|
buf.writeByte(')');
|
|
}
|
|
}
|
|
|
|
override void visit(Type t)
|
|
{
|
|
printf("t = %p, ty = %d\n", t, t.ty);
|
|
assert(0);
|
|
}
|
|
|
|
override void visit(TypeError t)
|
|
{
|
|
buf.writestring("_error_");
|
|
}
|
|
|
|
override void visit(TypeBasic t)
|
|
{
|
|
//printf("TypeBasic::toCBuffer2(t->mod = %d)\n", t->mod);
|
|
buf.writestring(t.dstring);
|
|
}
|
|
|
|
override void visit(TypeVector t)
|
|
{
|
|
//printf("TypeVector::toCBuffer2(t->mod = %d)\n", t->mod);
|
|
buf.writestring("__vector(");
|
|
visitWithMask(t.basetype, t.mod);
|
|
buf.writestring(")");
|
|
}
|
|
|
|
override void visit(TypeSArray t)
|
|
{
|
|
visitWithMask(t.next, t.mod);
|
|
buf.writeByte('[');
|
|
sizeToBuffer(t.dim);
|
|
buf.writeByte(']');
|
|
}
|
|
|
|
override void visit(TypeDArray t)
|
|
{
|
|
Type ut = t.castMod(0);
|
|
if (declstring)
|
|
goto L1;
|
|
if (ut.equals(Type.tstring))
|
|
buf.writestring("string");
|
|
else if (ut.equals(Type.twstring))
|
|
buf.writestring("wstring");
|
|
else if (ut.equals(Type.tdstring))
|
|
buf.writestring("dstring");
|
|
else
|
|
{
|
|
L1:
|
|
visitWithMask(t.next, t.mod);
|
|
buf.writestring("[]");
|
|
}
|
|
}
|
|
|
|
override void visit(TypeAArray t)
|
|
{
|
|
visitWithMask(t.next, t.mod);
|
|
buf.writeByte('[');
|
|
visitWithMask(t.index, 0);
|
|
buf.writeByte(']');
|
|
}
|
|
|
|
override void visit(TypePointer t)
|
|
{
|
|
//printf("TypePointer::toCBuffer2() next = %d\n", t->next->ty);
|
|
if (t.next.ty == Tfunction)
|
|
visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "function");
|
|
else
|
|
{
|
|
visitWithMask(t.next, t.mod);
|
|
buf.writeByte('*');
|
|
}
|
|
}
|
|
|
|
override void visit(TypeReference t)
|
|
{
|
|
visitWithMask(t.next, t.mod);
|
|
buf.writeByte('&');
|
|
}
|
|
|
|
override void visit(TypeFunction t)
|
|
{
|
|
//printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t->isref);
|
|
visitFuncIdentWithPostfix(t, null);
|
|
}
|
|
|
|
// callback for TypeFunction::attributesApply
|
|
struct PrePostAppendStrings
|
|
{
|
|
OutBuffer* buf;
|
|
bool isPostfixStyle;
|
|
bool isCtor;
|
|
|
|
extern (C++) static int fp(void* param, const(char)* str)
|
|
{
|
|
PrePostAppendStrings* p = cast(PrePostAppendStrings*)param;
|
|
// don't write 'ref' for ctors
|
|
if (p.isCtor && strcmp(str, "ref") == 0)
|
|
return 0;
|
|
if (p.isPostfixStyle)
|
|
p.buf.writeByte(' ');
|
|
p.buf.writestring(str);
|
|
if (!p.isPostfixStyle)
|
|
p.buf.writeByte(' ');
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void visitFuncIdentWithPostfix(TypeFunction t, const(char)* ident)
|
|
{
|
|
if (t.inuse)
|
|
{
|
|
t.inuse = 2; // flag error to caller
|
|
return;
|
|
}
|
|
t.inuse++;
|
|
PrePostAppendStrings pas;
|
|
pas.buf = buf;
|
|
pas.isCtor = false;
|
|
pas.isPostfixStyle = true;
|
|
if (t.linkage > LINKd && hgs.ddoc != 1 && !hgs.hdrgen)
|
|
{
|
|
linkageToBuffer(buf, t.linkage);
|
|
buf.writeByte(' ');
|
|
}
|
|
if (t.next)
|
|
{
|
|
typeToBuffer(t.next, null);
|
|
if (ident)
|
|
buf.writeByte(' ');
|
|
}
|
|
else if (hgs.ddoc)
|
|
buf.writestring("auto ");
|
|
if (ident)
|
|
buf.writestring(ident);
|
|
parametersToBuffer(t.parameters, t.varargs);
|
|
/* Use postfix style for attributes
|
|
*/
|
|
if (t.mod)
|
|
{
|
|
buf.writeByte(' ');
|
|
MODtoBuffer(buf, t.mod);
|
|
}
|
|
t.attributesApply(&pas, &PrePostAppendStrings.fp);
|
|
t.inuse--;
|
|
}
|
|
|
|
void visitFuncIdentWithPrefix(TypeFunction t, Identifier ident, TemplateDeclaration td, bool isPostfixStyle)
|
|
{
|
|
if (t.inuse)
|
|
{
|
|
t.inuse = 2; // flag error to caller
|
|
return;
|
|
}
|
|
t.inuse++;
|
|
PrePostAppendStrings pas;
|
|
pas.buf = buf;
|
|
pas.isCtor = (ident == Id.ctor);
|
|
pas.isPostfixStyle = false;
|
|
/* Use 'storage class' (prefix) style for attributes
|
|
*/
|
|
if (t.mod)
|
|
{
|
|
MODtoBuffer(buf, t.mod);
|
|
buf.writeByte(' ');
|
|
}
|
|
t.attributesApply(&pas, &PrePostAppendStrings.fp);
|
|
if (t.linkage > LINKd && hgs.ddoc != 1 && !hgs.hdrgen)
|
|
{
|
|
linkageToBuffer(buf, t.linkage);
|
|
buf.writeByte(' ');
|
|
}
|
|
if (ident && ident.toHChars2() != ident.toChars())
|
|
{
|
|
// Don't print return type for ctor, dtor, unittest, etc
|
|
}
|
|
else if (t.next)
|
|
{
|
|
typeToBuffer(t.next, null);
|
|
if (ident)
|
|
buf.writeByte(' ');
|
|
}
|
|
else if (hgs.ddoc)
|
|
buf.writestring("auto ");
|
|
if (ident)
|
|
buf.writestring(ident.toHChars2());
|
|
if (td)
|
|
{
|
|
buf.writeByte('(');
|
|
foreach (i, p; *td.origParameters)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
p.accept(this);
|
|
}
|
|
buf.writeByte(')');
|
|
}
|
|
parametersToBuffer(t.parameters, t.varargs);
|
|
t.inuse--;
|
|
}
|
|
|
|
override void visit(TypeDelegate t)
|
|
{
|
|
visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "delegate");
|
|
}
|
|
|
|
void visitTypeQualifiedHelper(TypeQualified t)
|
|
{
|
|
foreach (id; t.idents)
|
|
{
|
|
if (id.dyncast() == DYNCAST_DSYMBOL)
|
|
{
|
|
buf.writeByte('.');
|
|
TemplateInstance ti = cast(TemplateInstance)id;
|
|
ti.accept(this);
|
|
}
|
|
else if (id.dyncast() == DYNCAST_EXPRESSION)
|
|
{
|
|
buf.writeByte('[');
|
|
(cast(Expression)id).accept(this);
|
|
buf.writeByte(']');
|
|
}
|
|
else if (id.dyncast() == DYNCAST_TYPE)
|
|
{
|
|
buf.writeByte('[');
|
|
(cast(Type)id).accept(this);
|
|
buf.writeByte(']');
|
|
}
|
|
else
|
|
{
|
|
buf.writeByte('.');
|
|
buf.writestring(id.toChars());
|
|
}
|
|
}
|
|
}
|
|
|
|
override void visit(TypeIdentifier t)
|
|
{
|
|
buf.writestring(t.ident.toChars());
|
|
visitTypeQualifiedHelper(t);
|
|
}
|
|
|
|
override void visit(TypeInstance t)
|
|
{
|
|
t.tempinst.accept(this);
|
|
visitTypeQualifiedHelper(t);
|
|
}
|
|
|
|
override void visit(TypeTypeof t)
|
|
{
|
|
buf.writestring("typeof(");
|
|
t.exp.accept(this);
|
|
buf.writeByte(')');
|
|
visitTypeQualifiedHelper(t);
|
|
}
|
|
|
|
override void visit(TypeReturn t)
|
|
{
|
|
buf.writestring("typeof(return)");
|
|
visitTypeQualifiedHelper(t);
|
|
}
|
|
|
|
override void visit(TypeEnum t)
|
|
{
|
|
buf.writestring(t.sym.toChars());
|
|
}
|
|
|
|
override void visit(TypeStruct t)
|
|
{
|
|
// Bugzilla 13776: Don't use ti->toAlias() to avoid forward reference error
|
|
// while printing messages.
|
|
TemplateInstance ti = t.sym.parent.isTemplateInstance();
|
|
if (ti && ti.aliasdecl == t.sym)
|
|
buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars());
|
|
else
|
|
buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
|
|
}
|
|
|
|
override void visit(TypeClass t)
|
|
{
|
|
// Bugzilla 13776: Don't use ti->toAlias() to avoid forward reference error
|
|
// while printing messages.
|
|
TemplateInstance ti = t.sym.parent.isTemplateInstance();
|
|
if (ti && ti.aliasdecl == t.sym)
|
|
buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars());
|
|
else
|
|
buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
|
|
}
|
|
|
|
override void visit(TypeTuple t)
|
|
{
|
|
parametersToBuffer(t.arguments, 0);
|
|
}
|
|
|
|
override void visit(TypeSlice t)
|
|
{
|
|
visitWithMask(t.next, t.mod);
|
|
buf.writeByte('[');
|
|
sizeToBuffer(t.lwr);
|
|
buf.writestring(" .. ");
|
|
sizeToBuffer(t.upr);
|
|
buf.writeByte(']');
|
|
}
|
|
|
|
override void visit(TypeNull t)
|
|
{
|
|
buf.writestring("typeof(null)");
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
override void visit(Dsymbol s)
|
|
{
|
|
buf.writestring(s.toChars());
|
|
}
|
|
|
|
override void visit(StaticAssert s)
|
|
{
|
|
buf.writestring(s.kind());
|
|
buf.writeByte('(');
|
|
s.exp.accept(this);
|
|
if (s.msg)
|
|
{
|
|
buf.writestring(", ");
|
|
s.msg.accept(this);
|
|
}
|
|
buf.writestring(");");
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(DebugSymbol s)
|
|
{
|
|
buf.writestring("debug = ");
|
|
if (s.ident)
|
|
buf.writestring(s.ident.toChars());
|
|
else
|
|
buf.printf("%u", s.level);
|
|
buf.writestring(";");
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(VersionSymbol s)
|
|
{
|
|
buf.writestring("version = ");
|
|
if (s.ident)
|
|
buf.writestring(s.ident.toChars());
|
|
else
|
|
buf.printf("%u", s.level);
|
|
buf.writestring(";");
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(EnumMember em)
|
|
{
|
|
if (em.type)
|
|
typeToBuffer(em.type, em.ident);
|
|
else
|
|
buf.writestring(em.ident.toChars());
|
|
if (em.value)
|
|
{
|
|
buf.writestring(" = ");
|
|
em.value.accept(this);
|
|
}
|
|
}
|
|
|
|
override void visit(Import imp)
|
|
{
|
|
if (hgs.hdrgen && imp.id == Id.object)
|
|
return; // object is imported by default
|
|
if (imp.isstatic)
|
|
buf.writestring("static ");
|
|
buf.writestring("import ");
|
|
if (imp.aliasId)
|
|
{
|
|
buf.printf("%s = ", imp.aliasId.toChars());
|
|
}
|
|
if (imp.packages && imp.packages.dim)
|
|
{
|
|
foreach (const pid; *imp.packages)
|
|
{
|
|
buf.printf("%s.", pid.toChars());
|
|
}
|
|
}
|
|
buf.printf("%s", imp.id.toChars());
|
|
if (imp.names.dim)
|
|
{
|
|
buf.writestring(" : ");
|
|
foreach (const i, const name; imp.names)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
const _alias = imp.aliases[i];
|
|
if (_alias)
|
|
buf.printf("%s = %s", _alias.toChars(), name.toChars());
|
|
else
|
|
buf.printf("%s", name.toChars());
|
|
}
|
|
}
|
|
buf.printf(";");
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(AliasThis d)
|
|
{
|
|
buf.writestring("alias ");
|
|
buf.writestring(d.ident.toChars());
|
|
buf.writestring(" this;\n");
|
|
}
|
|
|
|
override void visit(AttribDeclaration d)
|
|
{
|
|
if (!d.decl)
|
|
{
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
return;
|
|
}
|
|
if (d.decl.dim == 0)
|
|
buf.writestring("{}");
|
|
else if (hgs.hdrgen && d.decl.dim == 1 && (*d.decl)[0].isUnitTestDeclaration())
|
|
{
|
|
// hack for bugzilla 8081
|
|
buf.writestring("{}");
|
|
}
|
|
else if (d.decl.dim == 1)
|
|
{
|
|
(*d.decl)[0].accept(this);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
foreach (de; *d.decl)
|
|
de.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
}
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(StorageClassDeclaration d)
|
|
{
|
|
if (stcToBuffer(buf, d.stc))
|
|
buf.writeByte(' ');
|
|
visit(cast(AttribDeclaration)d);
|
|
}
|
|
|
|
override void visit(DeprecatedDeclaration d)
|
|
{
|
|
buf.writestring("deprecated(");
|
|
d.msg.accept(this);
|
|
buf.writestring(") ");
|
|
visit(cast(AttribDeclaration)d);
|
|
}
|
|
|
|
override void visit(LinkDeclaration d)
|
|
{
|
|
const(char)* p;
|
|
switch (d.linkage)
|
|
{
|
|
case LINKd:
|
|
p = "D";
|
|
break;
|
|
case LINKc:
|
|
p = "C";
|
|
break;
|
|
case LINKcpp:
|
|
p = "C++";
|
|
break;
|
|
case LINKwindows:
|
|
p = "Windows";
|
|
break;
|
|
case LINKpascal:
|
|
p = "Pascal";
|
|
break;
|
|
case LINKobjc:
|
|
p = "Objective-C";
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
buf.writestring("extern (");
|
|
buf.writestring(p);
|
|
buf.writestring(") ");
|
|
visit(cast(AttribDeclaration)d);
|
|
}
|
|
|
|
override void visit(CPPMangleDeclaration d)
|
|
{
|
|
const(char)* p;
|
|
switch (d.cppmangle)
|
|
{
|
|
case CPPMANGLE.asClass:
|
|
p = "class";
|
|
break;
|
|
case CPPMANGLE.asStruct:
|
|
p = "struct";
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
buf.writestring("extern (C++, ");
|
|
buf.writestring(p);
|
|
buf.writestring(") ");
|
|
visit(cast(AttribDeclaration)d);
|
|
}
|
|
|
|
override void visit(ProtDeclaration d)
|
|
{
|
|
protectionToBuffer(buf, d.protection);
|
|
buf.writeByte(' ');
|
|
visit(cast(AttribDeclaration)d);
|
|
}
|
|
|
|
override void visit(AlignDeclaration d)
|
|
{
|
|
if (d.salign == STRUCTALIGN_DEFAULT)
|
|
buf.printf("align");
|
|
else
|
|
buf.printf("align (%d)", d.salign);
|
|
visit(cast(AttribDeclaration)d);
|
|
}
|
|
|
|
override void visit(AnonDeclaration d)
|
|
{
|
|
buf.printf(d.isunion ? "union" : "struct");
|
|
buf.writenl();
|
|
buf.writestring("{");
|
|
buf.writenl();
|
|
buf.level++;
|
|
if (d.decl)
|
|
{
|
|
foreach (de; *d.decl)
|
|
de.accept(this);
|
|
}
|
|
buf.level--;
|
|
buf.writestring("}");
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(PragmaDeclaration d)
|
|
{
|
|
buf.printf("pragma (%s", d.ident.toChars());
|
|
if (d.args && d.args.dim)
|
|
{
|
|
buf.writestring(", ");
|
|
argsToBuffer(d.args);
|
|
}
|
|
buf.writeByte(')');
|
|
visit(cast(AttribDeclaration)d);
|
|
}
|
|
|
|
override void visit(ConditionalDeclaration d)
|
|
{
|
|
d.condition.accept(this);
|
|
if (d.decl || d.elsedecl)
|
|
{
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
if (d.decl)
|
|
{
|
|
foreach (de; *d.decl)
|
|
de.accept(this);
|
|
}
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
if (d.elsedecl)
|
|
{
|
|
buf.writenl();
|
|
buf.writestring("else");
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
foreach (de; *d.elsedecl)
|
|
de.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
}
|
|
}
|
|
else
|
|
buf.writeByte(':');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(CompileDeclaration d)
|
|
{
|
|
buf.writestring("mixin(");
|
|
d.exp.accept(this);
|
|
buf.writestring(");");
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(UserAttributeDeclaration d)
|
|
{
|
|
buf.writestring("@(");
|
|
argsToBuffer(d.atts);
|
|
buf.writeByte(')');
|
|
visit(cast(AttribDeclaration)d);
|
|
}
|
|
|
|
override void visit(TemplateDeclaration d)
|
|
{
|
|
version (none)
|
|
{
|
|
// Should handle template functions for doc generation
|
|
if (onemember && onemember.isFuncDeclaration())
|
|
buf.writestring("foo ");
|
|
}
|
|
if (hgs.hdrgen && visitEponymousMember(d))
|
|
return;
|
|
if (hgs.ddoc)
|
|
buf.writestring(d.kind());
|
|
else
|
|
buf.writestring("template");
|
|
buf.writeByte(' ');
|
|
buf.writestring(d.ident.toChars());
|
|
buf.writeByte('(');
|
|
visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
|
|
buf.writeByte(')');
|
|
visitTemplateConstraint(d.constraint);
|
|
if (hgs.hdrgen)
|
|
{
|
|
hgs.tpltMember++;
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
foreach (s; *d.members)
|
|
s.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
hgs.tpltMember--;
|
|
}
|
|
}
|
|
|
|
bool visitEponymousMember(TemplateDeclaration d)
|
|
{
|
|
if (!d.members || d.members.dim != 1)
|
|
return false;
|
|
Dsymbol onemember = (*d.members)[0];
|
|
if (onemember.ident != d.ident)
|
|
return false;
|
|
if (FuncDeclaration fd = onemember.isFuncDeclaration())
|
|
{
|
|
assert(fd.type);
|
|
if (stcToBuffer(buf, fd.storage_class))
|
|
buf.writeByte(' ');
|
|
functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d);
|
|
visitTemplateConstraint(d.constraint);
|
|
hgs.tpltMember++;
|
|
bodyToBuffer(fd);
|
|
hgs.tpltMember--;
|
|
return true;
|
|
}
|
|
if (AggregateDeclaration ad = onemember.isAggregateDeclaration())
|
|
{
|
|
buf.writestring(ad.kind());
|
|
buf.writeByte(' ');
|
|
buf.writestring(ad.ident.toChars());
|
|
buf.writeByte('(');
|
|
visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
|
|
buf.writeByte(')');
|
|
visitTemplateConstraint(d.constraint);
|
|
visitBaseClasses(ad.isClassDeclaration());
|
|
hgs.tpltMember++;
|
|
if (ad.members)
|
|
{
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
foreach (s; *ad.members)
|
|
s.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
}
|
|
else
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
hgs.tpltMember--;
|
|
return true;
|
|
}
|
|
if (VarDeclaration vd = onemember.isVarDeclaration())
|
|
{
|
|
if (d.constraint)
|
|
return false;
|
|
if (stcToBuffer(buf, vd.storage_class))
|
|
buf.writeByte(' ');
|
|
if (vd.type)
|
|
typeToBuffer(vd.type, vd.ident);
|
|
else
|
|
buf.writestring(vd.ident.toChars());
|
|
buf.writeByte('(');
|
|
visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
|
|
buf.writeByte(')');
|
|
if (vd._init)
|
|
{
|
|
buf.writestring(" = ");
|
|
ExpInitializer ie = vd._init.isExpInitializer();
|
|
if (ie && (ie.exp.op == TOKconstruct || ie.exp.op == TOKblit))
|
|
(cast(AssignExp)ie.exp).e2.accept(this);
|
|
else
|
|
vd._init.accept(this);
|
|
}
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void visitTemplateParameters(TemplateParameters* parameters)
|
|
{
|
|
if (!parameters || !parameters.dim)
|
|
return;
|
|
foreach (i, p; *parameters)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
p.accept(this);
|
|
}
|
|
}
|
|
|
|
void visitTemplateConstraint(Expression constraint)
|
|
{
|
|
if (!constraint)
|
|
return;
|
|
buf.writestring(" if (");
|
|
constraint.accept(this);
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
override void visit(TemplateInstance ti)
|
|
{
|
|
buf.writestring(ti.name.toChars());
|
|
tiargsToBuffer(ti);
|
|
}
|
|
|
|
override void visit(TemplateMixin tm)
|
|
{
|
|
buf.writestring("mixin ");
|
|
typeToBuffer(tm.tqual, null);
|
|
tiargsToBuffer(tm);
|
|
if (tm.ident && memcmp(tm.ident.string, cast(char*)"__mixin", 7) != 0)
|
|
{
|
|
buf.writeByte(' ');
|
|
buf.writestring(tm.ident.toChars());
|
|
}
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
|
|
void tiargsToBuffer(TemplateInstance ti)
|
|
{
|
|
buf.writeByte('!');
|
|
if (ti.nest)
|
|
{
|
|
buf.writestring("(...)");
|
|
return;
|
|
}
|
|
if (!ti.tiargs)
|
|
{
|
|
buf.writestring("()");
|
|
return;
|
|
}
|
|
if (ti.tiargs.dim == 1)
|
|
{
|
|
RootObject oarg = (*ti.tiargs)[0];
|
|
if (Type t = isType(oarg))
|
|
{
|
|
if (t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0 && (t.isTypeBasic() || t.ty == Tident && (cast(TypeIdentifier)t).idents.dim == 0))
|
|
{
|
|
buf.writestring(t.toChars());
|
|
return;
|
|
}
|
|
}
|
|
else if (Expression e = isExpression(oarg))
|
|
{
|
|
if (e.op == TOKint64 || e.op == TOKfloat64 || e.op == TOKnull || e.op == TOKstring || e.op == TOKthis)
|
|
{
|
|
buf.writestring(e.toChars());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
buf.writeByte('(');
|
|
ti.nest++;
|
|
foreach (i, arg; *ti.tiargs)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
objectToBuffer(arg);
|
|
}
|
|
ti.nest--;
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
/****************************************
|
|
* This makes a 'pretty' version of the template arguments.
|
|
* It's analogous to genIdent() which makes a mangled version.
|
|
*/
|
|
void objectToBuffer(RootObject oarg)
|
|
{
|
|
//printf("objectToBuffer()\n");
|
|
/* The logic of this should match what genIdent() does. The _dynamic_cast()
|
|
* function relies on all the pretty strings to be unique for different classes
|
|
* (see Bugzilla 7375).
|
|
* Perhaps it would be better to demangle what genIdent() does.
|
|
*/
|
|
if (auto t = isType(oarg))
|
|
{
|
|
//printf("\tt: %s ty = %d\n", t->toChars(), t->ty);
|
|
typeToBuffer(t, null);
|
|
}
|
|
else if (auto e = isExpression(oarg))
|
|
{
|
|
if (e.op == TOKvar)
|
|
e = e.optimize(WANTvalue); // added to fix Bugzilla 7375
|
|
e.accept(this);
|
|
}
|
|
else if (Dsymbol s = isDsymbol(oarg))
|
|
{
|
|
const p = s.ident ? s.ident.toChars() : s.toChars();
|
|
buf.writestring(p);
|
|
}
|
|
else if (auto v = isTuple(oarg))
|
|
{
|
|
auto args = &v.objects;
|
|
foreach (i, arg; *args)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
objectToBuffer(arg);
|
|
}
|
|
}
|
|
else if (!oarg)
|
|
{
|
|
buf.writestring("NULL");
|
|
}
|
|
else
|
|
{
|
|
debug
|
|
{
|
|
printf("bad Object = %p\n", oarg);
|
|
}
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
override void visit(EnumDeclaration d)
|
|
{
|
|
buf.writestring("enum ");
|
|
if (d.ident)
|
|
{
|
|
buf.writestring(d.ident.toChars());
|
|
buf.writeByte(' ');
|
|
}
|
|
if (d.memtype)
|
|
{
|
|
buf.writestring(": ");
|
|
typeToBuffer(d.memtype, null);
|
|
}
|
|
if (!d.members)
|
|
{
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
return;
|
|
}
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
foreach (em; *d.members)
|
|
{
|
|
if (!em)
|
|
continue;
|
|
em.accept(this);
|
|
buf.writeByte(',');
|
|
buf.writenl();
|
|
}
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(Nspace d)
|
|
{
|
|
buf.writestring("extern (C++, ");
|
|
buf.writestring(d.ident.string);
|
|
buf.writeByte(')');
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
foreach (s; *d.members)
|
|
s.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(StructDeclaration d)
|
|
{
|
|
buf.printf("%s ", d.kind());
|
|
if (!d.isAnonymous())
|
|
buf.writestring(d.toChars());
|
|
if (!d.members)
|
|
{
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
return;
|
|
}
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
foreach (s; *d.members)
|
|
s.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(ClassDeclaration d)
|
|
{
|
|
if (!d.isAnonymous())
|
|
{
|
|
buf.writestring(d.kind());
|
|
buf.writeByte(' ');
|
|
buf.writestring(d.ident.toChars());
|
|
}
|
|
visitBaseClasses(d);
|
|
if (d.members)
|
|
{
|
|
buf.writenl();
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
foreach (s; *d.members)
|
|
s.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
}
|
|
else
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
|
|
void visitBaseClasses(ClassDeclaration d)
|
|
{
|
|
if (!d || !d.baseclasses.dim)
|
|
return;
|
|
buf.writestring(" : ");
|
|
foreach (i, b; *d.baseclasses)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
typeToBuffer(b.type, null);
|
|
}
|
|
}
|
|
|
|
override void visit(AliasDeclaration d)
|
|
{
|
|
buf.writestring("alias ");
|
|
if (d.aliassym)
|
|
{
|
|
buf.writestring(d.ident.toChars());
|
|
buf.writestring(" = ");
|
|
if (stcToBuffer(buf, d.storage_class))
|
|
buf.writeByte(' ');
|
|
d.aliassym.accept(this);
|
|
}
|
|
else if (d.type.ty == Tfunction)
|
|
{
|
|
if (stcToBuffer(buf, d.storage_class))
|
|
buf.writeByte(' ');
|
|
typeToBuffer(d.type, d.ident);
|
|
}
|
|
else
|
|
{
|
|
declstring = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id.dstring);
|
|
buf.writestring(d.ident.toChars());
|
|
buf.writestring(" = ");
|
|
if (stcToBuffer(buf, d.storage_class))
|
|
buf.writeByte(' ');
|
|
typeToBuffer(d.type, null);
|
|
declstring = false;
|
|
}
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
|
|
override void visit(VarDeclaration d)
|
|
{
|
|
visitVarDecl(d, false);
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
|
|
void visitVarDecl(VarDeclaration v, bool anywritten)
|
|
{
|
|
if (anywritten)
|
|
{
|
|
buf.writestring(", ");
|
|
buf.writestring(v.ident.toChars());
|
|
}
|
|
else
|
|
{
|
|
if (stcToBuffer(buf, v.storage_class))
|
|
buf.writeByte(' ');
|
|
if (v.type)
|
|
typeToBuffer(v.type, v.ident);
|
|
else
|
|
buf.writestring(v.ident.toChars());
|
|
}
|
|
if (v._init)
|
|
{
|
|
buf.writestring(" = ");
|
|
auto ie = v._init.isExpInitializer();
|
|
if (ie && (ie.exp.op == TOKconstruct || ie.exp.op == TOKblit))
|
|
(cast(AssignExp)ie.exp).e2.accept(this);
|
|
else
|
|
v._init.accept(this);
|
|
}
|
|
}
|
|
|
|
override void visit(FuncDeclaration f)
|
|
{
|
|
//printf("FuncDeclaration::toCBuffer() '%s'\n", f->toChars());
|
|
if (stcToBuffer(buf, f.storage_class))
|
|
buf.writeByte(' ');
|
|
typeToBuffer(f.type, f.ident);
|
|
if (hgs.hdrgen == 1)
|
|
{
|
|
version(IN_LLVM)
|
|
bool noBody = !global.params.hdrKeepAllBodies;
|
|
else
|
|
bool noBody = !global.params.useInline;
|
|
|
|
if (f.storage_class & STCauto)
|
|
{
|
|
hgs.autoMember++;
|
|
bodyToBuffer(f);
|
|
hgs.autoMember--;
|
|
}
|
|
else if (hgs.tpltMember == 0 && noBody)
|
|
{
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
else
|
|
bodyToBuffer(f);
|
|
}
|
|
else
|
|
bodyToBuffer(f);
|
|
}
|
|
|
|
void bodyToBuffer(FuncDeclaration f)
|
|
{
|
|
version(IN_LLVM)
|
|
bool noBody = !global.params.hdrKeepAllBodies;
|
|
else
|
|
bool noBody = !global.params.useInline;
|
|
|
|
if (!f.fbody || (hgs.hdrgen && noBody && !hgs.autoMember && !hgs.tpltMember))
|
|
{
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
return;
|
|
}
|
|
int savetlpt = hgs.tpltMember;
|
|
int saveauto = hgs.autoMember;
|
|
hgs.tpltMember = 0;
|
|
hgs.autoMember = 0;
|
|
buf.writenl();
|
|
// in{}
|
|
if (f.frequire)
|
|
{
|
|
buf.writestring("in");
|
|
buf.writenl();
|
|
f.frequire.accept(this);
|
|
}
|
|
// out{}
|
|
if (f.fensure)
|
|
{
|
|
buf.writestring("out");
|
|
if (f.outId)
|
|
{
|
|
buf.writeByte('(');
|
|
buf.writestring(f.outId.toChars());
|
|
buf.writeByte(')');
|
|
}
|
|
buf.writenl();
|
|
f.fensure.accept(this);
|
|
}
|
|
if (f.frequire || f.fensure)
|
|
{
|
|
buf.writestring("body");
|
|
buf.writenl();
|
|
}
|
|
buf.writeByte('{');
|
|
buf.writenl();
|
|
buf.level++;
|
|
f.fbody.accept(this);
|
|
buf.level--;
|
|
buf.writeByte('}');
|
|
buf.writenl();
|
|
hgs.tpltMember = savetlpt;
|
|
hgs.autoMember = saveauto;
|
|
}
|
|
|
|
override void visit(FuncLiteralDeclaration f)
|
|
{
|
|
if (f.type.ty == Terror)
|
|
{
|
|
buf.writestring("__error");
|
|
return;
|
|
}
|
|
if (f.tok != TOKreserved)
|
|
{
|
|
buf.writestring(f.kind());
|
|
buf.writeByte(' ');
|
|
}
|
|
TypeFunction tf = cast(TypeFunction)f.type;
|
|
// Don't print tf->mod, tf->trust, and tf->linkage
|
|
if (!f.inferRetType && tf.next)
|
|
typeToBuffer(tf.next, null);
|
|
parametersToBuffer(tf.parameters, tf.varargs);
|
|
CompoundStatement cs = f.fbody.isCompoundStatement();
|
|
Statement s1;
|
|
if (f.semanticRun >= PASSsemantic3done && cs)
|
|
{
|
|
s1 = (*cs.statements)[cs.statements.dim - 1];
|
|
}
|
|
else
|
|
s1 = !cs ? f.fbody : null;
|
|
ReturnStatement rs = s1 ? s1.isReturnStatement() : null;
|
|
if (rs && rs.exp)
|
|
{
|
|
buf.writestring(" => ");
|
|
rs.exp.accept(this);
|
|
}
|
|
else
|
|
{
|
|
hgs.tpltMember++;
|
|
bodyToBuffer(f);
|
|
hgs.tpltMember--;
|
|
}
|
|
}
|
|
|
|
override void visit(PostBlitDeclaration d)
|
|
{
|
|
buf.writestring("this(this)");
|
|
bodyToBuffer(d);
|
|
}
|
|
|
|
override void visit(DtorDeclaration d)
|
|
{
|
|
buf.writestring("~this()");
|
|
bodyToBuffer(d);
|
|
}
|
|
|
|
override void visit(StaticCtorDeclaration d)
|
|
{
|
|
if (stcToBuffer(buf, d.storage_class & ~STCstatic))
|
|
buf.writeByte(' ');
|
|
if (d.isSharedStaticCtorDeclaration())
|
|
buf.writestring("shared ");
|
|
buf.writestring("static this()");
|
|
if (hgs.hdrgen && !hgs.tpltMember)
|
|
{
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
else
|
|
bodyToBuffer(d);
|
|
}
|
|
|
|
override void visit(StaticDtorDeclaration d)
|
|
{
|
|
if (hgs.hdrgen)
|
|
return;
|
|
if (stcToBuffer(buf, d.storage_class & ~STCstatic))
|
|
buf.writeByte(' ');
|
|
if (d.isSharedStaticDtorDeclaration())
|
|
buf.writestring("shared ");
|
|
buf.writestring("static ~this()");
|
|
bodyToBuffer(d);
|
|
}
|
|
|
|
override void visit(InvariantDeclaration d)
|
|
{
|
|
if (hgs.hdrgen)
|
|
return;
|
|
if (stcToBuffer(buf, d.storage_class))
|
|
buf.writeByte(' ');
|
|
buf.writestring("invariant");
|
|
bodyToBuffer(d);
|
|
}
|
|
|
|
override void visit(UnitTestDeclaration d)
|
|
{
|
|
if (hgs.hdrgen)
|
|
return;
|
|
if (stcToBuffer(buf, d.storage_class))
|
|
buf.writeByte(' ');
|
|
buf.writestring("unittest");
|
|
bodyToBuffer(d);
|
|
}
|
|
|
|
override void visit(NewDeclaration d)
|
|
{
|
|
if (stcToBuffer(buf, d.storage_class & ~STCstatic))
|
|
buf.writeByte(' ');
|
|
buf.writestring("new");
|
|
parametersToBuffer(d.parameters, d.varargs);
|
|
bodyToBuffer(d);
|
|
}
|
|
|
|
override void visit(DeleteDeclaration d)
|
|
{
|
|
if (stcToBuffer(buf, d.storage_class & ~STCstatic))
|
|
buf.writeByte(' ');
|
|
buf.writestring("delete");
|
|
parametersToBuffer(d.parameters, 0);
|
|
bodyToBuffer(d);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
override void visit(ErrorInitializer iz)
|
|
{
|
|
buf.writestring("__error__");
|
|
}
|
|
|
|
override void visit(VoidInitializer iz)
|
|
{
|
|
buf.writestring("void");
|
|
}
|
|
|
|
override void visit(StructInitializer si)
|
|
{
|
|
//printf("StructInitializer::toCBuffer()\n");
|
|
buf.writeByte('{');
|
|
foreach (i, const id; si.field)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
if (id)
|
|
{
|
|
buf.writestring(id.toChars());
|
|
buf.writeByte(':');
|
|
}
|
|
if (auto iz = si.value[i])
|
|
iz.accept(this);
|
|
}
|
|
buf.writeByte('}');
|
|
}
|
|
|
|
override void visit(ArrayInitializer ai)
|
|
{
|
|
buf.writeByte('[');
|
|
foreach (i, ex; ai.index)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
if (ex)
|
|
{
|
|
ex.accept(this);
|
|
buf.writeByte(':');
|
|
}
|
|
if (auto iz = ai.value[i])
|
|
iz.accept(this);
|
|
}
|
|
buf.writeByte(']');
|
|
}
|
|
|
|
override void visit(ExpInitializer ei)
|
|
{
|
|
ei.exp.accept(this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
/**************************************************
|
|
* Write out argument list to buf.
|
|
*/
|
|
void argsToBuffer(Expressions* expressions, Expression basis = null)
|
|
{
|
|
if (!expressions || !expressions.dim)
|
|
return;
|
|
version (all)
|
|
{
|
|
foreach (i, el; *expressions)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
if (!el)
|
|
el = basis;
|
|
if (el)
|
|
expToBuffer(el, PREC_assign);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Sparse style formatting, for debug use only
|
|
// [0..dim: basis, 1: e1, 5: e5]
|
|
if (basis)
|
|
{
|
|
buf.printf("0..%llu: ", cast(ulong)expressions.dim);
|
|
expToBuffer(basis, PREC_assign);
|
|
}
|
|
foreach (i, el; *expressions)
|
|
{
|
|
if (el)
|
|
{
|
|
if (basis)
|
|
buf.printf(", %llu: ", cast(ulong)i);
|
|
else if (i)
|
|
buf.writestring(", ");
|
|
expToBuffer(el, PREC_assign);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void sizeToBuffer(Expression e)
|
|
{
|
|
if (e.type == Type.tsize_t)
|
|
{
|
|
Expression ex = (e.op == TOKcast ? (cast(CastExp)e).e1 : e);
|
|
ex = ex.optimize(WANTvalue);
|
|
dinteger_t uval = ex.op == TOKint64 ? ex.toInteger() : cast(dinteger_t)-1;
|
|
if (cast(sinteger_t)uval >= 0)
|
|
{
|
|
dinteger_t sizemax;
|
|
if (Target.ptrsize == 4)
|
|
sizemax = 0xFFFFFFFFU;
|
|
else if (Target.ptrsize == 8)
|
|
sizemax = 0xFFFFFFFFFFFFFFFFUL;
|
|
else
|
|
assert(0);
|
|
if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL)
|
|
{
|
|
buf.printf("%llu", uval);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
expToBuffer(e, PREC_assign);
|
|
}
|
|
|
|
/**************************************************
|
|
* Write expression out to buf, but wrap it
|
|
* in ( ) if its precedence is less than pr.
|
|
*/
|
|
void expToBuffer(Expression e, PREC pr)
|
|
{
|
|
debug
|
|
{
|
|
if (precedence[e.op] == PREC_zero)
|
|
printf("precedence not defined for token '%s'\n", Token.tochars[e.op]);
|
|
}
|
|
assert(precedence[e.op] != PREC_zero);
|
|
assert(pr != PREC_zero);
|
|
//if (precedence[e->op] == 0) e->print();
|
|
/* Despite precedence, we don't allow a<b<c expressions.
|
|
* They must be parenthesized.
|
|
*/
|
|
if (precedence[e.op] < pr || (pr == PREC_rel && precedence[e.op] == pr))
|
|
{
|
|
buf.writeByte('(');
|
|
e.accept(this);
|
|
buf.writeByte(')');
|
|
}
|
|
else
|
|
e.accept(this);
|
|
}
|
|
|
|
override void visit(Expression e)
|
|
{
|
|
buf.writestring(Token.toChars(e.op));
|
|
}
|
|
|
|
override void visit(IntegerExp e)
|
|
{
|
|
dinteger_t v = e.toInteger();
|
|
if (e.type)
|
|
{
|
|
Type t = e.type;
|
|
L1:
|
|
switch (t.ty)
|
|
{
|
|
case Tenum:
|
|
{
|
|
TypeEnum te = cast(TypeEnum)t;
|
|
buf.printf("cast(%s)", te.sym.toChars());
|
|
t = te.sym.memtype;
|
|
goto L1;
|
|
}
|
|
case Twchar:
|
|
// BUG: need to cast(wchar)
|
|
case Tdchar:
|
|
// BUG: need to cast(dchar)
|
|
if (cast(uinteger_t)v > 0xFF)
|
|
{
|
|
buf.printf("'\\U%08x'", v);
|
|
break;
|
|
}
|
|
goto case;
|
|
case Tchar:
|
|
{
|
|
size_t o = buf.offset;
|
|
if (v == '\'')
|
|
buf.writestring("'\\''");
|
|
else if (isprint(cast(int)v) && v != '\\')
|
|
buf.printf("'%c'", cast(int)v);
|
|
else
|
|
buf.printf("'\\x%02x'", cast(int)v);
|
|
if (hgs.ddoc)
|
|
escapeDdocString(buf, o);
|
|
break;
|
|
}
|
|
case Tint8:
|
|
buf.writestring("cast(byte)");
|
|
goto L2;
|
|
case Tint16:
|
|
buf.writestring("cast(short)");
|
|
goto L2;
|
|
case Tint32:
|
|
L2:
|
|
buf.printf("%d", cast(int)v);
|
|
break;
|
|
case Tuns8:
|
|
buf.writestring("cast(ubyte)");
|
|
goto L3;
|
|
case Tuns16:
|
|
buf.writestring("cast(ushort)");
|
|
goto L3;
|
|
case Tuns32:
|
|
L3:
|
|
buf.printf("%uu", cast(uint)v);
|
|
break;
|
|
case Tint64:
|
|
buf.printf("%lldL", v);
|
|
break;
|
|
case Tuns64:
|
|
L4:
|
|
buf.printf("%lluLU", v);
|
|
break;
|
|
case Tbool:
|
|
buf.writestring(v ? "true" : "false");
|
|
break;
|
|
case Tpointer:
|
|
buf.writestring("cast(");
|
|
buf.writestring(t.toChars());
|
|
buf.writeByte(')');
|
|
if (Target.ptrsize == 4)
|
|
goto L3;
|
|
else if (Target.ptrsize == 8)
|
|
goto L4;
|
|
else
|
|
assert(0);
|
|
default:
|
|
/* This can happen if errors, such as
|
|
* the type is painted on like in fromConstInitializer().
|
|
*/
|
|
if (!global.errors)
|
|
{
|
|
debug
|
|
{
|
|
t.print();
|
|
}
|
|
assert(0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (v & 0x8000000000000000L)
|
|
buf.printf("0x%llx", v);
|
|
else
|
|
buf.printf("%lld", v);
|
|
}
|
|
|
|
override void visit(ErrorExp e)
|
|
{
|
|
buf.writestring("__error");
|
|
}
|
|
|
|
void floatToBuffer(Type type, real_t value)
|
|
{
|
|
/** sizeof(value)*3 is because each byte of mantissa is max
|
|
of 256 (3 characters). The string will be "-M.MMMMe-4932".
|
|
(ie, 8 chars more than mantissa). Plus one for trailing \0.
|
|
Plus one for rounding. */
|
|
const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1;
|
|
char[BUFFER_LEN] buffer;
|
|
Port.ld_sprint(buffer.ptr, 'g', value);
|
|
assert(strlen(buffer.ptr) < BUFFER_LEN);
|
|
// IN_LLVM MSVC: LLVM's APFloat is used for strtold, which asserts for certain special float inputs
|
|
if (!IN_LLVM_MSVC || (!Port.isNan(value) && !Port.isInfinity(value)))
|
|
if (hgs.hdrgen)
|
|
{
|
|
real_t r = Port.strtold(buffer.ptr, null);
|
|
if (r != value) // if exact duplication
|
|
Port.ld_sprint(buffer.ptr, 'a', value);
|
|
}
|
|
buf.writestring(buffer.ptr);
|
|
if (type)
|
|
{
|
|
Type t = type.toBasetype();
|
|
switch (t.ty)
|
|
{
|
|
case Tfloat32:
|
|
case Timaginary32:
|
|
case Tcomplex32:
|
|
buf.writeByte('F');
|
|
break;
|
|
case Tfloat80:
|
|
case Timaginary80:
|
|
case Tcomplex80:
|
|
buf.writeByte('L');
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (t.isimaginary())
|
|
buf.writeByte('i');
|
|
}
|
|
}
|
|
|
|
override void visit(RealExp e)
|
|
{
|
|
floatToBuffer(e.type, e.value);
|
|
}
|
|
|
|
override void visit(ComplexExp e)
|
|
{
|
|
/* Print as:
|
|
* (re+imi)
|
|
*/
|
|
buf.writeByte('(');
|
|
floatToBuffer(e.type, creall(e.value));
|
|
buf.writeByte('+');
|
|
floatToBuffer(e.type, cimagl(e.value));
|
|
buf.writestring("i)");
|
|
}
|
|
|
|
override void visit(IdentifierExp e)
|
|
{
|
|
if (hgs.hdrgen || hgs.ddoc)
|
|
buf.writestring(e.ident.toHChars2());
|
|
else
|
|
buf.writestring(e.ident.toChars());
|
|
}
|
|
|
|
override void visit(DsymbolExp e)
|
|
{
|
|
buf.writestring(e.s.toChars());
|
|
}
|
|
|
|
override void visit(ThisExp e)
|
|
{
|
|
buf.writestring("this");
|
|
}
|
|
|
|
override void visit(SuperExp e)
|
|
{
|
|
buf.writestring("super");
|
|
}
|
|
|
|
override void visit(NullExp e)
|
|
{
|
|
buf.writestring("null");
|
|
}
|
|
|
|
override void visit(StringExp e)
|
|
{
|
|
buf.writeByte('"');
|
|
size_t o = buf.offset;
|
|
for (size_t i = 0; i < e.len; i++)
|
|
{
|
|
uint c = e.charAt(i);
|
|
switch (c)
|
|
{
|
|
case '"':
|
|
case '\\':
|
|
buf.writeByte('\\');
|
|
goto default;
|
|
default:
|
|
if (c <= 0xFF)
|
|
{
|
|
if (c <= 0x7F && isprint(c))
|
|
buf.writeByte(c);
|
|
else
|
|
buf.printf("\\x%02x", c);
|
|
}
|
|
else if (c <= 0xFFFF)
|
|
buf.printf("\\x%02x\\x%02x", c & 0xFF, c >> 8);
|
|
else
|
|
buf.printf("\\x%02x\\x%02x\\x%02x\\x%02x", c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24);
|
|
break;
|
|
}
|
|
}
|
|
if (hgs.ddoc)
|
|
escapeDdocString(buf, o);
|
|
buf.writeByte('"');
|
|
if (e.postfix)
|
|
buf.writeByte(e.postfix);
|
|
}
|
|
|
|
override void visit(ArrayLiteralExp e)
|
|
{
|
|
buf.writeByte('[');
|
|
argsToBuffer(e.elements, e.basis);
|
|
buf.writeByte(']');
|
|
}
|
|
|
|
override void visit(AssocArrayLiteralExp e)
|
|
{
|
|
buf.writeByte('[');
|
|
foreach (i, key; *e.keys)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
expToBuffer(key, PREC_assign);
|
|
buf.writeByte(':');
|
|
auto value = (*e.values)[i];
|
|
expToBuffer(value, PREC_assign);
|
|
}
|
|
buf.writeByte(']');
|
|
}
|
|
|
|
override void visit(StructLiteralExp e)
|
|
{
|
|
buf.writestring(e.sd.toChars());
|
|
buf.writeByte('(');
|
|
// CTFE can generate struct literals that contain an AddrExp pointing
|
|
// to themselves, need to avoid infinite recursion:
|
|
// struct S { this(int){ this.s = &this; } S* s; }
|
|
// const foo = new S(0);
|
|
if (e.stageflags & stageToCBuffer)
|
|
buf.writestring("<recursion>");
|
|
else
|
|
{
|
|
int old = e.stageflags;
|
|
e.stageflags |= stageToCBuffer;
|
|
argsToBuffer(e.elements);
|
|
e.stageflags = old;
|
|
}
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
override void visit(TypeExp e)
|
|
{
|
|
typeToBuffer(e.type, null);
|
|
}
|
|
|
|
override void visit(ScopeExp e)
|
|
{
|
|
if (e.sds.isTemplateInstance())
|
|
{
|
|
e.sds.accept(this);
|
|
}
|
|
else if (hgs !is null && hgs.ddoc)
|
|
{
|
|
// fixes bug 6491
|
|
Module m = e.sds.isModule();
|
|
if (m)
|
|
buf.writestring(m.md.toChars());
|
|
else
|
|
buf.writestring(e.sds.toChars());
|
|
}
|
|
else
|
|
{
|
|
buf.writestring(e.sds.kind());
|
|
buf.writeByte(' ');
|
|
buf.writestring(e.sds.toChars());
|
|
}
|
|
}
|
|
|
|
override void visit(TemplateExp e)
|
|
{
|
|
buf.writestring(e.td.toChars());
|
|
}
|
|
|
|
override void visit(NewExp e)
|
|
{
|
|
if (e.thisexp)
|
|
{
|
|
expToBuffer(e.thisexp, PREC_primary);
|
|
buf.writeByte('.');
|
|
}
|
|
buf.writestring("new ");
|
|
if (e.newargs && e.newargs.dim)
|
|
{
|
|
buf.writeByte('(');
|
|
argsToBuffer(e.newargs);
|
|
buf.writeByte(')');
|
|
}
|
|
typeToBuffer(e.newtype, null);
|
|
if (e.arguments && e.arguments.dim)
|
|
{
|
|
buf.writeByte('(');
|
|
argsToBuffer(e.arguments);
|
|
buf.writeByte(')');
|
|
}
|
|
}
|
|
|
|
override void visit(NewAnonClassExp e)
|
|
{
|
|
if (e.thisexp)
|
|
{
|
|
expToBuffer(e.thisexp, PREC_primary);
|
|
buf.writeByte('.');
|
|
}
|
|
buf.writestring("new");
|
|
if (e.newargs && e.newargs.dim)
|
|
{
|
|
buf.writeByte('(');
|
|
argsToBuffer(e.newargs);
|
|
buf.writeByte(')');
|
|
}
|
|
buf.writestring(" class ");
|
|
if (e.arguments && e.arguments.dim)
|
|
{
|
|
buf.writeByte('(');
|
|
argsToBuffer(e.arguments);
|
|
buf.writeByte(')');
|
|
}
|
|
if (e.cd)
|
|
e.cd.accept(this);
|
|
}
|
|
|
|
override void visit(SymOffExp e)
|
|
{
|
|
if (e.offset)
|
|
buf.printf("(& %s+%u)", e.var.toChars(), e.offset);
|
|
else if (e.var.isTypeInfoDeclaration())
|
|
buf.printf("%s", e.var.toChars());
|
|
else
|
|
buf.printf("& %s", e.var.toChars());
|
|
}
|
|
|
|
override void visit(VarExp e)
|
|
{
|
|
buf.writestring(e.var.toChars());
|
|
}
|
|
|
|
override void visit(OverExp e)
|
|
{
|
|
buf.writestring(e.vars.ident.toChars());
|
|
}
|
|
|
|
override void visit(TupleExp e)
|
|
{
|
|
if (e.e0)
|
|
{
|
|
buf.writeByte('(');
|
|
e.e0.accept(this);
|
|
buf.writestring(", tuple(");
|
|
argsToBuffer(e.exps);
|
|
buf.writestring("))");
|
|
}
|
|
else
|
|
{
|
|
buf.writestring("tuple(");
|
|
argsToBuffer(e.exps);
|
|
buf.writeByte(')');
|
|
}
|
|
}
|
|
|
|
override void visit(FuncExp e)
|
|
{
|
|
e.fd.accept(this);
|
|
//buf->writestring(e->fd->toChars());
|
|
}
|
|
|
|
override void visit(DeclarationExp e)
|
|
{
|
|
/* Normal dmd execution won't reach here - regular variable declarations
|
|
* are handled in visit(ExpStatement), so here would be used only when
|
|
* we'll directly call Expression.toChars() for debugging.
|
|
*/
|
|
if (auto v = e.declaration.isVarDeclaration())
|
|
{
|
|
// For debugging use:
|
|
// - Avoid printing newline.
|
|
// - Intentionally use the format (Type var;)
|
|
// which isn't correct as regular D code.
|
|
buf.writeByte('(');
|
|
visitVarDecl(v, false);
|
|
buf.writeByte(';');
|
|
buf.writeByte(')');
|
|
}
|
|
else
|
|
e.declaration.accept(this);
|
|
}
|
|
|
|
override void visit(TypeidExp e)
|
|
{
|
|
buf.writestring("typeid(");
|
|
objectToBuffer(e.obj);
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
override void visit(TraitsExp e)
|
|
{
|
|
buf.writestring("__traits(");
|
|
buf.writestring(e.ident.toChars());
|
|
if (e.args)
|
|
{
|
|
foreach (arg; *e.args)
|
|
{
|
|
buf.writestring(", ");
|
|
objectToBuffer(arg);
|
|
}
|
|
}
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
override void visit(HaltExp e)
|
|
{
|
|
buf.writestring("halt");
|
|
}
|
|
|
|
override void visit(IsExp e)
|
|
{
|
|
buf.writestring("is(");
|
|
typeToBuffer(e.targ, e.id);
|
|
if (e.tok2 != TOKreserved)
|
|
{
|
|
buf.printf(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2));
|
|
}
|
|
else if (e.tspec)
|
|
{
|
|
if (e.tok == TOKcolon)
|
|
buf.writestring(" : ");
|
|
else
|
|
buf.writestring(" == ");
|
|
typeToBuffer(e.tspec, null);
|
|
}
|
|
if (e.parameters && e.parameters.dim)
|
|
{
|
|
buf.writestring(", ");
|
|
visitTemplateParameters(e.parameters);
|
|
}
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
override void visit(UnaExp e)
|
|
{
|
|
buf.writestring(Token.toChars(e.op));
|
|
expToBuffer(e.e1, precedence[e.op]);
|
|
}
|
|
|
|
override void visit(BinExp e)
|
|
{
|
|
expToBuffer(e.e1, precedence[e.op]);
|
|
buf.writeByte(' ');
|
|
buf.writestring(Token.toChars(e.op));
|
|
buf.writeByte(' ');
|
|
expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1));
|
|
}
|
|
|
|
override void visit(CompileExp e)
|
|
{
|
|
buf.writestring("mixin(");
|
|
expToBuffer(e.e1, PREC_assign);
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
override void visit(ImportExp e)
|
|
{
|
|
buf.writestring("import(");
|
|
expToBuffer(e.e1, PREC_assign);
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
override void visit(AssertExp e)
|
|
{
|
|
buf.writestring("assert(");
|
|
expToBuffer(e.e1, PREC_assign);
|
|
if (e.msg)
|
|
{
|
|
buf.writestring(", ");
|
|
expToBuffer(e.msg, PREC_assign);
|
|
}
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
override void visit(DotIdExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writeByte('.');
|
|
buf.writestring(e.ident.toChars());
|
|
}
|
|
|
|
override void visit(DotTemplateExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writeByte('.');
|
|
buf.writestring(e.td.toChars());
|
|
}
|
|
|
|
override void visit(DotVarExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writeByte('.');
|
|
buf.writestring(e.var.toChars());
|
|
}
|
|
|
|
override void visit(DotTemplateInstanceExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writeByte('.');
|
|
e.ti.accept(this);
|
|
}
|
|
|
|
override void visit(DelegateExp e)
|
|
{
|
|
buf.writeByte('&');
|
|
if (!e.func.isNested())
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writeByte('.');
|
|
}
|
|
buf.writestring(e.func.toChars());
|
|
}
|
|
|
|
override void visit(DotTypeExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writeByte('.');
|
|
buf.writestring(e.sym.toChars());
|
|
}
|
|
|
|
override void visit(CallExp e)
|
|
{
|
|
if (e.e1.op == TOKtype)
|
|
{
|
|
/* Avoid parens around type to prevent forbidden cast syntax:
|
|
* (sometype)(arg1)
|
|
* This is ok since types in constructor calls
|
|
* can never depend on parens anyway
|
|
*/
|
|
e.e1.accept(this);
|
|
}
|
|
else
|
|
expToBuffer(e.e1, precedence[e.op]);
|
|
buf.writeByte('(');
|
|
argsToBuffer(e.arguments);
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
override void visit(PtrExp e)
|
|
{
|
|
buf.writeByte('*');
|
|
expToBuffer(e.e1, precedence[e.op]);
|
|
}
|
|
|
|
override void visit(DeleteExp e)
|
|
{
|
|
buf.writestring("delete ");
|
|
expToBuffer(e.e1, precedence[e.op]);
|
|
}
|
|
|
|
override void visit(CastExp e)
|
|
{
|
|
buf.writestring("cast(");
|
|
if (e.to)
|
|
typeToBuffer(e.to, null);
|
|
else
|
|
{
|
|
MODtoBuffer(buf, e.mod);
|
|
}
|
|
buf.writeByte(')');
|
|
expToBuffer(e.e1, precedence[e.op]);
|
|
}
|
|
|
|
override void visit(VectorExp e)
|
|
{
|
|
buf.writestring("cast(");
|
|
typeToBuffer(e.to, null);
|
|
buf.writeByte(')');
|
|
expToBuffer(e.e1, precedence[e.op]);
|
|
}
|
|
|
|
override void visit(SliceExp e)
|
|
{
|
|
expToBuffer(e.e1, precedence[e.op]);
|
|
buf.writeByte('[');
|
|
if (e.upr || e.lwr)
|
|
{
|
|
if (e.lwr)
|
|
sizeToBuffer(e.lwr);
|
|
else
|
|
buf.writeByte('0');
|
|
buf.writestring("..");
|
|
if (e.upr)
|
|
sizeToBuffer(e.upr);
|
|
else
|
|
buf.writeByte('$');
|
|
}
|
|
buf.writeByte(']');
|
|
}
|
|
|
|
override void visit(ArrayLengthExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writestring(".length");
|
|
}
|
|
|
|
override void visit(IntervalExp e)
|
|
{
|
|
expToBuffer(e.lwr, PREC_assign);
|
|
buf.writestring("..");
|
|
expToBuffer(e.upr, PREC_assign);
|
|
}
|
|
|
|
override void visit(DelegatePtrExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writestring(".ptr");
|
|
}
|
|
|
|
override void visit(DelegateFuncptrExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writestring(".funcptr");
|
|
}
|
|
|
|
override void visit(ArrayExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writeByte('[');
|
|
argsToBuffer(e.arguments);
|
|
buf.writeByte(']');
|
|
}
|
|
|
|
override void visit(DotExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writeByte('.');
|
|
expToBuffer(e.e2, PREC_primary);
|
|
}
|
|
|
|
override void visit(IndexExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writeByte('[');
|
|
sizeToBuffer(e.e2);
|
|
buf.writeByte(']');
|
|
}
|
|
|
|
override void visit(PostExp e)
|
|
{
|
|
expToBuffer(e.e1, precedence[e.op]);
|
|
buf.writestring(Token.toChars(e.op));
|
|
}
|
|
|
|
override void visit(PreExp e)
|
|
{
|
|
buf.writestring(Token.toChars(e.op));
|
|
expToBuffer(e.e1, precedence[e.op]);
|
|
}
|
|
|
|
override void visit(RemoveExp e)
|
|
{
|
|
expToBuffer(e.e1, PREC_primary);
|
|
buf.writestring(".remove(");
|
|
expToBuffer(e.e2, PREC_assign);
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
override void visit(CondExp e)
|
|
{
|
|
expToBuffer(e.econd, PREC_oror);
|
|
buf.writestring(" ? ");
|
|
expToBuffer(e.e1, PREC_expr);
|
|
buf.writestring(" : ");
|
|
expToBuffer(e.e2, PREC_cond);
|
|
}
|
|
|
|
override void visit(DefaultInitExp e)
|
|
{
|
|
buf.writestring(Token.toChars(e.subop));
|
|
}
|
|
|
|
override void visit(ClassReferenceExp e)
|
|
{
|
|
buf.writestring(e.value.toChars());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
override void visit(TemplateTypeParameter tp)
|
|
{
|
|
buf.writestring(tp.ident.toChars());
|
|
if (tp.specType)
|
|
{
|
|
buf.writestring(" : ");
|
|
typeToBuffer(tp.specType, null);
|
|
}
|
|
if (tp.defaultType)
|
|
{
|
|
buf.writestring(" = ");
|
|
typeToBuffer(tp.defaultType, null);
|
|
}
|
|
}
|
|
|
|
override void visit(TemplateThisParameter tp)
|
|
{
|
|
buf.writestring("this ");
|
|
visit(cast(TemplateTypeParameter)tp);
|
|
}
|
|
|
|
override void visit(TemplateAliasParameter tp)
|
|
{
|
|
buf.writestring("alias ");
|
|
if (tp.specType)
|
|
typeToBuffer(tp.specType, tp.ident);
|
|
else
|
|
buf.writestring(tp.ident.toChars());
|
|
if (tp.specAlias)
|
|
{
|
|
buf.writestring(" : ");
|
|
objectToBuffer(tp.specAlias);
|
|
}
|
|
if (tp.defaultAlias)
|
|
{
|
|
buf.writestring(" = ");
|
|
objectToBuffer(tp.defaultAlias);
|
|
}
|
|
}
|
|
|
|
override void visit(TemplateValueParameter tp)
|
|
{
|
|
typeToBuffer(tp.valType, tp.ident);
|
|
if (tp.specValue)
|
|
{
|
|
buf.writestring(" : ");
|
|
tp.specValue.accept(this);
|
|
}
|
|
if (tp.defaultValue)
|
|
{
|
|
buf.writestring(" = ");
|
|
tp.defaultValue.accept(this);
|
|
}
|
|
}
|
|
|
|
override void visit(TemplateTupleParameter tp)
|
|
{
|
|
buf.writestring(tp.ident.toChars());
|
|
buf.writestring("...");
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
override void visit(DebugCondition c)
|
|
{
|
|
if (c.ident)
|
|
buf.printf("debug (%s)", c.ident.toChars());
|
|
else
|
|
buf.printf("debug (%u)", c.level);
|
|
}
|
|
|
|
override void visit(VersionCondition c)
|
|
{
|
|
if (c.ident)
|
|
buf.printf("version (%s)", c.ident.toChars());
|
|
else
|
|
buf.printf("version (%u)", c.level);
|
|
}
|
|
|
|
override void visit(StaticIfCondition c)
|
|
{
|
|
buf.writestring("static if (");
|
|
c.exp.accept(this);
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
override void visit(Parameter p)
|
|
{
|
|
if (p.storageClass & STCauto)
|
|
buf.writestring("auto ");
|
|
if (p.storageClass & STCreturn)
|
|
buf.writestring("return ");
|
|
if (p.storageClass & STCout)
|
|
buf.writestring("out ");
|
|
else if (p.storageClass & STCref)
|
|
buf.writestring("ref ");
|
|
else if (p.storageClass & STCin)
|
|
buf.writestring("in ");
|
|
else if (p.storageClass & STClazy)
|
|
buf.writestring("lazy ");
|
|
else if (p.storageClass & STCalias)
|
|
buf.writestring("alias ");
|
|
StorageClass stc = p.storageClass;
|
|
if (p.type && p.type.mod & MODshared)
|
|
stc &= ~STCshared;
|
|
if (stcToBuffer(buf, stc & (STCconst | STCimmutable | STCwild | STCshared | STCscope)))
|
|
buf.writeByte(' ');
|
|
if (p.storageClass & STCalias)
|
|
{
|
|
if (p.ident)
|
|
buf.writestring(p.ident.toChars());
|
|
}
|
|
else if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident.len > 3 && strncmp((cast(TypeIdentifier)p.type).ident.string, "__T", 3) == 0)
|
|
{
|
|
// print parameter name, instead of undetermined type parameter
|
|
buf.writestring(p.ident.toChars());
|
|
}
|
|
else
|
|
typeToBuffer(p.type, p.ident);
|
|
if (p.defaultArg)
|
|
{
|
|
buf.writestring(" = ");
|
|
p.defaultArg.accept(this);
|
|
}
|
|
}
|
|
|
|
void parametersToBuffer(Parameters* parameters, int varargs)
|
|
{
|
|
buf.writeByte('(');
|
|
if (parameters)
|
|
{
|
|
size_t dim = Parameter.dim(parameters);
|
|
foreach (i; 0 .. dim)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
Parameter fparam = Parameter.getNth(parameters, i);
|
|
fparam.accept(this);
|
|
}
|
|
if (varargs)
|
|
{
|
|
if (parameters.dim && varargs == 1)
|
|
buf.writestring(", ");
|
|
buf.writestring("...");
|
|
}
|
|
}
|
|
buf.writeByte(')');
|
|
}
|
|
|
|
override void visit(Module m)
|
|
{
|
|
if (m.md)
|
|
{
|
|
if (m.userAttribDecl)
|
|
{
|
|
buf.writestring("@(");
|
|
argsToBuffer(m.userAttribDecl.atts);
|
|
buf.writeByte(')');
|
|
buf.writenl();
|
|
}
|
|
if (m.md.isdeprecated)
|
|
{
|
|
if (m.md.msg)
|
|
{
|
|
buf.writestring("deprecated(");
|
|
m.md.msg.accept(this);
|
|
buf.writestring(") ");
|
|
}
|
|
else
|
|
buf.writestring("deprecated ");
|
|
}
|
|
buf.writestring("module ");
|
|
buf.writestring(m.md.toChars());
|
|
buf.writeByte(';');
|
|
buf.writenl();
|
|
}
|
|
foreach (s; *m.members)
|
|
{
|
|
s.accept(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern (C++) void toCBuffer(Statement s, OutBuffer* buf, HdrGenState* hgs)
|
|
{
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
|
|
s.accept(v);
|
|
}
|
|
|
|
extern (C++) void toCBuffer(Type t, OutBuffer* buf, Identifier ident, HdrGenState* hgs)
|
|
{
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
|
|
v.typeToBuffer(t, ident);
|
|
}
|
|
|
|
extern (C++) void toCBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs)
|
|
{
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
|
|
s.accept(v);
|
|
}
|
|
|
|
// used from TemplateInstance::toChars() and TemplateMixin::toChars()
|
|
extern (C++) void toCBufferInstance(TemplateInstance ti, OutBuffer* buf, bool qualifyTypes = false)
|
|
{
|
|
HdrGenState hgs;
|
|
hgs.fullQual = qualifyTypes;
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs);
|
|
v.visit(ti);
|
|
}
|
|
|
|
extern (C++) void toCBuffer(Initializer iz, OutBuffer* buf, HdrGenState* hgs)
|
|
{
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
|
|
iz.accept(v);
|
|
}
|
|
|
|
extern (C++) bool stcToBuffer(OutBuffer* buf, StorageClass stc)
|
|
{
|
|
bool result = false;
|
|
while (stc)
|
|
{
|
|
const(char)* p = stcToChars(stc);
|
|
if (!p) // there's no visible storage classes
|
|
break;
|
|
if (!result)
|
|
result = true;
|
|
else
|
|
buf.writeByte(' ');
|
|
buf.writestring(p);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*************************************************
|
|
* Pick off one of the storage classes from stc,
|
|
* and return a pointer to a string representation of it.
|
|
* stc is reduced by the one picked.
|
|
*/
|
|
extern (C++) const(char)* stcToChars(ref StorageClass stc)
|
|
{
|
|
struct SCstring
|
|
{
|
|
StorageClass stc;
|
|
TOK tok;
|
|
const(char)* id;
|
|
}
|
|
|
|
static __gshared SCstring* table =
|
|
[
|
|
SCstring(STCauto, TOKauto),
|
|
SCstring(STCscope, TOKscope),
|
|
SCstring(STCstatic, TOKstatic),
|
|
SCstring(STCextern, TOKextern),
|
|
SCstring(STCconst, TOKconst),
|
|
SCstring(STCfinal, TOKfinal),
|
|
SCstring(STCabstract, TOKabstract),
|
|
SCstring(STCsynchronized, TOKsynchronized),
|
|
SCstring(STCdeprecated, TOKdeprecated),
|
|
SCstring(STCoverride, TOKoverride),
|
|
SCstring(STClazy, TOKlazy),
|
|
SCstring(STCalias, TOKalias),
|
|
SCstring(STCout, TOKout),
|
|
SCstring(STCin, TOKin),
|
|
SCstring(STCmanifest, TOKenum),
|
|
SCstring(STCimmutable, TOKimmutable),
|
|
SCstring(STCshared, TOKshared),
|
|
SCstring(STCnothrow, TOKnothrow),
|
|
SCstring(STCwild, TOKwild),
|
|
SCstring(STCpure, TOKpure),
|
|
SCstring(STCref, TOKref),
|
|
SCstring(STCtls),
|
|
SCstring(STCgshared, TOKgshared),
|
|
SCstring(STCnogc, TOKat, "@nogc"),
|
|
SCstring(STCproperty, TOKat, "@property"),
|
|
SCstring(STCsafe, TOKat, "@safe"),
|
|
SCstring(STCtrusted, TOKat, "@trusted"),
|
|
SCstring(STCsystem, TOKat, "@system"),
|
|
SCstring(STCdisable, TOKat, "@disable"),
|
|
SCstring(0, TOKreserved)
|
|
];
|
|
for (int i = 0; table[i].stc; i++)
|
|
{
|
|
StorageClass tbl = table[i].stc;
|
|
assert(tbl & STCStorageClass);
|
|
if (stc & tbl)
|
|
{
|
|
stc &= ~tbl;
|
|
if (tbl == STCtls) // TOKtls was removed
|
|
return "__thread";
|
|
TOK tok = table[i].tok;
|
|
if (tok == TOKat)
|
|
return table[i].id;
|
|
else
|
|
return Token.toChars(tok);
|
|
}
|
|
}
|
|
//printf("stc = %llx\n", stc);
|
|
return null;
|
|
}
|
|
|
|
extern (C++) void trustToBuffer(OutBuffer* buf, TRUST trust)
|
|
{
|
|
const(char)* p = trustToChars(trust);
|
|
if (p)
|
|
buf.writestring(p);
|
|
}
|
|
|
|
extern (C++) const(char)* trustToChars(TRUST trust)
|
|
{
|
|
switch (trust)
|
|
{
|
|
case TRUSTdefault:
|
|
return null;
|
|
case TRUSTsystem:
|
|
return "@system";
|
|
case TRUSTtrusted:
|
|
return "@trusted";
|
|
case TRUSTsafe:
|
|
return "@safe";
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
extern (C++) void linkageToBuffer(OutBuffer* buf, LINK linkage)
|
|
{
|
|
const(char)* p = linkageToChars(linkage);
|
|
if (p)
|
|
{
|
|
buf.writestring("extern (");
|
|
buf.writestring(p);
|
|
buf.writeByte(')');
|
|
}
|
|
}
|
|
|
|
extern (C++) const(char)* linkageToChars(LINK linkage)
|
|
{
|
|
switch (linkage)
|
|
{
|
|
case LINKdefault:
|
|
return null;
|
|
case LINKd:
|
|
return "D";
|
|
case LINKc:
|
|
return "C";
|
|
case LINKcpp:
|
|
return "C++";
|
|
case LINKwindows:
|
|
return "Windows";
|
|
case LINKpascal:
|
|
return "Pascal";
|
|
case LINKobjc:
|
|
return "Objective-C";
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
extern (C++) void protectionToBuffer(OutBuffer* buf, Prot prot)
|
|
{
|
|
const(char)* p = protectionToChars(prot.kind);
|
|
if (p)
|
|
buf.writestring(p);
|
|
if (prot.kind == PROTpackage && prot.pkg)
|
|
{
|
|
buf.writeByte('(');
|
|
buf.writestring(prot.pkg.toPrettyChars(true));
|
|
buf.writeByte(')');
|
|
}
|
|
}
|
|
|
|
extern (C++) const(char)* protectionToChars(PROTKIND kind)
|
|
{
|
|
switch (kind)
|
|
{
|
|
case PROTundefined:
|
|
return null;
|
|
case PROTnone:
|
|
return "none";
|
|
case PROTprivate:
|
|
return "private";
|
|
case PROTpackage:
|
|
return "package";
|
|
case PROTprotected:
|
|
return "protected";
|
|
case PROTpublic:
|
|
return "public";
|
|
case PROTexport:
|
|
return "export";
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
// Print the full function signature with correct ident, attributes and template args
|
|
extern (C++) void functionToBufferFull(TypeFunction tf, OutBuffer* buf, Identifier ident, HdrGenState* hgs, TemplateDeclaration td)
|
|
{
|
|
//printf("TypeFunction::toCBuffer() this = %p\n", this);
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
|
|
v.visitFuncIdentWithPrefix(tf, ident, td, true);
|
|
}
|
|
|
|
// ident is inserted before the argument list and will be "function" or "delegate" for a type
|
|
extern (C++) void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ident)
|
|
{
|
|
HdrGenState hgs;
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs);
|
|
v.visitFuncIdentWithPostfix(tf, ident);
|
|
}
|
|
|
|
extern (C++) void toCBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
|
|
{
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
|
|
e.accept(v);
|
|
}
|
|
|
|
/**************************************************
|
|
* Write out argument types to buf.
|
|
*/
|
|
extern (C++) void argExpTypesToCBuffer(OutBuffer* buf, Expressions* arguments)
|
|
{
|
|
if (!arguments || !arguments.dim)
|
|
return;
|
|
HdrGenState hgs;
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs);
|
|
foreach (i, arg; *arguments)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
v.typeToBuffer(arg.type, null);
|
|
}
|
|
}
|
|
|
|
extern (C++) void toCBuffer(TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs)
|
|
{
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs);
|
|
tp.accept(v);
|
|
}
|
|
|
|
extern (C++) void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects)
|
|
{
|
|
if (!objects || !objects.dim)
|
|
return;
|
|
HdrGenState hgs;
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs);
|
|
foreach (i, o; *objects)
|
|
{
|
|
if (i)
|
|
buf.writestring(", ");
|
|
v.objectToBuffer(o);
|
|
}
|
|
}
|
|
|
|
extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int varargs)
|
|
{
|
|
OutBuffer buf;
|
|
HdrGenState hgs;
|
|
scope PrettyPrintVisitor v = new PrettyPrintVisitor(&buf, &hgs);
|
|
v.parametersToBuffer(parameters, varargs);
|
|
return buf.extractString();
|
|
}
|