| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| // 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.identifier; | ||
|
|
||
| import core.stdc.stdio, core.stdc.string; | ||
| import ddmd.globals, ddmd.id, ddmd.root.outbuffer, ddmd.root.rootobject, ddmd.root.stringtable, ddmd.tokens; | ||
|
|
||
| extern (C++) final class Identifier : RootObject | ||
| { | ||
| public: | ||
| int value; | ||
| const(char)* string; | ||
| size_t len; | ||
|
|
||
| extern (D) this(const(char)* string, int value) | ||
| { | ||
| //printf("Identifier('%s', %d)\n", string, value); | ||
| this.string = string; | ||
| this.value = value; | ||
| this.len = strlen(string); | ||
| } | ||
|
|
||
| static Identifier create(const(char)* string, int value) | ||
| { | ||
| return new Identifier(string, value); | ||
| } | ||
|
|
||
| bool equals(RootObject o) | ||
| { | ||
| return this == o || strncmp(string, o.toChars(), len + 1) == 0; | ||
| } | ||
|
|
||
| int compare(RootObject o) | ||
| { | ||
| return strncmp(string, o.toChars(), len + 1); | ||
| } | ||
|
|
||
| void print() | ||
| { | ||
| fprintf(stderr, "%s", string); | ||
| } | ||
|
|
||
| char* toChars() | ||
| { | ||
| return cast(char*)string; | ||
| } | ||
|
|
||
| const(char)* toHChars2() | ||
| { | ||
| const(char)* p = null; | ||
| if (this == Id.ctor) | ||
| p = "this"; | ||
| else if (this == Id.dtor) | ||
| p = "~this"; | ||
| else if (this == Id.unitTest) | ||
| p = "unittest"; | ||
| else if (this == Id.dollar) | ||
| p = "$"; | ||
| else if (this == Id.withSym) | ||
| p = "with"; | ||
| else if (this == Id.result) | ||
| p = "result"; | ||
| else if (this == Id.returnLabel) | ||
| p = "return"; | ||
| else | ||
| { | ||
| p = toChars(); | ||
| if (*p == '_') | ||
| { | ||
| if (strncmp(p, "_staticCtor", 11) == 0) | ||
| p = "static this"; | ||
| else if (strncmp(p, "_staticDtor", 11) == 0) | ||
| p = "static ~this"; | ||
| else if (strncmp(p, "__invariant", 11) == 0) | ||
| p = "invariant"; | ||
| } | ||
| } | ||
| return p; | ||
| } | ||
|
|
||
| int dyncast() | ||
| { | ||
| return DYNCAST_IDENTIFIER; | ||
| } | ||
|
|
||
| extern (C++) static __gshared StringTable stringtable; | ||
|
|
||
| static Identifier generateId(const(char)* prefix) | ||
| { | ||
| static __gshared size_t i; | ||
| return generateId(prefix, ++i); | ||
| } | ||
|
|
||
| static Identifier generateId(const(char)* prefix, size_t i) | ||
| { | ||
| OutBuffer buf; | ||
| buf.writestring(prefix); | ||
| buf.printf("%llu", cast(ulong)i); | ||
| char* id = buf.peekString(); | ||
| return idPool(id); | ||
| } | ||
|
|
||
| /******************************************** | ||
| * Create an identifier in the string table. | ||
| */ | ||
| static Identifier idPool(const(char)* s) | ||
| { | ||
| return idPool(s, strlen(s)); | ||
| } | ||
|
|
||
| static Identifier idPool(const(char)* s, size_t len) | ||
| { | ||
| StringValue* sv = stringtable.update(s, len); | ||
| Identifier id = cast(Identifier)sv.ptrvalue; | ||
| if (!id) | ||
| { | ||
| id = new Identifier(sv.toDchars(), TOKidentifier); | ||
| sv.ptrvalue = cast(char*)id; | ||
| } | ||
| return id; | ||
| } | ||
|
|
||
| static Identifier lookup(const(char)* s, size_t len) | ||
| { | ||
| StringValue* sv = stringtable.lookup(s, len); | ||
| if (!sv) | ||
| return null; | ||
| return cast(Identifier)sv.ptrvalue; | ||
| } | ||
|
|
||
| static void initTable() | ||
| { | ||
| stringtable._init(28000); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| // 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.imphint; | ||
|
|
||
| import core.stdc.string; | ||
|
|
||
| /****************************************** | ||
| * Looks for undefined identifier s to see | ||
| * if it might be undefined because an import | ||
| * was not specified. | ||
| * Not meant to be a comprehensive list of names in each module, | ||
| * just the most common ones. | ||
| */ | ||
| extern (C++) const(char)* importHint(const(char)* s) | ||
| { | ||
| static __gshared const(char)** modules = ["core.stdc.stdio", "std.stdio", "std.math", "core.vararg", null]; | ||
| static __gshared const(char)** names = | ||
| [ | ||
| "printf", | ||
| null, | ||
| "writeln", | ||
| null, | ||
| "sin", | ||
| "cos", | ||
| "sqrt", | ||
| "fabs", | ||
| null, | ||
| "__va_argsave_t", | ||
| null | ||
| ]; | ||
| int m = 0; | ||
| for (int n = 0; modules[m]; n++) | ||
| { | ||
| const(char)* p = names[n]; | ||
| if (p is null) | ||
| { | ||
| m++; | ||
| continue; | ||
| } | ||
| assert(modules[m]); | ||
| if (strcmp(s, p) == 0) | ||
| return modules[m]; | ||
| } | ||
| return null; // didn't find it | ||
| } | ||
|
|
||
| version (unittest) | ||
| { | ||
| extern (C++) void unittest_importHint() | ||
| { | ||
| const(char)* p; | ||
| p = importHint("printf"); | ||
| assert(p); | ||
| p = importHint("fabs"); | ||
| assert(p); | ||
| p = importHint("xxxxx"); | ||
| assert(!p); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| // 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.lib; | ||
|
|
||
| import ddmd.globals; | ||
|
|
||
| extern (C++) Library LibOMF_factory(); | ||
| extern (C++) Library LibElf_factory(); | ||
| extern (C++) Library LibMSCoff_factory(); | ||
| extern (C++) Library LibMach_factory(); | ||
|
|
||
| extern (C++) class Library | ||
| { | ||
| public: | ||
| final static Library factory() | ||
| { | ||
| static if (TARGET_WINDOS) | ||
| { | ||
| return global.params.is64bit ? LibMSCoff_factory() : LibOMF_factory(); | ||
| } | ||
| else static if (TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS) | ||
| { | ||
| return LibElf_factory(); | ||
| } | ||
| else static if (TARGET_OSX) | ||
| { | ||
| return LibMach_factory(); | ||
| } | ||
| else | ||
| { | ||
| assert(0); // unsupported system | ||
| } | ||
| } | ||
|
|
||
| abstract void setFilename(const(char)* dir, const(char)* filename); | ||
|
|
||
| abstract void addObject(const(char)* module_name, void* buf, size_t buflen); | ||
|
|
||
| abstract void addLibrary(void* buf, size_t buflen); | ||
|
|
||
| abstract void write(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,187 @@ | ||
| // 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.nogc; | ||
|
|
||
| import ddmd.apply, ddmd.declaration, ddmd.dscope, ddmd.expression, ddmd.func, ddmd.globals, ddmd.id, ddmd.identifier, ddmd.init, ddmd.mtype, ddmd.sapply, ddmd.statement, ddmd.tokens, ddmd.visitor; | ||
|
|
||
| /************************************** | ||
| * Look for GC-allocations | ||
| */ | ||
| extern (C++) final class NOGCVisitor : StoppableVisitor | ||
| { | ||
| alias visit = super.visit; | ||
| public: | ||
| FuncDeclaration f; | ||
| bool err; | ||
|
|
||
| extern (D) this(FuncDeclaration f) | ||
| { | ||
| this.f = f; | ||
| this.err = false; | ||
| } | ||
|
|
||
| void doCond(Expression exp) | ||
| { | ||
| if (exp) | ||
| walkPostorder(exp, this); | ||
| } | ||
|
|
||
| void visit(Expression e) | ||
| { | ||
| } | ||
|
|
||
| void visit(DeclarationExp e) | ||
| { | ||
| // Note that, walkPostorder does not support DeclarationExp today. | ||
| VarDeclaration v = e.declaration.isVarDeclaration(); | ||
| if (v && !(v.storage_class & STCmanifest) && !v.isDataseg() && v._init) | ||
| { | ||
| if (v._init.isVoidInitializer()) | ||
| { | ||
| } | ||
| else | ||
| { | ||
| ExpInitializer ei = v._init.isExpInitializer(); | ||
| assert(ei); | ||
| doCond(ei.exp); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void visit(CallExp e) | ||
| { | ||
| } | ||
|
|
||
| void visit(ArrayLiteralExp e) | ||
| { | ||
| if (e.type.ty != Tarray || !e.elements || !e.elements.dim) | ||
| return; | ||
| if (f.setGC()) | ||
| { | ||
| e.error("array literal in @nogc function %s may cause GC allocation", f.toChars()); | ||
| err = true; | ||
| return; | ||
| } | ||
| f.printGCUsage(e.loc, "array literal may cause GC allocation"); | ||
| } | ||
|
|
||
| void visit(AssocArrayLiteralExp e) | ||
| { | ||
| if (!e.keys.dim) | ||
| return; | ||
| if (f.setGC()) | ||
| { | ||
| e.error("associative array literal in @nogc function %s may cause GC allocation", f.toChars()); | ||
| err = true; | ||
| return; | ||
| } | ||
| f.printGCUsage(e.loc, "associative array literal may cause GC allocation"); | ||
| } | ||
|
|
||
| void visit(NewExp e) | ||
| { | ||
| if (e.member && !e.member.isNogc() && f.setGC()) | ||
| { | ||
| // @nogc-ness is already checked in NewExp::semantic | ||
| return; | ||
| } | ||
| if (e.onstack) | ||
| return; | ||
| if (e.allocator) | ||
| return; | ||
| if (f.setGC()) | ||
| { | ||
| e.error("cannot use 'new' in @nogc function %s", f.toChars()); | ||
| err = true; | ||
| return; | ||
| } | ||
| f.printGCUsage(e.loc, "'new' causes GC allocation"); | ||
| } | ||
|
|
||
| void visit(DeleteExp e) | ||
| { | ||
| if (e.e1.op == TOKvar) | ||
| { | ||
| VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration(); | ||
| if (v && v.onstack) | ||
| return; // delete for scope allocated class object | ||
| } | ||
| if (f.setGC()) | ||
| { | ||
| e.error("cannot use 'delete' in @nogc function %s", f.toChars()); | ||
| err = true; | ||
| return; | ||
| } | ||
| f.printGCUsage(e.loc, "'delete' requires GC"); | ||
| } | ||
|
|
||
| void visit(IndexExp e) | ||
| { | ||
| Type t1b = e.e1.type.toBasetype(); | ||
| if (t1b.ty == Taarray) | ||
| { | ||
| if (f.setGC()) | ||
| { | ||
| e.error("indexing an associative array in @nogc function %s may cause GC allocation", f.toChars()); | ||
| err = true; | ||
| return; | ||
| } | ||
| f.printGCUsage(e.loc, "indexing an associative array may cause GC allocation"); | ||
| } | ||
| } | ||
|
|
||
| void visit(AssignExp e) | ||
| { | ||
| if (e.e1.op == TOKarraylength) | ||
| { | ||
| if (f.setGC()) | ||
| { | ||
| e.error("setting 'length' in @nogc function %s may cause GC allocation", f.toChars()); | ||
| err = true; | ||
| return; | ||
| } | ||
| f.printGCUsage(e.loc, "setting 'length' may cause GC allocation"); | ||
| } | ||
| } | ||
|
|
||
| void visit(CatAssignExp e) | ||
| { | ||
| if (f.setGC()) | ||
| { | ||
| e.error("cannot use operator ~= in @nogc function %s", f.toChars()); | ||
| err = true; | ||
| return; | ||
| } | ||
| f.printGCUsage(e.loc, "operator ~= may cause GC allocation"); | ||
| } | ||
|
|
||
| void visit(CatExp e) | ||
| { | ||
| if (f.setGC()) | ||
| { | ||
| e.error("cannot use operator ~ in @nogc function %s", f.toChars()); | ||
| err = true; | ||
| return; | ||
| } | ||
| f.printGCUsage(e.loc, "operator ~ may cause GC allocation"); | ||
| } | ||
| } | ||
|
|
||
| extern (C++) Expression checkGC(Scope* sc, Expression e) | ||
| { | ||
| FuncDeclaration f = sc.func; | ||
| if (e && e.op != TOKerror && f && sc.intypeof != 1 && !(sc.flags & SCOPEctfe) && (f.type.ty == Tfunction && (cast(TypeFunction)f.type).isnogc || (f.flags & FUNCFLAGnogcInprocess) || global.params.vgc)) | ||
| { | ||
| scope NOGCVisitor gcv = new NOGCVisitor(f); | ||
| walkPostorder(e, gcv); | ||
| if (gcv.err) | ||
| return new ErrorExp(); | ||
| } | ||
| return e; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,226 @@ | ||
| // 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.nspace; | ||
|
|
||
| import ddmd.aggregate, ddmd.arraytypes, ddmd.dscope, ddmd.dsymbol, ddmd.globals, ddmd.hdrgen, ddmd.identifier, ddmd.root.outbuffer, ddmd.visitor; | ||
|
|
||
| private enum LOG = false; | ||
|
|
||
| /* A namespace corresponding to a C++ namespace. | ||
| * Implies extern(C++). | ||
| */ | ||
| extern (C++) final class Nspace : ScopeDsymbol | ||
| { | ||
| public: | ||
| /* This implements namespaces. | ||
| */ | ||
| extern (D) this(Loc loc, Identifier ident, Dsymbols* members) | ||
| { | ||
| super(ident); | ||
| //printf("Nspace::Nspace(ident = %s)\n", ident->toChars()); | ||
| this.loc = loc; | ||
| this.members = members; | ||
| } | ||
|
|
||
| Dsymbol syntaxCopy(Dsymbol s) | ||
| { | ||
| auto ns = new Nspace(loc, ident, null); | ||
| return ScopeDsymbol.syntaxCopy(ns); | ||
| } | ||
|
|
||
| void semantic(Scope* sc) | ||
| { | ||
| if (semanticRun >= PASSsemantic) | ||
| return; | ||
| semanticRun = PASSsemantic; | ||
| static if (LOG) | ||
| { | ||
| printf("+Nspace::semantic('%s')\n", toChars()); | ||
| } | ||
| if (_scope) | ||
| { | ||
| sc = _scope; | ||
| _scope = null; | ||
| } | ||
| parent = sc.parent; | ||
| if (members) | ||
| { | ||
| if (!symtab) | ||
| symtab = new DsymbolTable(); | ||
| // The namespace becomes 'imported' into the enclosing scope | ||
| for (Scope* sce = sc; 1; sce = sce.enclosing) | ||
| { | ||
| ScopeDsymbol sds = cast(ScopeDsymbol)sce.scopesym; | ||
| if (sds) | ||
| { | ||
| sds.importScope(this, Prot(PROTpublic)); | ||
| break; | ||
| } | ||
| } | ||
| assert(sc); | ||
| sc = sc.push(this); | ||
| sc.linkage = LINKcpp; // note that namespaces imply C++ linkage | ||
| sc.parent = this; | ||
| for (size_t i = 0; i < members.dim; i++) | ||
| { | ||
| Dsymbol s = (*members)[i]; | ||
| //printf("add %s to scope %s\n", s->toChars(), toChars()); | ||
| s.addMember(sc, this); | ||
| } | ||
| for (size_t i = 0; i < members.dim; i++) | ||
| { | ||
| Dsymbol s = (*members)[i]; | ||
| s.setScope(sc); | ||
| } | ||
| for (size_t i = 0; i < members.dim; i++) | ||
| { | ||
| Dsymbol s = (*members)[i]; | ||
| s.importAll(sc); | ||
| } | ||
| for (size_t i = 0; i < members.dim; i++) | ||
| { | ||
| Dsymbol s = (*members)[i]; | ||
| static if (LOG) | ||
| { | ||
| printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); | ||
| } | ||
| s.semantic(sc); | ||
| } | ||
| sc.pop(); | ||
| } | ||
| static if (LOG) | ||
| { | ||
| printf("-Nspace::semantic('%s')\n", toChars()); | ||
| } | ||
| } | ||
|
|
||
| void semantic2(Scope* sc) | ||
| { | ||
| if (semanticRun >= PASSsemantic2) | ||
| return; | ||
| semanticRun = PASSsemantic2; | ||
| static if (LOG) | ||
| { | ||
| printf("+Nspace::semantic2('%s')\n", toChars()); | ||
| } | ||
| if (members) | ||
| { | ||
| assert(sc); | ||
| sc = sc.push(this); | ||
| sc.linkage = LINKcpp; | ||
| for (size_t i = 0; i < members.dim; i++) | ||
| { | ||
| Dsymbol s = (*members)[i]; | ||
| static if (LOG) | ||
| { | ||
| printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); | ||
| } | ||
| s.semantic2(sc); | ||
| } | ||
| sc.pop(); | ||
| } | ||
| static if (LOG) | ||
| { | ||
| printf("-Nspace::semantic2('%s')\n", toChars()); | ||
| } | ||
| } | ||
|
|
||
| void semantic3(Scope* sc) | ||
| { | ||
| if (semanticRun >= PASSsemantic3) | ||
| return; | ||
| semanticRun = PASSsemantic3; | ||
| static if (LOG) | ||
| { | ||
| printf("Nspace::semantic3('%s')\n", toChars()); | ||
| } | ||
| if (members) | ||
| { | ||
| sc = sc.push(this); | ||
| sc.linkage = LINKcpp; | ||
| for (size_t i = 0; i < members.dim; i++) | ||
| { | ||
| Dsymbol s = (*members)[i]; | ||
| s.semantic3(sc); | ||
| } | ||
| sc.pop(); | ||
| } | ||
| } | ||
|
|
||
| bool oneMember(Dsymbol* ps, Identifier ident) | ||
| { | ||
| return Dsymbol.oneMember(ps, ident); | ||
| } | ||
|
|
||
| int apply(Dsymbol_apply_ft_t fp, void* param) | ||
| { | ||
| if (members) | ||
| { | ||
| for (size_t i = 0; i < members.dim; i++) | ||
| { | ||
| Dsymbol s = (*members)[i]; | ||
| if (s) | ||
| { | ||
| if (s.apply(fp, param)) | ||
| return 1; | ||
| } | ||
| } | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| bool hasPointers() | ||
| { | ||
| //printf("Nspace::hasPointers() %s\n", toChars()); | ||
| if (members) | ||
| { | ||
| for (size_t i = 0; i < members.dim; i++) | ||
| { | ||
| Dsymbol s = (*members)[i]; | ||
| //printf(" s = %s %s\n", s->kind(), s->toChars()); | ||
| if (s.hasPointers()) | ||
| { | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) | ||
| { | ||
| //printf("Nspace::setFieldOffset() %s\n", toChars()); | ||
| if (_scope) // if fwd reference | ||
| semantic(null); // try to resolve it | ||
| if (members) | ||
| { | ||
| for (size_t i = 0; i < members.dim; i++) | ||
| { | ||
| Dsymbol s = (*members)[i]; | ||
| //printf("\t%s\n", s->toChars()); | ||
| s.setFieldOffset(ad, poffset, isunion); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| const(char)* kind() | ||
| { | ||
| return "namespace"; | ||
| } | ||
|
|
||
| Nspace isNspace() | ||
| { | ||
| return this; | ||
| } | ||
|
|
||
| void accept(Visitor v) | ||
| { | ||
| v.visit(this); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,213 @@ | ||
| // 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.objc; | ||
|
|
||
| import ddmd.arraytypes, ddmd.cond, ddmd.dclass, ddmd.dmangle, ddmd.dmodule, ddmd.dscope, ddmd.dstruct, ddmd.expression, ddmd.func, ddmd.globals, ddmd.id, ddmd.identifier, ddmd.mtype, ddmd.root.outbuffer, ddmd.root.stringtable; | ||
|
|
||
| extern(C++) void objc_initSymbols(); | ||
|
|
||
| struct ObjcSelector | ||
| { | ||
| // MARK: Selector | ||
| extern (C++) static __gshared StringTable stringtable; | ||
| extern (C++) static __gshared StringTable vTableDispatchSelectors; | ||
| extern (C++) static __gshared int incnum = 0; | ||
| const(char)* stringvalue; | ||
| size_t stringlen; | ||
| size_t paramCount; | ||
|
|
||
| extern (C++) static void _init() | ||
| { | ||
| stringtable._init(); | ||
| } | ||
|
|
||
| extern (D) this(const(char)* sv, size_t len, size_t pcount) | ||
| { | ||
| stringvalue = sv; | ||
| stringlen = len; | ||
| paramCount = pcount; | ||
| } | ||
|
|
||
| extern (C++) static ObjcSelector* lookup(const(char)* s) | ||
| { | ||
| size_t len = 0; | ||
| size_t pcount = 0; | ||
| const(char)* i = s; | ||
| while (*i != 0) | ||
| { | ||
| ++len; | ||
| if (*i == ':') | ||
| ++pcount; | ||
| ++i; | ||
| } | ||
| return lookup(s, len, pcount); | ||
| } | ||
|
|
||
| extern (C++) static ObjcSelector* lookup(const(char)* s, size_t len, size_t pcount) | ||
| { | ||
| StringValue* sv = stringtable.update(s, len); | ||
| ObjcSelector* sel = cast(ObjcSelector*)sv.ptrvalue; | ||
| if (!sel) | ||
| { | ||
| sel = new ObjcSelector(sv.toDchars(), len, pcount); | ||
| sv.ptrvalue = cast(char*)sel; | ||
| } | ||
| return sel; | ||
| } | ||
|
|
||
| extern (C++) static ObjcSelector* create(FuncDeclaration fdecl) | ||
| { | ||
| OutBuffer buf; | ||
| size_t pcount = 0; | ||
| TypeFunction ftype = cast(TypeFunction)fdecl.type; | ||
| // Special case: property setter | ||
| if (ftype.isproperty && ftype.parameters && ftype.parameters.dim == 1) | ||
| { | ||
| // rewrite "identifier" as "setIdentifier" | ||
| char firstChar = fdecl.ident.string[0]; | ||
| if (firstChar >= 'a' && firstChar <= 'z') | ||
| firstChar = cast(char)(firstChar - 'a' + 'A'); | ||
| buf.writestring("set"); | ||
| buf.writeByte(firstChar); | ||
| buf.write(fdecl.ident.string + 1, fdecl.ident.len - 1); | ||
| buf.writeByte(':'); | ||
| goto Lcomplete; | ||
| } | ||
| // write identifier in selector | ||
| buf.write(fdecl.ident.string, fdecl.ident.len); | ||
| // add mangled type and colon for each parameter | ||
| if (ftype.parameters && ftype.parameters.dim) | ||
| { | ||
| buf.writeByte('_'); | ||
| Parameters* arguments = ftype.parameters; | ||
| size_t dim = Parameter.dim(arguments); | ||
| for (size_t i = 0; i < dim; i++) | ||
| { | ||
| Parameter arg = Parameter.getNth(arguments, i); | ||
| mangleToBuffer(arg.type, &buf); | ||
| buf.writeByte(':'); | ||
| } | ||
| pcount = dim; | ||
| } | ||
| Lcomplete: | ||
| buf.writeByte('\0'); | ||
| return lookup(cast(const(char)*)buf.data, buf.size, pcount); | ||
| } | ||
| } | ||
|
|
||
| struct Objc_ClassDeclaration | ||
| { | ||
| // true if this is an Objective-C class/interface | ||
| bool objc; | ||
|
|
||
| // MARK: Objc_ClassDeclaration | ||
| extern (C++) bool isInterface() | ||
| { | ||
| return objc; | ||
| } | ||
| } | ||
|
|
||
| struct Objc_FuncDeclaration | ||
| { | ||
| FuncDeclaration fdecl; | ||
| // Objective-C method selector (member function only) | ||
| ObjcSelector* selector; | ||
|
|
||
| extern (D) this(FuncDeclaration fdecl) | ||
| { | ||
| this.fdecl = fdecl; | ||
| selector = null; | ||
| } | ||
| } | ||
|
|
||
| // MARK: semantic | ||
| extern (C++) void objc_ClassDeclaration_semantic_PASSinit_LINKobjc(ClassDeclaration cd) | ||
| { | ||
| cd.objc.objc = true; | ||
| } | ||
|
|
||
| extern (C++) void objc_InterfaceDeclaration_semantic_objcExtern(InterfaceDeclaration id, Scope* sc) | ||
| { | ||
| if (sc.linkage == LINKobjc) | ||
| id.objc.objc = true; | ||
| } | ||
|
|
||
| // MARK: semantic | ||
| extern (C++) void objc_FuncDeclaration_semantic_setSelector(FuncDeclaration fd, Scope* sc) | ||
| { | ||
| if (!fd.userAttribDecl) | ||
| return; | ||
| Expressions* udas = fd.userAttribDecl.getAttributes(); | ||
| arrayExpressionSemantic(udas, sc, true); | ||
| for (size_t i = 0; i < udas.dim; i++) | ||
| { | ||
| Expression uda = (*udas)[i]; | ||
| assert(uda.type); | ||
| if (uda.type.ty != Ttuple) | ||
| continue; | ||
| Expressions* exps = (cast(TupleExp)uda).exps; | ||
| for (size_t j = 0; j < exps.dim; j++) | ||
| { | ||
| Expression e = (*exps)[j]; | ||
| assert(e.type); | ||
| if (e.type.ty != Tstruct) | ||
| continue; | ||
| StructLiteralExp literal = cast(StructLiteralExp)e; | ||
| assert(literal.sd); | ||
| if (!objc_isUdaSelector(literal.sd)) | ||
| continue; | ||
| if (fd.objc.selector) | ||
| { | ||
| fd.error("can only have one Objective-C selector per method"); | ||
| return; | ||
| } | ||
| assert(literal.elements.dim == 1); | ||
| StringExp se = (*literal.elements)[0].toStringExp(); | ||
| assert(se); | ||
| fd.objc.selector = ObjcSelector.lookup(cast(const(char)*)se.toUTF8(sc).string); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| extern (C++) bool objc_isUdaSelector(StructDeclaration sd) | ||
| { | ||
| if (sd.ident != Id.udaSelector || !sd.parent) | ||
| return false; | ||
| Module _module = sd.parent.isModule(); | ||
| return _module && _module.isCoreModule(Id.attribute); | ||
| } | ||
|
|
||
| extern (C++) void objc_FuncDeclaration_semantic_validateSelector(FuncDeclaration fd) | ||
| { | ||
| if (!fd.objc.selector) | ||
| return; | ||
| TypeFunction tf = cast(TypeFunction)fd.type; | ||
| if (fd.objc.selector.paramCount != tf.parameters.dim) | ||
| fd.error("number of colons in Objective-C selector must match number of parameters"); | ||
| if (fd.parent && fd.parent.isTemplateInstance()) | ||
| fd.error("template cannot have an Objective-C selector attached"); | ||
| } | ||
|
|
||
| extern (C++) void objc_FuncDeclaration_semantic_checkLinkage(FuncDeclaration fd) | ||
| { | ||
| if (fd.linkage != LINKobjc && fd.objc.selector) | ||
| fd.error("must have Objective-C linkage to attach a selector"); | ||
| } | ||
|
|
||
| // MARK: init | ||
| extern (C++) void objc_tryMain_dObjc() | ||
| { | ||
| VersionCondition.addPredefinedGlobalIdent("D_ObjectiveC"); | ||
| } | ||
|
|
||
| extern (C++) void objc_tryMain_init() | ||
| { | ||
| objc_initSymbols(); | ||
| ObjcSelector._init(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| // 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.root.aav; | ||
|
|
||
| import core.stdc.stdlib, core.stdc.string; | ||
| import ddmd.root.rmem; | ||
|
|
||
| extern (C++) size_t hash(size_t a) | ||
| { | ||
| a ^= (a >> 20) ^ (a >> 12); | ||
| return a ^ (a >> 7) ^ (a >> 4); | ||
| } | ||
|
|
||
| alias Key = void*; | ||
| alias Value = void*; | ||
|
|
||
| struct aaA | ||
| { | ||
| aaA* next; | ||
| Key key; | ||
| Value value; | ||
| } | ||
|
|
||
| struct AA | ||
| { | ||
| aaA** b; | ||
| size_t b_length; | ||
| size_t nodes; // total number of aaA nodes | ||
| aaA*[4] binit; // initial value of b[] | ||
| aaA aafirst; // a lot of these AA's have only one entry | ||
| } | ||
|
|
||
| /**************************************************** | ||
| * Determine number of entries in associative array. | ||
| */ | ||
| extern (C++) size_t dmd_aaLen(AA* aa) | ||
| { | ||
| return aa ? aa.nodes : 0; | ||
| } | ||
|
|
||
| /************************************************* | ||
| * Get pointer to value in associative array indexed by key. | ||
| * Add entry for key if it is not already there, returning a pointer to a null Value. | ||
| * Create the associative array if it does not already exist. | ||
| */ | ||
| extern (C++) Value* dmd_aaGet(AA** paa, Key key) | ||
| { | ||
| //printf("paa = %p\n", paa); | ||
| if (!*paa) | ||
| { | ||
| AA* a = cast(AA*)mem.xmalloc(AA.sizeof); | ||
| a.b = cast(aaA**)a.binit; | ||
| a.b_length = 4; | ||
| a.nodes = 0; | ||
| a.binit[0] = null; | ||
| a.binit[1] = null; | ||
| a.binit[2] = null; | ||
| a.binit[3] = null; | ||
| *paa = a; | ||
| assert((*paa).b_length == 4); | ||
| } | ||
| //printf("paa = %p, *paa = %p\n", paa, *paa); | ||
| assert((*paa).b_length); | ||
| size_t i = hash(cast(size_t)key) & ((*paa).b_length - 1); | ||
| aaA** pe = &(*paa).b[i]; | ||
| aaA* e; | ||
| while ((e = *pe) !is null) | ||
| { | ||
| if (key == e.key) | ||
| return &e.value; | ||
| pe = &e.next; | ||
| } | ||
| // Not found, create new elem | ||
| //printf("create new one\n"); | ||
| size_t nodes = ++(*paa).nodes; | ||
| e = (nodes != 1) ? cast(aaA*)mem.xmalloc(aaA.sizeof) : &(*paa).aafirst; | ||
| //e = new aaA(); | ||
| e.next = null; | ||
| e.key = key; | ||
| e.value = null; | ||
| *pe = e; | ||
| //printf("length = %d, nodes = %d\n", (*paa)->b_length, nodes); | ||
| if (nodes > (*paa).b_length * 2) | ||
| { | ||
| //printf("rehash\n"); | ||
| dmd_aaRehash(paa); | ||
| } | ||
| return &e.value; | ||
| } | ||
|
|
||
| /************************************************* | ||
| * Get value in associative array indexed by key. | ||
| * Returns NULL if it is not already there. | ||
| */ | ||
| extern (C++) Value dmd_aaGetRvalue(AA* aa, Key key) | ||
| { | ||
| //printf("_aaGetRvalue(key = %p)\n", key); | ||
| if (aa) | ||
| { | ||
| size_t i; | ||
| size_t len = aa.b_length; | ||
| i = hash(cast(size_t)key) & (len - 1); | ||
| aaA* e = aa.b[i]; | ||
| while (e) | ||
| { | ||
| if (key == e.key) | ||
| return e.value; | ||
| e = e.next; | ||
| } | ||
| } | ||
| return null; // not found | ||
| } | ||
|
|
||
| /******************************************** | ||
| * Rehash an array. | ||
| */ | ||
| extern (C++) void dmd_aaRehash(AA** paa) | ||
| { | ||
| //printf("Rehash\n"); | ||
| if (*paa) | ||
| { | ||
| AA* aa = *paa; | ||
| if (aa) | ||
| { | ||
| size_t len = aa.b_length; | ||
| if (len == 4) | ||
| len = 32; | ||
| else | ||
| len *= 4; | ||
| aaA** newb = cast(aaA**)mem.xmalloc(aaA.sizeof * len); | ||
| memset(newb, 0, len * (aaA*).sizeof); | ||
| for (size_t k = 0; k < aa.b_length; k++) | ||
| { | ||
| aaA* e = aa.b[k]; | ||
| while (e) | ||
| { | ||
| aaA* enext = e.next; | ||
| size_t j = hash(cast(size_t)e.key) & (len - 1); | ||
| e.next = newb[j]; | ||
| newb[j] = e; | ||
| e = enext; | ||
| } | ||
| } | ||
| if (aa.b != cast(aaA**)aa.binit) | ||
| mem.xfree(aa.b); | ||
| aa.b = newb; | ||
| aa.b_length = len; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| version (unittest) | ||
| { | ||
| extern (C++) void unittest_aa() | ||
| { | ||
| AA* aa = null; | ||
| Value v = dmd_aaGetRvalue(aa, null); | ||
| assert(!v); | ||
| Value* pv = dmd_aaGet(&aa, null); | ||
| assert(pv); | ||
| *pv = cast(void*)3; | ||
| v = dmd_aaGetRvalue(aa, null); | ||
| assert(v == cast(void*)3); | ||
| } | ||
| } |