mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-09-20 04:10:18 +02:00
Remerged dmd2 frontend using git subtree
This commit is contained in:
+412
@@ -0,0 +1,412 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2012 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "rmem.h"
|
||||||
|
|
||||||
|
#include "enum.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "attrib.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "id.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "module.h"
|
||||||
|
|
||||||
|
#define LOG 0
|
||||||
|
|
||||||
|
/* Code to do access checks
|
||||||
|
*/
|
||||||
|
|
||||||
|
int hasPackageAccess(Scope *sc, Dsymbol *s);
|
||||||
|
|
||||||
|
/****************************************
|
||||||
|
* Return PROT access for Dsymbol smember in this declaration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum PROT AggregateDeclaration::getAccess(Dsymbol *smember)
|
||||||
|
{
|
||||||
|
return PROTpublic;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PROT StructDeclaration::getAccess(Dsymbol *smember)
|
||||||
|
{
|
||||||
|
enum PROT access_ret = PROTnone;
|
||||||
|
|
||||||
|
#if LOG
|
||||||
|
printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n",
|
||||||
|
toChars(), smember->toChars());
|
||||||
|
#endif
|
||||||
|
if (smember->toParent() == this)
|
||||||
|
{
|
||||||
|
access_ret = smember->prot();
|
||||||
|
}
|
||||||
|
else if (smember->isDeclaration()->isStatic())
|
||||||
|
{
|
||||||
|
access_ret = smember->prot();
|
||||||
|
}
|
||||||
|
return access_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PROT ClassDeclaration::getAccess(Dsymbol *smember)
|
||||||
|
{
|
||||||
|
enum PROT access_ret = PROTnone;
|
||||||
|
|
||||||
|
#if LOG
|
||||||
|
printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n",
|
||||||
|
toChars(), smember->toChars());
|
||||||
|
#endif
|
||||||
|
if (smember->toParent() == this)
|
||||||
|
{
|
||||||
|
access_ret = smember->prot();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (smember->isDeclaration()->isStatic())
|
||||||
|
{
|
||||||
|
access_ret = smember->prot();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < baseclasses->dim; i++)
|
||||||
|
{ BaseClass *b = (*baseclasses)[i];
|
||||||
|
|
||||||
|
enum PROT access = b->base->getAccess(smember);
|
||||||
|
switch (access)
|
||||||
|
{
|
||||||
|
case PROTnone:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROTprivate:
|
||||||
|
access_ret = PROTnone; // private members of base class not accessible
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROTpackage:
|
||||||
|
case PROTprotected:
|
||||||
|
case PROTpublic:
|
||||||
|
case PROTexport:
|
||||||
|
// If access is to be tightened
|
||||||
|
if (b->protection < access)
|
||||||
|
access = b->protection;
|
||||||
|
|
||||||
|
// Pick path with loosest access
|
||||||
|
if (access > access_ret)
|
||||||
|
access_ret = access;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if LOG
|
||||||
|
printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n",
|
||||||
|
toChars(), smember->toChars(), access_ret);
|
||||||
|
#endif
|
||||||
|
return access_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* Helper function for ClassDeclaration::accessCheck()
|
||||||
|
* Returns:
|
||||||
|
* 0 no access
|
||||||
|
* 1 access
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int accessCheckX(
|
||||||
|
Dsymbol *smember,
|
||||||
|
Dsymbol *sfunc,
|
||||||
|
AggregateDeclaration *dthis,
|
||||||
|
AggregateDeclaration *cdscope)
|
||||||
|
{
|
||||||
|
assert(dthis);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printf("accessCheckX for %s.%s in function %s() in scope %s\n",
|
||||||
|
dthis->toChars(), smember->toChars(),
|
||||||
|
sfunc ? sfunc->toChars() : "NULL",
|
||||||
|
cdscope ? cdscope->toChars() : "NULL");
|
||||||
|
#endif
|
||||||
|
if (dthis->hasPrivateAccess(sfunc) ||
|
||||||
|
dthis->isFriendOf(cdscope))
|
||||||
|
{
|
||||||
|
if (smember->toParent() == dthis)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClassDeclaration *cdthis = dthis->isClassDeclaration();
|
||||||
|
if (cdthis)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
|
||||||
|
{ BaseClass *b = (*cdthis->baseclasses)[i];
|
||||||
|
enum PROT access = b->base->getAccess(smember);
|
||||||
|
if (access >= PROTprotected ||
|
||||||
|
accessCheckX(smember, sfunc, b->base, cdscope)
|
||||||
|
)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (smember->toParent() != dthis)
|
||||||
|
{
|
||||||
|
ClassDeclaration *cdthis = dthis->isClassDeclaration();
|
||||||
|
if (cdthis)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
|
||||||
|
{ BaseClass *b = (*cdthis->baseclasses)[i];
|
||||||
|
|
||||||
|
if (accessCheckX(smember, sfunc, b->base, cdscope))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************
|
||||||
|
* Do access check for member of this class, this class being the
|
||||||
|
* type of the 'this' pointer used to access smember.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
FuncDeclaration *f = sc->func;
|
||||||
|
AggregateDeclaration *cdscope = sc->getStructClassScope();
|
||||||
|
enum PROT access;
|
||||||
|
|
||||||
|
#if LOG
|
||||||
|
printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
|
||||||
|
toChars(), smember->toChars(),
|
||||||
|
f ? f->toChars() : NULL,
|
||||||
|
cdscope ? cdscope->toChars() : NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Dsymbol *smemberparent = smember->toParent();
|
||||||
|
if (!smemberparent || !smemberparent->isAggregateDeclaration())
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
printf("not an aggregate member\n");
|
||||||
|
#endif
|
||||||
|
return; // then it is accessible
|
||||||
|
}
|
||||||
|
|
||||||
|
// BUG: should enable this check
|
||||||
|
//assert(smember->parent->isBaseOf(this, NULL));
|
||||||
|
|
||||||
|
if (smemberparent == this)
|
||||||
|
{ enum PROT access2 = smember->prot();
|
||||||
|
|
||||||
|
result = access2 >= PROTpublic ||
|
||||||
|
hasPrivateAccess(f) ||
|
||||||
|
isFriendOf(cdscope) ||
|
||||||
|
(access2 == PROTpackage && hasPackageAccess(sc, this));
|
||||||
|
#if LOG
|
||||||
|
printf("result1 = %d\n", result);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if ((access = this->getAccess(smember)) >= PROTpublic)
|
||||||
|
{
|
||||||
|
result = 1;
|
||||||
|
#if LOG
|
||||||
|
printf("result2 = %d\n", result);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (access == PROTpackage && hasPackageAccess(sc, this))
|
||||||
|
{
|
||||||
|
result = 1;
|
||||||
|
#if LOG
|
||||||
|
printf("result3 = %d\n", result);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = accessCheckX(smember, f, this, cdscope);
|
||||||
|
#if LOG
|
||||||
|
printf("result4 = %d\n", result);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
error(loc, "member %s is not accessible", smember->toChars());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************
|
||||||
|
* Determine if this is the same or friend of cd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd)
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null");
|
||||||
|
#endif
|
||||||
|
if (this == cd)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// Friends if both are in the same module
|
||||||
|
//if (toParent() == cd->toParent())
|
||||||
|
if (cd && getAccessModule() == cd->getAccessModule())
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
printf("\tin same module\n");
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LOG
|
||||||
|
printf("\tnot friend\n");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************
|
||||||
|
* Determine if scope sc has package level access to s.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int hasPackageAccess(Scope *sc, Dsymbol *s)
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (; s; s = s->parent)
|
||||||
|
{
|
||||||
|
if (s->isPackage() && !s->isModule())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#if LOG
|
||||||
|
if (s)
|
||||||
|
printf("\tthis is in package '%s'\n", s->toChars());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (s && s == sc->module->parent)
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
printf("\ts is in same package as sc\n");
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if LOG
|
||||||
|
printf("\tno package access\n");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* Determine if smember has access to private members of this declaration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember)
|
||||||
|
{
|
||||||
|
if (smember)
|
||||||
|
{ AggregateDeclaration *cd = NULL;
|
||||||
|
Dsymbol *smemberparent = smember->toParent();
|
||||||
|
if (smemberparent)
|
||||||
|
cd = smemberparent->isAggregateDeclaration();
|
||||||
|
|
||||||
|
#if LOG
|
||||||
|
printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n",
|
||||||
|
toChars(), smember->toChars());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (this == cd) // smember is a member of this class
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
printf("\tyes 1\n");
|
||||||
|
#endif
|
||||||
|
return 1; // so we get private access
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both are members of the same module, grant access
|
||||||
|
while (1)
|
||||||
|
{ Dsymbol *sp = smember->toParent();
|
||||||
|
if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
|
||||||
|
smember = sp;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!cd && toParent() == smember->toParent())
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
printf("\tyes 2\n");
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!cd && getAccessModule() == smember->getAccessModule())
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
printf("\tyes 3\n");
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if LOG
|
||||||
|
printf("\tno\n");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************
|
||||||
|
* Check access to d for expression e.d
|
||||||
|
*/
|
||||||
|
|
||||||
|
void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d)
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
if (e)
|
||||||
|
{ printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars());
|
||||||
|
printf("\te->type = %s\n", e->type->toChars());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("accessCheck(%s)\n", d->toPrettyChars());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!e)
|
||||||
|
{
|
||||||
|
if (d->prot() == PROTprivate && d->getAccessModule() != sc->module ||
|
||||||
|
d->prot() == PROTpackage && !hasPackageAccess(sc, d))
|
||||||
|
{
|
||||||
|
error(loc, "%s %s is not accessible from module %s",
|
||||||
|
d->kind(), d->toPrettyChars(), sc->module->toChars());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (e->type->ty == Tclass)
|
||||||
|
{ // Do access check
|
||||||
|
ClassDeclaration *cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
|
||||||
|
if (e->op == TOKsuper)
|
||||||
|
{
|
||||||
|
ClassDeclaration *cd2 = sc->func->toParent()->isClassDeclaration();
|
||||||
|
if (cd2)
|
||||||
|
cd = cd2;
|
||||||
|
}
|
||||||
|
cd->accessCheck(loc, sc, d);
|
||||||
|
}
|
||||||
|
else if (e->type->ty == Tstruct)
|
||||||
|
{ // Do access check
|
||||||
|
StructDeclaration *cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
|
||||||
|
cd->accessCheck(loc, sc, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,363 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_AGGREGATE_H
|
||||||
|
#define DMD_AGGREGATE_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
#include "dsymbol.h"
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Identifier;
|
||||||
|
struct Type;
|
||||||
|
struct TypeFunction;
|
||||||
|
struct Expression;
|
||||||
|
struct FuncDeclaration;
|
||||||
|
struct CtorDeclaration;
|
||||||
|
struct DtorDeclaration;
|
||||||
|
struct InvariantDeclaration;
|
||||||
|
struct NewDeclaration;
|
||||||
|
struct DeleteDeclaration;
|
||||||
|
struct InterfaceDeclaration;
|
||||||
|
struct TypeInfoClassDeclaration;
|
||||||
|
struct VarDeclaration;
|
||||||
|
struct dt_t;
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
struct ClassInfoDeclaration;
|
||||||
|
namespace llvm
|
||||||
|
{
|
||||||
|
class Type;
|
||||||
|
class Value;
|
||||||
|
class Constant;
|
||||||
|
class ConstantStruct;
|
||||||
|
class GlobalVariable;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct AggregateDeclaration : ScopeDsymbol
|
||||||
|
{
|
||||||
|
Type *type;
|
||||||
|
StorageClass storage_class;
|
||||||
|
enum PROT protection;
|
||||||
|
Type *handle; // 'this' type
|
||||||
|
unsigned structsize; // size of struct
|
||||||
|
unsigned alignsize; // size of struct for alignment purposes
|
||||||
|
unsigned structalign; // struct member alignment in effect
|
||||||
|
int hasUnions; // set if aggregate has overlapping fields
|
||||||
|
VarDeclarations fields; // VarDeclaration fields
|
||||||
|
unsigned sizeok; // set when structsize contains valid data
|
||||||
|
// 0: no size
|
||||||
|
// 1: size is correct
|
||||||
|
// 2: cannot determine size; fwd referenced
|
||||||
|
Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol
|
||||||
|
bool isdeprecated; // !=0 if deprecated
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
int isnested; // !=0 if is nested
|
||||||
|
VarDeclaration *vthis; // 'this' parameter if this aggregate is nested
|
||||||
|
#endif
|
||||||
|
// Special member functions
|
||||||
|
InvariantDeclaration *inv; // invariant
|
||||||
|
NewDeclaration *aggNew; // allocator
|
||||||
|
DeleteDeclaration *aggDelete; // deallocator
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
//CtorDeclaration *ctor;
|
||||||
|
Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration
|
||||||
|
CtorDeclaration *defaultCtor; // default constructor
|
||||||
|
Dsymbol *aliasthis; // forward unresolved lookups to aliasthis
|
||||||
|
bool noDefaultCtor; // no default construction
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FuncDeclarations dtors; // Array of destructors
|
||||||
|
FuncDeclaration *dtor; // aggregate destructor
|
||||||
|
|
||||||
|
#ifdef IN_GCC
|
||||||
|
Array methods; // flat list of all methods for debug information
|
||||||
|
#endif
|
||||||
|
|
||||||
|
AggregateDeclaration(Loc loc, Identifier *id);
|
||||||
|
void semantic2(Scope *sc);
|
||||||
|
void semantic3(Scope *sc);
|
||||||
|
void inlineScan();
|
||||||
|
unsigned size(Loc loc);
|
||||||
|
static void alignmember(unsigned salign, unsigned size, unsigned *poffset);
|
||||||
|
Type *getType();
|
||||||
|
void addField(Scope *sc, VarDeclaration *v);
|
||||||
|
int firstFieldInUnion(int indx); // first field in union that includes indx
|
||||||
|
int numFieldsInUnion(int firstIndex); // #fields in union starting at index
|
||||||
|
int isDeprecated(); // is aggregate deprecated?
|
||||||
|
FuncDeclaration *buildDtor(Scope *sc);
|
||||||
|
int isNested();
|
||||||
|
int isExport();
|
||||||
|
|
||||||
|
void emitComment(Scope *sc);
|
||||||
|
void toJsonBuffer(OutBuffer *buf);
|
||||||
|
void toDocBuffer(OutBuffer *buf);
|
||||||
|
|
||||||
|
// For access checking
|
||||||
|
virtual PROT getAccess(Dsymbol *smember); // determine access to smember
|
||||||
|
int isFriendOf(AggregateDeclaration *cd);
|
||||||
|
int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class?
|
||||||
|
void accessCheck(Loc loc, Scope *sc, Dsymbol *smember);
|
||||||
|
|
||||||
|
enum PROT prot();
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
// Back end
|
||||||
|
Symbol *stag; // tag symbol for debug data
|
||||||
|
Symbol *sinit;
|
||||||
|
Symbol *toInitializer();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
AggregateDeclaration *isAggregateDeclaration() { return this; }
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
// Aggregates that wouldn't have gotten semantic3'ed if we weren't inlining set this flag.
|
||||||
|
bool availableExternally;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnonymousAggregateDeclaration : AggregateDeclaration
|
||||||
|
{
|
||||||
|
AnonymousAggregateDeclaration()
|
||||||
|
: AggregateDeclaration(0, NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StructDeclaration : AggregateDeclaration
|
||||||
|
{
|
||||||
|
int zeroInit; // !=0 if initialize with 0 fill
|
||||||
|
#if DMDV2
|
||||||
|
int hasIdentityAssign; // !=0 if has identity opAssign
|
||||||
|
int hasIdentityEquals; // !=0 if has identity opEquals
|
||||||
|
FuncDeclaration *cpctor; // generated copy-constructor, if any
|
||||||
|
FuncDeclarations postblits; // Array of postblit functions
|
||||||
|
FuncDeclaration *postblit; // aggregate postblit
|
||||||
|
|
||||||
|
FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals
|
||||||
|
static FuncDeclaration *xerreq; // object.xopEquals
|
||||||
|
#endif
|
||||||
|
|
||||||
|
StructDeclaration(Loc loc, Identifier *id);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
Dsymbol *search(Loc, Identifier *ident, int flags);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
char *mangle();
|
||||||
|
const char *kind();
|
||||||
|
void finalizeSize();
|
||||||
|
#if DMDV1
|
||||||
|
Expression *cloneMembers();
|
||||||
|
#endif
|
||||||
|
#if DMDV2
|
||||||
|
int needOpAssign();
|
||||||
|
int needOpEquals();
|
||||||
|
FuncDeclaration *buildOpAssign(Scope *sc);
|
||||||
|
FuncDeclaration *buildOpEquals(Scope *sc);
|
||||||
|
FuncDeclaration *buildPostBlit(Scope *sc);
|
||||||
|
FuncDeclaration *buildCpCtor(Scope *sc);
|
||||||
|
|
||||||
|
FuncDeclaration *buildXopEquals(Scope *sc);
|
||||||
|
#endif
|
||||||
|
void toDocBuffer(OutBuffer *buf);
|
||||||
|
|
||||||
|
PROT getAccess(Dsymbol *smember); // determine access to smember
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
void toObjFile(int multiobj); // compile to .obj file
|
||||||
|
void toDt(dt_t **pdt);
|
||||||
|
void toDebug(); // to symbolic debug info
|
||||||
|
#endif
|
||||||
|
|
||||||
|
StructDeclaration *isStructDeclaration() { return this; }
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
void codegen(Ir*);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UnionDeclaration : StructDeclaration
|
||||||
|
{
|
||||||
|
UnionDeclaration(Loc loc, Identifier *id);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
const char *kind();
|
||||||
|
|
||||||
|
UnionDeclaration *isUnionDeclaration() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// warning: two classes with the same base class share the same
|
||||||
|
// BaseClass instance.
|
||||||
|
struct BaseClass
|
||||||
|
{
|
||||||
|
Type *type; // (before semantic processing)
|
||||||
|
enum PROT protection; // protection for the base interface
|
||||||
|
|
||||||
|
ClassDeclaration *base;
|
||||||
|
int offset; // 'this' pointer offset
|
||||||
|
FuncDeclarations vtbl; // for interfaces: Array of FuncDeclaration's
|
||||||
|
// making up the vtbl[]
|
||||||
|
|
||||||
|
size_t baseInterfaces_dim;
|
||||||
|
BaseClass *baseInterfaces; // if BaseClass is an interface, these
|
||||||
|
// are a copy of the InterfaceDeclaration::interfaces
|
||||||
|
|
||||||
|
BaseClass();
|
||||||
|
BaseClass(Type *type, enum PROT protection);
|
||||||
|
|
||||||
|
int fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance);
|
||||||
|
void copyBaseInterfaces(BaseClasses *);
|
||||||
|
};
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
#define CLASSINFO_SIZE_64 0x98 // value of ClassInfo.size
|
||||||
|
#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size
|
||||||
|
#else
|
||||||
|
#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ClassDeclaration : AggregateDeclaration
|
||||||
|
{
|
||||||
|
static ClassDeclaration *object;
|
||||||
|
static ClassDeclaration *classinfo;
|
||||||
|
static ClassDeclaration *throwable;
|
||||||
|
static ClassDeclaration *exception;
|
||||||
|
static ClassDeclaration *errorException;
|
||||||
|
|
||||||
|
ClassDeclaration *baseClass; // NULL only if this is Object
|
||||||
|
#if DMDV1
|
||||||
|
CtorDeclaration *ctor;
|
||||||
|
CtorDeclaration *defaultCtor; // default constructor
|
||||||
|
#endif
|
||||||
|
FuncDeclaration *staticCtor;
|
||||||
|
FuncDeclaration *staticDtor;
|
||||||
|
Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[]
|
||||||
|
Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[]
|
||||||
|
|
||||||
|
BaseClasses *baseclasses; // Array of BaseClass's; first is super,
|
||||||
|
// rest are Interface's
|
||||||
|
|
||||||
|
size_t interfaces_dim;
|
||||||
|
BaseClass **interfaces; // interfaces[interfaces_dim] for this class
|
||||||
|
// (does not include baseClass)
|
||||||
|
|
||||||
|
BaseClasses *vtblInterfaces; // array of base interfaces that have
|
||||||
|
// their own vtbl[]
|
||||||
|
TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration
|
||||||
|
int com; // !=0 if this is a COM class (meaning
|
||||||
|
// it derives from IUnknown)
|
||||||
|
int isscope; // !=0 if this is an auto class
|
||||||
|
int isabstract; // !=0 if abstract class
|
||||||
|
#if DMDV1
|
||||||
|
int isnested; // !=0 if is nested
|
||||||
|
VarDeclaration *vthis; // 'this' parameter if this class is nested
|
||||||
|
#endif
|
||||||
|
int inuse; // to prevent recursive attempts
|
||||||
|
|
||||||
|
ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
int isBaseOf2(ClassDeclaration *cd);
|
||||||
|
|
||||||
|
#define OFFSET_RUNTIME 0x76543210
|
||||||
|
virtual int isBaseOf(ClassDeclaration *cd, int *poffset);
|
||||||
|
|
||||||
|
virtual int isBaseInfoComplete();
|
||||||
|
Dsymbol *search(Loc, Identifier *ident, int flags);
|
||||||
|
Dsymbol *searchBase(Loc, Identifier *ident);
|
||||||
|
#if DMDV2
|
||||||
|
int isFuncHidden(FuncDeclaration *fd);
|
||||||
|
#endif
|
||||||
|
FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
|
||||||
|
void interfaceSemantic(Scope *sc);
|
||||||
|
#if DMDV1
|
||||||
|
int isNested();
|
||||||
|
#endif
|
||||||
|
int isCOMclass();
|
||||||
|
virtual int isCOMinterface();
|
||||||
|
#if DMDV2
|
||||||
|
virtual int isCPPinterface();
|
||||||
|
#endif
|
||||||
|
int isAbstract();
|
||||||
|
virtual int vtblOffset();
|
||||||
|
const char *kind();
|
||||||
|
char *mangle();
|
||||||
|
void toDocBuffer(OutBuffer *buf);
|
||||||
|
|
||||||
|
PROT getAccess(Dsymbol *smember); // determine access to smember
|
||||||
|
|
||||||
|
void addLocalClass(ClassDeclarations *);
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
// Back end
|
||||||
|
void toObjFile(int multiobj); // compile to .obj file
|
||||||
|
void toDebug();
|
||||||
|
unsigned baseVtblOffset(BaseClass *bc);
|
||||||
|
Symbol *toSymbol();
|
||||||
|
Symbol *toVtblSymbol();
|
||||||
|
void toDt(dt_t **pdt);
|
||||||
|
void toDt2(dt_t **pdt, ClassDeclaration *cd);
|
||||||
|
|
||||||
|
Symbol *vtblsym;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
virtual void codegen(Ir*);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InterfaceDeclaration : ClassDeclaration
|
||||||
|
{
|
||||||
|
#if DMDV2
|
||||||
|
int cpp; // !=0 if this is a C++ interface
|
||||||
|
#endif
|
||||||
|
InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
int isBaseOf(ClassDeclaration *cd, int *poffset);
|
||||||
|
int isBaseOf(BaseClass *bc, int *poffset);
|
||||||
|
const char *kind();
|
||||||
|
int isBaseInfoComplete();
|
||||||
|
int vtblOffset();
|
||||||
|
#if DMDV2
|
||||||
|
int isCPPinterface();
|
||||||
|
#endif
|
||||||
|
virtual int isCOMinterface();
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
void toObjFile(int multiobj); // compile to .obj file
|
||||||
|
Symbol *toSymbol();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
InterfaceDeclaration *isInterfaceDeclaration() { return this; }
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
void codegen(Ir*);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DMD_AGGREGATE_H */
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 2009-2009 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "identifier.h"
|
||||||
|
#include "aliasthis.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "dsymbol.h"
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
|
||||||
|
|
||||||
|
AliasThis::AliasThis(Loc loc, Identifier *ident)
|
||||||
|
: Dsymbol(NULL) // it's anonymous (no identifier)
|
||||||
|
{
|
||||||
|
this->loc = loc;
|
||||||
|
this->ident = ident;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dsymbol *AliasThis::syntaxCopy(Dsymbol *s)
|
||||||
|
{
|
||||||
|
assert(!s);
|
||||||
|
/* Since there is no semantic information stored here,
|
||||||
|
* we don't need to copy it.
|
||||||
|
*/
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AliasThis::semantic(Scope *sc)
|
||||||
|
{
|
||||||
|
Dsymbol *parent = sc->parent;
|
||||||
|
if (parent)
|
||||||
|
parent = parent->pastMixin();
|
||||||
|
AggregateDeclaration *ad = NULL;
|
||||||
|
if (parent)
|
||||||
|
ad = parent->isAggregateDeclaration();
|
||||||
|
if (ad)
|
||||||
|
{
|
||||||
|
assert(ad->members);
|
||||||
|
Dsymbol *s = ad->search(loc, ident, 0);
|
||||||
|
if (!s)
|
||||||
|
{ s = sc->search(loc, ident, 0);
|
||||||
|
if (s)
|
||||||
|
::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars());
|
||||||
|
else
|
||||||
|
::error(loc, "undefined identifier %s", ident->toChars());
|
||||||
|
}
|
||||||
|
else if (ad->aliasthis && s != ad->aliasthis)
|
||||||
|
error("there can be only one alias this");
|
||||||
|
ad->aliasthis = s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error("alias this can only appear in struct or class declaration, not %s", parent ? parent->toChars() : "nowhere");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *AliasThis::kind()
|
||||||
|
{
|
||||||
|
return "alias this";
|
||||||
|
}
|
||||||
|
|
||||||
|
void AliasThis::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
buf->writestring("alias ");
|
||||||
|
buf->writestring(ident->toChars());
|
||||||
|
buf->writestring(" this;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 2009-2009 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_ALIASTHIS_H
|
||||||
|
#define DMD_ALIASTHIS_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "dsymbol.h"
|
||||||
|
|
||||||
|
/**************************************************************/
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
|
||||||
|
struct AliasThis : Dsymbol
|
||||||
|
{
|
||||||
|
// alias Identifier this;
|
||||||
|
Identifier *ident;
|
||||||
|
|
||||||
|
AliasThis(Loc loc, Identifier *ident);
|
||||||
|
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
const char *kind();
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
AliasThis *isAliasThis() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
+165
@@ -0,0 +1,165 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "expression.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* An Expression tree walker that will visit each Expression e in the tree,
|
||||||
|
* in depth-first evaluation order, and call fp(e,param) on it.
|
||||||
|
* fp() signals whether the walking continues with its return value:
|
||||||
|
* Returns:
|
||||||
|
* 0 continue
|
||||||
|
* 1 done
|
||||||
|
* It's a bit slower than using virtual functions, but more encapsulated and less brittle.
|
||||||
|
* Creating an iterator for this would be much more complex.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef int (*fp_t)(Expression *, void *);
|
||||||
|
|
||||||
|
int Expression::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
return (*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
* Perform apply() on an array of Expressions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int arrayExpressionApply(Expressions *a, fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
//printf("arrayExpressionApply(%p)\n", a);
|
||||||
|
if (a)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < a->dim; i++)
|
||||||
|
{ Expression *e = (*a)[i];
|
||||||
|
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
if (e->apply(fp, param))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NewExp::apply(int (*fp)(Expression *, void *), void *param)
|
||||||
|
{
|
||||||
|
//printf("NewExp::apply(): %s\n", toChars());
|
||||||
|
|
||||||
|
return ((thisexp ? thisexp->apply(fp, param) : 0) ||
|
||||||
|
arrayExpressionApply(newargs, fp, param) ||
|
||||||
|
arrayExpressionApply(arguments, fp, param) ||
|
||||||
|
(*fp)(this, param));
|
||||||
|
}
|
||||||
|
|
||||||
|
int NewAnonClassExp::apply(int (*fp)(Expression *, void *), void *param)
|
||||||
|
{
|
||||||
|
//printf("NewAnonClassExp::apply(): %s\n", toChars());
|
||||||
|
|
||||||
|
return ((thisexp ? thisexp->apply(fp, param) : 0) ||
|
||||||
|
arrayExpressionApply(newargs, fp, param) ||
|
||||||
|
arrayExpressionApply(arguments, fp, param) ||
|
||||||
|
(*fp)(this, param));
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnaExp::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
return e1->apply(fp, param) ||
|
||||||
|
(*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
int BinExp::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
return e1->apply(fp, param) ||
|
||||||
|
e2->apply(fp, param) ||
|
||||||
|
(*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AssertExp::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
//printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars());
|
||||||
|
return e1->apply(fp, param) ||
|
||||||
|
(msg ? msg->apply(fp, param) : 0) ||
|
||||||
|
(*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CallExp::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
//printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars());
|
||||||
|
return e1->apply(fp, param) ||
|
||||||
|
arrayExpressionApply(arguments, fp, param) ||
|
||||||
|
(*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ArrayExp::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
//printf("ArrayExp::apply(fp_t fp, void *param): %s\n", toChars());
|
||||||
|
return e1->apply(fp, param) ||
|
||||||
|
arrayExpressionApply(arguments, fp, param) ||
|
||||||
|
(*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int SliceExp::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
return e1->apply(fp, param) ||
|
||||||
|
(lwr ? lwr->apply(fp, param) : 0) ||
|
||||||
|
(upr ? upr->apply(fp, param) : 0) ||
|
||||||
|
(*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ArrayLiteralExp::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
return arrayExpressionApply(elements, fp, param) ||
|
||||||
|
(*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int AssocArrayLiteralExp::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
return arrayExpressionApply(keys, fp, param) ||
|
||||||
|
arrayExpressionApply(values, fp, param) ||
|
||||||
|
(*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int StructLiteralExp::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
return arrayExpressionApply(elements, fp, param) ||
|
||||||
|
(*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int TupleExp::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
return arrayExpressionApply(exps, fp, param) ||
|
||||||
|
(*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CondExp::apply(fp_t fp, void *param)
|
||||||
|
{
|
||||||
|
return econd->apply(fp, param) ||
|
||||||
|
e1->apply(fp, param) ||
|
||||||
|
e2->apply(fp, param) ||
|
||||||
|
(*fp)(this, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+193
@@ -0,0 +1,193 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 2010-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// http://www.dsource.org/projects/dmd/browser/branches/dmd-1.x/src/argtypes.c
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "dsymbol.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "attrib.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "template.h"
|
||||||
|
#include "id.h"
|
||||||
|
#include "enum.h"
|
||||||
|
#include "import.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "hdrgen.h"
|
||||||
|
|
||||||
|
/****************************************************
|
||||||
|
* This breaks a type down into 'simpler' types that can be passed to a function
|
||||||
|
* in registers, and returned in registers.
|
||||||
|
* It's highly platform dependent.
|
||||||
|
* Returning a tuple of zero length means the type cannot be passed/returned in registers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
TypeTuple *Type::toArgTypes()
|
||||||
|
{
|
||||||
|
return NULL; // not valid for a parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TypeTuple *TypeBasic::toArgTypes()
|
||||||
|
{ Type *t1 = NULL;
|
||||||
|
Type *t2 = NULL;
|
||||||
|
switch (ty)
|
||||||
|
{
|
||||||
|
case Tvoid:
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
case Tbool:
|
||||||
|
case Tint8:
|
||||||
|
case Tuns8:
|
||||||
|
case Tint16:
|
||||||
|
case Tuns16:
|
||||||
|
case Tint32:
|
||||||
|
case Tuns32:
|
||||||
|
case Tfloat32:
|
||||||
|
case Tint64:
|
||||||
|
case Tuns64:
|
||||||
|
case Tfloat64:
|
||||||
|
case Tfloat80:
|
||||||
|
t1 = this;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Timaginary32:
|
||||||
|
t1 = Type::tfloat32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Timaginary64:
|
||||||
|
t1 = Type::tfloat64;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Timaginary80:
|
||||||
|
t1 = Type::tfloat80;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tcomplex32:
|
||||||
|
if (global.params.is64bit)
|
||||||
|
t1 = Type::tfloat64; // weird, eh?
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t1 = Type::tfloat64;
|
||||||
|
t2 = Type::tfloat64;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tcomplex64:
|
||||||
|
t1 = Type::tfloat64;
|
||||||
|
t2 = Type::tfloat64;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tcomplex80:
|
||||||
|
t1 = Type::tfloat80;
|
||||||
|
t2 = Type::tfloat80;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tascii:
|
||||||
|
t1 = Type::tuns8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twchar:
|
||||||
|
t1 = Type::tuns16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tdchar:
|
||||||
|
t1 = Type::tuns32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTuple *t;
|
||||||
|
if (t1)
|
||||||
|
{
|
||||||
|
if (t2)
|
||||||
|
t = new TypeTuple(t1, t2);
|
||||||
|
else
|
||||||
|
t = new TypeTuple(t1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
t = new TypeTuple();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTuple *TypeVector::toArgTypes()
|
||||||
|
{
|
||||||
|
return new TypeTuple(Type::tfloat64);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTuple *TypeSArray::toArgTypes()
|
||||||
|
{
|
||||||
|
#if DMDV2
|
||||||
|
return new TypeTuple(); // pass on the stack for efficiency
|
||||||
|
#else
|
||||||
|
return new TypeTuple(Type::tvoidptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTuple *TypeDArray::toArgTypes()
|
||||||
|
{
|
||||||
|
return new TypeTuple(); // pass on the stack for efficiency
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTuple *TypeAArray::toArgTypes()
|
||||||
|
{
|
||||||
|
return new TypeTuple(Type::tvoidptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTuple *TypePointer::toArgTypes()
|
||||||
|
{
|
||||||
|
return new TypeTuple(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTuple *TypeDelegate::toArgTypes()
|
||||||
|
{
|
||||||
|
return new TypeTuple(); // pass on the stack for efficiency
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTuple *TypeStruct::toArgTypes()
|
||||||
|
{
|
||||||
|
d_uns64 sz = size(0);
|
||||||
|
assert(sz < 0xFFFFFFFF);
|
||||||
|
switch ((unsigned)sz)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return new TypeTuple(Type::tint8);
|
||||||
|
case 2:
|
||||||
|
return new TypeTuple(Type::tint16);
|
||||||
|
case 4:
|
||||||
|
return new TypeTuple(Type::tint32);
|
||||||
|
case 8:
|
||||||
|
return new TypeTuple(Type::tint64);
|
||||||
|
}
|
||||||
|
return new TypeTuple(); // pass on the stack
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTuple *TypeEnum::toArgTypes()
|
||||||
|
{
|
||||||
|
return toBasetype()->toArgTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTuple *TypeTypedef::toArgTypes()
|
||||||
|
{
|
||||||
|
return sym->basetype->toArgTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeTuple *TypeClass::toArgTypes()
|
||||||
|
{
|
||||||
|
return new TypeTuple(Type::tvoidptr);
|
||||||
|
}
|
||||||
|
|
||||||
+682
@@ -0,0 +1,682 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "rmem.h"
|
||||||
|
|
||||||
|
#include "aav.h"
|
||||||
|
|
||||||
|
#include "expression.h"
|
||||||
|
#include "statement.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "id.h"
|
||||||
|
#include "module.h"
|
||||||
|
#include "init.h"
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
extern int binary(const char *p , const char **tab, int high);
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* Hash table of array op functions already generated or known about.
|
||||||
|
*/
|
||||||
|
|
||||||
|
AA *arrayfuncs;
|
||||||
|
#else
|
||||||
|
int binary(const char *p , const char **tab, int high)
|
||||||
|
{
|
||||||
|
int i = 0, j = high, k, l;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
k = (i + j) / 2;
|
||||||
|
l = strcmp(p, tab[k]);
|
||||||
|
if (!l)
|
||||||
|
return k;
|
||||||
|
else if (l < 0)
|
||||||
|
j = k;
|
||||||
|
else
|
||||||
|
i = k + 1;
|
||||||
|
}
|
||||||
|
while (i != j);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************************************
|
||||||
|
* Check that there are no uses of arrays without [].
|
||||||
|
*/
|
||||||
|
bool isArrayOpValid(Expression *e)
|
||||||
|
{
|
||||||
|
if (e->op == TOKslice)
|
||||||
|
return true;
|
||||||
|
Type *tb = e->type->toBasetype();
|
||||||
|
|
||||||
|
if ( (tb->ty == Tarray) || (tb->ty == Tsarray) )
|
||||||
|
{
|
||||||
|
switch (e->op)
|
||||||
|
{
|
||||||
|
case TOKadd:
|
||||||
|
case TOKmin:
|
||||||
|
case TOKmul:
|
||||||
|
case TOKdiv:
|
||||||
|
case TOKmod:
|
||||||
|
case TOKxor:
|
||||||
|
case TOKand:
|
||||||
|
case TOKor:
|
||||||
|
case TOKassign:
|
||||||
|
case TOKaddass:
|
||||||
|
case TOKminass:
|
||||||
|
case TOKmulass:
|
||||||
|
case TOKdivass:
|
||||||
|
case TOKmodass:
|
||||||
|
case TOKxorass:
|
||||||
|
case TOKandass:
|
||||||
|
case TOKorass:
|
||||||
|
#if DMDV2
|
||||||
|
case TOKpow:
|
||||||
|
case TOKpowass:
|
||||||
|
#endif
|
||||||
|
return isArrayOpValid(((BinExp *)e)->e1) && isArrayOpValid(((BinExp *)e)->e2);
|
||||||
|
|
||||||
|
case TOKcall:
|
||||||
|
return false; // TODO: Decide if [] is required after arrayop calls.
|
||||||
|
|
||||||
|
case TOKneg:
|
||||||
|
case TOKtilde:
|
||||||
|
return isArrayOpValid(((UnaExp *)e)->e1);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************
|
||||||
|
* Construct the array operation expression.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Expression *BinExp::arrayOp(Scope *sc)
|
||||||
|
{
|
||||||
|
|
||||||
|
Type *tb = type->toBasetype();
|
||||||
|
assert(tb->ty == Tarray || tb->ty == Tsarray);
|
||||||
|
if (tb->nextOf()->toBasetype()->ty == Tvoid)
|
||||||
|
{
|
||||||
|
error("Cannot perform array operations on void[] arrays");
|
||||||
|
return new ErrorExp();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isArrayOpValid(e2))
|
||||||
|
{
|
||||||
|
e2->error("invalid array operation %s (did you forget a [] ?)", toChars());
|
||||||
|
return new ErrorExp();
|
||||||
|
}
|
||||||
|
|
||||||
|
Expressions *arguments = new Expressions();
|
||||||
|
|
||||||
|
/* The expression to generate an array operation for is mangled
|
||||||
|
* into a name to use as the array operation function name.
|
||||||
|
* Mangle in the operands and operators in RPN order, and type.
|
||||||
|
*/
|
||||||
|
OutBuffer buf;
|
||||||
|
buf.writestring("_array");
|
||||||
|
buildArrayIdent(&buf, arguments);
|
||||||
|
buf.writeByte('_');
|
||||||
|
|
||||||
|
/* Append deco of array element type
|
||||||
|
*/
|
||||||
|
#if DMDV2
|
||||||
|
buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
|
||||||
|
#else
|
||||||
|
buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t namelen = buf.offset;
|
||||||
|
buf.writeByte(0);
|
||||||
|
char *name = buf.toChars();
|
||||||
|
Identifier *ident = Lexer::idPool(name);
|
||||||
|
|
||||||
|
/* Look up name in hash table
|
||||||
|
*/
|
||||||
|
#if IN_LLVM
|
||||||
|
FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&sc->module->arrayfuncs, ident);
|
||||||
|
#else
|
||||||
|
FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&arrayfuncs, ident);
|
||||||
|
#endif
|
||||||
|
FuncDeclaration *fd = (FuncDeclaration *)*pfd;
|
||||||
|
if (!fd)
|
||||||
|
{
|
||||||
|
/* Some of the array op functions are written as library functions,
|
||||||
|
* presumably to optimize them with special CPU vector instructions.
|
||||||
|
* List those library functions here, in alpha order.
|
||||||
|
*/
|
||||||
|
static const char *libArrayopFuncs[] =
|
||||||
|
{
|
||||||
|
"_arrayExpSliceAddass_a",
|
||||||
|
"_arrayExpSliceAddass_d", // T[]+=T
|
||||||
|
"_arrayExpSliceAddass_f", // T[]+=T
|
||||||
|
"_arrayExpSliceAddass_g",
|
||||||
|
"_arrayExpSliceAddass_h",
|
||||||
|
"_arrayExpSliceAddass_i",
|
||||||
|
"_arrayExpSliceAddass_k",
|
||||||
|
"_arrayExpSliceAddass_s",
|
||||||
|
"_arrayExpSliceAddass_t",
|
||||||
|
"_arrayExpSliceAddass_u",
|
||||||
|
"_arrayExpSliceAddass_w",
|
||||||
|
|
||||||
|
"_arrayExpSliceDivass_d", // T[]/=T
|
||||||
|
"_arrayExpSliceDivass_f", // T[]/=T
|
||||||
|
|
||||||
|
"_arrayExpSliceMinSliceAssign_a",
|
||||||
|
"_arrayExpSliceMinSliceAssign_d", // T[]=T-T[]
|
||||||
|
"_arrayExpSliceMinSliceAssign_f", // T[]=T-T[]
|
||||||
|
"_arrayExpSliceMinSliceAssign_g",
|
||||||
|
"_arrayExpSliceMinSliceAssign_h",
|
||||||
|
"_arrayExpSliceMinSliceAssign_i",
|
||||||
|
"_arrayExpSliceMinSliceAssign_k",
|
||||||
|
"_arrayExpSliceMinSliceAssign_s",
|
||||||
|
"_arrayExpSliceMinSliceAssign_t",
|
||||||
|
"_arrayExpSliceMinSliceAssign_u",
|
||||||
|
"_arrayExpSliceMinSliceAssign_w",
|
||||||
|
|
||||||
|
"_arrayExpSliceMinass_a",
|
||||||
|
"_arrayExpSliceMinass_d", // T[]-=T
|
||||||
|
"_arrayExpSliceMinass_f", // T[]-=T
|
||||||
|
"_arrayExpSliceMinass_g",
|
||||||
|
"_arrayExpSliceMinass_h",
|
||||||
|
"_arrayExpSliceMinass_i",
|
||||||
|
"_arrayExpSliceMinass_k",
|
||||||
|
"_arrayExpSliceMinass_s",
|
||||||
|
"_arrayExpSliceMinass_t",
|
||||||
|
"_arrayExpSliceMinass_u",
|
||||||
|
"_arrayExpSliceMinass_w",
|
||||||
|
|
||||||
|
"_arrayExpSliceMulass_d", // T[]*=T
|
||||||
|
"_arrayExpSliceMulass_f", // T[]*=T
|
||||||
|
"_arrayExpSliceMulass_i",
|
||||||
|
"_arrayExpSliceMulass_k",
|
||||||
|
"_arrayExpSliceMulass_s",
|
||||||
|
"_arrayExpSliceMulass_t",
|
||||||
|
"_arrayExpSliceMulass_u",
|
||||||
|
"_arrayExpSliceMulass_w",
|
||||||
|
|
||||||
|
"_arraySliceExpAddSliceAssign_a",
|
||||||
|
"_arraySliceExpAddSliceAssign_d", // T[]=T[]+T
|
||||||
|
"_arraySliceExpAddSliceAssign_f", // T[]=T[]+T
|
||||||
|
"_arraySliceExpAddSliceAssign_g",
|
||||||
|
"_arraySliceExpAddSliceAssign_h",
|
||||||
|
"_arraySliceExpAddSliceAssign_i",
|
||||||
|
"_arraySliceExpAddSliceAssign_k",
|
||||||
|
"_arraySliceExpAddSliceAssign_s",
|
||||||
|
"_arraySliceExpAddSliceAssign_t",
|
||||||
|
"_arraySliceExpAddSliceAssign_u",
|
||||||
|
"_arraySliceExpAddSliceAssign_w",
|
||||||
|
|
||||||
|
"_arraySliceExpDivSliceAssign_d", // T[]=T[]/T
|
||||||
|
"_arraySliceExpDivSliceAssign_f", // T[]=T[]/T
|
||||||
|
|
||||||
|
"_arraySliceExpMinSliceAssign_a",
|
||||||
|
"_arraySliceExpMinSliceAssign_d", // T[]=T[]-T
|
||||||
|
"_arraySliceExpMinSliceAssign_f", // T[]=T[]-T
|
||||||
|
"_arraySliceExpMinSliceAssign_g",
|
||||||
|
"_arraySliceExpMinSliceAssign_h",
|
||||||
|
"_arraySliceExpMinSliceAssign_i",
|
||||||
|
"_arraySliceExpMinSliceAssign_k",
|
||||||
|
"_arraySliceExpMinSliceAssign_s",
|
||||||
|
"_arraySliceExpMinSliceAssign_t",
|
||||||
|
"_arraySliceExpMinSliceAssign_u",
|
||||||
|
"_arraySliceExpMinSliceAssign_w",
|
||||||
|
|
||||||
|
"_arraySliceExpMulSliceAddass_d", // T[] += T[]*T
|
||||||
|
"_arraySliceExpMulSliceAddass_f",
|
||||||
|
"_arraySliceExpMulSliceAddass_r",
|
||||||
|
|
||||||
|
"_arraySliceExpMulSliceAssign_d", // T[]=T[]*T
|
||||||
|
"_arraySliceExpMulSliceAssign_f", // T[]=T[]*T
|
||||||
|
"_arraySliceExpMulSliceAssign_i",
|
||||||
|
"_arraySliceExpMulSliceAssign_k",
|
||||||
|
"_arraySliceExpMulSliceAssign_s",
|
||||||
|
"_arraySliceExpMulSliceAssign_t",
|
||||||
|
"_arraySliceExpMulSliceAssign_u",
|
||||||
|
"_arraySliceExpMulSliceAssign_w",
|
||||||
|
|
||||||
|
"_arraySliceExpMulSliceMinass_d", // T[] -= T[]*T
|
||||||
|
"_arraySliceExpMulSliceMinass_f",
|
||||||
|
"_arraySliceExpMulSliceMinass_r",
|
||||||
|
|
||||||
|
"_arraySliceSliceAddSliceAssign_a",
|
||||||
|
"_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[]
|
||||||
|
"_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[]
|
||||||
|
"_arraySliceSliceAddSliceAssign_g",
|
||||||
|
"_arraySliceSliceAddSliceAssign_h",
|
||||||
|
"_arraySliceSliceAddSliceAssign_i",
|
||||||
|
"_arraySliceSliceAddSliceAssign_k",
|
||||||
|
"_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[]
|
||||||
|
"_arraySliceSliceAddSliceAssign_s",
|
||||||
|
"_arraySliceSliceAddSliceAssign_t",
|
||||||
|
"_arraySliceSliceAddSliceAssign_u",
|
||||||
|
"_arraySliceSliceAddSliceAssign_w",
|
||||||
|
|
||||||
|
"_arraySliceSliceAddass_a",
|
||||||
|
"_arraySliceSliceAddass_d", // T[]+=T[]
|
||||||
|
"_arraySliceSliceAddass_f", // T[]+=T[]
|
||||||
|
"_arraySliceSliceAddass_g",
|
||||||
|
"_arraySliceSliceAddass_h",
|
||||||
|
"_arraySliceSliceAddass_i",
|
||||||
|
"_arraySliceSliceAddass_k",
|
||||||
|
"_arraySliceSliceAddass_s",
|
||||||
|
"_arraySliceSliceAddass_t",
|
||||||
|
"_arraySliceSliceAddass_u",
|
||||||
|
"_arraySliceSliceAddass_w",
|
||||||
|
|
||||||
|
"_arraySliceSliceMinSliceAssign_a",
|
||||||
|
"_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[]
|
||||||
|
"_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[]
|
||||||
|
"_arraySliceSliceMinSliceAssign_g",
|
||||||
|
"_arraySliceSliceMinSliceAssign_h",
|
||||||
|
"_arraySliceSliceMinSliceAssign_i",
|
||||||
|
"_arraySliceSliceMinSliceAssign_k",
|
||||||
|
"_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[]
|
||||||
|
"_arraySliceSliceMinSliceAssign_s",
|
||||||
|
"_arraySliceSliceMinSliceAssign_t",
|
||||||
|
"_arraySliceSliceMinSliceAssign_u",
|
||||||
|
"_arraySliceSliceMinSliceAssign_w",
|
||||||
|
|
||||||
|
"_arraySliceSliceMinass_a",
|
||||||
|
"_arraySliceSliceMinass_d", // T[]-=T[]
|
||||||
|
"_arraySliceSliceMinass_f", // T[]-=T[]
|
||||||
|
"_arraySliceSliceMinass_g",
|
||||||
|
"_arraySliceSliceMinass_h",
|
||||||
|
"_arraySliceSliceMinass_i",
|
||||||
|
"_arraySliceSliceMinass_k",
|
||||||
|
"_arraySliceSliceMinass_s",
|
||||||
|
"_arraySliceSliceMinass_t",
|
||||||
|
"_arraySliceSliceMinass_u",
|
||||||
|
"_arraySliceSliceMinass_w",
|
||||||
|
|
||||||
|
"_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[]
|
||||||
|
"_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[]
|
||||||
|
"_arraySliceSliceMulSliceAssign_i",
|
||||||
|
"_arraySliceSliceMulSliceAssign_k",
|
||||||
|
"_arraySliceSliceMulSliceAssign_s",
|
||||||
|
"_arraySliceSliceMulSliceAssign_t",
|
||||||
|
"_arraySliceSliceMulSliceAssign_u",
|
||||||
|
"_arraySliceSliceMulSliceAssign_w",
|
||||||
|
|
||||||
|
"_arraySliceSliceMulass_d", // T[]*=T[]
|
||||||
|
"_arraySliceSliceMulass_f", // T[]*=T[]
|
||||||
|
"_arraySliceSliceMulass_i",
|
||||||
|
"_arraySliceSliceMulass_k",
|
||||||
|
"_arraySliceSliceMulass_s",
|
||||||
|
"_arraySliceSliceMulass_t",
|
||||||
|
"_arraySliceSliceMulass_u",
|
||||||
|
"_arraySliceSliceMulass_w",
|
||||||
|
};
|
||||||
|
|
||||||
|
int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *));
|
||||||
|
if (i == -1)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG // Make sure our array is alphabetized
|
||||||
|
for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++)
|
||||||
|
{
|
||||||
|
if (strcmp(name, libArrayopFuncs[i]) == 0)
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* Not in library, so generate it.
|
||||||
|
* Construct the function body:
|
||||||
|
* foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++)
|
||||||
|
* loopbody;
|
||||||
|
* return p;
|
||||||
|
*/
|
||||||
|
|
||||||
|
Parameters *fparams = new Parameters();
|
||||||
|
Expression *loopbody = buildArrayLoop(fparams);
|
||||||
|
Parameter *p = (*fparams)[0 /*fparams->dim - 1*/];
|
||||||
|
#if DMDV1
|
||||||
|
// for (size_t i = 0; i < p.length; i++)
|
||||||
|
Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t));
|
||||||
|
Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init);
|
||||||
|
Statement *s1 = new ForStatement(0,
|
||||||
|
new DeclarationStatement(0, d),
|
||||||
|
new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))),
|
||||||
|
new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)),
|
||||||
|
new ExpStatement(0, loopbody));
|
||||||
|
#else
|
||||||
|
// foreach (i; 0 .. p.length)
|
||||||
|
Statement *s1 = new ForeachRangeStatement(0, TOKforeach,
|
||||||
|
new Parameter(0, NULL, Id::p, NULL),
|
||||||
|
new IntegerExp(0, 0, Type::tint32),
|
||||||
|
new ArrayLengthExp(0, new IdentifierExp(0, p->ident)),
|
||||||
|
new ExpStatement(0, loopbody));
|
||||||
|
#endif
|
||||||
|
Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident));
|
||||||
|
//printf("s2: %s\n", s2->toChars());
|
||||||
|
Statement *fbody = new CompoundStatement(0, s1, s2);
|
||||||
|
|
||||||
|
/* Construct the function
|
||||||
|
*/
|
||||||
|
TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc);
|
||||||
|
//printf("ftype: %s\n", ftype->toChars());
|
||||||
|
fd = new FuncDeclaration(loc, 0, ident, STCundefined, ftype);
|
||||||
|
fd->fbody = fbody;
|
||||||
|
fd->protection = PROTpublic;
|
||||||
|
fd->linkage = LINKd;
|
||||||
|
fd->isArrayOp = 1;
|
||||||
|
|
||||||
|
sc->module->importedFrom->members->push(fd);
|
||||||
|
|
||||||
|
sc = sc->push();
|
||||||
|
sc->parent = sc->module->importedFrom;
|
||||||
|
sc->stc = 0;
|
||||||
|
sc->linkage = LINKc;
|
||||||
|
fd->semantic(sc);
|
||||||
|
fd->semantic2(sc);
|
||||||
|
fd->semantic3(sc);
|
||||||
|
sc->pop();
|
||||||
|
}
|
||||||
|
#if IN_LLVM
|
||||||
|
else
|
||||||
|
{ /* In library, refer to it.
|
||||||
|
*/
|
||||||
|
Parameters *fparams = new Parameters();
|
||||||
|
buildArrayLoop(fparams);
|
||||||
|
fd = FuncDeclaration::genCfunc(fparams, type, ident);
|
||||||
|
fd->isArrayOp = 2;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
else
|
||||||
|
{ /* In library, refer to it.
|
||||||
|
*/
|
||||||
|
fd = FuncDeclaration::genCfunc(type, ident);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*pfd = fd; // cache symbol in hash table
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the function fd(arguments)
|
||||||
|
*/
|
||||||
|
Expression *ec = new VarExp(0, fd);
|
||||||
|
Expression *e = new CallExp(loc, ec, arguments);
|
||||||
|
e->type = type;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* Construct the identifier for the array operation function,
|
||||||
|
* and build the argument list to pass to it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||||
|
{
|
||||||
|
buf->writestring("Exp");
|
||||||
|
arguments->shift(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CastExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||||
|
{
|
||||||
|
Type *tb = type->toBasetype();
|
||||||
|
if (tb->ty == Tarray || tb->ty == Tsarray)
|
||||||
|
{
|
||||||
|
e1->buildArrayIdent(buf, arguments);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Expression::buildArrayIdent(buf, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||||
|
{
|
||||||
|
buf->writestring("Slice");
|
||||||
|
arguments->shift(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||||
|
{
|
||||||
|
/* Evaluate assign expressions right to left
|
||||||
|
*/
|
||||||
|
e2->buildArrayIdent(buf, arguments);
|
||||||
|
e1->buildArrayIdent(buf, arguments);
|
||||||
|
buf->writestring("Assign");
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X(Str) \
|
||||||
|
void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \
|
||||||
|
{ \
|
||||||
|
/* Evaluate assign expressions right to left \
|
||||||
|
*/ \
|
||||||
|
e2->buildArrayIdent(buf, arguments); \
|
||||||
|
e1->buildArrayIdent(buf, arguments); \
|
||||||
|
buf->writestring(#Str); \
|
||||||
|
buf->writestring("ass"); \
|
||||||
|
}
|
||||||
|
|
||||||
|
X(Add)
|
||||||
|
X(Min)
|
||||||
|
X(Mul)
|
||||||
|
X(Div)
|
||||||
|
X(Mod)
|
||||||
|
X(Xor)
|
||||||
|
X(And)
|
||||||
|
X(Or)
|
||||||
|
#if DMDV2
|
||||||
|
X(Pow)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||||
|
{
|
||||||
|
e1->buildArrayIdent(buf, arguments);
|
||||||
|
buf->writestring("Neg");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments)
|
||||||
|
{
|
||||||
|
e1->buildArrayIdent(buf, arguments);
|
||||||
|
buf->writestring("Com");
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X(Str) \
|
||||||
|
void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \
|
||||||
|
{ \
|
||||||
|
/* Evaluate assign expressions left to right \
|
||||||
|
*/ \
|
||||||
|
e1->buildArrayIdent(buf, arguments); \
|
||||||
|
e2->buildArrayIdent(buf, arguments); \
|
||||||
|
buf->writestring(#Str); \
|
||||||
|
}
|
||||||
|
|
||||||
|
X(Add)
|
||||||
|
X(Min)
|
||||||
|
X(Mul)
|
||||||
|
X(Div)
|
||||||
|
X(Mod)
|
||||||
|
X(Xor)
|
||||||
|
X(And)
|
||||||
|
X(Or)
|
||||||
|
#if DMDV2
|
||||||
|
X(Pow)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* Construct the inner loop for the array operation function,
|
||||||
|
* and build the parameter list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Expression *Expression::buildArrayLoop(Parameters *fparams)
|
||||||
|
{
|
||||||
|
Identifier *id = Identifier::generateId("c", fparams->dim);
|
||||||
|
Parameter *param = new Parameter(0, type, id, NULL);
|
||||||
|
fparams->shift(param);
|
||||||
|
Expression *e = new IdentifierExp(0, id);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression *CastExp::buildArrayLoop(Parameters *fparams)
|
||||||
|
{
|
||||||
|
Type *tb = type->toBasetype();
|
||||||
|
if (tb->ty == Tarray || tb->ty == Tsarray)
|
||||||
|
{
|
||||||
|
return e1->buildArrayLoop(fparams);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Expression::buildArrayLoop(fparams);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression *SliceExp::buildArrayLoop(Parameters *fparams)
|
||||||
|
{
|
||||||
|
Identifier *id = Identifier::generateId("p", fparams->dim);
|
||||||
|
Parameter *param = new Parameter(STCconst, type, id, NULL);
|
||||||
|
fparams->shift(param);
|
||||||
|
Expression *e = new IdentifierExp(0, id);
|
||||||
|
Expressions *arguments = new Expressions();
|
||||||
|
Expression *index = new IdentifierExp(0, Id::p);
|
||||||
|
arguments->push(index);
|
||||||
|
e = new ArrayExp(0, e, arguments);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression *AssignExp::buildArrayLoop(Parameters *fparams)
|
||||||
|
{
|
||||||
|
/* Evaluate assign expressions right to left
|
||||||
|
*/
|
||||||
|
Expression *ex2 = e2->buildArrayLoop(fparams);
|
||||||
|
#if DMDV2
|
||||||
|
/* Need the cast because:
|
||||||
|
* b = c + p[i];
|
||||||
|
* where b is a byte fails because (c + p[i]) is an int
|
||||||
|
* which cannot be implicitly cast to byte.
|
||||||
|
*/
|
||||||
|
ex2 = new CastExp(0, ex2, e1->type->nextOf());
|
||||||
|
#endif
|
||||||
|
Expression *ex1 = e1->buildArrayLoop(fparams);
|
||||||
|
Parameter *param = (*fparams)[0];
|
||||||
|
param->storageClass = 0;
|
||||||
|
Expression *e = new AssignExp(0, ex1, ex2);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X(Str) \
|
||||||
|
Expression *Str##AssignExp::buildArrayLoop(Parameters *fparams) \
|
||||||
|
{ \
|
||||||
|
/* Evaluate assign expressions right to left \
|
||||||
|
*/ \
|
||||||
|
Expression *ex2 = e2->buildArrayLoop(fparams); \
|
||||||
|
Expression *ex1 = e1->buildArrayLoop(fparams); \
|
||||||
|
Parameter *param = (*fparams)[0]; \
|
||||||
|
param->storageClass = 0; \
|
||||||
|
Expression *e = new Str##AssignExp(loc, ex1, ex2); \
|
||||||
|
return e; \
|
||||||
|
}
|
||||||
|
|
||||||
|
X(Add)
|
||||||
|
X(Min)
|
||||||
|
X(Mul)
|
||||||
|
X(Div)
|
||||||
|
X(Mod)
|
||||||
|
X(Xor)
|
||||||
|
X(And)
|
||||||
|
X(Or)
|
||||||
|
#if DMDV2
|
||||||
|
X(Pow)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
Expression *NegExp::buildArrayLoop(Parameters *fparams)
|
||||||
|
{
|
||||||
|
Expression *ex1 = e1->buildArrayLoop(fparams);
|
||||||
|
Expression *e = new NegExp(0, ex1);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression *ComExp::buildArrayLoop(Parameters *fparams)
|
||||||
|
{
|
||||||
|
Expression *ex1 = e1->buildArrayLoop(fparams);
|
||||||
|
Expression *e = new ComExp(0, ex1);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X(Str) \
|
||||||
|
Expression *Str##Exp::buildArrayLoop(Parameters *fparams) \
|
||||||
|
{ \
|
||||||
|
/* Evaluate assign expressions left to right \
|
||||||
|
*/ \
|
||||||
|
Expression *ex1 = e1->buildArrayLoop(fparams); \
|
||||||
|
Expression *ex2 = e2->buildArrayLoop(fparams); \
|
||||||
|
Expression *e = new Str##Exp(0, ex1, ex2); \
|
||||||
|
return e; \
|
||||||
|
}
|
||||||
|
|
||||||
|
X(Add)
|
||||||
|
X(Min)
|
||||||
|
X(Mul)
|
||||||
|
X(Div)
|
||||||
|
X(Mod)
|
||||||
|
X(Xor)
|
||||||
|
X(And)
|
||||||
|
X(Or)
|
||||||
|
#if DMDV2
|
||||||
|
X(Pow)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************
|
||||||
|
* Test if operand is a valid array op operand.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int Expression::isArrayOperand()
|
||||||
|
{
|
||||||
|
//printf("Expression::isArrayOperand() %s\n", toChars());
|
||||||
|
if (op == TOKslice)
|
||||||
|
return 1;
|
||||||
|
if (type->toBasetype()->ty == Tarray)
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case TOKadd:
|
||||||
|
case TOKmin:
|
||||||
|
case TOKmul:
|
||||||
|
case TOKdiv:
|
||||||
|
case TOKmod:
|
||||||
|
case TOKxor:
|
||||||
|
case TOKand:
|
||||||
|
case TOKor:
|
||||||
|
case TOKassign:
|
||||||
|
case TOKaddass:
|
||||||
|
case TOKminass:
|
||||||
|
case TOKmulass:
|
||||||
|
case TOKdivass:
|
||||||
|
case TOKmodass:
|
||||||
|
case TOKxorass:
|
||||||
|
case TOKandass:
|
||||||
|
case TOKorass:
|
||||||
|
#if DMDV2
|
||||||
|
case TOKpow:
|
||||||
|
case TOKpowass:
|
||||||
|
#endif
|
||||||
|
case TOKneg:
|
||||||
|
case TOKtilde:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 2006-2007 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_ARRAYTYPES_H
|
||||||
|
#define DMD_ARRAYTYPES_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
typedef ArrayBase<struct TemplateParameter> TemplateParameters;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct Expression> Expressions;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct Statement> Statements;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct BaseClass> BaseClasses;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct ClassDeclaration> ClassDeclarations;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct Dsymbol> Dsymbols;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct Object> Objects;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct FuncDeclaration> FuncDeclarations;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct Parameter> Parameters;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct Identifier> Identifiers;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct Initializer> Initializers;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct VarDeclaration> VarDeclarations;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct Type> Types;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct ScopeDsymbol> ScopeDsymbols;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct Catch> Catches;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct StaticDtorDeclaration> StaticDtorDeclarations;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct SharedStaticDtorDeclaration> SharedStaticDtorDeclarations;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct AliasDeclaration> AliasDeclarations;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct Module> Modules;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct File> Files;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct CaseStatement> CaseStatements;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct CompoundStatement> CompoundStatements;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct GotoCaseStatement> GotoCaseStatements;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct TemplateInstance> TemplateInstances;
|
||||||
|
|
||||||
|
//typedef ArrayBase<char> Strings;
|
||||||
|
|
||||||
|
typedef ArrayBase<void> Voids;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct block> Blocks;
|
||||||
|
|
||||||
|
typedef ArrayBase<struct Symbol> Symbols;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The "Artistic License"
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The intent of this document is to state the conditions under which a
|
||||||
|
Package may be copied, such that the Copyright Holder maintains some
|
||||||
|
semblance of artistic control over the development of the package,
|
||||||
|
while giving the users of the package the right to use and distribute
|
||||||
|
the Package in a more-or-less customary fashion, plus the right to make
|
||||||
|
reasonable modifications.
|
||||||
|
|
||||||
|
Definitions:
|
||||||
|
|
||||||
|
"Package" refers to the collection of files distributed by the
|
||||||
|
Copyright Holder, and derivatives of that collection of files
|
||||||
|
created through textual modification.
|
||||||
|
|
||||||
|
"Standard Version" refers to such a Package if it has not been
|
||||||
|
modified, or has been modified in accordance with the wishes
|
||||||
|
of the Copyright Holder as specified below.
|
||||||
|
|
||||||
|
"Copyright Holder" is whoever is named in the copyright or
|
||||||
|
copyrights for the package.
|
||||||
|
|
||||||
|
"You" is you, if you're thinking about copying or distributing
|
||||||
|
this Package.
|
||||||
|
|
||||||
|
"Reasonable copying fee" is whatever you can justify on the
|
||||||
|
basis of media cost, duplication charges, time of people involved,
|
||||||
|
and so on. (You will not be required to justify it to the
|
||||||
|
Copyright Holder, but only to the computing community at large
|
||||||
|
as a market that must bear the fee.)
|
||||||
|
|
||||||
|
"Freely Available" means that no fee is charged for the item
|
||||||
|
itself, though there may be fees involved in handling the item.
|
||||||
|
It also means that recipients of the item may redistribute it
|
||||||
|
under the same conditions they received it.
|
||||||
|
|
||||||
|
1. You may make and give away verbatim copies of the source form of the
|
||||||
|
Standard Version of this Package without restriction, provided that you
|
||||||
|
duplicate all of the original copyright notices and associated disclaimers.
|
||||||
|
|
||||||
|
2. You may apply bug fixes, portability fixes and other modifications
|
||||||
|
derived from the Public Domain or from the Copyright Holder. A Package
|
||||||
|
modified in such a way shall still be considered the Standard Version.
|
||||||
|
|
||||||
|
3. You may otherwise modify your copy of this Package in any way, provided
|
||||||
|
that you insert a prominent notice in each changed file stating how and
|
||||||
|
when you changed that file, and provided that you do at least ONE of the
|
||||||
|
following:
|
||||||
|
|
||||||
|
a) place your modifications in the Public Domain or otherwise make them
|
||||||
|
Freely Available, such as by posting said modifications to Usenet or
|
||||||
|
an equivalent medium, or placing the modifications on a major archive
|
||||||
|
site such as uunet.uu.net, or by allowing the Copyright Holder to include
|
||||||
|
your modifications in the Standard Version of the Package.
|
||||||
|
|
||||||
|
b) use the modified Package only within your corporation or organization.
|
||||||
|
|
||||||
|
c) rename any non-standard executables so the names do not conflict
|
||||||
|
with standard executables, which must also be provided, and provide
|
||||||
|
a separate manual page for each non-standard executable that clearly
|
||||||
|
documents how it differs from the Standard Version.
|
||||||
|
|
||||||
|
d) make other distribution arrangements with the Copyright Holder.
|
||||||
|
|
||||||
|
4. You may distribute the programs of this Package in object code or
|
||||||
|
executable form, provided that you do at least ONE of the following:
|
||||||
|
|
||||||
|
a) distribute a Standard Version of the executables and library files,
|
||||||
|
together with instructions (in the manual page or equivalent) on where
|
||||||
|
to get the Standard Version.
|
||||||
|
|
||||||
|
b) accompany the distribution with the machine-readable source of
|
||||||
|
the Package with your modifications.
|
||||||
|
|
||||||
|
c) give non-standard executables non-standard names, and clearly
|
||||||
|
document the differences in manual pages (or equivalent), together
|
||||||
|
with instructions on where to get the Standard Version.
|
||||||
|
|
||||||
|
d) make other distribution arrangements with the Copyright Holder.
|
||||||
|
|
||||||
|
5. You may charge a reasonable copying fee for any distribution of this
|
||||||
|
Package. You may charge any fee you choose for support of this
|
||||||
|
Package. You may not charge a fee for this Package itself. However,
|
||||||
|
you may distribute this Package in aggregate with other (possibly
|
||||||
|
commercial) programs as part of a larger (possibly commercial) software
|
||||||
|
distribution provided that you do not advertise this Package as a
|
||||||
|
product of your own. You may embed this Package's interpreter within
|
||||||
|
an executable of yours (by linking); this shall be construed as a mere
|
||||||
|
form of aggregation, provided that the complete Standard Version of the
|
||||||
|
interpreter is so embedded.
|
||||||
|
|
||||||
|
6. The source code and object code supplied as input to or produced as
|
||||||
|
output from the programs of this Package do not automatically fall
|
||||||
|
under the copyright of this Package, but belong to whoever generated
|
||||||
|
them, and may be sold commercially, and may be aggregated with this
|
||||||
|
Package.
|
||||||
|
|
||||||
|
7. Aggregation of this Package with a commercial distribution is always
|
||||||
|
permitted provided that the use of this Package is embedded; that is,
|
||||||
|
when no overt attempt is made to make this Package's interfaces visible
|
||||||
|
to the end user of the commercial distribution. Such use shall not be
|
||||||
|
construed as a distribution of this Package.
|
||||||
|
|
||||||
|
8. The name of the Copyright Holder may not be used to endorse or promote
|
||||||
|
products derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
The End
|
||||||
+1565
File diff suppressed because it is too large
Load Diff
+202
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_ATTRIB_H
|
||||||
|
#define DMD_ATTRIB_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include "dsymbol.h"
|
||||||
|
|
||||||
|
struct Expression;
|
||||||
|
struct Statement;
|
||||||
|
struct LabelDsymbol;
|
||||||
|
struct Initializer;
|
||||||
|
struct Module;
|
||||||
|
struct Condition;
|
||||||
|
struct HdrGenState;
|
||||||
|
|
||||||
|
/**************************************************************/
|
||||||
|
|
||||||
|
struct AttribDeclaration : Dsymbol
|
||||||
|
{
|
||||||
|
Dsymbols *decl; // array of Dsymbol's
|
||||||
|
|
||||||
|
AttribDeclaration(Dsymbols *decl);
|
||||||
|
virtual Dsymbols *include(Scope *sc, ScopeDsymbol *s);
|
||||||
|
int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
|
||||||
|
void setScopeNewSc(Scope *sc,
|
||||||
|
StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection,
|
||||||
|
unsigned structalign);
|
||||||
|
void semanticNewSc(Scope *sc,
|
||||||
|
StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection,
|
||||||
|
unsigned structalign);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
void semantic2(Scope *sc);
|
||||||
|
void semantic3(Scope *sc);
|
||||||
|
void inlineScan();
|
||||||
|
void addComment(unsigned char *comment);
|
||||||
|
void emitComment(Scope *sc);
|
||||||
|
const char *kind();
|
||||||
|
int oneMember(Dsymbol **ps, Identifier *ident);
|
||||||
|
int hasPointers();
|
||||||
|
bool hasStaticCtorOrDtor();
|
||||||
|
void checkCtorConstInit();
|
||||||
|
void addLocalClass(ClassDeclarations *);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
void toJsonBuffer(OutBuffer *buf);
|
||||||
|
AttribDeclaration *isAttribDeclaration() { return this; }
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
void toObjFile(int multiobj); // compile to .obj file
|
||||||
|
int cvMember(unsigned char *p);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
virtual void codegen(Ir*);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StorageClassDeclaration: AttribDeclaration
|
||||||
|
{
|
||||||
|
StorageClass stc;
|
||||||
|
|
||||||
|
StorageClassDeclaration(StorageClass stc, Dsymbols *decl);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
void setScope(Scope *sc);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
int oneMember(Dsymbol **ps, Identifier *ident);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
|
||||||
|
static void stcToCBuffer(OutBuffer *buf, StorageClass stc);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LinkDeclaration : AttribDeclaration
|
||||||
|
{
|
||||||
|
enum LINK linkage;
|
||||||
|
|
||||||
|
LinkDeclaration(enum LINK p, Dsymbols *decl);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
void setScope(Scope *sc);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
void semantic3(Scope *sc);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
char *toChars();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProtDeclaration : AttribDeclaration
|
||||||
|
{
|
||||||
|
enum PROT protection;
|
||||||
|
|
||||||
|
ProtDeclaration(enum PROT p, Dsymbols *decl);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
void importAll(Scope *sc);
|
||||||
|
void setScope(Scope *sc);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
|
||||||
|
static void protectionToCBuffer(OutBuffer *buf, enum PROT protection);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AlignDeclaration : AttribDeclaration
|
||||||
|
{
|
||||||
|
unsigned salign;
|
||||||
|
|
||||||
|
AlignDeclaration(Loc loc, unsigned sa, Dsymbols *decl);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
void setScope(Scope *sc);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnonDeclaration : AttribDeclaration
|
||||||
|
{
|
||||||
|
int isunion;
|
||||||
|
int sem; // 1 if successful semantic()
|
||||||
|
|
||||||
|
AnonDeclaration(Loc loc, int isunion, Dsymbols *decl);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
const char *kind();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PragmaDeclaration : AttribDeclaration
|
||||||
|
{
|
||||||
|
Expressions *args; // array of Expression's
|
||||||
|
|
||||||
|
PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
void setScope(Scope *sc);
|
||||||
|
int oneMember(Dsymbol **ps, Identifier *ident);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
const char *kind();
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
void toObjFile(int multiobj); // compile to .obj file
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
void codegen(Ir*);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConditionalDeclaration : AttribDeclaration
|
||||||
|
{
|
||||||
|
Condition *condition;
|
||||||
|
Dsymbols *elsedecl; // array of Dsymbol's for else block
|
||||||
|
|
||||||
|
ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
int oneMember(Dsymbol **ps, Identifier *ident);
|
||||||
|
void emitComment(Scope *sc);
|
||||||
|
Dsymbols *include(Scope *sc, ScopeDsymbol *s);
|
||||||
|
void addComment(unsigned char *comment);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
void toJsonBuffer(OutBuffer *buf);
|
||||||
|
void importAll(Scope *sc);
|
||||||
|
void setScope(Scope *sc);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StaticIfDeclaration : ConditionalDeclaration
|
||||||
|
{
|
||||||
|
ScopeDsymbol *sd;
|
||||||
|
int addisdone;
|
||||||
|
|
||||||
|
StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
void importAll(Scope *sc);
|
||||||
|
void setScope(Scope *sc);
|
||||||
|
const char *kind();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mixin declarations
|
||||||
|
|
||||||
|
struct CompileDeclaration : AttribDeclaration
|
||||||
|
{
|
||||||
|
Expression *exp;
|
||||||
|
|
||||||
|
ScopeDsymbol *sd;
|
||||||
|
int compiled;
|
||||||
|
|
||||||
|
CompileDeclaration(Loc loc, Expression *exp);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
int addMember(Scope *sc, ScopeDsymbol *sd, int memnum);
|
||||||
|
void compileIt(Scope *sc);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DMD_ATTRIB_H */
|
||||||
+234
@@ -0,0 +1,234 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2009 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#if __FreeBSD__
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
long double sinl(long double);
|
||||||
|
long double cosl(long double);
|
||||||
|
long double tanl(long double);
|
||||||
|
long double sqrtl(long double);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "attrib.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "identifier.h"
|
||||||
|
#include "id.h"
|
||||||
|
#include "module.h"
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* Determine if function is a builtin one that we can
|
||||||
|
* evaluate at compile time.
|
||||||
|
*/
|
||||||
|
enum BUILTIN FuncDeclaration::isBuiltin()
|
||||||
|
{
|
||||||
|
static const char FeZe [] = "FNaNbNfeZe"; // @safe pure nothrow real function(real)
|
||||||
|
static const char FeZe2[] = "FNaNbNeeZe"; // @trusted pure nothrow real function(real)
|
||||||
|
static const char FuintZint[] = "FNaNbkZi"; // pure nothrow int function(uint)
|
||||||
|
static const char FuintZuint[] = "FNaNbkZk"; // pure nothrow uint function(uint)
|
||||||
|
static const char FulongZulong[] = "FNaNbkZk"; // pure nothrow int function(ulong)
|
||||||
|
static const char FulongZint[] = "FNaNbmZi"; // pure nothrow int function(uint)
|
||||||
|
static const char FrealrealZreal [] = "FNaNbNfeeZe"; // @safe pure nothrow real function(real, real)
|
||||||
|
static const char FrealZlong [] = "FNaNbNfeZl"; // @safe pure nothrow long function(real)
|
||||||
|
|
||||||
|
//printf("FuncDeclaration::isBuiltin() %s, %d\n", toChars(), builtin);
|
||||||
|
if (builtin == BUILTINunknown)
|
||||||
|
{
|
||||||
|
builtin = BUILTINnot;
|
||||||
|
if (parent && parent->isModule())
|
||||||
|
{
|
||||||
|
// If it's in the std.math package
|
||||||
|
if (parent->ident == Id::math &&
|
||||||
|
parent->parent && (parent->parent->ident == Id::std || parent->parent->ident == Id::core) &&
|
||||||
|
!parent->parent->parent)
|
||||||
|
{
|
||||||
|
//printf("deco = %s\n", type->deco);
|
||||||
|
if (strcmp(type->deco, FeZe) == 0 || strcmp(type->deco, FeZe2) == 0)
|
||||||
|
{
|
||||||
|
if (ident == Id::sin)
|
||||||
|
builtin = BUILTINsin;
|
||||||
|
else if (ident == Id::cos)
|
||||||
|
builtin = BUILTINcos;
|
||||||
|
else if (ident == Id::tan)
|
||||||
|
builtin = BUILTINtan;
|
||||||
|
else if (ident == Id::_sqrt)
|
||||||
|
builtin = BUILTINsqrt;
|
||||||
|
else if (ident == Id::fabs)
|
||||||
|
builtin = BUILTINfabs;
|
||||||
|
else if (ident == Id::expm1)
|
||||||
|
builtin = BUILTINexpm1;
|
||||||
|
else if (ident == Id::exp2)
|
||||||
|
builtin = BUILTINexp2;
|
||||||
|
//printf("builtin = %d\n", builtin);
|
||||||
|
}
|
||||||
|
// if float or double versions
|
||||||
|
else if (strcmp(type->deco, "FNaNbNfdZd") == 0 ||
|
||||||
|
strcmp(type->deco, "FNaNbNffZf") == 0)
|
||||||
|
{
|
||||||
|
if (ident == Id::_sqrt)
|
||||||
|
builtin = BUILTINsqrt;
|
||||||
|
}
|
||||||
|
else if (strcmp(type->deco, FrealrealZreal) == 0)
|
||||||
|
{
|
||||||
|
if (ident == Id::atan2)
|
||||||
|
builtin = BUILTINatan2;
|
||||||
|
else if (ident == Id::yl2x)
|
||||||
|
builtin = BUILTINyl2x;
|
||||||
|
else if (ident == Id::yl2xp1)
|
||||||
|
builtin = BUILTINyl2xp1;
|
||||||
|
}
|
||||||
|
else if (strcmp(type->deco, FrealZlong) == 0 && ident == Id::rndtol)
|
||||||
|
builtin = BUILTINrndtol;
|
||||||
|
}
|
||||||
|
if (parent->ident == Id::bitop &&
|
||||||
|
parent->parent && parent->parent->ident == Id::core &&
|
||||||
|
!parent->parent->parent)
|
||||||
|
{
|
||||||
|
//printf("deco = %s\n", type->deco);
|
||||||
|
if (strcmp(type->deco, FuintZint) == 0 || strcmp(type->deco, FulongZint) == 0)
|
||||||
|
{
|
||||||
|
if (ident == Id::bsf)
|
||||||
|
builtin = BUILTINbsf;
|
||||||
|
else if (ident == Id::bsr)
|
||||||
|
builtin = BUILTINbsr;
|
||||||
|
}
|
||||||
|
else if (strcmp(type->deco, FuintZuint) == 0)
|
||||||
|
{
|
||||||
|
if (ident == Id::bswap)
|
||||||
|
builtin = BUILTINbswap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builtin;
|
||||||
|
}
|
||||||
|
|
||||||
|
int eval_bsf(uinteger_t n)
|
||||||
|
{
|
||||||
|
n = (n ^ (n - 1)) >> 1; // convert trailing 0s to 1, and zero rest
|
||||||
|
int k = 0;
|
||||||
|
while( n )
|
||||||
|
{ ++k;
|
||||||
|
n >>=1;
|
||||||
|
}
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
int eval_bsr(uinteger_t n)
|
||||||
|
{ int k= 0;
|
||||||
|
while(n>>=1)
|
||||||
|
{
|
||||||
|
++k;
|
||||||
|
}
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
uinteger_t eval_bswap(Expression *arg0)
|
||||||
|
{ uinteger_t n = arg0->toInteger();
|
||||||
|
#define BYTEMASK 0x00FF00FF00FF00FFLL
|
||||||
|
#define SHORTMASK 0x0000FFFF0000FFFFLL
|
||||||
|
#define INTMASK 0x0000FFFF0000FFFFLL
|
||||||
|
// swap adjacent ubytes
|
||||||
|
n = ((n >> 8 ) & BYTEMASK) | ((n & BYTEMASK) << 8 );
|
||||||
|
// swap adjacent ushorts
|
||||||
|
n = ((n >> 16) & SHORTMASK) | ((n & SHORTMASK) << 16);
|
||||||
|
TY ty = arg0->type->toBasetype()->ty;
|
||||||
|
// If 64 bits, we need to swap high and low uints
|
||||||
|
if (ty == Tint64 || ty == Tuns64)
|
||||||
|
n = ((n >> 32) & INTMASK) | ((n & INTMASK) << 32);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* Evaluate builtin function.
|
||||||
|
* Return result; NULL if cannot evaluate it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments)
|
||||||
|
{
|
||||||
|
assert(arguments && arguments->dim);
|
||||||
|
Expression *arg0 = arguments->tdata()[0];
|
||||||
|
Expression *e = NULL;
|
||||||
|
switch (builtin)
|
||||||
|
{
|
||||||
|
case BUILTINsin:
|
||||||
|
if (arg0->op == TOKfloat64)
|
||||||
|
e = new RealExp(0, sinl(arg0->toReal()), arg0->type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUILTINcos:
|
||||||
|
if (arg0->op == TOKfloat64)
|
||||||
|
e = new RealExp(0, cosl(arg0->toReal()), arg0->type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUILTINtan:
|
||||||
|
if (arg0->op == TOKfloat64)
|
||||||
|
e = new RealExp(0, tanl(arg0->toReal()), arg0->type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUILTINsqrt:
|
||||||
|
if (arg0->op == TOKfloat64)
|
||||||
|
e = new RealExp(0, sqrtl(arg0->toReal()), arg0->type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUILTINfabs:
|
||||||
|
if (arg0->op == TOKfloat64)
|
||||||
|
e = new RealExp(0, fabsl(arg0->toReal()), arg0->type);
|
||||||
|
break;
|
||||||
|
// These math intrinsics are not yet implemented
|
||||||
|
case BUILTINatan2:
|
||||||
|
break;
|
||||||
|
case BUILTINrndtol:
|
||||||
|
break;
|
||||||
|
case BUILTINexpm1:
|
||||||
|
break;
|
||||||
|
case BUILTINexp2:
|
||||||
|
break;
|
||||||
|
case BUILTINyl2x:
|
||||||
|
break;
|
||||||
|
case BUILTINyl2xp1:
|
||||||
|
break;
|
||||||
|
case BUILTINbsf:
|
||||||
|
if (arg0->op == TOKint64)
|
||||||
|
{ if (arg0->toInteger()==0)
|
||||||
|
error(loc, "bsf(0) is undefined");
|
||||||
|
else
|
||||||
|
e = new IntegerExp(loc, eval_bsf(arg0->toInteger()), Type::tint32);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BUILTINbsr:
|
||||||
|
if (arg0->op == TOKint64)
|
||||||
|
{ if (arg0->toInteger()==0)
|
||||||
|
error(loc, "bsr(0) is undefined");
|
||||||
|
else
|
||||||
|
e = new IntegerExp(loc, eval_bsr(arg0->toInteger()), Type::tint32);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BUILTINbswap:
|
||||||
|
if (arg0->op == TOKint64)
|
||||||
|
e = new IntegerExp(loc, eval_bswap(arg0), arg0->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
+189
@@ -0,0 +1,189 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "template.h"
|
||||||
|
#include "statement.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "utf.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "attrib.h"
|
||||||
|
|
||||||
|
int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow);
|
||||||
|
int lambdaCanThrow(Expression *e, void *param);
|
||||||
|
|
||||||
|
/********************************************
|
||||||
|
* Convert from expression to delegate that returns the expression,
|
||||||
|
* i.e. convert:
|
||||||
|
* expr
|
||||||
|
* to:
|
||||||
|
* t delegate() { return expr; }
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct CanThrow
|
||||||
|
{
|
||||||
|
bool can;
|
||||||
|
bool mustnot;
|
||||||
|
};
|
||||||
|
|
||||||
|
int Expression::canThrow(bool mustNotThrow)
|
||||||
|
{
|
||||||
|
CanThrow ct;
|
||||||
|
ct.can = FALSE;
|
||||||
|
ct.mustnot = mustNotThrow;
|
||||||
|
apply(&lambdaCanThrow, &ct);
|
||||||
|
return ct.can;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lambdaCanThrow(Expression *e, void *param)
|
||||||
|
{
|
||||||
|
CanThrow *pct = (CanThrow *)param;
|
||||||
|
switch (e->op)
|
||||||
|
{
|
||||||
|
case TOKdeclaration:
|
||||||
|
{ DeclarationExp *de = (DeclarationExp *)e;
|
||||||
|
pct->can = Dsymbol_canThrow(de->declaration, pct->mustnot);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOKcall:
|
||||||
|
{ CallExp *ce = (CallExp *)e;
|
||||||
|
|
||||||
|
if (global.errors && !ce->e1->type)
|
||||||
|
break; // error recovery
|
||||||
|
|
||||||
|
/* If calling a function or delegate that is typed as nothrow,
|
||||||
|
* then this expression cannot throw.
|
||||||
|
* Note that pure functions can throw.
|
||||||
|
*/
|
||||||
|
Type *t = ce->e1->type->toBasetype();
|
||||||
|
if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow)
|
||||||
|
;
|
||||||
|
else if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pct->mustnot)
|
||||||
|
e->error("%s is not nothrow", ce->e1->toChars());
|
||||||
|
pct->can = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOKnew:
|
||||||
|
{ NewExp *ne = (NewExp *)e;
|
||||||
|
if (ne->member)
|
||||||
|
{
|
||||||
|
// See if constructor call can throw
|
||||||
|
Type *t = ne->member->type->toBasetype();
|
||||||
|
if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
|
||||||
|
{
|
||||||
|
if (pct->mustnot)
|
||||||
|
e->error("constructor %s is not nothrow", ne->member->toChars());
|
||||||
|
pct->can = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// regard storage allocation failures as not recoverable
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOKnewanonclass:
|
||||||
|
assert(0); // should have been lowered by semantic()
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return pct->can; // stop walking if we determine this expression can throw
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* Does symbol, when initialized, throw?
|
||||||
|
* Mirrors logic in Dsymbol_toElem().
|
||||||
|
*/
|
||||||
|
|
||||||
|
int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow)
|
||||||
|
{
|
||||||
|
AttribDeclaration *ad;
|
||||||
|
VarDeclaration *vd;
|
||||||
|
TemplateMixin *tm;
|
||||||
|
TupleDeclaration *td;
|
||||||
|
|
||||||
|
//printf("Dsymbol_toElem() %s\n", s->toChars());
|
||||||
|
ad = s->isAttribDeclaration();
|
||||||
|
if (ad)
|
||||||
|
{
|
||||||
|
Dsymbols *decl = ad->include(NULL, NULL);
|
||||||
|
if (decl && decl->dim)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < decl->dim; i++)
|
||||||
|
{
|
||||||
|
s = decl->tdata()[i];
|
||||||
|
if (Dsymbol_canThrow(s, mustNotThrow))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((vd = s->isVarDeclaration()) != NULL)
|
||||||
|
{
|
||||||
|
s = s->toAlias();
|
||||||
|
if (s != vd)
|
||||||
|
return Dsymbol_canThrow(s, mustNotThrow);
|
||||||
|
if (vd->storage_class & STCmanifest)
|
||||||
|
;
|
||||||
|
else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared))
|
||||||
|
;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (vd->init)
|
||||||
|
{ ExpInitializer *ie = vd->init->isExpInitializer();
|
||||||
|
if (ie && ie->exp->canThrow(mustNotThrow))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (vd->edtor && !vd->noscope)
|
||||||
|
return vd->edtor->canThrow(mustNotThrow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((tm = s->isTemplateMixin()) != NULL)
|
||||||
|
{
|
||||||
|
//printf("%s\n", tm->toChars());
|
||||||
|
if (tm->members)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < tm->members->dim; i++)
|
||||||
|
{
|
||||||
|
Dsymbol *sm = tm->members->tdata()[i];
|
||||||
|
if (Dsymbol_canThrow(sm, mustNotThrow))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((td = s->isTupleDeclaration()) != NULL)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < td->objects->dim; i++)
|
||||||
|
{ Object *o = td->objects->tdata()[i];
|
||||||
|
if (o->dyncast() == DYNCAST_EXPRESSION)
|
||||||
|
{ Expression *eo = (Expression *)o;
|
||||||
|
if (eo->op == TOKdsymbol)
|
||||||
|
{ DsymbolExp *se = (DsymbolExp *)eo;
|
||||||
|
if (Dsymbol_canThrow(se->s, mustNotThrow))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+2641
File diff suppressed because it is too large
Load Diff
+1656
File diff suppressed because it is too large
Load Diff
+694
@@ -0,0 +1,694 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "module.h"
|
||||||
|
#include "id.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "statement.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "template.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************
|
||||||
|
* We need an opAssign for the struct if
|
||||||
|
* it has a destructor or a postblit.
|
||||||
|
* We need to generate one if a user-specified one does not exist.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int StructDeclaration::needOpAssign()
|
||||||
|
{
|
||||||
|
#define X 0
|
||||||
|
if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars());
|
||||||
|
if (hasIdentityAssign)
|
||||||
|
goto Ldontneed;
|
||||||
|
|
||||||
|
if (dtor || postblit)
|
||||||
|
goto Lneed;
|
||||||
|
|
||||||
|
/* If any of the fields need an opAssign, then we
|
||||||
|
* need it too.
|
||||||
|
*/
|
||||||
|
for (size_t i = 0; i < fields.dim; i++)
|
||||||
|
{
|
||||||
|
Dsymbol *s = fields.tdata()[i];
|
||||||
|
VarDeclaration *v = s->isVarDeclaration();
|
||||||
|
assert(v && v->storage_class & STCfield);
|
||||||
|
if (v->storage_class & STCref)
|
||||||
|
continue;
|
||||||
|
Type *tv = v->type->toBasetype();
|
||||||
|
while (tv->ty == Tsarray)
|
||||||
|
{ TypeSArray *ta = (TypeSArray *)tv;
|
||||||
|
tv = tv->nextOf()->toBasetype();
|
||||||
|
}
|
||||||
|
if (tv->ty == Tstruct)
|
||||||
|
{ TypeStruct *ts = (TypeStruct *)tv;
|
||||||
|
StructDeclaration *sd = ts->sym;
|
||||||
|
if (sd->needOpAssign())
|
||||||
|
goto Lneed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ldontneed:
|
||||||
|
if (X) printf("\tdontneed\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Lneed:
|
||||||
|
if (X) printf("\tneed\n");
|
||||||
|
return 1;
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* Build opAssign for struct.
|
||||||
|
* S* opAssign(S s) { ... }
|
||||||
|
*
|
||||||
|
* Note that s will be constructed onto the stack, probably copy-constructed.
|
||||||
|
* Then, the body is:
|
||||||
|
* S tmp = *this; // bit copy
|
||||||
|
* *this = s; // bit copy
|
||||||
|
* tmp.dtor();
|
||||||
|
* Instead of running the destructor on s, run it on tmp instead.
|
||||||
|
*/
|
||||||
|
|
||||||
|
FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
|
||||||
|
{
|
||||||
|
if (!needOpAssign())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
//printf("StructDeclaration::buildOpAssign() %s\n", toChars());
|
||||||
|
|
||||||
|
FuncDeclaration *fop = NULL;
|
||||||
|
|
||||||
|
Parameters *fparams = new Parameters;
|
||||||
|
fparams->push(new Parameter(STCnodtor, type, Id::p, NULL));
|
||||||
|
Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd);
|
||||||
|
#if STRUCTTHISREF
|
||||||
|
((TypeFunction *)ftype)->isref = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fop = new FuncDeclaration(loc, 0, Id::assign, STCundefined, ftype);
|
||||||
|
|
||||||
|
Expression *e = NULL;
|
||||||
|
if (postblit)
|
||||||
|
{ /* Swap:
|
||||||
|
* tmp = *this; *this = s; tmp.dtor();
|
||||||
|
*/
|
||||||
|
//printf("\tswap copy\n");
|
||||||
|
Identifier *idtmp = Lexer::uniqueId("__tmp");
|
||||||
|
VarDeclaration *tmp;
|
||||||
|
AssignExp *ec = NULL;
|
||||||
|
if (dtor)
|
||||||
|
{
|
||||||
|
tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0));
|
||||||
|
tmp->noscope = 1;
|
||||||
|
tmp->storage_class |= STCctfe;
|
||||||
|
e = new DeclarationExp(0, tmp);
|
||||||
|
ec = new AssignExp(0,
|
||||||
|
new VarExp(0, tmp),
|
||||||
|
#if STRUCTTHISREF
|
||||||
|
new ThisExp(0)
|
||||||
|
#else
|
||||||
|
new PtrExp(0, new ThisExp(0))
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
ec->op = TOKblit;
|
||||||
|
e = Expression::combine(e, ec);
|
||||||
|
}
|
||||||
|
ec = new AssignExp(0,
|
||||||
|
#if STRUCTTHISREF
|
||||||
|
new ThisExp(0),
|
||||||
|
#else
|
||||||
|
new PtrExp(0, new ThisExp(0)),
|
||||||
|
#endif
|
||||||
|
new IdentifierExp(0, Id::p));
|
||||||
|
ec->op = TOKblit;
|
||||||
|
e = Expression::combine(e, ec);
|
||||||
|
if (dtor)
|
||||||
|
{
|
||||||
|
/* Instead of running the destructor on s, run it
|
||||||
|
* on tmp. This avoids needing to copy tmp back in to s.
|
||||||
|
*/
|
||||||
|
Expression *ec2 = new DotVarExp(0, new VarExp(0, tmp), dtor, 0);
|
||||||
|
ec2 = new CallExp(0, ec2);
|
||||||
|
e = Expression::combine(e, ec2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* Do memberwise copy
|
||||||
|
*/
|
||||||
|
//printf("\tmemberwise copy\n");
|
||||||
|
for (size_t i = 0; i < fields.dim; i++)
|
||||||
|
{
|
||||||
|
Dsymbol *s = fields.tdata()[i];
|
||||||
|
VarDeclaration *v = s->isVarDeclaration();
|
||||||
|
assert(v && v->storage_class & STCfield);
|
||||||
|
// this.v = s.v;
|
||||||
|
AssignExp *ec = new AssignExp(0,
|
||||||
|
new DotVarExp(0, new ThisExp(0), v, 0),
|
||||||
|
new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0));
|
||||||
|
ec->op = TOKblit;
|
||||||
|
e = Expression::combine(e, ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement *s1 = new ExpStatement(0, e);
|
||||||
|
|
||||||
|
/* Add:
|
||||||
|
* return this;
|
||||||
|
*/
|
||||||
|
e = new ThisExp(0);
|
||||||
|
Statement *s2 = new ReturnStatement(0, e);
|
||||||
|
|
||||||
|
fop->fbody = new CompoundStatement(0, s1, s2);
|
||||||
|
|
||||||
|
members->push(fop);
|
||||||
|
fop->addMember(sc, this, 1);
|
||||||
|
|
||||||
|
sc = sc->push();
|
||||||
|
sc->stc = 0;
|
||||||
|
sc->linkage = LINKd;
|
||||||
|
|
||||||
|
fop->semantic(sc);
|
||||||
|
|
||||||
|
sc->pop();
|
||||||
|
|
||||||
|
//printf("-StructDeclaration::buildOpAssign() %s\n", toChars());
|
||||||
|
|
||||||
|
return fop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************
|
||||||
|
* We need an opEquals for the struct if
|
||||||
|
* any fields has an opEquals.
|
||||||
|
* Generate one if a user-specified one does not exist.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int StructDeclaration::needOpEquals()
|
||||||
|
{
|
||||||
|
#define X 0
|
||||||
|
if (X) printf("StructDeclaration::needOpEquals() %s\n", toChars());
|
||||||
|
|
||||||
|
if (hasIdentityEquals)
|
||||||
|
goto Lneed;
|
||||||
|
|
||||||
|
/* If any of the fields has an opEquals, then we
|
||||||
|
* need it too.
|
||||||
|
*/
|
||||||
|
for (size_t i = 0; i < fields.dim; i++)
|
||||||
|
{
|
||||||
|
Dsymbol *s = fields.tdata()[i];
|
||||||
|
VarDeclaration *v = s->isVarDeclaration();
|
||||||
|
assert(v && v->storage_class & STCfield);
|
||||||
|
if (v->storage_class & STCref)
|
||||||
|
continue;
|
||||||
|
Type *tv = v->type->toBasetype();
|
||||||
|
while (tv->ty == Tsarray)
|
||||||
|
{ TypeSArray *ta = (TypeSArray *)tv;
|
||||||
|
tv = tv->nextOf()->toBasetype();
|
||||||
|
}
|
||||||
|
if (tv->ty == Tstruct)
|
||||||
|
{ TypeStruct *ts = (TypeStruct *)tv;
|
||||||
|
StructDeclaration *sd = ts->sym;
|
||||||
|
if (sd->needOpEquals())
|
||||||
|
goto Lneed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (X) printf("\tdontneed\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Lneed:
|
||||||
|
if (X) printf("\tneed\n");
|
||||||
|
return 1;
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* Build opEquals for struct.
|
||||||
|
* const bool opEquals(const S s) { ... }
|
||||||
|
*/
|
||||||
|
|
||||||
|
FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc)
|
||||||
|
{
|
||||||
|
Dsymbol *eq = search_function(this, Id::eq);
|
||||||
|
if (eq)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i <= 1; i++)
|
||||||
|
{
|
||||||
|
Expression *e =
|
||||||
|
i == 0 ? new NullExp(loc, type->constOf()) // dummy rvalue
|
||||||
|
: type->constOf()->defaultInit(); // dummy lvalue
|
||||||
|
Expressions *arguments = new Expressions();
|
||||||
|
arguments->push(e);
|
||||||
|
|
||||||
|
// check identity opEquals exists
|
||||||
|
FuncDeclaration *fd = eq->isFuncDeclaration();
|
||||||
|
if (fd)
|
||||||
|
{ fd = fd->overloadResolve(loc, e, arguments, 1);
|
||||||
|
if (fd && !(fd->storage_class & STCdisable))
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateDeclaration *td = eq->isTemplateDeclaration();
|
||||||
|
if (td)
|
||||||
|
{ fd = td->deduceFunctionTemplate(sc, loc, NULL, e, arguments, 1);
|
||||||
|
if (fd && !(fd->storage_class & STCdisable))
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needOpEquals())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
//printf("StructDeclaration::buildOpEquals() %s\n", toChars());
|
||||||
|
|
||||||
|
Parameters *parameters = new Parameters;
|
||||||
|
parameters->push(new Parameter(STCin, type, Id::p, NULL));
|
||||||
|
TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
|
||||||
|
tf->mod = MODconst;
|
||||||
|
tf = (TypeFunction *)tf->semantic(loc, sc);
|
||||||
|
|
||||||
|
FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::eq, STCundefined, tf);
|
||||||
|
|
||||||
|
Expression *e = NULL;
|
||||||
|
/* Do memberwise compare
|
||||||
|
*/
|
||||||
|
//printf("\tmemberwise compare\n");
|
||||||
|
for (size_t i = 0; i < fields.dim; i++)
|
||||||
|
{
|
||||||
|
Dsymbol *s = fields.tdata()[i];
|
||||||
|
VarDeclaration *v = s->isVarDeclaration();
|
||||||
|
assert(v && v->storage_class & STCfield);
|
||||||
|
if (v->storage_class & STCref)
|
||||||
|
assert(0); // what should we do with this?
|
||||||
|
// this.v == s.v;
|
||||||
|
EqualExp *ec = new EqualExp(TOKequal, loc,
|
||||||
|
new DotVarExp(loc, new ThisExp(loc), v, 0),
|
||||||
|
new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0));
|
||||||
|
if (e)
|
||||||
|
e = new AndAndExp(loc, e, ec);
|
||||||
|
else
|
||||||
|
e = ec;
|
||||||
|
}
|
||||||
|
if (!e)
|
||||||
|
e = new IntegerExp(loc, 1, Type::tbool);
|
||||||
|
fop->fbody = new ReturnStatement(loc, e);
|
||||||
|
|
||||||
|
members->push(fop);
|
||||||
|
fop->addMember(sc, this, 1);
|
||||||
|
|
||||||
|
sc = sc->push();
|
||||||
|
sc->stc = 0;
|
||||||
|
sc->linkage = LINKd;
|
||||||
|
|
||||||
|
fop->semantic(sc);
|
||||||
|
|
||||||
|
sc->pop();
|
||||||
|
|
||||||
|
//printf("-StructDeclaration::buildOpEquals() %s\n", toChars());
|
||||||
|
|
||||||
|
return fop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* Build __xopEquals for TypeInfo_Struct
|
||||||
|
* bool __xopEquals(in void* p, in void* q) { ... }
|
||||||
|
*/
|
||||||
|
|
||||||
|
FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc)
|
||||||
|
{
|
||||||
|
if (!search_function(this, Id::eq))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* static bool__xopEquals(in void* p, in void* q) {
|
||||||
|
* return ( *cast(const S*)(p) ).opEquals( *cast(const S*)(q) );
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
Parameters *parameters = new Parameters;
|
||||||
|
parameters->push(new Parameter(STCin, Type::tvoidptr, Id::p, NULL));
|
||||||
|
parameters->push(new Parameter(STCin, Type::tvoidptr, Id::q, NULL));
|
||||||
|
TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
|
||||||
|
tf = (TypeFunction *)tf->semantic(loc, sc);
|
||||||
|
|
||||||
|
Identifier *id = Lexer::idPool("__xopEquals");
|
||||||
|
FuncDeclaration *fop = new FuncDeclaration(loc, 0, id, STCstatic, tf);
|
||||||
|
|
||||||
|
Expression *e = new CallExp(0,
|
||||||
|
new DotIdExp(0,
|
||||||
|
new PtrExp(0, new CastExp(0,
|
||||||
|
new IdentifierExp(0, Id::p), type->pointerTo()->constOf())),
|
||||||
|
Id::eq),
|
||||||
|
new PtrExp(0, new CastExp(0,
|
||||||
|
new IdentifierExp(0, Id::q), type->pointerTo()->constOf())));
|
||||||
|
|
||||||
|
fop->fbody = new ReturnStatement(loc, e);
|
||||||
|
|
||||||
|
size_t index = members->dim;
|
||||||
|
members->push(fop);
|
||||||
|
|
||||||
|
sc = sc->push();
|
||||||
|
sc->stc = 0;
|
||||||
|
sc->linkage = LINKd;
|
||||||
|
|
||||||
|
unsigned errors = global.startGagging();
|
||||||
|
fop->semantic(sc);
|
||||||
|
if (errors == global.gaggedErrors)
|
||||||
|
{ fop->semantic2(sc);
|
||||||
|
if (errors == global.gaggedErrors)
|
||||||
|
{ fop->semantic3(sc);
|
||||||
|
if (errors == global.gaggedErrors)
|
||||||
|
fop->addMember(sc, this, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (global.endGagging(errors)) // if errors happened
|
||||||
|
{
|
||||||
|
members->remove(index);
|
||||||
|
|
||||||
|
if (!xerreq)
|
||||||
|
{
|
||||||
|
Expression *e = new IdentifierExp(loc, Id::empty);
|
||||||
|
e = new DotIdExp(loc, e, Id::object);
|
||||||
|
e = new DotIdExp(loc, e, Lexer::idPool("_xopEquals"));
|
||||||
|
e = e->semantic(sc);
|
||||||
|
Dsymbol *s = getDsymbol(e);
|
||||||
|
FuncDeclaration *fd = s->isFuncDeclaration();
|
||||||
|
|
||||||
|
xerreq = fd;
|
||||||
|
}
|
||||||
|
fop = xerreq;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->pop();
|
||||||
|
|
||||||
|
return fop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************
|
||||||
|
* Build copy constructor for struct.
|
||||||
|
* Copy constructors are compiler generated only, and are only
|
||||||
|
* callable from the compiler. They are not user accessible.
|
||||||
|
* A copy constructor is:
|
||||||
|
* void cpctpr(ref const S s) const
|
||||||
|
* {
|
||||||
|
* (*cast(S*)&this) = *cast(S*)s;
|
||||||
|
* (*cast(S*)&this).postBlit();
|
||||||
|
* }
|
||||||
|
* This is done so:
|
||||||
|
* - postBlit() never sees uninitialized data
|
||||||
|
* - memcpy can be much more efficient than memberwise copy
|
||||||
|
* - no fields are overlooked
|
||||||
|
*/
|
||||||
|
|
||||||
|
FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
|
||||||
|
{
|
||||||
|
//printf("StructDeclaration::buildCpCtor() %s\n", toChars());
|
||||||
|
FuncDeclaration *fcp = NULL;
|
||||||
|
|
||||||
|
/* Copy constructor is only necessary if there is a postblit function,
|
||||||
|
* otherwise the code generator will just do a bit copy.
|
||||||
|
*/
|
||||||
|
if (postblit)
|
||||||
|
{
|
||||||
|
//printf("generating cpctor\n");
|
||||||
|
|
||||||
|
StorageClass stc = postblit->storage_class &
|
||||||
|
(STCdisable | STCsafe | STCtrusted | STCsystem | STCpure | STCnothrow);
|
||||||
|
if (stc & (STCsafe | STCtrusted))
|
||||||
|
stc = stc & ~STCsafe | STCtrusted;
|
||||||
|
|
||||||
|
Parameters *fparams = new Parameters;
|
||||||
|
fparams->push(new Parameter(STCref, type->constOf(), Id::p, NULL));
|
||||||
|
Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd, stc);
|
||||||
|
ftype->mod = MODconst;
|
||||||
|
|
||||||
|
fcp = new FuncDeclaration(loc, 0, Id::cpctor, stc, ftype);
|
||||||
|
|
||||||
|
if (!(fcp->storage_class & STCdisable))
|
||||||
|
{
|
||||||
|
// Build *this = p;
|
||||||
|
Expression *e = new ThisExp(0);
|
||||||
|
#if !STRUCTTHISREF
|
||||||
|
e = new PtrExp(0, e);
|
||||||
|
#endif
|
||||||
|
AssignExp *ea = new AssignExp(0,
|
||||||
|
new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo())),
|
||||||
|
new PtrExp(0, new CastExp(0, new AddrExp(0, new IdentifierExp(0, Id::p)), type->mutableOf()->pointerTo()))
|
||||||
|
);
|
||||||
|
ea->op = TOKblit;
|
||||||
|
Statement *s = new ExpStatement(0, ea);
|
||||||
|
|
||||||
|
// Build postBlit();
|
||||||
|
e = new ThisExp(0);
|
||||||
|
#if !STRUCTTHISREF
|
||||||
|
e = new PtrExp(0, e);
|
||||||
|
#endif
|
||||||
|
e = new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo()));
|
||||||
|
e = new DotVarExp(0, e, postblit, 0);
|
||||||
|
e = new CallExp(0, e);
|
||||||
|
|
||||||
|
s = new CompoundStatement(0, s, new ExpStatement(0, e));
|
||||||
|
fcp->fbody = s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fcp->fbody = new ExpStatement(0, (Expression *)NULL);
|
||||||
|
|
||||||
|
members->push(fcp);
|
||||||
|
|
||||||
|
sc = sc->push();
|
||||||
|
sc->stc = 0;
|
||||||
|
sc->linkage = LINKd;
|
||||||
|
|
||||||
|
fcp->semantic(sc);
|
||||||
|
|
||||||
|
sc->pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return fcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************
|
||||||
|
* Create inclusive postblit for struct by aggregating
|
||||||
|
* all the postblits in postblits[] with the postblits for
|
||||||
|
* all the members.
|
||||||
|
* Note the close similarity with AggregateDeclaration::buildDtor(),
|
||||||
|
* and the ordering changes (runs forward instead of backwards).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc)
|
||||||
|
{
|
||||||
|
//printf("StructDeclaration::buildPostBlit() %s\n", toChars());
|
||||||
|
Expression *e = NULL;
|
||||||
|
StorageClass stc = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fields.dim; i++)
|
||||||
|
{
|
||||||
|
Dsymbol *s = fields.tdata()[i];
|
||||||
|
VarDeclaration *v = s->isVarDeclaration();
|
||||||
|
assert(v && v->storage_class & STCfield);
|
||||||
|
if (v->storage_class & STCref)
|
||||||
|
continue;
|
||||||
|
Type *tv = v->type->toBasetype();
|
||||||
|
dinteger_t dim = (tv->ty == Tsarray ? 1 : 0);
|
||||||
|
while (tv->ty == Tsarray)
|
||||||
|
{ TypeSArray *ta = (TypeSArray *)tv;
|
||||||
|
dim *= ((TypeSArray *)tv)->dim->toInteger();
|
||||||
|
tv = tv->nextOf()->toBasetype();
|
||||||
|
}
|
||||||
|
if (tv->ty == Tstruct)
|
||||||
|
{ TypeStruct *ts = (TypeStruct *)tv;
|
||||||
|
StructDeclaration *sd = ts->sym;
|
||||||
|
if (sd->postblit)
|
||||||
|
{
|
||||||
|
stc |= sd->postblit->storage_class & STCdisable;
|
||||||
|
|
||||||
|
if (stc & STCdisable)
|
||||||
|
{
|
||||||
|
e = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this.v
|
||||||
|
Expression *ex = new ThisExp(0);
|
||||||
|
ex = new DotVarExp(0, ex, v, 0);
|
||||||
|
|
||||||
|
if (dim == 0)
|
||||||
|
{ // this.v.postblit()
|
||||||
|
ex = new DotVarExp(0, ex, sd->postblit, 0);
|
||||||
|
ex = new CallExp(0, ex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Typeinfo.postblit(cast(void*)&this.v);
|
||||||
|
Expression *ea = new AddrExp(0, ex);
|
||||||
|
ea = new CastExp(0, ea, Type::tvoid->pointerTo());
|
||||||
|
|
||||||
|
Expression *et = v->type->getTypeInfo(sc);
|
||||||
|
et = new DotIdExp(0, et, Id::postblit);
|
||||||
|
|
||||||
|
ex = new CallExp(0, et, ea);
|
||||||
|
}
|
||||||
|
e = Expression::combine(e, ex); // combine in forward order
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build our own "postblit" which executes e
|
||||||
|
*/
|
||||||
|
if (e || (stc & STCdisable))
|
||||||
|
{ //printf("Building __fieldPostBlit()\n");
|
||||||
|
PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, Lexer::idPool("__fieldPostBlit"));
|
||||||
|
dd->storage_class |= stc;
|
||||||
|
dd->fbody = new ExpStatement(0, e);
|
||||||
|
postblits.shift(dd);
|
||||||
|
members->push(dd);
|
||||||
|
dd->semantic(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (postblits.dim)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return postblits.tdata()[0];
|
||||||
|
|
||||||
|
default:
|
||||||
|
e = NULL;
|
||||||
|
for (size_t i = 0; i < postblits.dim; i++)
|
||||||
|
{ FuncDeclaration *fd = postblits.tdata()[i];
|
||||||
|
stc |= fd->storage_class & STCdisable;
|
||||||
|
if (stc & STCdisable)
|
||||||
|
{
|
||||||
|
e = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Expression *ex = new ThisExp(0);
|
||||||
|
ex = new DotVarExp(0, ex, fd, 0);
|
||||||
|
ex = new CallExp(0, ex);
|
||||||
|
e = Expression::combine(e, ex);
|
||||||
|
}
|
||||||
|
PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, Lexer::idPool("__aggrPostBlit"));
|
||||||
|
dd->storage_class |= stc;
|
||||||
|
dd->fbody = new ExpStatement(0, e);
|
||||||
|
members->push(dd);
|
||||||
|
dd->semantic(sc);
|
||||||
|
return dd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************
|
||||||
|
* Create inclusive destructor for struct/class by aggregating
|
||||||
|
* all the destructors in dtors[] with the destructors for
|
||||||
|
* all the members.
|
||||||
|
* Note the close similarity with StructDeclaration::buildPostBlit(),
|
||||||
|
* and the ordering changes (runs backward instead of forwards).
|
||||||
|
*/
|
||||||
|
|
||||||
|
FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc)
|
||||||
|
{
|
||||||
|
//printf("AggregateDeclaration::buildDtor() %s\n", toChars());
|
||||||
|
Expression *e = NULL;
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
for (size_t i = 0; i < fields.dim; i++)
|
||||||
|
{
|
||||||
|
Dsymbol *s = fields.tdata()[i];
|
||||||
|
VarDeclaration *v = s->isVarDeclaration();
|
||||||
|
assert(v && v->storage_class & STCfield);
|
||||||
|
if (v->storage_class & STCref)
|
||||||
|
continue;
|
||||||
|
Type *tv = v->type->toBasetype();
|
||||||
|
dinteger_t dim = (tv->ty == Tsarray ? 1 : 0);
|
||||||
|
while (tv->ty == Tsarray)
|
||||||
|
{ TypeSArray *ta = (TypeSArray *)tv;
|
||||||
|
dim *= ((TypeSArray *)tv)->dim->toInteger();
|
||||||
|
tv = tv->nextOf()->toBasetype();
|
||||||
|
}
|
||||||
|
if (tv->ty == Tstruct)
|
||||||
|
{ TypeStruct *ts = (TypeStruct *)tv;
|
||||||
|
StructDeclaration *sd = ts->sym;
|
||||||
|
if (sd->dtor)
|
||||||
|
{ Expression *ex;
|
||||||
|
|
||||||
|
// this.v
|
||||||
|
ex = new ThisExp(0);
|
||||||
|
ex = new DotVarExp(0, ex, v, 0);
|
||||||
|
|
||||||
|
if (dim == 0)
|
||||||
|
{ // this.v.dtor()
|
||||||
|
ex = new DotVarExp(0, ex, sd->dtor, 0);
|
||||||
|
ex = new CallExp(0, ex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Typeinfo.destroy(cast(void*)&this.v);
|
||||||
|
Expression *ea = new AddrExp(0, ex);
|
||||||
|
ea = new CastExp(0, ea, Type::tvoid->pointerTo());
|
||||||
|
|
||||||
|
Expression *et = v->type->getTypeInfo(sc);
|
||||||
|
et = new DotIdExp(0, et, Id::destroy);
|
||||||
|
|
||||||
|
ex = new CallExp(0, et, ea);
|
||||||
|
}
|
||||||
|
e = Expression::combine(ex, e); // combine in reverse order
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build our own "destructor" which executes e
|
||||||
|
*/
|
||||||
|
if (e)
|
||||||
|
{ //printf("Building __fieldDtor()\n");
|
||||||
|
DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__fieldDtor"));
|
||||||
|
dd->fbody = new ExpStatement(0, e);
|
||||||
|
dtors.shift(dd);
|
||||||
|
members->push(dd);
|
||||||
|
dd->semantic(sc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (dtors.dim)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return dtors.tdata()[0];
|
||||||
|
|
||||||
|
default:
|
||||||
|
e = NULL;
|
||||||
|
for (size_t i = 0; i < dtors.dim; i++)
|
||||||
|
{ FuncDeclaration *fd = dtors.tdata()[i];
|
||||||
|
Expression *ex = new ThisExp(0);
|
||||||
|
ex = new DotVarExp(0, ex, fd, 0);
|
||||||
|
ex = new CallExp(0, ex);
|
||||||
|
e = Expression::combine(ex, e);
|
||||||
|
}
|
||||||
|
DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__aggrDtor"));
|
||||||
|
dd->fbody = new ExpStatement(0, e);
|
||||||
|
members->push(dd);
|
||||||
|
dd->semantic(sc);
|
||||||
|
return dd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2006 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright and Burton Radons
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_COMPLEX_T_H
|
||||||
|
#define DMD_COMPLEX_T_H
|
||||||
|
|
||||||
|
/* Roll our own complex type for compilers that don't support complex
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct complex_t
|
||||||
|
{
|
||||||
|
long double re;
|
||||||
|
long double im;
|
||||||
|
|
||||||
|
complex_t() { this->re = 0; this->im = 0; }
|
||||||
|
complex_t(long double re) { this->re = re; this->im = 0; }
|
||||||
|
complex_t(long double re, long double im) { this->re = re; this->im = im; }
|
||||||
|
|
||||||
|
complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; }
|
||||||
|
complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; }
|
||||||
|
complex_t operator - () { complex_t r; r.re = -re; r.im = -im; return r; }
|
||||||
|
complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); }
|
||||||
|
|
||||||
|
complex_t operator / (complex_t y)
|
||||||
|
{
|
||||||
|
long double abs_y_re = y.re < 0 ? -y.re : y.re;
|
||||||
|
long double abs_y_im = y.im < 0 ? -y.im : y.im;
|
||||||
|
long double r, den;
|
||||||
|
|
||||||
|
if (abs_y_re < abs_y_im)
|
||||||
|
{
|
||||||
|
r = y.re / y.im;
|
||||||
|
den = y.im + r * y.re;
|
||||||
|
return complex_t((re * r + im) / den,
|
||||||
|
(im * r - re) / den);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r = y.im / y.re;
|
||||||
|
den = y.re + r * y.im;
|
||||||
|
return complex_t((re + r * im) / den,
|
||||||
|
(im - r * re) / den);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator bool () { return re || im; }
|
||||||
|
|
||||||
|
int operator == (complex_t y) { return re == y.re && im == y.im; }
|
||||||
|
int operator != (complex_t y) { return re != y.re || im != y.im; }
|
||||||
|
};
|
||||||
|
|
||||||
|
inline complex_t operator * (long double x, complex_t y) { return complex_t(x) * y; }
|
||||||
|
inline complex_t operator * (complex_t x, long double y) { return x * complex_t(y); }
|
||||||
|
inline complex_t operator / (complex_t x, long double y) { return x / complex_t(y); }
|
||||||
|
|
||||||
|
|
||||||
|
inline long double creall(complex_t x)
|
||||||
|
{
|
||||||
|
return x.re;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline long double cimagl(complex_t x)
|
||||||
|
{
|
||||||
|
return x.im;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
+405
@@ -0,0 +1,405 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "id.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "identifier.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "module.h"
|
||||||
|
#include "template.h"
|
||||||
|
#include "lexer.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "scope.h"
|
||||||
|
|
||||||
|
int findCondition(Strings *ids, Identifier *ident)
|
||||||
|
{
|
||||||
|
if (ids)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < ids->dim; i++)
|
||||||
|
{
|
||||||
|
const char *id = ids->tdata()[i];
|
||||||
|
|
||||||
|
if (strcmp(id, ident->toChars()) == 0)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
|
||||||
|
Condition::Condition(Loc loc)
|
||||||
|
{
|
||||||
|
this->loc = loc;
|
||||||
|
inc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
|
||||||
|
DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
|
||||||
|
: Condition(0)
|
||||||
|
{
|
||||||
|
this->mod = mod;
|
||||||
|
this->level = level;
|
||||||
|
this->ident = ident;
|
||||||
|
}
|
||||||
|
|
||||||
|
Condition *DVCondition::syntaxCopy()
|
||||||
|
{
|
||||||
|
return this; // don't need to copy
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
|
||||||
|
void DebugCondition::setGlobalLevel(unsigned level)
|
||||||
|
{
|
||||||
|
global.params.debuglevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugCondition::addGlobalIdent(const char *ident)
|
||||||
|
{
|
||||||
|
if (!global.params.debugids)
|
||||||
|
global.params.debugids = new Strings();
|
||||||
|
global.params.debugids->push((char *)ident);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
|
||||||
|
: DVCondition(mod, level, ident)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int DebugCondition::include(Scope *sc, ScopeDsymbol *s)
|
||||||
|
{
|
||||||
|
//printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
|
||||||
|
if (inc == 0)
|
||||||
|
{
|
||||||
|
inc = 2;
|
||||||
|
if (ident)
|
||||||
|
{
|
||||||
|
if (findCondition(mod->debugids, ident))
|
||||||
|
inc = 1;
|
||||||
|
else if (findCondition(global.params.debugids, ident))
|
||||||
|
inc = 1;
|
||||||
|
else
|
||||||
|
{ if (!mod->debugidsNot)
|
||||||
|
mod->debugidsNot = new Strings();
|
||||||
|
mod->debugidsNot->push(ident->toChars());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (level <= global.params.debuglevel || level <= mod->debuglevel)
|
||||||
|
inc = 1;
|
||||||
|
}
|
||||||
|
return (inc == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
if (ident)
|
||||||
|
buf->printf("debug (%s)", ident->toChars());
|
||||||
|
else
|
||||||
|
buf->printf("debug (%u)", level);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
|
||||||
|
void VersionCondition::setGlobalLevel(unsigned level)
|
||||||
|
{
|
||||||
|
global.params.versionlevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionCondition::checkPredefined(Loc loc, const char *ident)
|
||||||
|
{
|
||||||
|
static const char* reserved[] =
|
||||||
|
{
|
||||||
|
"DigitalMars", "X86", "X86_64",
|
||||||
|
"Windows", "Win32", "Win64",
|
||||||
|
"linux",
|
||||||
|
#if DMDV2
|
||||||
|
/* Although Posix is predefined by D1, disallowing its
|
||||||
|
* redefinition breaks makefiles and older builds.
|
||||||
|
*/
|
||||||
|
"Posix",
|
||||||
|
"D_NET",
|
||||||
|
#endif
|
||||||
|
"OSX", "FreeBSD",
|
||||||
|
"OpenBSD",
|
||||||
|
"Solaris",
|
||||||
|
"LittleEndian", "BigEndian",
|
||||||
|
"all",
|
||||||
|
"none",
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
"LLVM", "LDC", "LLVM64",
|
||||||
|
"PPC", "PPC64",
|
||||||
|
"darwin","solaris","freebsd"
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++)
|
||||||
|
{
|
||||||
|
if (strcmp(ident, reserved[i]) == 0)
|
||||||
|
goto Lerror;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ident[0] == 'D' && ident[1] == '_')
|
||||||
|
goto Lerror;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
Lerror:
|
||||||
|
error(loc, "version identifier '%s' is reserved and cannot be set", ident);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionCondition::addGlobalIdent(const char *ident)
|
||||||
|
{
|
||||||
|
checkPredefined(0, ident);
|
||||||
|
addPredefinedGlobalIdent(ident);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionCondition::addPredefinedGlobalIdent(const char *ident)
|
||||||
|
{
|
||||||
|
if (!global.params.versionids)
|
||||||
|
global.params.versionids = new Strings();
|
||||||
|
global.params.versionids->push((char *)ident);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
|
||||||
|
: DVCondition(mod, level, ident)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int VersionCondition::include(Scope *sc, ScopeDsymbol *s)
|
||||||
|
{
|
||||||
|
//printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
|
||||||
|
//if (ident) printf("\tident = '%s'\n", ident->toChars());
|
||||||
|
if (inc == 0)
|
||||||
|
{
|
||||||
|
inc = 2;
|
||||||
|
if (ident)
|
||||||
|
{
|
||||||
|
if (findCondition(mod->versionids, ident))
|
||||||
|
inc = 1;
|
||||||
|
else if (findCondition(global.params.versionids, ident))
|
||||||
|
inc = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!mod->versionidsNot)
|
||||||
|
mod->versionidsNot = new Strings();
|
||||||
|
mod->versionidsNot->push(ident->toChars());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (level <= global.params.versionlevel || level <= mod->versionlevel)
|
||||||
|
inc = 1;
|
||||||
|
}
|
||||||
|
return (inc == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
if (ident)
|
||||||
|
buf->printf("version (%s)", ident->toChars());
|
||||||
|
else
|
||||||
|
buf->printf("version (%u)", level);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************** StaticIfCondition *******************************/
|
||||||
|
|
||||||
|
StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
|
||||||
|
: Condition(loc)
|
||||||
|
{
|
||||||
|
this->exp = exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Condition *StaticIfCondition::syntaxCopy()
|
||||||
|
{
|
||||||
|
return new StaticIfCondition(loc, exp->syntaxCopy());
|
||||||
|
}
|
||||||
|
|
||||||
|
int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s);
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (inc == 0)
|
||||||
|
{
|
||||||
|
if (!sc)
|
||||||
|
{
|
||||||
|
error(loc, "static if conditional cannot be at global scope");
|
||||||
|
inc = 2;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc = sc->push(sc->scopesym);
|
||||||
|
sc->sd = s; // s gets any addMember()
|
||||||
|
sc->flags |= SCOPEstaticif;
|
||||||
|
Expression *e = exp->semantic(sc);
|
||||||
|
sc->pop();
|
||||||
|
e = e->optimize(WANTvalue | WANTinterpret);
|
||||||
|
if (e->isBool(TRUE))
|
||||||
|
inc = 1;
|
||||||
|
else if (e->isBool(FALSE))
|
||||||
|
inc = 2;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
e->error("expression %s is not constant or does not evaluate to a bool", e->toChars());
|
||||||
|
inc = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (inc == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
buf->writestring("static if(");
|
||||||
|
exp->toCBuffer(buf, hgs);
|
||||||
|
buf->writeByte(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************** IftypeCondition *******************************/
|
||||||
|
|
||||||
|
IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec)
|
||||||
|
: Condition(loc)
|
||||||
|
{
|
||||||
|
this->targ = targ;
|
||||||
|
this->id = id;
|
||||||
|
this->tok = tok;
|
||||||
|
this->tspec = tspec;
|
||||||
|
}
|
||||||
|
|
||||||
|
Condition *IftypeCondition::syntaxCopy()
|
||||||
|
{
|
||||||
|
return new IftypeCondition(loc,
|
||||||
|
targ->syntaxCopy(),
|
||||||
|
id,
|
||||||
|
tok,
|
||||||
|
tspec ? tspec->syntaxCopy() : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd)
|
||||||
|
{
|
||||||
|
//printf("IftypeCondition::include()\n");
|
||||||
|
if (inc == 0)
|
||||||
|
{
|
||||||
|
if (!sc)
|
||||||
|
{
|
||||||
|
error(loc, "iftype conditional cannot be at global scope");
|
||||||
|
inc = 2;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Type *t = targ->trySemantic(loc, sc);
|
||||||
|
if (t)
|
||||||
|
targ = t;
|
||||||
|
else
|
||||||
|
inc = 2; // condition is false
|
||||||
|
|
||||||
|
if (!t)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (id && tspec)
|
||||||
|
{
|
||||||
|
/* Evaluate to TRUE if targ matches tspec.
|
||||||
|
* If TRUE, declare id as an alias for the specialized type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
MATCH m;
|
||||||
|
TemplateTypeParameter tp(loc, id, NULL, NULL);
|
||||||
|
|
||||||
|
TemplateParameters parameters;
|
||||||
|
parameters.setDim(1);
|
||||||
|
parameters.tdata()[0] = &tp;
|
||||||
|
|
||||||
|
Objects dedtypes;
|
||||||
|
dedtypes.setDim(1);
|
||||||
|
|
||||||
|
m = targ->deduceType(sc, tspec, ¶meters, &dedtypes);
|
||||||
|
if (m == MATCHnomatch ||
|
||||||
|
(m != MATCHexact && tok == TOKequal))
|
||||||
|
inc = 2;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inc = 1;
|
||||||
|
Type *tded = (Type *)dedtypes.tdata()[0];
|
||||||
|
if (!tded)
|
||||||
|
tded = targ;
|
||||||
|
Dsymbol *s = new AliasDeclaration(loc, id, tded);
|
||||||
|
s->semantic(sc);
|
||||||
|
sc->insert(s);
|
||||||
|
if (sd)
|
||||||
|
s->addMember(sc, sd, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (id)
|
||||||
|
{
|
||||||
|
/* Declare id as an alias for type targ. Evaluate to TRUE
|
||||||
|
*/
|
||||||
|
Dsymbol *s = new AliasDeclaration(loc, id, targ);
|
||||||
|
s->semantic(sc);
|
||||||
|
sc->insert(s);
|
||||||
|
if (sd)
|
||||||
|
s->addMember(sc, sd, 1);
|
||||||
|
inc = 1;
|
||||||
|
}
|
||||||
|
else if (tspec)
|
||||||
|
{
|
||||||
|
/* Evaluate to TRUE if targ matches tspec
|
||||||
|
*/
|
||||||
|
tspec = tspec->semantic(loc, sc);
|
||||||
|
//printf("targ = %s\n", targ->toChars());
|
||||||
|
//printf("tspec = %s\n", tspec->toChars());
|
||||||
|
if (tok == TOKcolon)
|
||||||
|
{ if (targ->implicitConvTo(tspec))
|
||||||
|
inc = 1;
|
||||||
|
else
|
||||||
|
inc = 2;
|
||||||
|
}
|
||||||
|
else /* == */
|
||||||
|
{ if (targ->equals(tspec))
|
||||||
|
inc = 1;
|
||||||
|
else
|
||||||
|
inc = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
inc = 1;
|
||||||
|
//printf("inc = %d\n", inc);
|
||||||
|
}
|
||||||
|
return (inc == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
buf->writestring("iftype(");
|
||||||
|
targ->toCBuffer(buf, id, hgs);
|
||||||
|
if (tspec)
|
||||||
|
{
|
||||||
|
if (tok == TOKcolon)
|
||||||
|
buf->writestring(" : ");
|
||||||
|
else
|
||||||
|
buf->writestring(" == ");
|
||||||
|
tspec->toCBuffer(buf, NULL, hgs);
|
||||||
|
}
|
||||||
|
buf->writeByte(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+105
@@ -0,0 +1,105 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_DEBCOND_H
|
||||||
|
#define DMD_DEBCOND_H
|
||||||
|
|
||||||
|
struct Expression;
|
||||||
|
struct Identifier;
|
||||||
|
struct OutBuffer;
|
||||||
|
struct Module;
|
||||||
|
struct Scope;
|
||||||
|
struct ScopeDsymbol;
|
||||||
|
struct DebugCondition;
|
||||||
|
#include "lexer.h" // dmdhg
|
||||||
|
enum TOK;
|
||||||
|
struct HdrGenState;
|
||||||
|
|
||||||
|
int findCondition(Strings *ids, Identifier *ident);
|
||||||
|
|
||||||
|
struct Condition
|
||||||
|
{
|
||||||
|
Loc loc;
|
||||||
|
int inc; // 0: not computed yet
|
||||||
|
// 1: include
|
||||||
|
// 2: do not include
|
||||||
|
|
||||||
|
Condition(Loc loc);
|
||||||
|
|
||||||
|
virtual Condition *syntaxCopy() = 0;
|
||||||
|
virtual int include(Scope *sc, ScopeDsymbol *s) = 0;
|
||||||
|
virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0;
|
||||||
|
virtual DebugCondition *isDebugCondition() { return NULL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DVCondition : Condition
|
||||||
|
{
|
||||||
|
unsigned level;
|
||||||
|
Identifier *ident;
|
||||||
|
Module *mod;
|
||||||
|
|
||||||
|
DVCondition(Module *mod, unsigned level, Identifier *ident);
|
||||||
|
|
||||||
|
Condition *syntaxCopy();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DebugCondition : DVCondition
|
||||||
|
{
|
||||||
|
static void setGlobalLevel(unsigned level);
|
||||||
|
static void addGlobalIdent(const char *ident);
|
||||||
|
static void addPredefinedGlobalIdent(const char *ident);
|
||||||
|
|
||||||
|
DebugCondition(Module *mod, unsigned level, Identifier *ident);
|
||||||
|
|
||||||
|
int include(Scope *sc, ScopeDsymbol *s);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
DebugCondition *isDebugCondition() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VersionCondition : DVCondition
|
||||||
|
{
|
||||||
|
static void setGlobalLevel(unsigned level);
|
||||||
|
static void checkPredefined(Loc loc, const char *ident);
|
||||||
|
static void addGlobalIdent(const char *ident);
|
||||||
|
static void addPredefinedGlobalIdent(const char *ident);
|
||||||
|
|
||||||
|
VersionCondition(Module *mod, unsigned level, Identifier *ident);
|
||||||
|
|
||||||
|
int include(Scope *sc, ScopeDsymbol *s);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StaticIfCondition : Condition
|
||||||
|
{
|
||||||
|
Expression *exp;
|
||||||
|
|
||||||
|
StaticIfCondition(Loc loc, Expression *exp);
|
||||||
|
Condition *syntaxCopy();
|
||||||
|
int include(Scope *sc, ScopeDsymbol *s);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IftypeCondition : Condition
|
||||||
|
{
|
||||||
|
/* iftype (targ id tok tspec)
|
||||||
|
*/
|
||||||
|
Type *targ;
|
||||||
|
Identifier *id; // can be NULL
|
||||||
|
enum TOK tok; // ':' or '=='
|
||||||
|
Type *tspec; // can be NULL
|
||||||
|
|
||||||
|
IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec);
|
||||||
|
Condition *syntaxCopy();
|
||||||
|
int include(Scope *sc, ScopeDsymbol *s);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
+1876
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,454 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2010 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "dsymbol.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "attrib.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "template.h"
|
||||||
|
#include "id.h"
|
||||||
|
#include "enum.h"
|
||||||
|
#include "import.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
|
||||||
|
#if CPP_MANGLE
|
||||||
|
|
||||||
|
/* Do mangling for C++ linkage.
|
||||||
|
* Follows Itanium C++ ABI 1.86
|
||||||
|
* No attempt is made to support mangling of templates, operator
|
||||||
|
* overloading, or special functions.
|
||||||
|
*
|
||||||
|
* So why don't we use the C++ ABI for D name mangling?
|
||||||
|
* Because D supports a lot of things (like modules) that the C++
|
||||||
|
* ABI has no concept of. These affect every D mangled name,
|
||||||
|
* so nothing would be compatible anyway.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct CppMangleState
|
||||||
|
{
|
||||||
|
static Voids components;
|
||||||
|
|
||||||
|
int substitute(OutBuffer *buf, void *p);
|
||||||
|
int exist(void *p);
|
||||||
|
void store(void *p);
|
||||||
|
};
|
||||||
|
|
||||||
|
Voids CppMangleState::components;
|
||||||
|
|
||||||
|
|
||||||
|
void writeBase36(OutBuffer *buf, unsigned i)
|
||||||
|
{
|
||||||
|
if (i >= 36)
|
||||||
|
{
|
||||||
|
writeBase36(buf, i / 36);
|
||||||
|
i %= 36;
|
||||||
|
}
|
||||||
|
if (i < 10)
|
||||||
|
buf->writeByte(i + '0');
|
||||||
|
else if (i < 36)
|
||||||
|
buf->writeByte(i - 10 + 'A');
|
||||||
|
else
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CppMangleState::substitute(OutBuffer *buf, void *p)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < components.dim; i++)
|
||||||
|
{
|
||||||
|
if (p == components.tdata()[i])
|
||||||
|
{
|
||||||
|
/* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
|
||||||
|
*/
|
||||||
|
buf->writeByte('S');
|
||||||
|
if (i)
|
||||||
|
writeBase36(buf, i - 1);
|
||||||
|
buf->writeByte('_');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
components.push(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CppMangleState::exist(void *p)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < components.dim; i++)
|
||||||
|
{
|
||||||
|
if (p == components.tdata()[i])
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CppMangleState::store(void *p)
|
||||||
|
{
|
||||||
|
components.push(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void source_name(OutBuffer *buf, Dsymbol *s)
|
||||||
|
{
|
||||||
|
char *name = s->ident->toChars();
|
||||||
|
buf->printf("%d%s", strlen(name), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void prefix_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s)
|
||||||
|
{
|
||||||
|
if (!cms->substitute(buf, s))
|
||||||
|
{
|
||||||
|
Dsymbol *p = s->toParent();
|
||||||
|
if (p && !p->isModule())
|
||||||
|
{
|
||||||
|
prefix_name(buf, cms, p);
|
||||||
|
}
|
||||||
|
source_name(buf, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpp_mangle_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s)
|
||||||
|
{
|
||||||
|
Dsymbol *p = s->toParent();
|
||||||
|
if (p && !p->isModule())
|
||||||
|
{
|
||||||
|
buf->writeByte('N');
|
||||||
|
|
||||||
|
FuncDeclaration *fd = s->isFuncDeclaration();
|
||||||
|
if (!fd)
|
||||||
|
{
|
||||||
|
s->error("C++ static variables not supported");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (fd->isConst())
|
||||||
|
buf->writeByte('K');
|
||||||
|
|
||||||
|
prefix_name(buf, cms, p);
|
||||||
|
source_name(buf, s);
|
||||||
|
|
||||||
|
buf->writeByte('E');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
source_name(buf, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *cpp_mangle(Dsymbol *s)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* <mangled-name> ::= _Z <encoding>
|
||||||
|
* <encoding> ::= <function name> <bare-function-type>
|
||||||
|
* ::= <data name>
|
||||||
|
* ::= <special-name>
|
||||||
|
*/
|
||||||
|
|
||||||
|
CppMangleState cms;
|
||||||
|
memset(&cms, 0, sizeof(cms));
|
||||||
|
cms.components.setDim(0);
|
||||||
|
|
||||||
|
OutBuffer buf;
|
||||||
|
#if MACHOBJ
|
||||||
|
buf.writestring("__Z");
|
||||||
|
#else
|
||||||
|
buf.writestring("_Z");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cpp_mangle_name(&buf, &cms, s);
|
||||||
|
|
||||||
|
FuncDeclaration *fd = s->isFuncDeclaration();
|
||||||
|
if (fd)
|
||||||
|
{ // add <bare-function-type>
|
||||||
|
TypeFunction *tf = (TypeFunction *)fd->type;
|
||||||
|
assert(tf->ty == Tfunction);
|
||||||
|
Parameter::argsCppMangle(&buf, &cms, tf->parameters, tf->varargs);
|
||||||
|
}
|
||||||
|
buf.writeByte(0);
|
||||||
|
return (char *)buf.extractData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============= Type Encodings ============================================= */
|
||||||
|
|
||||||
|
void Type::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
/* Make this the 'vendor extended type' when there is no
|
||||||
|
* C++ analog.
|
||||||
|
* u <source-name>
|
||||||
|
*/
|
||||||
|
if (!cms->substitute(buf, this))
|
||||||
|
{ assert(deco);
|
||||||
|
buf->printf("u%d%s", strlen(deco), deco);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeBasic::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{ char c;
|
||||||
|
char p = 0;
|
||||||
|
|
||||||
|
/* ABI spec says:
|
||||||
|
* v void
|
||||||
|
* w wchar_t
|
||||||
|
* b bool
|
||||||
|
* c char
|
||||||
|
* a signed char
|
||||||
|
* h unsigned char
|
||||||
|
* s short
|
||||||
|
* t unsigned short
|
||||||
|
* i int
|
||||||
|
* j unsigned int
|
||||||
|
* l long
|
||||||
|
* m unsigned long
|
||||||
|
* x long long, __int64
|
||||||
|
* y unsigned long long, __int64
|
||||||
|
* n __int128
|
||||||
|
* o unsigned __int128
|
||||||
|
* f float
|
||||||
|
* d double
|
||||||
|
* e long double, __float80
|
||||||
|
* g __float128
|
||||||
|
* z ellipsis
|
||||||
|
* u <source-name> # vendor extended type
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch (ty)
|
||||||
|
{
|
||||||
|
case Tvoid: c = 'v'; break;
|
||||||
|
case Tint8: c = 'a'; break;
|
||||||
|
case Tuns8: c = 'h'; break;
|
||||||
|
case Tint16: c = 's'; break;
|
||||||
|
case Tuns16: c = 't'; break;
|
||||||
|
case Tint32: c = 'i'; break;
|
||||||
|
case Tuns32: c = 'j'; break;
|
||||||
|
case Tfloat32: c = 'f'; break;
|
||||||
|
case Tint64: c = 'x'; break;
|
||||||
|
case Tuns64: c = 'y'; break;
|
||||||
|
case Tfloat64: c = 'd'; break;
|
||||||
|
case Tfloat80: c = 'e'; break;
|
||||||
|
case Tbool: c = 'b'; break;
|
||||||
|
case Tchar: c = 'c'; break;
|
||||||
|
case Twchar: c = 't'; break;
|
||||||
|
case Tdchar: c = 'w'; break;
|
||||||
|
|
||||||
|
case Timaginary32: p = 'G'; c = 'f'; break;
|
||||||
|
case Timaginary64: p = 'G'; c = 'd'; break;
|
||||||
|
case Timaginary80: p = 'G'; c = 'e'; break;
|
||||||
|
case Tcomplex32: p = 'C'; c = 'f'; break;
|
||||||
|
case Tcomplex64: p = 'C'; c = 'd'; break;
|
||||||
|
case Tcomplex80: p = 'C'; c = 'e'; break;
|
||||||
|
|
||||||
|
default: assert(0);
|
||||||
|
}
|
||||||
|
if (p || isConst())
|
||||||
|
{
|
||||||
|
if (cms->substitute(buf, this))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isConst())
|
||||||
|
buf->writeByte('K');
|
||||||
|
|
||||||
|
if (p)
|
||||||
|
buf->writeByte(p);
|
||||||
|
|
||||||
|
buf->writeByte(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TypeVector::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
if (!cms->substitute(buf, this))
|
||||||
|
{ buf->writestring("U8__vector");
|
||||||
|
basetype->toCppMangle(buf, cms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeSArray::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
if (!cms->substitute(buf, this))
|
||||||
|
{ buf->printf("A%ju_", dim ? dim->toInteger() : 0);
|
||||||
|
next->toCppMangle(buf, cms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeDArray::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
Type::toCppMangle(buf, cms);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TypeAArray::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
Type::toCppMangle(buf, cms);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TypePointer::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
if (!cms->exist(this))
|
||||||
|
{ buf->writeByte('P');
|
||||||
|
next->toCppMangle(buf, cms);
|
||||||
|
cms->store(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cms->substitute(buf, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TypeReference::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
if (!cms->exist(this))
|
||||||
|
{ buf->writeByte('R');
|
||||||
|
next->toCppMangle(buf, cms);
|
||||||
|
cms->store(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cms->substitute(buf, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TypeFunction::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{ /*
|
||||||
|
* <function-type> ::= F [Y] <bare-function-type> E
|
||||||
|
* <bare-function-type> ::= <signature type>+
|
||||||
|
* # types are possible return type, then parameter types
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ABI says:
|
||||||
|
"The type of a non-static member function is considered to be different,
|
||||||
|
for the purposes of substitution, from the type of a namespace-scope or
|
||||||
|
static member function whose type appears similar. The types of two
|
||||||
|
non-static member functions are considered to be different, for the
|
||||||
|
purposes of substitution, if the functions are members of different
|
||||||
|
classes. In other words, for the purposes of substitution, the class of
|
||||||
|
which the function is a member is considered part of the type of
|
||||||
|
function."
|
||||||
|
|
||||||
|
BUG: Right now, types of functions are never merged, so our simplistic
|
||||||
|
component matcher always finds them to be different.
|
||||||
|
We should use Type::equals on these, and use different
|
||||||
|
TypeFunctions for non-static member functions, and non-static
|
||||||
|
member functions of different classes.
|
||||||
|
*/
|
||||||
|
if (!cms->substitute(buf, this))
|
||||||
|
{
|
||||||
|
buf->writeByte('F');
|
||||||
|
if (linkage == LINKc)
|
||||||
|
buf->writeByte('Y');
|
||||||
|
next->toCppMangle(buf, cms);
|
||||||
|
Parameter::argsCppMangle(buf, cms, parameters, varargs);
|
||||||
|
buf->writeByte('E');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TypeDelegate::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
Type::toCppMangle(buf, cms);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TypeStruct::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
if (!cms->exist(this))
|
||||||
|
{
|
||||||
|
if (isConst())
|
||||||
|
buf->writeByte('K');
|
||||||
|
|
||||||
|
if (!cms->substitute(buf, sym))
|
||||||
|
cpp_mangle_name(buf, cms, sym);
|
||||||
|
|
||||||
|
if (isConst())
|
||||||
|
cms->store(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cms->substitute(buf, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TypeEnum::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
if (!cms->exist(this))
|
||||||
|
{
|
||||||
|
if (isConst())
|
||||||
|
buf->writeByte('K');
|
||||||
|
|
||||||
|
if (!cms->substitute(buf, sym))
|
||||||
|
cpp_mangle_name(buf, cms, sym);
|
||||||
|
|
||||||
|
if (isConst())
|
||||||
|
cms->store(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cms->substitute(buf, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TypeTypedef::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
Type::toCppMangle(buf, cms);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TypeClass::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
||||||
|
{
|
||||||
|
if (!cms->substitute(buf, this))
|
||||||
|
{ buf->writeByte('P');
|
||||||
|
if (!cms->substitute(buf, sym))
|
||||||
|
cpp_mangle_name(buf, cms, sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Parameter::argsCppMangle(OutBuffer *buf, CppMangleState *cms, Parameters *arguments, int varargs)
|
||||||
|
{ int n = 0;
|
||||||
|
if (arguments)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < arguments->dim; i++)
|
||||||
|
{ Parameter *arg = arguments->tdata()[i];
|
||||||
|
Type *t = arg->type;
|
||||||
|
if (arg->storageClass & (STCout | STCref))
|
||||||
|
t = t->referenceTo();
|
||||||
|
else if (arg->storageClass & STClazy)
|
||||||
|
{ // Mangle as delegate
|
||||||
|
Type *td = new TypeFunction(NULL, t, 0, LINKd);
|
||||||
|
td = new TypeDelegate(td);
|
||||||
|
t = t->merge();
|
||||||
|
}
|
||||||
|
if (t->ty == Tsarray)
|
||||||
|
{ // Mangle static arrays as pointers
|
||||||
|
t = t->pointerTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If it is a basic, enum or struct type,
|
||||||
|
* then don't mark it const
|
||||||
|
*/
|
||||||
|
if ((t->ty == Tenum || t->ty == Tstruct || t->isTypeBasic()) && t->isConst())
|
||||||
|
t->mutableOf()->toCppMangle(buf, cms);
|
||||||
|
else
|
||||||
|
t->toCppMangle(buf, cms);
|
||||||
|
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (varargs)
|
||||||
|
buf->writestring("z");
|
||||||
|
else if (!n)
|
||||||
|
buf->writeByte('v'); // encode ( ) arguments
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+2327
File diff suppressed because it is too large
Load Diff
+1107
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,140 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "statement.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "utf.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "scope.h"
|
||||||
|
|
||||||
|
/********************************************
|
||||||
|
* Convert from expression to delegate that returns the expression,
|
||||||
|
* i.e. convert:
|
||||||
|
* expr
|
||||||
|
* to:
|
||||||
|
* t delegate() { return expr; }
|
||||||
|
*/
|
||||||
|
|
||||||
|
int lambdaSetParent(Expression *e, void *param);
|
||||||
|
int lambdaCheckForNestedRef(Expression *e, void *param);
|
||||||
|
|
||||||
|
Expression *Expression::toDelegate(Scope *sc, Type *t)
|
||||||
|
{
|
||||||
|
//printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), toChars());
|
||||||
|
TypeFunction *tf = new TypeFunction(NULL, t, 0, LINKd);
|
||||||
|
FuncLiteralDeclaration *fld =
|
||||||
|
new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL);
|
||||||
|
Expression *e;
|
||||||
|
sc = sc->push();
|
||||||
|
sc->parent = fld; // set current function to be the delegate
|
||||||
|
e = this;
|
||||||
|
e->apply(&lambdaSetParent, sc);
|
||||||
|
e->apply(&lambdaCheckForNestedRef, sc);
|
||||||
|
sc = sc->pop();
|
||||||
|
Statement *s;
|
||||||
|
if (t->ty == Tvoid)
|
||||||
|
s = new ExpStatement(loc, e);
|
||||||
|
else
|
||||||
|
s = new ReturnStatement(loc, e);
|
||||||
|
fld->fbody = s;
|
||||||
|
e = new FuncExp(loc, fld);
|
||||||
|
e = e->semantic(sc);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* Patch the parent of declarations to be the new function literal.
|
||||||
|
*/
|
||||||
|
int lambdaSetParent(Expression *e, void *param)
|
||||||
|
{
|
||||||
|
Scope *sc = (Scope *)param;
|
||||||
|
/* We could use virtual functions instead of a switch,
|
||||||
|
* but it doesn't seem worth the bother.
|
||||||
|
*/
|
||||||
|
switch (e->op)
|
||||||
|
{
|
||||||
|
case TOKdeclaration:
|
||||||
|
{ DeclarationExp *de = (DeclarationExp *)e;
|
||||||
|
de->declaration->parent = sc->parent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOKindex:
|
||||||
|
{ IndexExp *de = (IndexExp *)e;
|
||||||
|
if (de->lengthVar)
|
||||||
|
{ //printf("lengthVar\n");
|
||||||
|
de->lengthVar->parent = sc->parent;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOKslice:
|
||||||
|
{ SliceExp *se = (SliceExp *)e;
|
||||||
|
if (se->lengthVar)
|
||||||
|
{ //printf("lengthVar\n");
|
||||||
|
se->lengthVar->parent = sc->parent;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************
|
||||||
|
* Look for references to variables in a scope enclosing the new function literal.
|
||||||
|
*/
|
||||||
|
int lambdaCheckForNestedRef(Expression *e, void *param)
|
||||||
|
{
|
||||||
|
Scope *sc = (Scope *)param;
|
||||||
|
/* We could use virtual functions instead of a switch,
|
||||||
|
* but it doesn't seem worth the bother.
|
||||||
|
*/
|
||||||
|
switch (e->op)
|
||||||
|
{
|
||||||
|
case TOKsymoff:
|
||||||
|
{ SymOffExp *se = (SymOffExp *)e;
|
||||||
|
VarDeclaration *v = se->var->isVarDeclaration();
|
||||||
|
if (v)
|
||||||
|
v->checkNestedReference(sc, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOKvar:
|
||||||
|
{ VarExp *ve = (VarExp *)e;
|
||||||
|
VarDeclaration *v = ve->var->isVarDeclaration();
|
||||||
|
if (v)
|
||||||
|
v->checkNestedReference(sc, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOKthis:
|
||||||
|
case TOKsuper:
|
||||||
|
{ ThisExp *te = (ThisExp *)e;
|
||||||
|
VarDeclaration *v = te->var->isVarDeclaration();
|
||||||
|
if (v)
|
||||||
|
v->checkNestedReference(sc, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
+2226
File diff suppressed because it is too large
Load Diff
+20
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2006 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_DOC_H
|
||||||
|
#define DMD_DOC_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
void escapeDdocString(OutBuffer *buf, unsigned start);
|
||||||
|
|
||||||
|
#endif
|
||||||
+1476
File diff suppressed because it is too large
Load Diff
+389
@@ -0,0 +1,389 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_DSYMBOL_H
|
||||||
|
#define DMD_DSYMBOL_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "stringtable.h"
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "arraytypes.h"
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
#include "../ir/irdsymbol.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Identifier;
|
||||||
|
struct Scope;
|
||||||
|
struct DsymbolTable;
|
||||||
|
struct Declaration;
|
||||||
|
struct ThisDeclaration;
|
||||||
|
struct TupleDeclaration;
|
||||||
|
struct TypedefDeclaration;
|
||||||
|
struct AliasDeclaration;
|
||||||
|
struct AggregateDeclaration;
|
||||||
|
struct EnumDeclaration;
|
||||||
|
struct ClassDeclaration;
|
||||||
|
struct InterfaceDeclaration;
|
||||||
|
struct StructDeclaration;
|
||||||
|
struct UnionDeclaration;
|
||||||
|
struct FuncDeclaration;
|
||||||
|
struct FuncAliasDeclaration;
|
||||||
|
struct FuncLiteralDeclaration;
|
||||||
|
struct CtorDeclaration;
|
||||||
|
struct PostBlitDeclaration;
|
||||||
|
struct DtorDeclaration;
|
||||||
|
struct StaticCtorDeclaration;
|
||||||
|
struct StaticDtorDeclaration;
|
||||||
|
struct SharedStaticCtorDeclaration;
|
||||||
|
struct SharedStaticDtorDeclaration;
|
||||||
|
struct InvariantDeclaration;
|
||||||
|
struct UnitTestDeclaration;
|
||||||
|
struct NewDeclaration;
|
||||||
|
struct VarDeclaration;
|
||||||
|
struct AttribDeclaration;
|
||||||
|
#if IN_DMD
|
||||||
|
struct Symbol;
|
||||||
|
#endif
|
||||||
|
struct Package;
|
||||||
|
struct Module;
|
||||||
|
struct Import;
|
||||||
|
struct Type;
|
||||||
|
struct TypeTuple;
|
||||||
|
struct WithStatement;
|
||||||
|
struct LabelDsymbol;
|
||||||
|
struct ScopeDsymbol;
|
||||||
|
struct TemplateDeclaration;
|
||||||
|
struct TemplateInstance;
|
||||||
|
struct TemplateMixin;
|
||||||
|
struct EnumMember;
|
||||||
|
struct ScopeDsymbol;
|
||||||
|
struct WithScopeSymbol;
|
||||||
|
struct ArrayScopeSymbol;
|
||||||
|
struct StaticStructInitDeclaration;
|
||||||
|
struct Expression;
|
||||||
|
struct DeleteDeclaration;
|
||||||
|
struct HdrGenState;
|
||||||
|
struct OverloadSet;
|
||||||
|
struct AA;
|
||||||
|
#if TARGET_NET
|
||||||
|
struct PragmaScope;
|
||||||
|
#endif
|
||||||
|
#if IN_LLVM
|
||||||
|
struct TypeInfoDeclaration;
|
||||||
|
struct ClassInfoDeclaration;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IN_GCC
|
||||||
|
union tree_node;
|
||||||
|
typedef union tree_node TYPE;
|
||||||
|
#else
|
||||||
|
struct TYPE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
class Ir;
|
||||||
|
class IrSymbol;
|
||||||
|
namespace llvm
|
||||||
|
{
|
||||||
|
class Value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if IN_DMD
|
||||||
|
// Back end
|
||||||
|
struct Classsym;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum PROT
|
||||||
|
{
|
||||||
|
PROTundefined,
|
||||||
|
PROTnone, // no access
|
||||||
|
PROTprivate,
|
||||||
|
PROTpackage,
|
||||||
|
PROTprotected,
|
||||||
|
PROTpublic,
|
||||||
|
PROTexport,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* State of symbol in winding its way through the passes of the compiler
|
||||||
|
*/
|
||||||
|
enum PASS
|
||||||
|
{
|
||||||
|
PASSinit, // initial state
|
||||||
|
PASSsemantic, // semantic() started
|
||||||
|
PASSsemanticdone, // semantic() done
|
||||||
|
PASSsemantic2, // semantic2() run
|
||||||
|
PASSsemantic3, // semantic3() started
|
||||||
|
PASSsemantic3done, // semantic3() done
|
||||||
|
PASSobj, // toObjFile() run
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Dsymbol : Object
|
||||||
|
{
|
||||||
|
Identifier *ident;
|
||||||
|
Identifier *c_ident;
|
||||||
|
Dsymbol *parent;
|
||||||
|
#if IN_DMD
|
||||||
|
Symbol *csym; // symbol for code generator
|
||||||
|
Symbol *isym; // import version of csym
|
||||||
|
#endif
|
||||||
|
unsigned char *comment; // documentation comment for this Dsymbol
|
||||||
|
Loc loc; // where defined
|
||||||
|
Scope *scope; // !=NULL means context to use for semantic()
|
||||||
|
|
||||||
|
Dsymbol();
|
||||||
|
Dsymbol(Identifier *);
|
||||||
|
char *toChars();
|
||||||
|
char *locToChars();
|
||||||
|
int equals(Object *o);
|
||||||
|
int isAnonymous();
|
||||||
|
void error(Loc loc, const char *format, ...) IS_PRINTF(3);
|
||||||
|
void error(const char *format, ...) IS_PRINTF(2);
|
||||||
|
void verror(Loc loc, const char *format, va_list ap);
|
||||||
|
void checkDeprecated(Loc loc, Scope *sc);
|
||||||
|
Module *getModule(); // module where declared
|
||||||
|
Module *getAccessModule();
|
||||||
|
Dsymbol *pastMixin();
|
||||||
|
Dsymbol *toParent();
|
||||||
|
Dsymbol *toParent2();
|
||||||
|
TemplateInstance *inTemplateInstance();
|
||||||
|
|
||||||
|
int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol()
|
||||||
|
|
||||||
|
static Dsymbols *arraySyntaxCopy(Dsymbols *a);
|
||||||
|
|
||||||
|
virtual const char *toPrettyChars();
|
||||||
|
virtual const char *kind();
|
||||||
|
virtual Dsymbol *toAlias(); // resolve real symbol
|
||||||
|
virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
|
||||||
|
virtual void setScope(Scope *sc);
|
||||||
|
virtual void importAll(Scope *sc);
|
||||||
|
virtual void semantic0(Scope *sc);
|
||||||
|
virtual void semantic(Scope *sc);
|
||||||
|
virtual void semantic2(Scope *sc);
|
||||||
|
virtual void semantic3(Scope *sc);
|
||||||
|
virtual void inlineScan();
|
||||||
|
virtual Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||||
|
Dsymbol *search_correct(Identifier *id);
|
||||||
|
Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id);
|
||||||
|
virtual int overloadInsert(Dsymbol *s);
|
||||||
|
char *toHChars();
|
||||||
|
virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
virtual void toDocBuffer(OutBuffer *buf);
|
||||||
|
virtual void toJsonBuffer(OutBuffer *buf);
|
||||||
|
virtual unsigned size(Loc loc);
|
||||||
|
virtual int isforwardRef();
|
||||||
|
virtual void defineRef(Dsymbol *s);
|
||||||
|
virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member
|
||||||
|
AggregateDeclaration *isAggregateMember(); // are we a member of an aggregate?
|
||||||
|
ClassDeclaration *isClassMember(); // are we a member of a class?
|
||||||
|
virtual int isExport(); // is Dsymbol exported?
|
||||||
|
virtual int isImportedSymbol(); // is Dsymbol imported?
|
||||||
|
virtual int isDeprecated(); // is Dsymbol deprecated?
|
||||||
|
#if DMDV2
|
||||||
|
virtual int isOverloadable();
|
||||||
|
#endif
|
||||||
|
virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol?
|
||||||
|
virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration?
|
||||||
|
virtual Type *getType(); // is this a type?
|
||||||
|
virtual char *mangle();
|
||||||
|
virtual int needThis(); // need a 'this' pointer?
|
||||||
|
virtual enum PROT prot();
|
||||||
|
virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
|
||||||
|
virtual int oneMember(Dsymbol **ps, Identifier *ident);
|
||||||
|
static int oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident = NULL);
|
||||||
|
virtual int hasPointers();
|
||||||
|
virtual bool hasStaticCtorOrDtor();
|
||||||
|
virtual void addLocalClass(ClassDeclarations *) { }
|
||||||
|
virtual void checkCtorConstInit() { }
|
||||||
|
|
||||||
|
virtual void addComment(unsigned char *comment);
|
||||||
|
virtual void emitComment(Scope *sc);
|
||||||
|
void emitDitto(Scope *sc);
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
// Backend
|
||||||
|
|
||||||
|
virtual Symbol *toSymbol(); // to backend symbol
|
||||||
|
virtual void toObjFile(int multiobj); // compile to .obj file
|
||||||
|
virtual int cvMember(unsigned char *p); // emit cv debug info for member
|
||||||
|
|
||||||
|
Symbol *toImport(); // to backend import symbol
|
||||||
|
static Symbol *toImport(Symbol *s); // to backend import symbol
|
||||||
|
|
||||||
|
Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Eliminate need for dynamic_cast
|
||||||
|
virtual Package *isPackage() { return NULL; }
|
||||||
|
virtual Module *isModule() { return NULL; }
|
||||||
|
virtual EnumMember *isEnumMember() { return NULL; }
|
||||||
|
virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; }
|
||||||
|
virtual TemplateInstance *isTemplateInstance() { return NULL; }
|
||||||
|
virtual TemplateMixin *isTemplateMixin() { return NULL; }
|
||||||
|
virtual Declaration *isDeclaration() { return NULL; }
|
||||||
|
virtual ThisDeclaration *isThisDeclaration() { return NULL; }
|
||||||
|
virtual TupleDeclaration *isTupleDeclaration() { return NULL; }
|
||||||
|
virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; }
|
||||||
|
virtual AliasDeclaration *isAliasDeclaration() { return NULL; }
|
||||||
|
virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; }
|
||||||
|
virtual FuncDeclaration *isFuncDeclaration() { return NULL; }
|
||||||
|
virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; }
|
||||||
|
virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; }
|
||||||
|
virtual CtorDeclaration *isCtorDeclaration() { return NULL; }
|
||||||
|
virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; }
|
||||||
|
virtual DtorDeclaration *isDtorDeclaration() { return NULL; }
|
||||||
|
virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; }
|
||||||
|
virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; }
|
||||||
|
virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; }
|
||||||
|
virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; }
|
||||||
|
virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; }
|
||||||
|
virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; }
|
||||||
|
virtual NewDeclaration *isNewDeclaration() { return NULL; }
|
||||||
|
virtual VarDeclaration *isVarDeclaration() { return NULL; }
|
||||||
|
virtual ClassDeclaration *isClassDeclaration() { return NULL; }
|
||||||
|
virtual StructDeclaration *isStructDeclaration() { return NULL; }
|
||||||
|
virtual UnionDeclaration *isUnionDeclaration() { return NULL; }
|
||||||
|
virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; }
|
||||||
|
virtual ScopeDsymbol *isScopeDsymbol() { return NULL; }
|
||||||
|
virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; }
|
||||||
|
virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; }
|
||||||
|
virtual Import *isImport() { return NULL; }
|
||||||
|
virtual EnumDeclaration *isEnumDeclaration() { return NULL; }
|
||||||
|
virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; }
|
||||||
|
virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; }
|
||||||
|
virtual AttribDeclaration *isAttribDeclaration() { return NULL; }
|
||||||
|
virtual OverloadSet *isOverloadSet() { return NULL; }
|
||||||
|
virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; }
|
||||||
|
virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; }
|
||||||
|
#if TARGET_NET
|
||||||
|
virtual PragmaScope* isPragmaScope() { return NULL; }
|
||||||
|
#endif
|
||||||
|
#if IN_LLVM
|
||||||
|
/// Codegen traversal
|
||||||
|
virtual void codegen(Ir* ir);
|
||||||
|
|
||||||
|
// llvm stuff
|
||||||
|
int llvmInternal;
|
||||||
|
|
||||||
|
IrDsymbol ir;
|
||||||
|
IrSymbol* irsym;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Dsymbol that generates a scope
|
||||||
|
|
||||||
|
struct ScopeDsymbol : Dsymbol
|
||||||
|
{
|
||||||
|
Dsymbols *members; // all Dsymbol's in this scope
|
||||||
|
DsymbolTable *symtab; // members[] sorted into table
|
||||||
|
|
||||||
|
Dsymbols *imports; // imported Dsymbol's
|
||||||
|
unsigned char *prots; // array of PROT, one for each import
|
||||||
|
|
||||||
|
ScopeDsymbol();
|
||||||
|
ScopeDsymbol(Identifier *id);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||||
|
void importScope(Dsymbol *s, enum PROT protection);
|
||||||
|
int isforwardRef();
|
||||||
|
void defineRef(Dsymbol *s);
|
||||||
|
static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2);
|
||||||
|
Dsymbol *nameCollision(Dsymbol *s);
|
||||||
|
const char *kind();
|
||||||
|
FuncDeclaration *findGetMembers();
|
||||||
|
virtual Dsymbol *symtabInsert(Dsymbol *s);
|
||||||
|
bool hasStaticCtorOrDtor();
|
||||||
|
|
||||||
|
void emitMemberComments(Scope *sc);
|
||||||
|
|
||||||
|
static size_t dim(Dsymbols *members);
|
||||||
|
static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL);
|
||||||
|
|
||||||
|
typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
|
||||||
|
static int foreach(Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn=NULL);
|
||||||
|
|
||||||
|
ScopeDsymbol *isScopeDsymbol() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// With statement scope
|
||||||
|
|
||||||
|
struct WithScopeSymbol : ScopeDsymbol
|
||||||
|
{
|
||||||
|
WithStatement *withstate;
|
||||||
|
|
||||||
|
WithScopeSymbol(WithStatement *withstate);
|
||||||
|
Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||||
|
|
||||||
|
WithScopeSymbol *isWithScopeSymbol() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Array Index/Slice scope
|
||||||
|
|
||||||
|
struct ArrayScopeSymbol : ScopeDsymbol
|
||||||
|
{
|
||||||
|
Expression *exp; // IndexExp or SliceExp
|
||||||
|
TypeTuple *type; // for tuple[length]
|
||||||
|
TupleDeclaration *td; // for tuples of objects
|
||||||
|
Scope *sc;
|
||||||
|
|
||||||
|
ArrayScopeSymbol(Scope *sc, Expression *e);
|
||||||
|
ArrayScopeSymbol(Scope *sc, TypeTuple *t);
|
||||||
|
ArrayScopeSymbol(Scope *sc, TupleDeclaration *td);
|
||||||
|
Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||||
|
|
||||||
|
ArrayScopeSymbol *isArrayScopeSymbol() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload Sets
|
||||||
|
|
||||||
|
#if DMDV2
|
||||||
|
struct OverloadSet : Dsymbol
|
||||||
|
{
|
||||||
|
Dsymbols a; // array of Dsymbols
|
||||||
|
|
||||||
|
OverloadSet();
|
||||||
|
void push(Dsymbol *s);
|
||||||
|
OverloadSet *isOverloadSet() { return this; }
|
||||||
|
const char *kind();
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Table of Dsymbol's
|
||||||
|
|
||||||
|
struct DsymbolTable : Object
|
||||||
|
{
|
||||||
|
AA *tab;
|
||||||
|
|
||||||
|
DsymbolTable();
|
||||||
|
~DsymbolTable();
|
||||||
|
|
||||||
|
// Look up Identifier. Return Dsymbol if found, NULL if not.
|
||||||
|
Dsymbol *lookup(Identifier *ident);
|
||||||
|
|
||||||
|
// Insert Dsymbol in table. Return NULL if already there.
|
||||||
|
Dsymbol *insert(Dsymbol *s);
|
||||||
|
|
||||||
|
// Look for Dsymbol in table. If there, return it. If not, insert s and return that.
|
||||||
|
Dsymbol *update(Dsymbol *s);
|
||||||
|
Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DMD_DSYMBOL_H */
|
||||||
+152
@@ -0,0 +1,152 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "template.h"
|
||||||
|
|
||||||
|
static void indent(int indent)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < indent; i++)
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *type_print(Type *type)
|
||||||
|
{
|
||||||
|
return type ? type->toChars() : (char *) "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
void dumpExpressions(int i, Expressions *exps)
|
||||||
|
{
|
||||||
|
if (exps)
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < exps->dim; j++)
|
||||||
|
{ Expression *e = exps->tdata()[j];
|
||||||
|
indent(i);
|
||||||
|
printf("(\n");
|
||||||
|
e->dump(i + 2);
|
||||||
|
indent(i);
|
||||||
|
printf(")\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Expression::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
printf("%p %s type=%s\n", this, Token::toChars(op), type_print(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntegerExp::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
printf("%p %jd type=%s\n", this, (intmax_t)value, type_print(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdentifierExp::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
printf("%p ident '%s' type=%s\n", this, ident->toChars(), type_print(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DsymbolExp::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
printf("%p %s type=%s\n", this, s->toChars(), type_print(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VarExp::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
printf("%p %s var=%s type=%s\n", this, Token::toChars(op), var->toChars(), type_print(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnaExp::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1);
|
||||||
|
if (e1)
|
||||||
|
e1->dump(i + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallExp::dump(int i)
|
||||||
|
{
|
||||||
|
UnaExp::dump(i);
|
||||||
|
dumpExpressions(i, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SliceExp::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1);
|
||||||
|
if (e1)
|
||||||
|
e1->dump(i + 2);
|
||||||
|
if (lwr)
|
||||||
|
lwr->dump(i + 2);
|
||||||
|
if (upr)
|
||||||
|
upr->dump(i + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DotIdExp::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
printf("%p %s type=%s ident=%s e1=%p\n", this, Token::toChars(op), type_print(type), ident->toChars(), e1);
|
||||||
|
if (e1)
|
||||||
|
e1->dump(i + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DotVarExp::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
printf("%p %s type=%s var='%s' e1=%p\n", this, Token::toChars(op), type_print(type), var->toChars(), e1);
|
||||||
|
if (e1)
|
||||||
|
e1->dump(i + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DotTemplateInstanceExp::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
printf("%p %s type=%s ti='%s' e1=%p\n", this, Token::toChars(op), type_print(type), ti->toChars(), e1);
|
||||||
|
if (e1)
|
||||||
|
e1->dump(i + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DelegateExp::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
printf("%p %s func=%s type=%s e1=%p\n", this, Token::toChars(op), func->toChars(), type_print(type), e1);
|
||||||
|
if (e1)
|
||||||
|
e1->dump(i + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BinExp::dump(int i)
|
||||||
|
{
|
||||||
|
indent(i);
|
||||||
|
const char *sop = Token::toChars(op);
|
||||||
|
if (op == TOKblit)
|
||||||
|
sop = "blit";
|
||||||
|
else if (op == TOKconstruct)
|
||||||
|
sop = "construct";
|
||||||
|
printf("%p %s type=%s e1=%p e2=%p\n", this, sop, type_print(type), e1, e2);
|
||||||
|
if (e1)
|
||||||
|
e1->dump(i + 2);
|
||||||
|
if (e2)
|
||||||
|
e2->dump(i + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+2391
File diff suppressed because it is too large
Load Diff
+427
@@ -0,0 +1,427 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "enum.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "id.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "module.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
|
||||||
|
/********************************* EnumDeclaration ****************************/
|
||||||
|
|
||||||
|
EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
|
||||||
|
: ScopeDsymbol(id)
|
||||||
|
{
|
||||||
|
this->loc = loc;
|
||||||
|
type = new TypeEnum(this);
|
||||||
|
this->memtype = memtype;
|
||||||
|
maxval = NULL;
|
||||||
|
minval = NULL;
|
||||||
|
defaultval = NULL;
|
||||||
|
#if IN_DMD
|
||||||
|
sinit = NULL;
|
||||||
|
#endif
|
||||||
|
isdeprecated = 0;
|
||||||
|
isdone = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
|
||||||
|
{
|
||||||
|
Type *t = NULL;
|
||||||
|
if (memtype)
|
||||||
|
t = memtype->syntaxCopy();
|
||||||
|
|
||||||
|
EnumDeclaration *ed;
|
||||||
|
if (s)
|
||||||
|
{ ed = (EnumDeclaration *)s;
|
||||||
|
ed->memtype = t;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ed = new EnumDeclaration(loc, ident, t);
|
||||||
|
ScopeDsymbol::syntaxCopy(ed);
|
||||||
|
return ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnumDeclaration::semantic0(Scope *sc)
|
||||||
|
{
|
||||||
|
/* This function is a hack to get around a significant problem.
|
||||||
|
* The members of anonymous enums, like:
|
||||||
|
* enum { A, B, C }
|
||||||
|
* don't get installed into the symbol table until after they are
|
||||||
|
* semantically analyzed, yet they're supposed to go into the enclosing
|
||||||
|
* scope's table. Hence, when forward referenced, they come out as
|
||||||
|
* 'undefined'. The real fix is to add them in at addSymbol() time.
|
||||||
|
* But to get code to compile, we'll just do this quick hack at the moment
|
||||||
|
* to compile it if it doesn't depend on anything else.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (isdone || !scope)
|
||||||
|
return;
|
||||||
|
if (!isAnonymous() || memtype)
|
||||||
|
return;
|
||||||
|
for (size_t i = 0; i < members->dim; i++)
|
||||||
|
{
|
||||||
|
EnumMember *em = (*members)[i]->isEnumMember();
|
||||||
|
if (em && (em->type || em->value))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can do it
|
||||||
|
semantic(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnumDeclaration::semantic(Scope *sc)
|
||||||
|
{
|
||||||
|
Type *t;
|
||||||
|
Scope *sce;
|
||||||
|
|
||||||
|
//printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars());
|
||||||
|
//printf("EnumDeclaration::semantic() %s\n", toChars());
|
||||||
|
if (!members) // enum ident;
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!memtype && !isAnonymous())
|
||||||
|
{ // Set memtype if we can to reduce fwd reference errors
|
||||||
|
memtype = Type::tint32; // case 1) enum ident { ... }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symtab) // if already done
|
||||||
|
{ if (isdone || !scope)
|
||||||
|
return; // semantic() already completed
|
||||||
|
}
|
||||||
|
else
|
||||||
|
symtab = new DsymbolTable();
|
||||||
|
|
||||||
|
Scope *scx = NULL;
|
||||||
|
if (scope)
|
||||||
|
{ sc = scope;
|
||||||
|
scx = scope; // save so we don't make redundant copies
|
||||||
|
scope = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned dprogress_save = Module::dprogress;
|
||||||
|
|
||||||
|
if (sc->stc & STCdeprecated)
|
||||||
|
isdeprecated = 1;
|
||||||
|
|
||||||
|
parent = sc->parent;
|
||||||
|
|
||||||
|
/* The separate, and distinct, cases are:
|
||||||
|
* 1. enum { ... }
|
||||||
|
* 2. enum : memtype { ... }
|
||||||
|
* 3. enum ident { ... }
|
||||||
|
* 4. enum ident : memtype { ... }
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (memtype)
|
||||||
|
{
|
||||||
|
memtype = memtype->semantic(loc, sc);
|
||||||
|
|
||||||
|
/* Check to see if memtype is forward referenced
|
||||||
|
*/
|
||||||
|
if (memtype->ty == Tenum)
|
||||||
|
{ EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc);
|
||||||
|
if (!sym->memtype || !sym->members || !sym->symtab || sym->scope)
|
||||||
|
{ // memtype is forward referenced, so try again later
|
||||||
|
scope = scx ? scx : new Scope(*sc);
|
||||||
|
scope->setNoFree();
|
||||||
|
scope->module->addDeferredSemantic(this);
|
||||||
|
Module::dprogress = dprogress_save;
|
||||||
|
//printf("\tdeferring %s\n", toChars());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0 // Decided to abandon this restriction for D 2.0
|
||||||
|
if (!memtype->isintegral())
|
||||||
|
{ error("base type must be of integral type, not %s", memtype->toChars());
|
||||||
|
memtype = Type::tint32;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
isdone = 1;
|
||||||
|
Module::dprogress++;
|
||||||
|
|
||||||
|
type = type->semantic(loc, sc);
|
||||||
|
if (isAnonymous())
|
||||||
|
sce = sc;
|
||||||
|
else
|
||||||
|
{ sce = sc->push(this);
|
||||||
|
sce->parent = this;
|
||||||
|
}
|
||||||
|
if (members->dim == 0)
|
||||||
|
error("enum %s must have at least one member", toChars());
|
||||||
|
int first = 1;
|
||||||
|
Expression *elast = NULL;
|
||||||
|
for (size_t i = 0; i < members->dim; i++)
|
||||||
|
{
|
||||||
|
EnumMember *em = (*members)[i]->isEnumMember();
|
||||||
|
Expression *e;
|
||||||
|
|
||||||
|
if (!em)
|
||||||
|
/* The e->semantic(sce) can insert other symbols, such as
|
||||||
|
* template instances and function literals.
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//printf(" Enum member '%s'\n",em->toChars());
|
||||||
|
if (em->type)
|
||||||
|
em->type = em->type->semantic(em->loc, sce);
|
||||||
|
e = em->value;
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
assert(e->dyncast() == DYNCAST_EXPRESSION);
|
||||||
|
e = e->semantic(sce);
|
||||||
|
e = e->optimize(WANTvalue | WANTinterpret);
|
||||||
|
if (memtype)
|
||||||
|
{
|
||||||
|
e = e->implicitCastTo(sce, memtype);
|
||||||
|
e = e->optimize(WANTvalue | WANTinterpret);
|
||||||
|
if (!isAnonymous())
|
||||||
|
e = e->castTo(sce, type);
|
||||||
|
t = memtype;
|
||||||
|
}
|
||||||
|
else if (em->type)
|
||||||
|
{
|
||||||
|
e = e->implicitCastTo(sce, em->type);
|
||||||
|
e = e->optimize(WANTvalue | WANTinterpret);
|
||||||
|
assert(isAnonymous());
|
||||||
|
t = e->type;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
t = e->type;
|
||||||
|
}
|
||||||
|
else if (first)
|
||||||
|
{
|
||||||
|
if (memtype)
|
||||||
|
t = memtype;
|
||||||
|
else if (em->type)
|
||||||
|
t = em->type;
|
||||||
|
else
|
||||||
|
t = Type::tint32;
|
||||||
|
e = new IntegerExp(em->loc, 0, Type::tint32);
|
||||||
|
e = e->implicitCastTo(sce, t);
|
||||||
|
e = e->optimize(WANTvalue | WANTinterpret);
|
||||||
|
if (!isAnonymous())
|
||||||
|
e = e->castTo(sce, type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Set value to (elast + 1).
|
||||||
|
// But first check that (elast != t.max)
|
||||||
|
assert(elast);
|
||||||
|
e = new EqualExp(TOKequal, em->loc, elast, t->getProperty(0, Id::max));
|
||||||
|
e = e->semantic(sce);
|
||||||
|
e = e->optimize(WANTvalue | WANTinterpret);
|
||||||
|
if (e->toInteger())
|
||||||
|
error("overflow of enum value %s", elast->toChars());
|
||||||
|
|
||||||
|
// Now set e to (elast + 1)
|
||||||
|
e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32));
|
||||||
|
e = e->semantic(sce);
|
||||||
|
e = e->castTo(sce, elast->type);
|
||||||
|
e = e->optimize(WANTvalue | WANTinterpret);
|
||||||
|
}
|
||||||
|
elast = e;
|
||||||
|
em->value = e;
|
||||||
|
|
||||||
|
// Add to symbol table only after evaluating 'value'
|
||||||
|
if (isAnonymous())
|
||||||
|
{
|
||||||
|
/* Anonymous enum members get added to enclosing scope.
|
||||||
|
*/
|
||||||
|
for (Scope *sct = sce; sct; sct = sct->enclosing)
|
||||||
|
{
|
||||||
|
if (sct->scopesym)
|
||||||
|
{
|
||||||
|
if (!sct->scopesym->symtab)
|
||||||
|
sct->scopesym->symtab = new DsymbolTable();
|
||||||
|
em->addMember(sce, sct->scopesym, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
em->addMember(sc, this, 1);
|
||||||
|
|
||||||
|
/* Compute .min, .max and .default values.
|
||||||
|
* If enum doesn't have a name, we can never identify the enum type,
|
||||||
|
* so there is no purpose for a .min, .max or .default
|
||||||
|
*/
|
||||||
|
if (!isAnonymous())
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
{ defaultval = e;
|
||||||
|
minval = e;
|
||||||
|
maxval = e;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ Expression *ec;
|
||||||
|
|
||||||
|
/* In order to work successfully with UDTs,
|
||||||
|
* build expressions to do the comparisons,
|
||||||
|
* and let the semantic analyzer and constant
|
||||||
|
* folder give us the result.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Compute if(e < minval)
|
||||||
|
ec = new CmpExp(TOKlt, em->loc, e, minval);
|
||||||
|
ec = ec->semantic(sce);
|
||||||
|
ec = ec->optimize(WANTvalue | WANTinterpret);
|
||||||
|
if (ec->toInteger())
|
||||||
|
minval = e;
|
||||||
|
|
||||||
|
ec = new CmpExp(TOKgt, em->loc, e, maxval);
|
||||||
|
ec = ec->semantic(sce);
|
||||||
|
ec = ec->optimize(WANTvalue | WANTinterpret);
|
||||||
|
if (ec->toInteger())
|
||||||
|
maxval = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
first = 0;
|
||||||
|
}
|
||||||
|
//printf("defaultval = %lld\n", defaultval);
|
||||||
|
|
||||||
|
//if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars());
|
||||||
|
if (sc != sce)
|
||||||
|
sce->pop();
|
||||||
|
//members->print();
|
||||||
|
}
|
||||||
|
|
||||||
|
int EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
|
||||||
|
{
|
||||||
|
if (isAnonymous())
|
||||||
|
return Dsymbol::oneMembers(members, ps, ident);
|
||||||
|
return Dsymbol::oneMember(ps, ident);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
buf->writestring("enum ");
|
||||||
|
if (ident)
|
||||||
|
{ buf->writestring(ident->toChars());
|
||||||
|
buf->writeByte(' ');
|
||||||
|
}
|
||||||
|
if (memtype)
|
||||||
|
{
|
||||||
|
buf->writestring(": ");
|
||||||
|
memtype->toCBuffer(buf, NULL, hgs);
|
||||||
|
}
|
||||||
|
if (!members)
|
||||||
|
{
|
||||||
|
buf->writeByte(';');
|
||||||
|
buf->writenl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buf->writenl();
|
||||||
|
buf->writeByte('{');
|
||||||
|
buf->writenl();
|
||||||
|
for (size_t i = 0; i < members->dim; i++)
|
||||||
|
{
|
||||||
|
EnumMember *em = (*members)[i]->isEnumMember();
|
||||||
|
if (!em)
|
||||||
|
continue;
|
||||||
|
//buf->writestring(" ");
|
||||||
|
em->toCBuffer(buf, hgs);
|
||||||
|
buf->writeByte(',');
|
||||||
|
buf->writenl();
|
||||||
|
}
|
||||||
|
buf->writeByte('}');
|
||||||
|
buf->writenl();
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *EnumDeclaration::getType()
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *EnumDeclaration::kind()
|
||||||
|
{
|
||||||
|
return "enum";
|
||||||
|
}
|
||||||
|
|
||||||
|
int EnumDeclaration::isDeprecated()
|
||||||
|
{
|
||||||
|
return isdeprecated;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dsymbol *EnumDeclaration::search(Loc loc, Identifier *ident, int flags)
|
||||||
|
{
|
||||||
|
//printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars());
|
||||||
|
if (scope)
|
||||||
|
// Try one last time to resolve this enum
|
||||||
|
semantic(scope);
|
||||||
|
|
||||||
|
if (!members || !symtab || scope)
|
||||||
|
{ error("is forward referenced when looking for '%s'", ident->toChars());
|
||||||
|
//*(char*)0=0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************* EnumMember ****************************/
|
||||||
|
|
||||||
|
EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *type)
|
||||||
|
: Dsymbol(id)
|
||||||
|
{
|
||||||
|
this->value = value;
|
||||||
|
this->type = type;
|
||||||
|
this->loc = loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dsymbol *EnumMember::syntaxCopy(Dsymbol *s)
|
||||||
|
{
|
||||||
|
Expression *e = NULL;
|
||||||
|
if (value)
|
||||||
|
e = value->syntaxCopy();
|
||||||
|
|
||||||
|
Type *t = NULL;
|
||||||
|
if (type)
|
||||||
|
t = type->syntaxCopy();
|
||||||
|
|
||||||
|
EnumMember *em;
|
||||||
|
if (s)
|
||||||
|
{ em = (EnumMember *)s;
|
||||||
|
em->loc = loc;
|
||||||
|
em->value = e;
|
||||||
|
em->type = t;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
em = new EnumMember(loc, ident, e, t);
|
||||||
|
return em;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
if (type)
|
||||||
|
type->toCBuffer(buf, ident, hgs);
|
||||||
|
else
|
||||||
|
buf->writestring(ident->toChars());
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
buf->writestring(" = ");
|
||||||
|
value->toCBuffer(buf, hgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *EnumMember::kind()
|
||||||
|
{
|
||||||
|
return "enum member";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2008 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_ENUM_H
|
||||||
|
#define DMD_ENUM_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "dsymbol.h"
|
||||||
|
|
||||||
|
struct Identifier;
|
||||||
|
struct Type;
|
||||||
|
struct Expression;
|
||||||
|
struct HdrGenState;
|
||||||
|
|
||||||
|
|
||||||
|
struct EnumDeclaration : ScopeDsymbol
|
||||||
|
{ /* enum ident : memtype { ... }
|
||||||
|
*/
|
||||||
|
Type *type; // the TypeEnum
|
||||||
|
Type *memtype; // type of the members
|
||||||
|
|
||||||
|
#if DMDV1
|
||||||
|
dinteger_t maxval;
|
||||||
|
dinteger_t minval;
|
||||||
|
dinteger_t defaultval; // default initializer
|
||||||
|
#else
|
||||||
|
Expression *maxval;
|
||||||
|
Expression *minval;
|
||||||
|
Expression *defaultval; // default initializer
|
||||||
|
#endif
|
||||||
|
int isdeprecated;
|
||||||
|
int isdone; // 0: not done
|
||||||
|
// 1: semantic() successfully completed
|
||||||
|
|
||||||
|
EnumDeclaration(Loc loc, Identifier *id, Type *memtype);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
void semantic0(Scope *sc);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
int oneMember(Dsymbol **ps, Identifier *ident = NULL);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
Type *getType();
|
||||||
|
const char *kind();
|
||||||
|
#if DMDV2
|
||||||
|
Dsymbol *search(Loc, Identifier *ident, int flags);
|
||||||
|
#endif
|
||||||
|
int isDeprecated(); // is Dsymbol deprecated?
|
||||||
|
|
||||||
|
void emitComment(Scope *sc);
|
||||||
|
void toJsonBuffer(OutBuffer *buf);
|
||||||
|
void toDocBuffer(OutBuffer *buf);
|
||||||
|
|
||||||
|
EnumDeclaration *isEnumDeclaration() { return this; }
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
void toObjFile(int multiobj); // compile to .obj file
|
||||||
|
void toDebug();
|
||||||
|
int cvMember(unsigned char *p);
|
||||||
|
|
||||||
|
Symbol *sinit;
|
||||||
|
Symbol *toInitializer();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
void codegen(Ir*);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct EnumMember : Dsymbol
|
||||||
|
{
|
||||||
|
Expression *value;
|
||||||
|
Type *type;
|
||||||
|
|
||||||
|
EnumMember(Loc loc, Identifier *id, Expression *value, Type *type);
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
const char *kind();
|
||||||
|
|
||||||
|
void emitComment(Scope *sc);
|
||||||
|
void toJsonBuffer(OutBuffer *buf);
|
||||||
|
void toDocBuffer(OutBuffer *buf);
|
||||||
|
|
||||||
|
EnumMember *isEnumMember() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DMD_ENUM_H */
|
||||||
+12570
File diff suppressed because it is too large
Load Diff
+2141
File diff suppressed because it is too large
Load Diff
+4236
File diff suppressed because it is too large
Load Diff
+248
@@ -0,0 +1,248 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 1, February 1989
|
||||||
|
|
||||||
|
Copyright (C) 1989 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The license agreements of most software companies try to keep users
|
||||||
|
at the mercy of those companies. By contrast, our General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. The
|
||||||
|
General Public License applies to the Free Software Foundation's
|
||||||
|
software and to any other program whose authors commit to using it.
|
||||||
|
You can use it for your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Specifically, the General Public License is designed to make
|
||||||
|
sure that you have the freedom to give away or sell copies of free
|
||||||
|
software, that you receive source code or can get it if you want it,
|
||||||
|
that you can change the software or use pieces of it in new free
|
||||||
|
programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of a such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must tell them their rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any program or other work which
|
||||||
|
contains a notice placed by the copyright holder saying it may be
|
||||||
|
distributed under the terms of this General Public License. The
|
||||||
|
"Program", below, refers to any such program or work, and a "work based
|
||||||
|
on the Program" means either the Program or any work containing the
|
||||||
|
Program or a portion of it, either verbatim or with modifications. Each
|
||||||
|
licensee is addressed as "you".
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's source
|
||||||
|
code as you receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice and
|
||||||
|
disclaimer of warranty; keep intact all the notices that refer to this
|
||||||
|
General Public License and to the absence of any warranty; and give any
|
||||||
|
other recipients of the Program a copy of this General Public License
|
||||||
|
along with the Program. You may charge a fee for the physical act of
|
||||||
|
transferring a copy.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion of
|
||||||
|
it, and copy and distribute such modifications under the terms of Paragraph
|
||||||
|
1 above, provided that you also do the following:
|
||||||
|
|
||||||
|
a) cause the modified files to carry prominent notices stating that
|
||||||
|
you changed the files and the date of any change; and
|
||||||
|
|
||||||
|
b) cause the whole of any work that you distribute or publish, that
|
||||||
|
in whole or in part contains the Program or any part thereof, either
|
||||||
|
with or without modifications, to be licensed at no charge to all
|
||||||
|
third parties under the terms of this General Public License (except
|
||||||
|
that you may choose to grant warranty protection to some or all
|
||||||
|
third parties, at your option).
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively when
|
||||||
|
run, you must cause it, when started running for such interactive use
|
||||||
|
in the simplest and most usual way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a notice
|
||||||
|
that there is no warranty (or else, saying that you provide a
|
||||||
|
warranty) and that users may redistribute the program under these
|
||||||
|
conditions, and telling the user how to view a copy of this General
|
||||||
|
Public License.
|
||||||
|
|
||||||
|
d) You may charge a fee for the physical act of transferring a
|
||||||
|
copy, and you may at your option offer warranty protection in
|
||||||
|
exchange for a fee.
|
||||||
|
|
||||||
|
Mere aggregation of another independent work with the Program (or its
|
||||||
|
derivative) on a volume of a storage or distribution medium does not bring
|
||||||
|
the other work under the scope of these terms.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a portion or derivative of
|
||||||
|
it, under Paragraph 2) in object code or executable form under the terms of
|
||||||
|
Paragraphs 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of
|
||||||
|
Paragraphs 1 and 2 above; or,
|
||||||
|
|
||||||
|
b) accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party free (except for a nominal charge
|
||||||
|
for the cost of distribution) a complete machine-readable copy of the
|
||||||
|
corresponding source code, to be distributed under the terms of
|
||||||
|
Paragraphs 1 and 2 above; or,
|
||||||
|
|
||||||
|
c) accompany it with the information you received as to where the
|
||||||
|
corresponding source code may be obtained. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form alone.)
|
||||||
|
|
||||||
|
Source code for a work means the preferred form of the work for making
|
||||||
|
modifications to it. For an executable file, complete source code means
|
||||||
|
all the source code for all modules it contains; but, as a special
|
||||||
|
exception, it need not include source code for modules which are standard
|
||||||
|
libraries that accompany the operating system on which the executable
|
||||||
|
file runs, or for standard header files or definitions files that
|
||||||
|
accompany that operating system.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, distribute or transfer the
|
||||||
|
Program except as expressly provided under this General Public License.
|
||||||
|
Any attempt otherwise to copy, modify, sublicense, distribute or transfer
|
||||||
|
the Program is void, and will automatically terminate your rights to use
|
||||||
|
the Program under this License. However, parties who have received
|
||||||
|
copies, or rights to use copies, from you under this General Public
|
||||||
|
License will not have their licenses terminated so long as such parties
|
||||||
|
remain in full compliance.
|
||||||
|
|
||||||
|
5. By copying, distributing or modifying the Program (or any work based
|
||||||
|
on the Program) you indicate your acceptance of this license to do so,
|
||||||
|
and all its terms and conditions.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the original
|
||||||
|
licensor to copy, distribute or modify the Program subject to these
|
||||||
|
terms and conditions. You may not impose any further restrictions on the
|
||||||
|
recipients' exercise of the rights granted herein.
|
||||||
|
|
||||||
|
7. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of the license which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
the license, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
8. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
Appendix: How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to humanity, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these
|
||||||
|
terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest to
|
||||||
|
attach them to the start of each source file to most effectively convey
|
||||||
|
the exclusion of warranty; and each file should have at least the
|
||||||
|
"copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) 19yy <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 1, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software Foundation,
|
||||||
|
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) 19xx name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the
|
||||||
|
appropriate parts of the General Public License. Of course, the
|
||||||
|
commands you use may be called something other than `show w' and `show
|
||||||
|
c'; they could even be mouse-clicks or menu items--whatever suits your
|
||||||
|
program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||||
|
program `Gnomovision' (a program to direct compilers to make passes
|
||||||
|
at assemblers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
That's all there is to it!
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// Initial header generation implementation by Dave Fladebo
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
// Routines to emit header files
|
||||||
|
|
||||||
|
#define PRETTY_PRINT
|
||||||
|
#define TEST_EMIT_ALL 0 // For Testing
|
||||||
|
|
||||||
|
#define LOG 0
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#if __DMC__
|
||||||
|
#include <complex.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "rmem.h"
|
||||||
|
|
||||||
|
#include "id.h"
|
||||||
|
#include "init.h"
|
||||||
|
|
||||||
|
#include "attrib.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "enum.h"
|
||||||
|
#include "import.h"
|
||||||
|
#include "module.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "staticassert.h"
|
||||||
|
#include "template.h"
|
||||||
|
#include "utf.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "statement.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "hdrgen.h"
|
||||||
|
|
||||||
|
void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs);
|
||||||
|
|
||||||
|
void Module::genhdrfile()
|
||||||
|
{
|
||||||
|
OutBuffer hdrbufr;
|
||||||
|
|
||||||
|
hdrbufr.printf("// D import file generated from '%s'", srcfile->toChars());
|
||||||
|
hdrbufr.writenl();
|
||||||
|
|
||||||
|
HdrGenState hgs;
|
||||||
|
memset(&hgs, 0, sizeof(hgs));
|
||||||
|
hgs.hdrgen = 1;
|
||||||
|
|
||||||
|
toCBuffer(&hdrbufr, &hgs);
|
||||||
|
|
||||||
|
// Transfer image to file
|
||||||
|
hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset);
|
||||||
|
hdrbufr.data = NULL;
|
||||||
|
|
||||||
|
char *pt = FileName::path(hdrfile->toChars());
|
||||||
|
if (*pt)
|
||||||
|
FileName::ensurePathExists(pt);
|
||||||
|
mem.free(pt);
|
||||||
|
hdrfile->writev();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Module::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
if (md)
|
||||||
|
{
|
||||||
|
buf->writestring("module ");
|
||||||
|
buf->writestring(md->toChars());
|
||||||
|
buf->writebyte(';');
|
||||||
|
buf->writenl();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < members->dim; i++)
|
||||||
|
{ Dsymbol *s = members->tdata()[i];
|
||||||
|
|
||||||
|
s->toHBuffer(buf, hgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Dsymbol::toHBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
toCBuffer(buf, hgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************/
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2006 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// initial header generation implementation by Dave Fladebo
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
|
||||||
|
struct HdrGenState
|
||||||
|
{
|
||||||
|
int hdrgen; // 1 if generating header file
|
||||||
|
int ddoc; // 1 if generating Ddoc file
|
||||||
|
int console; // 1 if writing to console
|
||||||
|
int tpltMember;
|
||||||
|
int inCallExp;
|
||||||
|
int inPtrExp;
|
||||||
|
int inSlcExp;
|
||||||
|
int inDotExp;
|
||||||
|
int inBinExp;
|
||||||
|
int inArrExp;
|
||||||
|
int emitInst;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int init;
|
||||||
|
int decl;
|
||||||
|
} FLinit;
|
||||||
|
|
||||||
|
HdrGenState() { memset(this, 0, sizeof(HdrGenState)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
+772
@@ -0,0 +1,772 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2009 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gpl.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
|
||||||
|
/* HTML parser
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#define MARS 1
|
||||||
|
#include "html.h"
|
||||||
|
|
||||||
|
#if MARS
|
||||||
|
#include <assert.h>
|
||||||
|
#include "root.h"
|
||||||
|
//#include "../mars/mars.h"
|
||||||
|
#else
|
||||||
|
#include "outbuf.h"
|
||||||
|
#include "msgs2.h"
|
||||||
|
|
||||||
|
extern void html_err(const char *, unsigned, unsigned, ...);
|
||||||
|
|
||||||
|
static char __file__[] = __FILE__; /* for tassert.h */
|
||||||
|
#include "tassert.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC__
|
||||||
|
int memicmp(const char *s1, const char *s2, int n);
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{ char c1 = s1[i];
|
||||||
|
char c2 = s2[i];
|
||||||
|
|
||||||
|
result = c1 - c2;
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
if ('A' <= c1 && c1 <= 'Z')
|
||||||
|
c1 += 'a' - 'A';
|
||||||
|
if ('A' <= c2 && c2 <= 'Z')
|
||||||
|
c2 += 'a' - 'A';
|
||||||
|
result = c1 - c2;
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int HtmlNamedEntity(unsigned char *p, int length);
|
||||||
|
|
||||||
|
static int isLineSeparator(const unsigned char* p);
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* Determine if beginning of tag identifier
|
||||||
|
* or a continuation of a tag identifier.
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline int istagstart(int c)
|
||||||
|
{
|
||||||
|
return (isalpha(c) || c == '_');
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int istag(int c)
|
||||||
|
{
|
||||||
|
return (isalnum(c) || c == '_');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
Html::Html(const char *sourcename, unsigned char *base, unsigned length)
|
||||||
|
{
|
||||||
|
//printf("Html::Html()\n");
|
||||||
|
this->sourcename = sourcename;
|
||||||
|
this->base = base;
|
||||||
|
p = base;
|
||||||
|
end = base + length;
|
||||||
|
linnum = 1;
|
||||||
|
dbuf = NULL;
|
||||||
|
inCode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************
|
||||||
|
* Print error & quit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Html::error(const char *format, ...)
|
||||||
|
{
|
||||||
|
printf("%s(%d) : HTML Error: ", sourcename, linnum);
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
vprintf(format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
//#if MARS
|
||||||
|
// global.errors++;
|
||||||
|
//#else
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************
|
||||||
|
* Extract all the code from an HTML file,
|
||||||
|
* concatenate it all together, and store in buf.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if MARS
|
||||||
|
void Html::extractCode(OutBuffer *buf)
|
||||||
|
#else
|
||||||
|
void Html::extractCode(Outbuffer *buf)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
//printf("Html::extractCode()\n");
|
||||||
|
dbuf = buf; // save for other routines
|
||||||
|
buf->reserve(end - p);
|
||||||
|
inCode = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
//printf("p = %p, *p = x%x\n", p, *p);
|
||||||
|
switch (*p)
|
||||||
|
{
|
||||||
|
#if 0 // strings are not recognized outside of tags
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
skipString();
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
case '<':
|
||||||
|
if (p[1] == '!' && isCommentStart())
|
||||||
|
{ // Comments start with <!--
|
||||||
|
scanComment();
|
||||||
|
}
|
||||||
|
else if(p[1] == '!' && isCDATAStart())
|
||||||
|
{
|
||||||
|
scanCDATA();
|
||||||
|
}
|
||||||
|
else if (p[1] == '/' && istagstart(*skipWhite(p + 2)))
|
||||||
|
skipTag();
|
||||||
|
else if (istagstart(*skipWhite(p + 1)))
|
||||||
|
skipTag();
|
||||||
|
else
|
||||||
|
goto Ldefault;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
case 0x1a:
|
||||||
|
break; // end of file
|
||||||
|
|
||||||
|
case '&':
|
||||||
|
if (inCode)
|
||||||
|
{ // Translate character entity into ascii for D parser
|
||||||
|
int c;
|
||||||
|
|
||||||
|
c = charEntity();
|
||||||
|
#if MARS
|
||||||
|
buf->writeUTF8(c);
|
||||||
|
#else
|
||||||
|
buf->writeByte(c);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p++;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
if (p[1] == '\n')
|
||||||
|
goto Ldefault;
|
||||||
|
case '\n':
|
||||||
|
linnum++;
|
||||||
|
// Always extract new lines, so that D lexer counts the
|
||||||
|
// lines right.
|
||||||
|
buf->writeByte(*p);
|
||||||
|
p++;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Ldefault:
|
||||||
|
if (inCode)
|
||||||
|
buf->writeByte(*p);
|
||||||
|
p++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf->writeByte(0); // ending sentinel
|
||||||
|
#if SCPP
|
||||||
|
//printf("Code is: '%s'\n", buf->toString() + 3);
|
||||||
|
#endif
|
||||||
|
#if MARS
|
||||||
|
//printf("D code is: '%s'\n", (char *)buf->data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************
|
||||||
|
* Scan to end of <> tag.
|
||||||
|
* Look for <code> and </code> tags to start/stop D processing.
|
||||||
|
* Input:
|
||||||
|
* p is on opening '<' of tag; it's already verified that
|
||||||
|
* it's a tag by lookahead
|
||||||
|
* Output:
|
||||||
|
* p is past closing '>' of tag
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Html::skipTag()
|
||||||
|
{
|
||||||
|
enum TagState // what parsing state we're in
|
||||||
|
{
|
||||||
|
TStagstart, // start of tag name
|
||||||
|
TStag, // in a tag name
|
||||||
|
TSrest, // following tag name
|
||||||
|
};
|
||||||
|
enum TagState state = TStagstart;
|
||||||
|
int inot;
|
||||||
|
unsigned char *tagstart = NULL;
|
||||||
|
int taglen = 0;
|
||||||
|
|
||||||
|
p++;
|
||||||
|
inot = 0;
|
||||||
|
if (*p == '/')
|
||||||
|
{ inot = 1;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
switch (*p)
|
||||||
|
{
|
||||||
|
case '>': // found end of tag
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
state = TSrest;
|
||||||
|
skipString();
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '<':
|
||||||
|
if (p[1] == '!' && isCommentStart())
|
||||||
|
{ // Comments start with <!--
|
||||||
|
scanComment();
|
||||||
|
}
|
||||||
|
else if (p[1] == '/' && istagstart(*skipWhite(p + 2)))
|
||||||
|
{ error("nested tag");
|
||||||
|
skipTag();
|
||||||
|
}
|
||||||
|
else if (istagstart(*skipWhite(p + 1)))
|
||||||
|
{ error("nested tag");
|
||||||
|
skipTag();
|
||||||
|
}
|
||||||
|
// Treat comments as if they were whitespace
|
||||||
|
state = TSrest;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
case 0x1a:
|
||||||
|
error("end of file before end of tag");
|
||||||
|
break; // end of file
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
if (p[1] == '\n')
|
||||||
|
goto Ldefault;
|
||||||
|
case '\n':
|
||||||
|
linnum++;
|
||||||
|
// Always extract new lines, so that code lexer counts the
|
||||||
|
// lines right.
|
||||||
|
dbuf->writeByte(*p);
|
||||||
|
state = TSrest; // end of tag
|
||||||
|
p++;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\f':
|
||||||
|
case '\v':
|
||||||
|
if (state == TStagstart)
|
||||||
|
{ p++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Ldefault:
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case TStagstart: // start of tag name
|
||||||
|
assert(istagstart(*p));
|
||||||
|
state = TStag;
|
||||||
|
tagstart = p;
|
||||||
|
taglen = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TStag:
|
||||||
|
if (istag(*p))
|
||||||
|
{ // Continuing tag name
|
||||||
|
taglen++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // End of tag name
|
||||||
|
state = TSrest;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TSrest:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if we parsed a <code> or </code> tag
|
||||||
|
if (taglen && memicmp((char *) tagstart, (char *) "CODE", taglen) == 0
|
||||||
|
&& *(p - 2) != '/') // ignore "<code />" (XHTML)
|
||||||
|
{
|
||||||
|
if (inot)
|
||||||
|
{ inCode--;
|
||||||
|
if (inCode < 0)
|
||||||
|
inCode = 0; // ignore extra </code>'s
|
||||||
|
}
|
||||||
|
else
|
||||||
|
inCode++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************
|
||||||
|
* Scan to end of attribute string.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Html::skipString()
|
||||||
|
{
|
||||||
|
int tc = *p;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
switch (*p)
|
||||||
|
{
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
if (*p == tc)
|
||||||
|
{ p++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
if (p[1] == '\n')
|
||||||
|
goto Ldefault;
|
||||||
|
case '\n':
|
||||||
|
linnum++;
|
||||||
|
// Always extract new lines, so that D lexer counts the
|
||||||
|
// lines right.
|
||||||
|
dbuf->writeByte(*p);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
case 0x1a:
|
||||||
|
Leof:
|
||||||
|
error("end of file before closing %c of string", tc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Ldefault:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* If p points to any white space, skip it
|
||||||
|
* and return pointer just past it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned char *Html::skipWhite(unsigned char *q)
|
||||||
|
{
|
||||||
|
for (; 1; q++)
|
||||||
|
{
|
||||||
|
switch (*q)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\f':
|
||||||
|
case '\v':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
continue;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************
|
||||||
|
* Scan to end of comment.
|
||||||
|
* Comments are defined any of a number of ways.
|
||||||
|
* IE 5.0: <!-- followed by >
|
||||||
|
* "HTML The Definitive Guide": <!-- text with at least one space in it -->
|
||||||
|
* Netscape: <!-- --> comments nest
|
||||||
|
* w3c: whitespace can appear between -- and > of comment close
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Html::scanComment()
|
||||||
|
{
|
||||||
|
// Most of the complexity is dealing with the case that
|
||||||
|
// an arbitrary amount of whitespace can appear between
|
||||||
|
// the -- and the > of a comment close.
|
||||||
|
int scangt = 0;
|
||||||
|
|
||||||
|
//printf("scanComment()\n");
|
||||||
|
if (*p == '\n')
|
||||||
|
{ linnum++;
|
||||||
|
// Always extract new lines, so that D lexer counts the
|
||||||
|
// lines right.
|
||||||
|
dbuf->writeByte(*p);
|
||||||
|
}
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
//scangt = 1; // IE 5.0 compatibility
|
||||||
|
p++;
|
||||||
|
switch (*p)
|
||||||
|
{
|
||||||
|
case '-':
|
||||||
|
if (p[1] == '-')
|
||||||
|
{
|
||||||
|
if (p[2] == '>') // optimize for most common case
|
||||||
|
{
|
||||||
|
p += 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
scangt = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
scangt = 0;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '>':
|
||||||
|
if (scangt)
|
||||||
|
{ // found -->
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\f':
|
||||||
|
case '\v':
|
||||||
|
// skip white space
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
if (p[1] == '\n')
|
||||||
|
goto Ldefault;
|
||||||
|
case '\n':
|
||||||
|
linnum++; // remember to count lines
|
||||||
|
// Always extract new lines, so that D lexer counts the
|
||||||
|
// lines right.
|
||||||
|
dbuf->writeByte(*p);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
case 0x1a:
|
||||||
|
error("end of file before closing --> of comment");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Ldefault:
|
||||||
|
scangt = 0; // it's not -->
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//printf("*p = '%c'\n", *p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************
|
||||||
|
* Determine if we are at the start of a comment.
|
||||||
|
* Input:
|
||||||
|
* p is on the opening '<'
|
||||||
|
* Returns:
|
||||||
|
* 0 if not start of a comment
|
||||||
|
* 1 if start of a comment, p is adjusted to point past --
|
||||||
|
*/
|
||||||
|
|
||||||
|
int Html::isCommentStart()
|
||||||
|
#ifdef __DMC__
|
||||||
|
__out(result)
|
||||||
|
{
|
||||||
|
if (result == 0)
|
||||||
|
;
|
||||||
|
else if (result == 1)
|
||||||
|
{
|
||||||
|
assert(p[-2] == '-' && p[-1] == '-');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
__body
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
{ unsigned char *s;
|
||||||
|
|
||||||
|
if (p[0] == '<' && p[1] == '!')
|
||||||
|
{
|
||||||
|
for (s = p + 2; 1; s++)
|
||||||
|
{
|
||||||
|
switch (*s)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\f':
|
||||||
|
case '\v':
|
||||||
|
// skip white space, even though spec says no
|
||||||
|
// white space is allowed
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
if (s[1] == '-')
|
||||||
|
{
|
||||||
|
p = s + 2;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
goto No;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto No;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
No:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Html::isCDATAStart()
|
||||||
|
{
|
||||||
|
const char * CDATA_START_MARKER = "<![CDATA[";
|
||||||
|
size_t len = strlen(CDATA_START_MARKER);
|
||||||
|
|
||||||
|
if (strncmp((char*)p, CDATA_START_MARKER, len) == 0)
|
||||||
|
{
|
||||||
|
p += len;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Html::scanCDATA()
|
||||||
|
{
|
||||||
|
while(*p && *p != 0x1A)
|
||||||
|
{
|
||||||
|
int lineSepLength = isLineSeparator(p);
|
||||||
|
if (lineSepLength>0)
|
||||||
|
{
|
||||||
|
/* Always extract new lines, so that D lexer counts the lines
|
||||||
|
* right.
|
||||||
|
*/
|
||||||
|
linnum++;
|
||||||
|
dbuf->writeByte('\n');
|
||||||
|
p += lineSepLength;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (p[0] == ']' && p[1] == ']' && p[2] == '>')
|
||||||
|
{
|
||||||
|
/* end of CDATA section */
|
||||||
|
p += 3;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (inCode)
|
||||||
|
{
|
||||||
|
/* this CDATA section contains D code */
|
||||||
|
dbuf->writeByte(*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************
|
||||||
|
* Convert an HTML character entity into a character.
|
||||||
|
* Forms are:
|
||||||
|
* &name; named entity
|
||||||
|
* &#ddd; decimal
|
||||||
|
* &#xhhhh; hex
|
||||||
|
* Input:
|
||||||
|
* p is on the &
|
||||||
|
*/
|
||||||
|
|
||||||
|
int Html::charEntity()
|
||||||
|
{ int c = 0;
|
||||||
|
int v;
|
||||||
|
int hex;
|
||||||
|
unsigned char *pstart = p;
|
||||||
|
|
||||||
|
//printf("Html::charEntity('%c')\n", *p);
|
||||||
|
if (p[1] == '#')
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
if (p[1] == 'x' || p[1] == 'X')
|
||||||
|
{ p++;
|
||||||
|
hex = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hex = 0;
|
||||||
|
if (p[1] == ';')
|
||||||
|
goto Linvalid;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
switch (*p)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 0x1a:
|
||||||
|
error("end of file before end of character entity");
|
||||||
|
goto Lignore;
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
case '<': // tag start
|
||||||
|
// Termination is assumed
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ';':
|
||||||
|
// Termination is explicit
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
v = *p - '0';
|
||||||
|
goto Lvalue;
|
||||||
|
|
||||||
|
case 'a': case 'b': case 'c':
|
||||||
|
case 'd': case 'e': case 'f':
|
||||||
|
if (!hex)
|
||||||
|
goto Linvalid;
|
||||||
|
v = (*p - 'a') + 10;
|
||||||
|
goto Lvalue;
|
||||||
|
|
||||||
|
case 'A': case 'B': case 'C':
|
||||||
|
case 'D': case 'E': case 'F':
|
||||||
|
if (!hex)
|
||||||
|
goto Linvalid;
|
||||||
|
v = (*p - 'A') + 10;
|
||||||
|
goto Lvalue;
|
||||||
|
|
||||||
|
Lvalue:
|
||||||
|
if (hex)
|
||||||
|
c = (c << 4) + v;
|
||||||
|
else
|
||||||
|
c = (c * 10) + v;
|
||||||
|
if (c > 0x10FFFF)
|
||||||
|
{
|
||||||
|
error("character entity out of range");
|
||||||
|
goto Lignore;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Linvalid:
|
||||||
|
error("invalid numeric character reference");
|
||||||
|
goto Lignore;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// It's a named entity; gather all characters until ;
|
||||||
|
unsigned char *idstart = p + 1;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
switch (*p)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 0x1a:
|
||||||
|
error("end of file before end of character entity");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
case '<': // tag start
|
||||||
|
// Termination is assumed
|
||||||
|
c = HtmlNamedEntity(idstart, p - idstart);
|
||||||
|
if (c == -1)
|
||||||
|
goto Lignore;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ';':
|
||||||
|
// Termination is explicit
|
||||||
|
c = HtmlNamedEntity(idstart, p - idstart);
|
||||||
|
if (c == -1)
|
||||||
|
goto Lignore;
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kludge to convert non-breaking space to ascii space
|
||||||
|
if (c == 160)
|
||||||
|
c = ' ';
|
||||||
|
|
||||||
|
return c;
|
||||||
|
|
||||||
|
Lignore:
|
||||||
|
//printf("Lignore\n");
|
||||||
|
p = pstart + 1;
|
||||||
|
return '&';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* identify DOS, Linux, Mac, Next and Unicode line endings
|
||||||
|
* 0 if this is no line separator
|
||||||
|
* >0 the length of the separator
|
||||||
|
* Note: input has to be UTF-8
|
||||||
|
*/
|
||||||
|
static int isLineSeparator(const unsigned char* p)
|
||||||
|
{
|
||||||
|
// Linux
|
||||||
|
if( p[0]=='\n')
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// Mac & Dos
|
||||||
|
if( p[0]=='\r')
|
||||||
|
return (p[1]=='\n') ? 2 : 1;
|
||||||
|
|
||||||
|
// Unicode (line || paragraph sep.)
|
||||||
|
if( p[0]==0xE2 && p[1]==0x80 && (p[2]==0xA8 || p[2]==0xA9))
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
// Next
|
||||||
|
if( p[0]==0xC2 && p[1]==0x85)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2009 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gpl.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
|
||||||
|
#if MARS
|
||||||
|
struct OutBuffer;
|
||||||
|
#else
|
||||||
|
struct Outbuffer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Html
|
||||||
|
{
|
||||||
|
const char *sourcename;
|
||||||
|
|
||||||
|
unsigned char *base; // pointer to start of buffer
|
||||||
|
unsigned char *end; // past end of buffer
|
||||||
|
unsigned char *p; // current character
|
||||||
|
unsigned linnum; // current line number
|
||||||
|
#if MARS
|
||||||
|
OutBuffer *dbuf; // code source buffer
|
||||||
|
#else
|
||||||
|
Outbuffer *dbuf; // code source buffer
|
||||||
|
#endif
|
||||||
|
int inCode; // !=0 if in code
|
||||||
|
|
||||||
|
|
||||||
|
Html(const char *sourcename, unsigned char *base, unsigned length);
|
||||||
|
|
||||||
|
void error(const char *format, ...);
|
||||||
|
#if MARS
|
||||||
|
void extractCode(OutBuffer *buf);
|
||||||
|
#else
|
||||||
|
void extractCode(Outbuffer *buf);
|
||||||
|
#endif
|
||||||
|
void skipTag();
|
||||||
|
void skipString();
|
||||||
|
unsigned char *skipWhite(unsigned char *q);
|
||||||
|
void scanComment();
|
||||||
|
int isCommentStart();
|
||||||
|
void scanCDATA();
|
||||||
|
int isCDATAStart();
|
||||||
|
int charEntity();
|
||||||
|
static int namedEntity(unsigned char *p, int length);
|
||||||
|
};
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2006 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "identifier.h"
|
||||||
|
#include "mars.h"
|
||||||
|
#include "lexer.h"
|
||||||
|
#include "id.h"
|
||||||
|
|
||||||
|
Identifier::Identifier(const char *string, int value)
|
||||||
|
{
|
||||||
|
//printf("Identifier('%s', %d)\n", string, value);
|
||||||
|
this->string = string;
|
||||||
|
this->value = value;
|
||||||
|
this->len = strlen(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_t Identifier::hashCode()
|
||||||
|
{
|
||||||
|
return String::calcHash(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Identifier::equals(Object *o)
|
||||||
|
{
|
||||||
|
return this == o || memcmp(string,o->toChars(),len+1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Identifier::compare(Object *o)
|
||||||
|
{
|
||||||
|
return memcmp(string, o->toChars(), len + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Identifier::toChars()
|
||||||
|
{
|
||||||
|
return (char *)string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Identifier::toHChars2()
|
||||||
|
{
|
||||||
|
const char *p = NULL;
|
||||||
|
|
||||||
|
if (this == Id::ctor) p = "this";
|
||||||
|
else if (this == Id::dtor) p = "~this";
|
||||||
|
else if (this == Id::classInvariant) p = "invariant";
|
||||||
|
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 (memcmp(p, "_staticCtor", 11) == 0)
|
||||||
|
p = "static this";
|
||||||
|
else if (memcmp(p, "_staticDtor", 11) == 0)
|
||||||
|
p = "static ~this";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Identifier::print()
|
||||||
|
{
|
||||||
|
fprintf(stdmsg, "%s",string);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Identifier::dyncast()
|
||||||
|
{
|
||||||
|
return DYNCAST_IDENTIFIER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BUG: these are redundant with Lexer::uniqueId()
|
||||||
|
|
||||||
|
Identifier *Identifier::generateId(const char *prefix)
|
||||||
|
{
|
||||||
|
static size_t i;
|
||||||
|
|
||||||
|
return generateId(prefix, ++i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Identifier *Identifier::generateId(const char *prefix, size_t i)
|
||||||
|
{ OutBuffer buf;
|
||||||
|
|
||||||
|
buf.writestring(prefix);
|
||||||
|
buf.printf("%zu", i);
|
||||||
|
|
||||||
|
char *id = buf.toChars();
|
||||||
|
buf.data = NULL;
|
||||||
|
return Lexer::idPool(id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2006 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_IDENTIFIER_H
|
||||||
|
#define DMD_IDENTIFIER_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
namespace llvm
|
||||||
|
{
|
||||||
|
class Value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Identifier : Object
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
const char *string;
|
||||||
|
unsigned len;
|
||||||
|
|
||||||
|
Identifier(const char *string, int value);
|
||||||
|
int equals(Object *o);
|
||||||
|
hash_t hashCode();
|
||||||
|
int compare(Object *o);
|
||||||
|
void print();
|
||||||
|
char *toChars();
|
||||||
|
char *toHChars();
|
||||||
|
const char *toHChars2();
|
||||||
|
int dyncast();
|
||||||
|
|
||||||
|
static Identifier *generateId(const char *prefix);
|
||||||
|
static Identifier *generateId(const char *prefix, size_t i);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DMD_IDENTIFIER_H */
|
||||||
+435
@@ -0,0 +1,435 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// http://www.dsource.org/projects/dmd/browser/trunk/src/idgen.c
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
// Program to generate string files in d data structures.
|
||||||
|
// Saves much tedious typing, and eliminates typo problems.
|
||||||
|
// Generates:
|
||||||
|
// id.h
|
||||||
|
// id.c
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
struct Msgtable
|
||||||
|
{
|
||||||
|
const char *ident; // name to use in DMD source
|
||||||
|
const char *name; // name in D executable
|
||||||
|
};
|
||||||
|
|
||||||
|
Msgtable msgtable[] =
|
||||||
|
{
|
||||||
|
{ "IUnknown" },
|
||||||
|
{ "Object" },
|
||||||
|
{ "object" },
|
||||||
|
{ "max" },
|
||||||
|
{ "min" },
|
||||||
|
{ "This", "this" },
|
||||||
|
{ "super" },
|
||||||
|
{ "ctor", "__ctor" },
|
||||||
|
{ "dtor", "__dtor" },
|
||||||
|
{ "cpctor", "__cpctor" },
|
||||||
|
{ "_postblit", "__postblit" },
|
||||||
|
{ "classInvariant", "__invariant" },
|
||||||
|
{ "unitTest", "__unitTest" },
|
||||||
|
{ "require", "__require" },
|
||||||
|
{ "ensure", "__ensure" },
|
||||||
|
{ "init" },
|
||||||
|
{ "size" },
|
||||||
|
{ "__sizeof", "sizeof" },
|
||||||
|
{ "__xalignof", "alignof" },
|
||||||
|
{ "mangleof" },
|
||||||
|
{ "stringof" },
|
||||||
|
{ "tupleof" },
|
||||||
|
{ "length" },
|
||||||
|
{ "remove" },
|
||||||
|
{ "ptr" },
|
||||||
|
{ "array" },
|
||||||
|
{ "funcptr" },
|
||||||
|
{ "dollar", "__dollar" },
|
||||||
|
{ "ctfe", "__ctfe" },
|
||||||
|
{ "offset" },
|
||||||
|
{ "offsetof" },
|
||||||
|
{ "ModuleInfo" },
|
||||||
|
{ "ClassInfo" },
|
||||||
|
{ "classinfo" },
|
||||||
|
{ "typeinfo" },
|
||||||
|
{ "outer" },
|
||||||
|
{ "Exception" },
|
||||||
|
{ "AssociativeArray" },
|
||||||
|
{ "Throwable" },
|
||||||
|
{ "Error" },
|
||||||
|
{ "withSym", "__withSym" },
|
||||||
|
{ "result", "__result" },
|
||||||
|
{ "returnLabel", "__returnLabel" },
|
||||||
|
{ "delegate" },
|
||||||
|
{ "line" },
|
||||||
|
{ "empty", "" },
|
||||||
|
{ "p" },
|
||||||
|
{ "q" },
|
||||||
|
{ "coverage", "__coverage" },
|
||||||
|
{ "__vptr" },
|
||||||
|
{ "__monitor" },
|
||||||
|
|
||||||
|
{ "TypeInfo" },
|
||||||
|
{ "TypeInfo_Class" },
|
||||||
|
{ "TypeInfo_Interface" },
|
||||||
|
{ "TypeInfo_Struct" },
|
||||||
|
{ "TypeInfo_Enum" },
|
||||||
|
{ "TypeInfo_Typedef" },
|
||||||
|
{ "TypeInfo_Pointer" },
|
||||||
|
{ "TypeInfo_Vector" },
|
||||||
|
{ "TypeInfo_Array" },
|
||||||
|
{ "TypeInfo_StaticArray" },
|
||||||
|
{ "TypeInfo_AssociativeArray" },
|
||||||
|
{ "TypeInfo_Function" },
|
||||||
|
{ "TypeInfo_Delegate" },
|
||||||
|
{ "TypeInfo_Tuple" },
|
||||||
|
{ "TypeInfo_Const" },
|
||||||
|
{ "TypeInfo_Invariant" },
|
||||||
|
{ "TypeInfo_Shared" },
|
||||||
|
{ "TypeInfo_Wild", "TypeInfo_Inout" },
|
||||||
|
{ "elements" },
|
||||||
|
{ "_arguments_typeinfo" },
|
||||||
|
{ "_arguments" },
|
||||||
|
{ "_argptr" },
|
||||||
|
{ "_match" },
|
||||||
|
{ "destroy" },
|
||||||
|
{ "postblit" },
|
||||||
|
|
||||||
|
{ "LINE", "__LINE__" },
|
||||||
|
{ "FILE", "__FILE__" },
|
||||||
|
{ "DATE", "__DATE__" },
|
||||||
|
{ "TIME", "__TIME__" },
|
||||||
|
{ "TIMESTAMP", "__TIMESTAMP__" },
|
||||||
|
{ "VENDOR", "__VENDOR__" },
|
||||||
|
{ "VERSIONX", "__VERSION__" },
|
||||||
|
{ "EOFX", "__EOF__" },
|
||||||
|
|
||||||
|
{ "nan" },
|
||||||
|
{ "infinity" },
|
||||||
|
{ "dig" },
|
||||||
|
{ "epsilon" },
|
||||||
|
{ "mant_dig" },
|
||||||
|
{ "max_10_exp" },
|
||||||
|
{ "max_exp" },
|
||||||
|
{ "min_10_exp" },
|
||||||
|
{ "min_exp" },
|
||||||
|
{ "min_normal" },
|
||||||
|
{ "re" },
|
||||||
|
{ "im" },
|
||||||
|
|
||||||
|
{ "C" },
|
||||||
|
{ "D" },
|
||||||
|
{ "Windows" },
|
||||||
|
{ "Pascal" },
|
||||||
|
{ "System" },
|
||||||
|
|
||||||
|
{ "exit" },
|
||||||
|
{ "success" },
|
||||||
|
{ "failure" },
|
||||||
|
|
||||||
|
{ "keys" },
|
||||||
|
{ "values" },
|
||||||
|
{ "rehash" },
|
||||||
|
|
||||||
|
{ "sort" },
|
||||||
|
{ "reverse" },
|
||||||
|
{ "dup" },
|
||||||
|
{ "idup" },
|
||||||
|
|
||||||
|
{ "property" },
|
||||||
|
{ "safe" },
|
||||||
|
{ "trusted" },
|
||||||
|
{ "system" },
|
||||||
|
{ "disable" },
|
||||||
|
|
||||||
|
// For inline assembler
|
||||||
|
{ "___out", "out" },
|
||||||
|
{ "___in", "in" },
|
||||||
|
{ "__int", "int" },
|
||||||
|
{ "__dollar", "$" },
|
||||||
|
{ "__LOCAL_SIZE" },
|
||||||
|
|
||||||
|
// For operator overloads
|
||||||
|
{ "uadd", "opPos" },
|
||||||
|
{ "neg", "opNeg" },
|
||||||
|
{ "com", "opCom" },
|
||||||
|
{ "add", "opAdd" },
|
||||||
|
{ "add_r", "opAdd_r" },
|
||||||
|
{ "sub", "opSub" },
|
||||||
|
{ "sub_r", "opSub_r" },
|
||||||
|
{ "mul", "opMul" },
|
||||||
|
{ "mul_r", "opMul_r" },
|
||||||
|
{ "div", "opDiv" },
|
||||||
|
{ "div_r", "opDiv_r" },
|
||||||
|
{ "mod", "opMod" },
|
||||||
|
{ "mod_r", "opMod_r" },
|
||||||
|
{ "eq", "opEquals" },
|
||||||
|
{ "cmp", "opCmp" },
|
||||||
|
{ "iand", "opAnd" },
|
||||||
|
{ "iand_r", "opAnd_r" },
|
||||||
|
{ "ior", "opOr" },
|
||||||
|
{ "ior_r", "opOr_r" },
|
||||||
|
{ "ixor", "opXor" },
|
||||||
|
{ "ixor_r", "opXor_r" },
|
||||||
|
{ "shl", "opShl" },
|
||||||
|
{ "shl_r", "opShl_r" },
|
||||||
|
{ "shr", "opShr" },
|
||||||
|
{ "shr_r", "opShr_r" },
|
||||||
|
{ "ushr", "opUShr" },
|
||||||
|
{ "ushr_r", "opUShr_r" },
|
||||||
|
{ "cat", "opCat" },
|
||||||
|
{ "cat_r", "opCat_r" },
|
||||||
|
{ "assign", "opAssign" },
|
||||||
|
{ "addass", "opAddAssign" },
|
||||||
|
{ "subass", "opSubAssign" },
|
||||||
|
{ "mulass", "opMulAssign" },
|
||||||
|
{ "divass", "opDivAssign" },
|
||||||
|
{ "modass", "opModAssign" },
|
||||||
|
{ "andass", "opAndAssign" },
|
||||||
|
{ "orass", "opOrAssign" },
|
||||||
|
{ "xorass", "opXorAssign" },
|
||||||
|
{ "shlass", "opShlAssign" },
|
||||||
|
{ "shrass", "opShrAssign" },
|
||||||
|
{ "ushrass", "opUShrAssign" },
|
||||||
|
{ "catass", "opCatAssign" },
|
||||||
|
{ "postinc", "opPostInc" },
|
||||||
|
{ "postdec", "opPostDec" },
|
||||||
|
{ "index", "opIndex" },
|
||||||
|
{ "indexass", "opIndexAssign" },
|
||||||
|
{ "slice", "opSlice" },
|
||||||
|
{ "sliceass", "opSliceAssign" },
|
||||||
|
{ "call", "opCall" },
|
||||||
|
{ "cast", "opCast" },
|
||||||
|
{ "match", "opMatch" },
|
||||||
|
{ "next", "opNext" },
|
||||||
|
{ "opIn" },
|
||||||
|
{ "opIn_r" },
|
||||||
|
{ "opStar" },
|
||||||
|
{ "opDot" },
|
||||||
|
{ "opDispatch" },
|
||||||
|
{ "opDollar" },
|
||||||
|
{ "opUnary" },
|
||||||
|
{ "opIndexUnary" },
|
||||||
|
{ "opSliceUnary" },
|
||||||
|
{ "opBinary" },
|
||||||
|
{ "opBinaryRight" },
|
||||||
|
{ "opOpAssign" },
|
||||||
|
{ "opIndexOpAssign" },
|
||||||
|
{ "opSliceOpAssign" },
|
||||||
|
{ "pow", "opPow" },
|
||||||
|
{ "pow_r", "opPow_r" },
|
||||||
|
{ "powass", "opPowAssign" },
|
||||||
|
|
||||||
|
{ "classNew", "new" },
|
||||||
|
{ "classDelete", "delete" },
|
||||||
|
|
||||||
|
// For foreach
|
||||||
|
{ "apply", "opApply" },
|
||||||
|
{ "applyReverse", "opApplyReverse" },
|
||||||
|
|
||||||
|
// Ranges
|
||||||
|
{ "Fempty", "empty" },
|
||||||
|
{ "Ffront", "front" },
|
||||||
|
{ "Fback", "back" },
|
||||||
|
{ "FpopFront", "popFront" },
|
||||||
|
{ "FpopBack", "popBack" },
|
||||||
|
|
||||||
|
{ "adDup", "_adDupT" },
|
||||||
|
{ "adReverse", "_adReverse" },
|
||||||
|
|
||||||
|
// For internal functions
|
||||||
|
{ "aaLen", "_aaLen" },
|
||||||
|
{ "aaKeys", "_aaKeys" },
|
||||||
|
{ "aaValues", "_aaValues" },
|
||||||
|
{ "aaRehash", "_aaRehash" },
|
||||||
|
{ "monitorenter", "_d_monitorenter" },
|
||||||
|
{ "monitorexit", "_d_monitorexit" },
|
||||||
|
{ "criticalenter", "_d_criticalenter" },
|
||||||
|
{ "criticalexit", "_d_criticalexit" },
|
||||||
|
{ "_ArrayEq" },
|
||||||
|
|
||||||
|
// For pragma's
|
||||||
|
{ "GNU_asm" },
|
||||||
|
{ "lib" },
|
||||||
|
{ "msg" },
|
||||||
|
{ "startaddress" },
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
// LDC pragma's
|
||||||
|
{ "intrinsic" },
|
||||||
|
{ "va_intrinsic" },
|
||||||
|
{ "no_typeinfo" },
|
||||||
|
{ "no_moduleinfo" },
|
||||||
|
{ "Alloca", "alloca" },
|
||||||
|
{ "vastart", "va_start" },
|
||||||
|
{ "vacopy", "va_copy" },
|
||||||
|
{ "vaend", "va_end" },
|
||||||
|
{ "vaarg", "va_arg" },
|
||||||
|
{ "ldc" },
|
||||||
|
{ "allow_inline" },
|
||||||
|
{ "llvm_inline_asm" },
|
||||||
|
{ "fence" },
|
||||||
|
{ "atomic_load" },
|
||||||
|
{ "atomic_store" },
|
||||||
|
{ "atomic_cmp_xchg" },
|
||||||
|
{ "atomic_rmw" },
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// For special functions
|
||||||
|
{ "tohash", "toHash" },
|
||||||
|
{ "tostring", "toString" },
|
||||||
|
{ "getmembers", "getMembers" },
|
||||||
|
|
||||||
|
// Special functions
|
||||||
|
#if IN_DMD
|
||||||
|
{ "alloca" },
|
||||||
|
#endif
|
||||||
|
{ "main" },
|
||||||
|
{ "WinMain" },
|
||||||
|
{ "DllMain" },
|
||||||
|
{ "tls_get_addr", "___tls_get_addr" },
|
||||||
|
|
||||||
|
// varargs implementation
|
||||||
|
{ "va_argsave_t", "__va_argsave_t" },
|
||||||
|
{ "va_argsave", "__va_argsave" },
|
||||||
|
|
||||||
|
// Builtin functions
|
||||||
|
{ "std" },
|
||||||
|
{ "core" },
|
||||||
|
{ "math" },
|
||||||
|
{ "sin" },
|
||||||
|
{ "cos" },
|
||||||
|
{ "tan" },
|
||||||
|
{ "_sqrt", "sqrt" },
|
||||||
|
{ "_pow", "pow" },
|
||||||
|
{ "atan2" },
|
||||||
|
{ "rndtol" },
|
||||||
|
{ "expm1" },
|
||||||
|
{ "exp2" },
|
||||||
|
{ "yl2x" },
|
||||||
|
{ "yl2xp1" },
|
||||||
|
{ "fabs" },
|
||||||
|
{ "bitop" },
|
||||||
|
{ "bsf" },
|
||||||
|
{ "bsr" },
|
||||||
|
{ "bswap" },
|
||||||
|
|
||||||
|
// Traits
|
||||||
|
{ "isAbstractClass" },
|
||||||
|
{ "isArithmetic" },
|
||||||
|
{ "isAssociativeArray" },
|
||||||
|
{ "isFinalClass" },
|
||||||
|
{ "isFloating" },
|
||||||
|
{ "isIntegral" },
|
||||||
|
{ "isScalar" },
|
||||||
|
{ "isStaticArray" },
|
||||||
|
{ "isUnsigned" },
|
||||||
|
{ "isVirtualFunction" },
|
||||||
|
{ "isVirtualMethod" },
|
||||||
|
{ "isAbstractFunction" },
|
||||||
|
{ "isFinalFunction" },
|
||||||
|
{ "isStaticFunction" },
|
||||||
|
{ "isRef" },
|
||||||
|
{ "isOut" },
|
||||||
|
{ "isLazy" },
|
||||||
|
{ "hasMember" },
|
||||||
|
{ "identifier" },
|
||||||
|
{ "parent" },
|
||||||
|
{ "getMember" },
|
||||||
|
{ "getOverloads" },
|
||||||
|
{ "getVirtualFunctions" },
|
||||||
|
{ "getVirtualMethods" },
|
||||||
|
{ "classInstanceSize" },
|
||||||
|
{ "allMembers" },
|
||||||
|
{ "derivedMembers" },
|
||||||
|
{ "isSame" },
|
||||||
|
{ "compiles" },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
{
|
||||||
|
fp = fopen("id.h","w");
|
||||||
|
if (!fp)
|
||||||
|
{ printf("can't open id.h\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "// File generated by idgen.c\n");
|
||||||
|
#if __DMC__
|
||||||
|
fprintf(fp, "#pragma once\n");
|
||||||
|
#endif
|
||||||
|
fprintf(fp, "#ifndef DMD_ID_H\n");
|
||||||
|
fprintf(fp, "#define DMD_ID_H 1\n");
|
||||||
|
fprintf(fp, "struct Identifier;\n");
|
||||||
|
fprintf(fp, "struct Id\n");
|
||||||
|
fprintf(fp, "{\n");
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
|
||||||
|
{ const char *id = msgtable[i].ident;
|
||||||
|
|
||||||
|
fprintf(fp," static Identifier *%s;\n", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, " static void initialize();\n");
|
||||||
|
fprintf(fp, "};\n");
|
||||||
|
fprintf(fp, "#endif\n");
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
fp = fopen("id.c","w");
|
||||||
|
if (!fp)
|
||||||
|
{ printf("can't open id.c\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "// File generated by idgen.c\n");
|
||||||
|
fprintf(fp, "#include \"id.h\"\n");
|
||||||
|
fprintf(fp, "#include \"identifier.h\"\n");
|
||||||
|
fprintf(fp, "#include \"lexer.h\"\n");
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
|
||||||
|
{ const char *id = msgtable[i].ident;
|
||||||
|
const char *p = msgtable[i].name;
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
p = id;
|
||||||
|
fprintf(fp,"Identifier *Id::%s;\n", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "void Id::initialize()\n");
|
||||||
|
fprintf(fp, "{\n");
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
|
||||||
|
{ const char *id = msgtable[i].ident;
|
||||||
|
const char *p = msgtable[i].name;
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
p = id;
|
||||||
|
fprintf(fp," %s = Lexer::idPool(\"%s\");\n", id, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "}\n");
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,427 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2006 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "mtype.h"
|
||||||
|
|
||||||
|
TY impcnvResult[TMAX][TMAX];
|
||||||
|
TY impcnvType1[TMAX][TMAX];
|
||||||
|
TY impcnvType2[TMAX][TMAX];
|
||||||
|
int impcnvWarn[TMAX][TMAX];
|
||||||
|
|
||||||
|
int integral_promotion(int t)
|
||||||
|
{
|
||||||
|
switch (t)
|
||||||
|
{
|
||||||
|
case Tchar:
|
||||||
|
case Twchar:
|
||||||
|
case Tbool:
|
||||||
|
case Tint8:
|
||||||
|
case Tuns8:
|
||||||
|
case Tint16:
|
||||||
|
case Tuns16: return Tint32;
|
||||||
|
case Tdchar: return Tuns32;
|
||||||
|
default: return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{ int i, j;
|
||||||
|
|
||||||
|
// Set conversion tables
|
||||||
|
for (i = 0; i < TMAX; i++)
|
||||||
|
for (j = 0; j < TMAX; j++)
|
||||||
|
{ impcnvResult[i][j] = Terror;
|
||||||
|
impcnvType1[i][j] = Terror;
|
||||||
|
impcnvType2[i][j] = Terror;
|
||||||
|
impcnvWarn[i][j] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X(t1,t2, nt1,nt2, rt) \
|
||||||
|
impcnvResult[t1][t2] = rt; \
|
||||||
|
impcnvType1[t1][t2] = nt1; \
|
||||||
|
impcnvType2[t1][t2] = nt2;
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tbool,Tbool, Tbool,Tbool, Tbool)
|
||||||
|
X(Tbool,Tint8, Tint32,Tint32, Tint32)
|
||||||
|
X(Tbool,Tuns8, Tint32,Tint32, Tint32)
|
||||||
|
X(Tbool,Tint16, Tint32,Tint32, Tint32)
|
||||||
|
X(Tbool,Tuns16, Tint32,Tint32, Tint32)
|
||||||
|
X(Tbool,Tint32, Tint32,Tint32, Tint32)
|
||||||
|
X(Tbool,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||||
|
X(Tbool,Tint64, Tint64,Tint64, Tint64)
|
||||||
|
X(Tbool,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||||
|
|
||||||
|
X(Tbool,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||||
|
X(Tbool,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||||
|
X(Tbool,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||||
|
X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
X(Tbool,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Tbool,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tbool,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tint8,Tint8, Tint32,Tint32, Tint32)
|
||||||
|
X(Tint8,Tuns8, Tint32,Tint32, Tint32)
|
||||||
|
X(Tint8,Tint16, Tint32,Tint32, Tint32)
|
||||||
|
X(Tint8,Tuns16, Tint32,Tint32, Tint32)
|
||||||
|
X(Tint8,Tint32, Tint32,Tint32, Tint32)
|
||||||
|
X(Tint8,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||||
|
X(Tint8,Tint64, Tint64,Tint64, Tint64)
|
||||||
|
X(Tint8,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||||
|
|
||||||
|
X(Tint8,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||||
|
X(Tint8,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||||
|
X(Tint8,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||||
|
X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
X(Tint8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Tint8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tint8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tuns8,Tuns8, Tint32,Tint32, Tint32)
|
||||||
|
X(Tuns8,Tint16, Tint32,Tint32, Tint32)
|
||||||
|
X(Tuns8,Tuns16, Tint32,Tint32, Tint32)
|
||||||
|
X(Tuns8,Tint32, Tint32,Tint32, Tint32)
|
||||||
|
X(Tuns8,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||||
|
X(Tuns8,Tint64, Tint64,Tint64, Tint64)
|
||||||
|
X(Tuns8,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||||
|
|
||||||
|
X(Tuns8,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||||
|
X(Tuns8,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||||
|
X(Tuns8,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||||
|
X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
X(Tuns8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Tuns8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tuns8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tint16,Tint16, Tint32,Tint32, Tint32)
|
||||||
|
X(Tint16,Tuns16, Tint32,Tint32, Tint32)
|
||||||
|
X(Tint16,Tint32, Tint32,Tint32, Tint32)
|
||||||
|
X(Tint16,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||||
|
X(Tint16,Tint64, Tint64,Tint64, Tint64)
|
||||||
|
X(Tint16,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||||
|
|
||||||
|
X(Tint16,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||||
|
X(Tint16,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||||
|
X(Tint16,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||||
|
X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
X(Tint16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Tint16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tint16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tuns16,Tuns16, Tint32,Tint32, Tint32)
|
||||||
|
X(Tuns16,Tint32, Tint32,Tint32, Tint32)
|
||||||
|
X(Tuns16,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||||
|
X(Tuns16,Tint64, Tint64,Tint64, Tint64)
|
||||||
|
X(Tuns16,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||||
|
|
||||||
|
X(Tuns16,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||||
|
X(Tuns16,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||||
|
X(Tuns16,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||||
|
X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
X(Tuns16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Tuns16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tuns16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tint32,Tint32, Tint32,Tint32, Tint32)
|
||||||
|
X(Tint32,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||||
|
X(Tint32,Tint64, Tint64,Tint64, Tint64)
|
||||||
|
X(Tint32,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||||
|
|
||||||
|
X(Tint32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||||
|
X(Tint32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||||
|
X(Tint32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||||
|
X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
X(Tint32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Tint32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tint32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tuns32,Tuns32, Tuns32,Tuns32, Tuns32)
|
||||||
|
X(Tuns32,Tint64, Tint64,Tint64, Tint64)
|
||||||
|
X(Tuns32,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||||
|
|
||||||
|
X(Tuns32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||||
|
X(Tuns32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||||
|
X(Tuns32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||||
|
X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
X(Tuns32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Tuns32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tuns32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tint64,Tint64, Tint64,Tint64, Tint64)
|
||||||
|
X(Tint64,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||||
|
|
||||||
|
X(Tint64,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||||
|
X(Tint64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||||
|
X(Tint64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||||
|
X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
X(Tint64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Tint64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tint64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tuns64,Tuns64, Tuns64,Tuns64, Tuns64)
|
||||||
|
|
||||||
|
X(Tuns64,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||||
|
X(Tuns64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||||
|
X(Tuns64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||||
|
X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
X(Tuns64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Tuns64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tuns64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tfloat32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
|
||||||
|
X(Tfloat32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||||
|
X(Tfloat32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
|
||||||
|
X(Tfloat32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
|
||||||
|
X(Tfloat32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tfloat32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
|
||||||
|
X(Tfloat32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Tfloat32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tfloat32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tfloat64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
|
||||||
|
X(Tfloat64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
|
||||||
|
X(Tfloat64,Timaginary32, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tfloat64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
|
||||||
|
X(Tfloat64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
|
||||||
|
X(Tfloat64,Tcomplex32, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tfloat64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tfloat64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tfloat80,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
|
||||||
|
|
||||||
|
X(Tfloat80,Timaginary32, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
X(Tfloat80,Timaginary64, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
X(Tfloat80,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
|
||||||
|
|
||||||
|
X(Tfloat80,Tcomplex32, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
X(Tfloat80,Tcomplex64, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
X(Tfloat80,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Timaginary32,Timaginary32, Timaginary32,Timaginary32, Timaginary32)
|
||||||
|
X(Timaginary32,Timaginary64, Timaginary64,Timaginary64, Timaginary64)
|
||||||
|
X(Timaginary32,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
|
||||||
|
|
||||||
|
X(Timaginary32,Tcomplex32, Timaginary32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Timaginary32,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Timaginary32,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Timaginary64,Timaginary64, Timaginary64,Timaginary64, Timaginary64)
|
||||||
|
X(Timaginary64,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
|
||||||
|
|
||||||
|
X(Timaginary64,Tcomplex32, Timaginary64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Timaginary64,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Timaginary64,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Timaginary80,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
|
||||||
|
|
||||||
|
X(Timaginary80,Tcomplex32, Timaginary80,Tcomplex80, Tcomplex80)
|
||||||
|
X(Timaginary80,Tcomplex64, Timaginary80,Tcomplex80, Tcomplex80)
|
||||||
|
X(Timaginary80,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tcomplex32,Tcomplex32, Tcomplex32,Tcomplex32, Tcomplex32)
|
||||||
|
X(Tcomplex32,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tcomplex32,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tcomplex64,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64)
|
||||||
|
X(Tcomplex64,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
/* ======================= */
|
||||||
|
|
||||||
|
X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
|
||||||
|
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
#define Y(t1,t2) impcnvWarn[t1][t2] = 1;
|
||||||
|
|
||||||
|
Y(Tuns8, Tint8)
|
||||||
|
Y(Tint16, Tint8)
|
||||||
|
Y(Tuns16, Tint8)
|
||||||
|
Y(Tint32, Tint8)
|
||||||
|
Y(Tuns32, Tint8)
|
||||||
|
Y(Tint64, Tint8)
|
||||||
|
Y(Tuns64, Tint8)
|
||||||
|
|
||||||
|
Y(Tint8, Tuns8)
|
||||||
|
Y(Tint16, Tuns8)
|
||||||
|
Y(Tuns16, Tuns8)
|
||||||
|
Y(Tint32, Tuns8)
|
||||||
|
Y(Tuns32, Tuns8)
|
||||||
|
Y(Tint64, Tuns8)
|
||||||
|
Y(Tuns64, Tuns8)
|
||||||
|
|
||||||
|
Y(Tint8, Tchar)
|
||||||
|
Y(Tint16, Tchar)
|
||||||
|
Y(Tuns16, Tchar)
|
||||||
|
Y(Tint32, Tchar)
|
||||||
|
Y(Tuns32, Tchar)
|
||||||
|
Y(Tint64, Tchar)
|
||||||
|
Y(Tuns64, Tchar)
|
||||||
|
|
||||||
|
Y(Tuns16, Tint16)
|
||||||
|
Y(Tint32, Tint16)
|
||||||
|
Y(Tuns32, Tint16)
|
||||||
|
Y(Tint64, Tint16)
|
||||||
|
Y(Tuns64, Tint16)
|
||||||
|
|
||||||
|
Y(Tint16, Tuns16)
|
||||||
|
Y(Tint32, Tuns16)
|
||||||
|
Y(Tuns32, Tuns16)
|
||||||
|
Y(Tint64, Tuns16)
|
||||||
|
Y(Tuns64, Tuns16)
|
||||||
|
|
||||||
|
Y(Tint16, Twchar)
|
||||||
|
Y(Tint32, Twchar)
|
||||||
|
Y(Tuns32, Twchar)
|
||||||
|
Y(Tint64, Twchar)
|
||||||
|
Y(Tuns64, Twchar)
|
||||||
|
|
||||||
|
// Y(Tuns32, Tint32)
|
||||||
|
Y(Tint64, Tint32)
|
||||||
|
Y(Tuns64, Tint32)
|
||||||
|
|
||||||
|
// Y(Tint32, Tuns32)
|
||||||
|
Y(Tint64, Tuns32)
|
||||||
|
Y(Tuns64, Tuns32)
|
||||||
|
|
||||||
|
Y(Tint64, Tdchar)
|
||||||
|
Y(Tuns64, Tdchar)
|
||||||
|
|
||||||
|
// Y(Tint64, Tuns64)
|
||||||
|
// Y(Tuns64, Tint64)
|
||||||
|
|
||||||
|
for (i = 0; i < TMAX; i++)
|
||||||
|
for (j = 0; j < TMAX; j++)
|
||||||
|
{
|
||||||
|
if (impcnvResult[i][j] == Terror)
|
||||||
|
{
|
||||||
|
impcnvResult[i][j] = impcnvResult[j][i];
|
||||||
|
impcnvType1[i][j] = impcnvType2[j][i];
|
||||||
|
impcnvType2[i][j] = impcnvType1[j][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{ FILE *fp;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
fp = fopen("impcnvtab.c","w");
|
||||||
|
|
||||||
|
fprintf(fp,"// This file is generated by impcnvgen.c\n");
|
||||||
|
fprintf(fp,"#include \"mtype.h\"\n");
|
||||||
|
|
||||||
|
fprintf(fp,"unsigned char Type::impcnvResult[TMAX][TMAX] =\n{\n");
|
||||||
|
for (i = 0; i < TMAX; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < TMAX; j++)
|
||||||
|
{
|
||||||
|
fprintf(fp, "%d,",impcnvResult[i][j]);
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
}
|
||||||
|
fprintf(fp,"};\n");
|
||||||
|
|
||||||
|
fprintf(fp,"unsigned char Type::impcnvType1[TMAX][TMAX] =\n{\n");
|
||||||
|
for (i = 0; i < TMAX; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < TMAX; j++)
|
||||||
|
{
|
||||||
|
fprintf(fp, "%d,",impcnvType1[i][j]);
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
}
|
||||||
|
fprintf(fp,"};\n");
|
||||||
|
|
||||||
|
fprintf(fp,"unsigned char Type::impcnvType2[TMAX][TMAX] =\n{\n");
|
||||||
|
for (i = 0; i < TMAX; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < TMAX; j++)
|
||||||
|
{
|
||||||
|
fprintf(fp, "%d,",impcnvType2[i][j]);
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
}
|
||||||
|
fprintf(fp,"};\n");
|
||||||
|
|
||||||
|
fprintf(fp,"unsigned char Type::impcnvWarn[TMAX][TMAX] =\n{\n");
|
||||||
|
for (i = 0; i < TMAX; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < TMAX; j++)
|
||||||
|
{
|
||||||
|
fprintf(fp, "%d,",impcnvWarn[i][j]);
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
}
|
||||||
|
fprintf(fp,"};\n");
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
|
||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 2010 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *importHint(const char *s)
|
||||||
|
{
|
||||||
|
#if DMDV1
|
||||||
|
static const char *modules[] =
|
||||||
|
{ "std.c.stdio",
|
||||||
|
"std.stdio",
|
||||||
|
"std.math",
|
||||||
|
"std.c.stdarg",
|
||||||
|
};
|
||||||
|
static const char *names[] =
|
||||||
|
{
|
||||||
|
"printf", NULL,
|
||||||
|
"writefln", NULL,
|
||||||
|
"sin", "cos", "sqrt", "fabs", NULL,
|
||||||
|
"__va_argsave_t", NULL,
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
static const char *modules[] =
|
||||||
|
{ "core.stdc.stdio",
|
||||||
|
"std.stdio",
|
||||||
|
"std.math",
|
||||||
|
"core.vararg",
|
||||||
|
};
|
||||||
|
static const char *names[] =
|
||||||
|
{
|
||||||
|
"printf", NULL,
|
||||||
|
"writeln", NULL,
|
||||||
|
"sin", "cos", "sqrt", "fabs", NULL,
|
||||||
|
"__va_argsave_t", NULL,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
int m = 0;
|
||||||
|
for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++)
|
||||||
|
{
|
||||||
|
const char *p = names[n];
|
||||||
|
if (p == NULL)
|
||||||
|
{ m++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
assert(m < sizeof(modules)/sizeof(modules[0]));
|
||||||
|
if (strcmp(s, p) == 0)
|
||||||
|
return modules[m];
|
||||||
|
}
|
||||||
|
return NULL; // didn't find it
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITTEST
|
||||||
|
|
||||||
|
void unittest_importHint()
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
p = importHint("printf");
|
||||||
|
assert(p);
|
||||||
|
p = importHint("fabs");
|
||||||
|
assert(p);
|
||||||
|
p = importHint("xxxxx");
|
||||||
|
assert(!p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
+397
@@ -0,0 +1,397 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2009 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "dsymbol.h"
|
||||||
|
#include "import.h"
|
||||||
|
#include "identifier.h"
|
||||||
|
#include "module.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "hdrgen.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "id.h"
|
||||||
|
#include "attrib.h"
|
||||||
|
|
||||||
|
/********************************* Import ****************************/
|
||||||
|
|
||||||
|
Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId,
|
||||||
|
int isstatic)
|
||||||
|
: Dsymbol(NULL)
|
||||||
|
{
|
||||||
|
assert(id);
|
||||||
|
this->loc = loc;
|
||||||
|
this->packages = packages;
|
||||||
|
this->id = id;
|
||||||
|
this->aliasId = aliasId;
|
||||||
|
this->isstatic = isstatic;
|
||||||
|
this->protection = PROTprivate; // default to private
|
||||||
|
this->pkg = NULL;
|
||||||
|
this->mod = NULL;
|
||||||
|
|
||||||
|
// Set symbol name (bracketed)
|
||||||
|
// import [cstdio] = std.stdio;
|
||||||
|
if (aliasId)
|
||||||
|
this->ident = aliasId;
|
||||||
|
// import [std].stdio;
|
||||||
|
else if (packages && packages->dim)
|
||||||
|
this->ident = packages->tdata()[0];
|
||||||
|
// import [foo];
|
||||||
|
else
|
||||||
|
this->ident = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Import::addAlias(Identifier *name, Identifier *alias)
|
||||||
|
{
|
||||||
|
if (isstatic)
|
||||||
|
error("cannot have an import bind list");
|
||||||
|
|
||||||
|
if (!aliasId)
|
||||||
|
this->ident = NULL; // make it an anonymous import
|
||||||
|
|
||||||
|
names.push(name);
|
||||||
|
aliases.push(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Import::kind()
|
||||||
|
{
|
||||||
|
return isstatic ? (char *)"static import" : (char *)"import";
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PROT Import::prot()
|
||||||
|
{
|
||||||
|
return protection;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dsymbol *Import::syntaxCopy(Dsymbol *s)
|
||||||
|
{
|
||||||
|
assert(!s);
|
||||||
|
|
||||||
|
Import *si;
|
||||||
|
|
||||||
|
si = new Import(loc, packages, id, aliasId, isstatic);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < names.dim; i++)
|
||||||
|
{
|
||||||
|
si->addAlias(names.tdata()[i], aliases.tdata()[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Import::load(Scope *sc)
|
||||||
|
{
|
||||||
|
//printf("Import::load('%s')\n", toChars());
|
||||||
|
|
||||||
|
// See if existing module
|
||||||
|
DsymbolTable *dst = Package::resolve(packages, NULL, &pkg);
|
||||||
|
|
||||||
|
Dsymbol *s = dst->lookup(id);
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
#if TARGET_NET
|
||||||
|
mod = (Module *)s;
|
||||||
|
#else
|
||||||
|
if (s->isModule())
|
||||||
|
mod = (Module *)s;
|
||||||
|
else
|
||||||
|
error("package and module have the same name");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mod)
|
||||||
|
{
|
||||||
|
// Load module
|
||||||
|
mod = Module::load(loc, packages, id);
|
||||||
|
dst->insert(id, mod); // id may be different from mod->ident,
|
||||||
|
// if so then insert alias
|
||||||
|
if (!mod->importedFrom)
|
||||||
|
mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule;
|
||||||
|
}
|
||||||
|
if (!pkg)
|
||||||
|
pkg = mod;
|
||||||
|
|
||||||
|
//printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void escapePath(OutBuffer *buf, const char *fname)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
switch (*fname)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return;
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case '\\':
|
||||||
|
buf->writebyte('\\');
|
||||||
|
default:
|
||||||
|
buf->writebyte(*fname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fname++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Import::importAll(Scope *sc)
|
||||||
|
{
|
||||||
|
if (!mod)
|
||||||
|
{
|
||||||
|
load(sc);
|
||||||
|
mod->importAll(0);
|
||||||
|
|
||||||
|
if (!isstatic && !aliasId && !names.dim)
|
||||||
|
{
|
||||||
|
if (sc->explicitProtection)
|
||||||
|
protection = sc->protection;
|
||||||
|
sc->scopesym->importScope(mod, protection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Import::semantic(Scope *sc)
|
||||||
|
{
|
||||||
|
//printf("Import::semantic('%s')\n", toChars());
|
||||||
|
|
||||||
|
// Load if not already done so
|
||||||
|
if (!mod)
|
||||||
|
{ load(sc);
|
||||||
|
mod->importAll(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if (mod->loc.linnum != 0)
|
||||||
|
{ /* If the line number is not 0, then this is not
|
||||||
|
* a 'root' module, i.e. it was not specified on the command line.
|
||||||
|
*/
|
||||||
|
mod->importedFrom = sc->module->importedFrom;
|
||||||
|
assert(mod->importedFrom);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Modules need a list of each imported module
|
||||||
|
//printf("%s imports %s\n", sc->module->toChars(), mod->toChars());
|
||||||
|
sc->module->aimports.push(mod);
|
||||||
|
|
||||||
|
if (!isstatic && !aliasId && !names.dim)
|
||||||
|
{
|
||||||
|
if (sc->explicitProtection)
|
||||||
|
protection = sc->protection;
|
||||||
|
for (Scope *scd = sc; scd; scd = scd->enclosing)
|
||||||
|
{
|
||||||
|
if (scd->scopesym)
|
||||||
|
{
|
||||||
|
scd->scopesym->importScope(mod, protection);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod->semantic();
|
||||||
|
|
||||||
|
if (mod->needmoduleinfo)
|
||||||
|
{ //printf("module4 %s because of %s\n", sc->module->toChars(), mod->toChars());
|
||||||
|
sc->module->needmoduleinfo = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc = sc->push(mod);
|
||||||
|
/* BUG: Protection checks can't be enabled yet. The issue is
|
||||||
|
* that Dsymbol::search errors before overload resolution.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
sc->protection = protection;
|
||||||
|
#else
|
||||||
|
sc->protection = PROTpublic;
|
||||||
|
#endif
|
||||||
|
for (size_t i = 0; i < aliasdecls.dim; i++)
|
||||||
|
{ Dsymbol *s = aliasdecls.tdata()[i];
|
||||||
|
|
||||||
|
//printf("\tImport alias semantic('%s')\n", s->toChars());
|
||||||
|
if (!mod->search(loc, names.tdata()[i], 0))
|
||||||
|
error("%s not found", (names.tdata()[i])->toChars());
|
||||||
|
|
||||||
|
s->semantic(sc);
|
||||||
|
}
|
||||||
|
sc = sc->pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global.params.moduleDeps != NULL)
|
||||||
|
{
|
||||||
|
/* The grammar of the file is:
|
||||||
|
* ImportDeclaration
|
||||||
|
* ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
|
||||||
|
* ModuleAliasIdentifier ] "\n"
|
||||||
|
*
|
||||||
|
* BasicImportDeclaration
|
||||||
|
* ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection
|
||||||
|
* " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
|
||||||
|
*
|
||||||
|
* FilePath
|
||||||
|
* - any string with '(', ')' and '\' escaped with the '\' character
|
||||||
|
*/
|
||||||
|
|
||||||
|
OutBuffer *ob = global.params.moduleDeps;
|
||||||
|
|
||||||
|
ob->writestring(sc->module->toPrettyChars());
|
||||||
|
ob->writestring(" (");
|
||||||
|
escapePath(ob, sc->module->srcfile->toChars());
|
||||||
|
ob->writestring(") : ");
|
||||||
|
|
||||||
|
ProtDeclaration::protectionToCBuffer(ob, sc->protection);
|
||||||
|
if (isstatic)
|
||||||
|
StorageClassDeclaration::stcToCBuffer(ob, STCstatic);
|
||||||
|
ob->writestring(": ");
|
||||||
|
|
||||||
|
if (packages)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < packages->dim; i++)
|
||||||
|
{
|
||||||
|
Identifier *pid = packages->tdata()[i];
|
||||||
|
ob->printf("%s.", pid->toChars());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ob->writestring(id->toChars());
|
||||||
|
ob->writestring(" (");
|
||||||
|
if (mod)
|
||||||
|
escapePath(ob, mod->srcfile->toChars());
|
||||||
|
else
|
||||||
|
ob->writestring("???");
|
||||||
|
ob->writebyte(')');
|
||||||
|
|
||||||
|
for (size_t i = 0; i < names.dim; i++)
|
||||||
|
{
|
||||||
|
if (i == 0)
|
||||||
|
ob->writebyte(':');
|
||||||
|
else
|
||||||
|
ob->writebyte(',');
|
||||||
|
|
||||||
|
Identifier *name = names.tdata()[i];
|
||||||
|
Identifier *alias = aliases.tdata()[i];
|
||||||
|
|
||||||
|
if (!alias)
|
||||||
|
{
|
||||||
|
ob->printf("%s", name->toChars());
|
||||||
|
alias = name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ob->printf("%s=%s", alias->toChars(), name->toChars());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aliasId)
|
||||||
|
ob->printf(" -> %s", aliasId->toChars());
|
||||||
|
|
||||||
|
ob->writenl();
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Import::semantic2(Scope *sc)
|
||||||
|
{
|
||||||
|
//printf("Import::semantic2('%s')\n", toChars());
|
||||||
|
mod->semantic2();
|
||||||
|
if (mod->needmoduleinfo)
|
||||||
|
{ //printf("module5 %s because of %s\n", sc->module->toChars(), mod->toChars());
|
||||||
|
sc->module->needmoduleinfo = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dsymbol *Import::toAlias()
|
||||||
|
{
|
||||||
|
if (aliasId)
|
||||||
|
return mod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
* Add import to sd's symbol table.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int Import::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (names.dim == 0)
|
||||||
|
return Dsymbol::addMember(sc, sd, memnum);
|
||||||
|
|
||||||
|
if (aliasId)
|
||||||
|
result = Dsymbol::addMember(sc, sd, memnum);
|
||||||
|
|
||||||
|
/* Instead of adding the import to sd's symbol table,
|
||||||
|
* add each of the alias=name pairs
|
||||||
|
*/
|
||||||
|
for (size_t i = 0; i < names.dim; i++)
|
||||||
|
{
|
||||||
|
Identifier *name = names.tdata()[i];
|
||||||
|
Identifier *alias = aliases.tdata()[i];
|
||||||
|
|
||||||
|
if (!alias)
|
||||||
|
alias = name;
|
||||||
|
|
||||||
|
TypeIdentifier *tname = new TypeIdentifier(loc, name);
|
||||||
|
AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname);
|
||||||
|
result |= ad->addMember(sc, sd, memnum);
|
||||||
|
|
||||||
|
aliasdecls.push(ad);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dsymbol *Import::search(Loc loc, Identifier *ident, int flags)
|
||||||
|
{
|
||||||
|
//printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
|
||||||
|
|
||||||
|
if (!pkg)
|
||||||
|
{ load(NULL);
|
||||||
|
mod->semantic();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward it to the package/module
|
||||||
|
return pkg->search(loc, ident, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Import::overloadInsert(Dsymbol *s)
|
||||||
|
{
|
||||||
|
// Allow multiple imports of the same name
|
||||||
|
return s->isImport() != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
if (hgs->hdrgen && id == Id::object)
|
||||||
|
return; // object is imported by default
|
||||||
|
|
||||||
|
if (isstatic)
|
||||||
|
buf->writestring("static ");
|
||||||
|
buf->writestring("import ");
|
||||||
|
if (aliasId)
|
||||||
|
{
|
||||||
|
buf->printf("%s = ", aliasId->toChars());
|
||||||
|
}
|
||||||
|
if (packages && packages->dim)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < packages->dim; i++)
|
||||||
|
{ Identifier *pid = packages->tdata()[i];
|
||||||
|
|
||||||
|
buf->printf("%s.", pid->toChars());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf->printf("%s;", id->toChars());
|
||||||
|
buf->writenl();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2007 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_IMPORT_H
|
||||||
|
#define DMD_IMPORT_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include "dsymbol.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct Identifier;
|
||||||
|
struct Scope;
|
||||||
|
struct OutBuffer;
|
||||||
|
struct Module;
|
||||||
|
struct Package;
|
||||||
|
struct AliasDeclaration;
|
||||||
|
struct HdrGenState;
|
||||||
|
|
||||||
|
struct Import : Dsymbol
|
||||||
|
{
|
||||||
|
Identifiers *packages; // array of Identifier's representing packages
|
||||||
|
Identifier *id; // module Identifier
|
||||||
|
Identifier *aliasId;
|
||||||
|
int isstatic; // !=0 if static import
|
||||||
|
enum PROT protection;
|
||||||
|
|
||||||
|
// Pairs of alias=name to bind into current namespace
|
||||||
|
Identifiers names;
|
||||||
|
Identifiers aliases;
|
||||||
|
|
||||||
|
AliasDeclarations aliasdecls; // AliasDeclarations for names/aliases
|
||||||
|
|
||||||
|
Module *mod;
|
||||||
|
Package *pkg; // leftmost package/module
|
||||||
|
|
||||||
|
Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId,
|
||||||
|
int isstatic);
|
||||||
|
void addAlias(Identifier *name, Identifier *alias);
|
||||||
|
|
||||||
|
const char *kind();
|
||||||
|
enum PROT prot();
|
||||||
|
Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
|
||||||
|
void load(Scope *sc);
|
||||||
|
void importAll(Scope *sc);
|
||||||
|
void semantic(Scope *sc);
|
||||||
|
void semantic2(Scope *sc);
|
||||||
|
Dsymbol *toAlias();
|
||||||
|
int addMember(Scope *sc, ScopeDsymbol *s, int memnum);
|
||||||
|
Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||||
|
int overloadInsert(Dsymbol *s);
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
|
||||||
|
Import *isImport() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DMD_IMPORT_H */
|
||||||
+328
@@ -0,0 +1,328 @@
|
|||||||
|
/*
|
||||||
|
* Some portions copyright (c) 1994-1995 by Symantec
|
||||||
|
* Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
* All Rights Reserved
|
||||||
|
* http://www.digitalmars.com
|
||||||
|
* Written by Walter Bright
|
||||||
|
*
|
||||||
|
* This source file is made available for personal use
|
||||||
|
* only. The license is in /dmd/src/dmd/backendlicense.txt
|
||||||
|
* For any other uses, please contact Digital Mars.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __APPLE__
|
||||||
|
#include <sys/syslimits.h>
|
||||||
|
#endif
|
||||||
|
#if __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||||
|
// for PATH_MAX
|
||||||
|
#include <limits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __sun&&__SVR4
|
||||||
|
#include <alloca.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "rmem.h"
|
||||||
|
|
||||||
|
#define LOG 0
|
||||||
|
|
||||||
|
char *skipspace(const char *p);
|
||||||
|
|
||||||
|
#if __GNUC__
|
||||||
|
char *strupr(char *s)
|
||||||
|
{
|
||||||
|
char *t = s;
|
||||||
|
|
||||||
|
while (*s)
|
||||||
|
{
|
||||||
|
*s = toupper(*s);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
#endif /* unix */
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
* Read and analyze .ini file.
|
||||||
|
* Input:
|
||||||
|
* argv0 program name (argv[0])
|
||||||
|
* inifile .ini file name
|
||||||
|
* Returns:
|
||||||
|
* file name of ini file
|
||||||
|
* Note: this is a memory leak
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *inifile(const char *argv0x, const char *inifilex)
|
||||||
|
{
|
||||||
|
char *argv0 = (char *)argv0x;
|
||||||
|
char *inifile = (char *)inifilex; // do const-correct later
|
||||||
|
char *path; // need path for @P macro
|
||||||
|
char *filename;
|
||||||
|
OutBuffer buf;
|
||||||
|
int envsection = 0;
|
||||||
|
|
||||||
|
#if LOG
|
||||||
|
printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile);
|
||||||
|
#endif
|
||||||
|
if (FileName::absolute(inifile))
|
||||||
|
{
|
||||||
|
filename = inifile;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Look for inifile in the following sequence of places:
|
||||||
|
* o current directory
|
||||||
|
* o home directory
|
||||||
|
* o directory off of argv0
|
||||||
|
* o /etc/
|
||||||
|
*/
|
||||||
|
if (FileName::exists(inifile))
|
||||||
|
{
|
||||||
|
filename = inifile;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filename = FileName::combine(getenv("HOME"), inifile);
|
||||||
|
if (!FileName::exists(filename))
|
||||||
|
{
|
||||||
|
#if _WIN32 // This fix by Tim Matthews
|
||||||
|
char resolved_name[MAX_PATH + 1];
|
||||||
|
if(GetModuleFileName(NULL, resolved_name, MAX_PATH + 1) && FileName::exists(resolved_name))
|
||||||
|
{
|
||||||
|
filename = (char *)FileName::replaceName(resolved_name, inifile);
|
||||||
|
if(FileName::exists(filename))
|
||||||
|
goto Ldone;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
filename = (char *)FileName::replaceName(argv0, inifile);
|
||||||
|
if (!FileName::exists(filename))
|
||||||
|
{
|
||||||
|
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||||
|
#if __GLIBC__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 // This fix by Thomas Kuehne
|
||||||
|
/* argv0 might be a symbolic link,
|
||||||
|
* so try again looking past it to the real path
|
||||||
|
*/
|
||||||
|
#if __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||||
|
char resolved_name[PATH_MAX + 1];
|
||||||
|
char* real_argv0 = realpath(argv0, resolved_name);
|
||||||
|
#else
|
||||||
|
char* real_argv0 = realpath(argv0, NULL);
|
||||||
|
#endif
|
||||||
|
//printf("argv0 = %s, real_argv0 = %p\n", argv0, real_argv0);
|
||||||
|
if (real_argv0)
|
||||||
|
{
|
||||||
|
filename = (char *)FileName::replaceName(real_argv0, inifile);
|
||||||
|
#if !(__APPLE__ || __FreeBSD__ || __sun&&__SVR4)
|
||||||
|
free(real_argv0);
|
||||||
|
#endif
|
||||||
|
if (FileName::exists(filename))
|
||||||
|
goto Ldone;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error use of glibc non-standard extension realpath(char*, NULL)
|
||||||
|
#endif
|
||||||
|
if (1){
|
||||||
|
// Search PATH for argv0
|
||||||
|
const char *p = getenv("PATH");
|
||||||
|
Strings *paths = FileName::splitPath(p);
|
||||||
|
filename = FileName::searchPath(paths, argv0, 0);
|
||||||
|
if (!filename)
|
||||||
|
goto Letc; // argv0 not found on path
|
||||||
|
filename = (char *)FileName::replaceName(filename, inifile);
|
||||||
|
if (FileName::exists(filename))
|
||||||
|
goto Ldone;
|
||||||
|
}
|
||||||
|
// Search /etc/ for inifile
|
||||||
|
Letc:
|
||||||
|
#endif
|
||||||
|
filename = FileName::combine((char *)"/etc/", inifile);
|
||||||
|
|
||||||
|
Ldone:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path = FileName::path(filename);
|
||||||
|
#if LOG
|
||||||
|
printf("\tpath = '%s', filename = '%s'\n", path, filename);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
File file(filename);
|
||||||
|
|
||||||
|
if (file.read())
|
||||||
|
return filename; // error reading file
|
||||||
|
|
||||||
|
// Parse into lines
|
||||||
|
int eof = 0;
|
||||||
|
for (size_t i = 0; i < file.len && !eof; i++)
|
||||||
|
{
|
||||||
|
size_t linestart = i;
|
||||||
|
|
||||||
|
for (; i < file.len; i++)
|
||||||
|
{
|
||||||
|
switch (file.buffer[i])
|
||||||
|
{
|
||||||
|
case '\r':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
// Skip if it was preceded by '\r'
|
||||||
|
if (i && file.buffer[i - 1] == '\r')
|
||||||
|
goto Lskip;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
case 0x1A:
|
||||||
|
eof = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The line is file.buffer[linestart..i]
|
||||||
|
char *line;
|
||||||
|
size_t len;
|
||||||
|
char *p;
|
||||||
|
char *pn;
|
||||||
|
|
||||||
|
line = (char *)&file.buffer[linestart];
|
||||||
|
len = i - linestart;
|
||||||
|
|
||||||
|
buf.reset();
|
||||||
|
|
||||||
|
// First, expand the macros.
|
||||||
|
// Macros are bracketed by % characters.
|
||||||
|
|
||||||
|
for (size_t k = 0; k < len; k++)
|
||||||
|
{
|
||||||
|
if (line[k] == '%')
|
||||||
|
{
|
||||||
|
for (size_t j = k + 1; j < len; j++)
|
||||||
|
{
|
||||||
|
if (line[j] == '%')
|
||||||
|
{
|
||||||
|
if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0)
|
||||||
|
{
|
||||||
|
// %@P% is special meaning the path to the .ini file
|
||||||
|
p = path;
|
||||||
|
if (!*p)
|
||||||
|
p = (char *)".";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ size_t len2 = j - k;
|
||||||
|
char tmp[10]; // big enough most of the time
|
||||||
|
|
||||||
|
if (len2 <= sizeof(tmp))
|
||||||
|
p = tmp;
|
||||||
|
else
|
||||||
|
p = (char *)alloca(len2);
|
||||||
|
len2--;
|
||||||
|
memcpy(p, &line[k + 1], len2);
|
||||||
|
p[len2] = 0;
|
||||||
|
strupr(p);
|
||||||
|
p = getenv(p);
|
||||||
|
if (!p)
|
||||||
|
p = (char *)"";
|
||||||
|
}
|
||||||
|
buf.writestring(p);
|
||||||
|
k = j;
|
||||||
|
goto L1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.writeByte(line[k]);
|
||||||
|
L1:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing spaces
|
||||||
|
while (buf.offset && isspace(buf.data[buf.offset - 1]))
|
||||||
|
buf.offset--;
|
||||||
|
|
||||||
|
p = buf.toChars();
|
||||||
|
|
||||||
|
// The expanded line is in p.
|
||||||
|
// Now parse it for meaning.
|
||||||
|
|
||||||
|
p = skipspace(p);
|
||||||
|
switch (*p)
|
||||||
|
{
|
||||||
|
case ';': // comment
|
||||||
|
case 0: // blank
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '[': // look for [Environment]
|
||||||
|
p = skipspace(p + 1);
|
||||||
|
for (pn = p; isalnum((unsigned char)*pn); pn++)
|
||||||
|
;
|
||||||
|
if (pn - p == 11 &&
|
||||||
|
memicmp(p, "Environment", 11) == 0 &&
|
||||||
|
*skipspace(pn) == ']'
|
||||||
|
)
|
||||||
|
envsection = 1;
|
||||||
|
else
|
||||||
|
envsection = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (envsection)
|
||||||
|
{
|
||||||
|
pn = p;
|
||||||
|
|
||||||
|
// Convert name to upper case;
|
||||||
|
// remove spaces bracketing =
|
||||||
|
for (p = pn; *p; p++)
|
||||||
|
{ if (islower((unsigned char)*p))
|
||||||
|
*p &= ~0x20;
|
||||||
|
else if (isspace((unsigned char)*p))
|
||||||
|
memmove(p, p + 1, strlen(p));
|
||||||
|
else if (*p == '=')
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
while (isspace((unsigned char)*p))
|
||||||
|
memmove(p, p + 1, strlen(p));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
putenv(strdup(pn));
|
||||||
|
#if LOG
|
||||||
|
printf("\tputenv('%s')\n", pn);
|
||||||
|
//printf("getenv(\"TEST\") = '%s'\n",getenv("TEST"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lskip:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************
|
||||||
|
* Skip spaces.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char *skipspace(const char *p)
|
||||||
|
{
|
||||||
|
while (isspace((unsigned char)*p))
|
||||||
|
p++;
|
||||||
|
return (char *)p;
|
||||||
|
}
|
||||||
|
|
||||||
+911
@@ -0,0 +1,911 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "expression.h"
|
||||||
|
#include "statement.h"
|
||||||
|
#include "identifier.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "hdrgen.h"
|
||||||
|
|
||||||
|
/********************************** Initializer *******************************/
|
||||||
|
|
||||||
|
Initializer::Initializer(Loc loc)
|
||||||
|
{
|
||||||
|
this->loc = loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Initializer *Initializer::syntaxCopy()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Initializer *Initializer::semantic(Scope *sc, Type *t, int needInterpret)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *Initializer::inferType(Scope *sc)
|
||||||
|
{
|
||||||
|
error(loc, "cannot infer type from initializer");
|
||||||
|
return Type::terror;
|
||||||
|
}
|
||||||
|
|
||||||
|
Initializers *Initializer::arraySyntaxCopy(Initializers *ai)
|
||||||
|
{ Initializers *a = NULL;
|
||||||
|
|
||||||
|
if (ai)
|
||||||
|
{
|
||||||
|
a = new Initializers();
|
||||||
|
a->setDim(ai->dim);
|
||||||
|
for (size_t i = 0; i < a->dim; i++)
|
||||||
|
{ Initializer *e = ai->tdata()[i];
|
||||||
|
|
||||||
|
e = e->syntaxCopy();
|
||||||
|
a->tdata()[i] = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Initializer::toChars()
|
||||||
|
{ OutBuffer *buf;
|
||||||
|
HdrGenState hgs;
|
||||||
|
|
||||||
|
memset(&hgs, 0, sizeof(hgs));
|
||||||
|
buf = new OutBuffer();
|
||||||
|
toCBuffer(buf, &hgs);
|
||||||
|
return buf->toChars();
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************** VoidInitializer ***************************/
|
||||||
|
|
||||||
|
VoidInitializer::VoidInitializer(Loc loc)
|
||||||
|
: Initializer(loc)
|
||||||
|
{
|
||||||
|
type = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Initializer *VoidInitializer::syntaxCopy()
|
||||||
|
{
|
||||||
|
return new VoidInitializer(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Initializer *VoidInitializer::semantic(Scope *sc, Type *t, int needInterpret)
|
||||||
|
{
|
||||||
|
//printf("VoidInitializer::semantic(t = %p)\n", t);
|
||||||
|
type = t;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Expression *VoidInitializer::toExpression()
|
||||||
|
{
|
||||||
|
error(loc, "void initializer has no value");
|
||||||
|
return new IntegerExp(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VoidInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
buf->writestring("void");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************** StructInitializer *************************/
|
||||||
|
|
||||||
|
StructInitializer::StructInitializer(Loc loc)
|
||||||
|
: Initializer(loc)
|
||||||
|
{
|
||||||
|
ad = NULL;
|
||||||
|
#if IN_LLVM
|
||||||
|
ltype = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Initializer *StructInitializer::syntaxCopy()
|
||||||
|
{
|
||||||
|
StructInitializer *ai = new StructInitializer(loc);
|
||||||
|
|
||||||
|
assert(field.dim == value.dim);
|
||||||
|
ai->field.setDim(field.dim);
|
||||||
|
ai->value.setDim(value.dim);
|
||||||
|
for (size_t i = 0; i < field.dim; i++)
|
||||||
|
{
|
||||||
|
ai->field.tdata()[i] = field.tdata()[i];
|
||||||
|
|
||||||
|
Initializer *init = value.tdata()[i];
|
||||||
|
init = init->syntaxCopy();
|
||||||
|
ai->value.tdata()[i] = init;
|
||||||
|
}
|
||||||
|
return ai;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructInitializer::addInit(Identifier *field, Initializer *value)
|
||||||
|
{
|
||||||
|
//printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
|
||||||
|
this->field.push(field);
|
||||||
|
this->value.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
//printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars());
|
||||||
|
vars.setDim(field.dim);
|
||||||
|
t = t->toBasetype();
|
||||||
|
if (t->ty == Tstruct)
|
||||||
|
{
|
||||||
|
unsigned fieldi = 0;
|
||||||
|
|
||||||
|
TypeStruct *ts = (TypeStruct *)t;
|
||||||
|
ad = ts->sym;
|
||||||
|
if (ad->ctor)
|
||||||
|
error(loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead",
|
||||||
|
ad->kind(), ad->toChars(), ad->toChars());
|
||||||
|
size_t nfields = ad->fields.dim;
|
||||||
|
if (((StructDeclaration *)ad)->isnested) nfields--;
|
||||||
|
for (size_t i = 0; i < field.dim; i++)
|
||||||
|
{
|
||||||
|
Identifier *id = field.tdata()[i];
|
||||||
|
Initializer *val = value.tdata()[i];
|
||||||
|
Dsymbol *s;
|
||||||
|
VarDeclaration *v;
|
||||||
|
|
||||||
|
if (id == NULL)
|
||||||
|
{
|
||||||
|
if (fieldi >= nfields)
|
||||||
|
{ error(loc, "too many initializers for %s", ad->toChars());
|
||||||
|
errors = 1;
|
||||||
|
field.remove(i);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s = ad->fields.tdata()[fieldi];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//s = ad->symtab->lookup(id);
|
||||||
|
s = ad->search(loc, id, 0);
|
||||||
|
if (!s)
|
||||||
|
{
|
||||||
|
error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars());
|
||||||
|
errors = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
s = s->toAlias();
|
||||||
|
|
||||||
|
// Find out which field index it is
|
||||||
|
for (fieldi = 0; 1; fieldi++)
|
||||||
|
{
|
||||||
|
if (fieldi >= nfields)
|
||||||
|
{
|
||||||
|
error(loc, "%s.%s is not a per-instance initializable field",
|
||||||
|
t->toChars(), s->toChars());
|
||||||
|
errors = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (s == ad->fields.tdata()[fieldi])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s && (v = s->isVarDeclaration()) != NULL)
|
||||||
|
{
|
||||||
|
val = val->semantic(sc, v->type, needInterpret);
|
||||||
|
value.tdata()[i] = val;
|
||||||
|
vars.tdata()[i] = v;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars());
|
||||||
|
errors = 1;
|
||||||
|
}
|
||||||
|
fieldi++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (t->ty == Tdelegate && value.dim == 0)
|
||||||
|
{ /* Rewrite as empty delegate literal { }
|
||||||
|
*/
|
||||||
|
Parameters *arguments = new Parameters;
|
||||||
|
Type *tf = new TypeFunction(arguments, NULL, 0, LINKd);
|
||||||
|
FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL);
|
||||||
|
fd->fbody = new CompoundStatement(loc, new Statements());
|
||||||
|
fd->endloc = loc;
|
||||||
|
Expression *e = new FuncExp(loc, fd);
|
||||||
|
ExpInitializer *ie = new ExpInitializer(loc, e);
|
||||||
|
return ie->semantic(sc, t, needInterpret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error(loc, "a struct is not a valid initializer for a %s", t->toChars());
|
||||||
|
errors = 1;
|
||||||
|
}
|
||||||
|
if (errors)
|
||||||
|
{
|
||||||
|
field.setDim(0);
|
||||||
|
value.setDim(0);
|
||||||
|
vars.setDim(0);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************
|
||||||
|
* This works by transforming a struct initializer into
|
||||||
|
* a struct literal. In the future, the two should be the
|
||||||
|
* same thing.
|
||||||
|
*/
|
||||||
|
Expression *StructInitializer::toExpression()
|
||||||
|
{ Expression *e;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
//printf("StructInitializer::toExpression() %s\n", toChars());
|
||||||
|
if (!ad) // if fwd referenced
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
StructDeclaration *sd = ad->isStructDeclaration();
|
||||||
|
if (!sd)
|
||||||
|
return NULL;
|
||||||
|
Expressions *elements = new Expressions();
|
||||||
|
size_t nfields = ad->fields.dim;
|
||||||
|
#if DMDV2
|
||||||
|
if (sd->isnested)
|
||||||
|
nfields--;
|
||||||
|
#endif
|
||||||
|
elements->setDim(nfields);
|
||||||
|
for (size_t i = 0; i < elements->dim; i++)
|
||||||
|
{
|
||||||
|
elements->tdata()[i] = NULL;
|
||||||
|
}
|
||||||
|
unsigned fieldi = 0;
|
||||||
|
for (size_t i = 0; i < value.dim; i++)
|
||||||
|
{
|
||||||
|
Identifier *id = field.tdata()[i];
|
||||||
|
if (id)
|
||||||
|
{
|
||||||
|
Dsymbol * s = ad->search(loc, id, 0);
|
||||||
|
if (!s)
|
||||||
|
{
|
||||||
|
error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars());
|
||||||
|
goto Lno;
|
||||||
|
}
|
||||||
|
s = s->toAlias();
|
||||||
|
|
||||||
|
// Find out which field index it is
|
||||||
|
for (fieldi = 0; 1; fieldi++)
|
||||||
|
{
|
||||||
|
if (fieldi >= nfields)
|
||||||
|
{
|
||||||
|
s->error("is not a per-instance initializable field");
|
||||||
|
goto Lno;
|
||||||
|
}
|
||||||
|
if (s == ad->fields.tdata()[fieldi])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fieldi >= nfields)
|
||||||
|
{ error(loc, "too many initializers for '%s'", ad->toChars());
|
||||||
|
goto Lno;
|
||||||
|
}
|
||||||
|
Initializer *iz = value.tdata()[i];
|
||||||
|
if (!iz)
|
||||||
|
goto Lno;
|
||||||
|
Expression *ex = iz->toExpression();
|
||||||
|
if (!ex)
|
||||||
|
goto Lno;
|
||||||
|
if (elements->tdata()[fieldi])
|
||||||
|
{ error(loc, "duplicate initializer for field '%s'",
|
||||||
|
ad->fields.tdata()[fieldi]->toChars());
|
||||||
|
goto Lno;
|
||||||
|
}
|
||||||
|
elements->tdata()[fieldi] = ex;
|
||||||
|
++fieldi;
|
||||||
|
}
|
||||||
|
// Now, fill in any missing elements with default initializers.
|
||||||
|
// We also need to validate any anonymous unions
|
||||||
|
offset = 0;
|
||||||
|
for (size_t i = 0; i < elements->dim; )
|
||||||
|
{
|
||||||
|
VarDeclaration * vd = ad->fields.tdata()[i]->isVarDeclaration();
|
||||||
|
|
||||||
|
//printf("test2 [%d] : %s %d %d\n", i, vd->toChars(), (int)offset, (int)vd->offset);
|
||||||
|
if (vd->offset < offset)
|
||||||
|
{
|
||||||
|
// Only the first field of a union can have an initializer
|
||||||
|
if (elements->tdata()[i])
|
||||||
|
goto Lno;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!elements->tdata()[i])
|
||||||
|
// Default initialize
|
||||||
|
elements->tdata()[i] = vd->type->defaultInit();
|
||||||
|
}
|
||||||
|
offset = vd->offset + vd->type->size();
|
||||||
|
i++;
|
||||||
|
#if 0
|
||||||
|
int unionSize = ad->numFieldsInUnion(i);
|
||||||
|
if (unionSize == 1)
|
||||||
|
{ // Not a union -- default initialize if missing
|
||||||
|
if (!elements->tdata()[i])
|
||||||
|
elements->tdata()[i] = vd->type->defaultInit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // anonymous union -- check for errors
|
||||||
|
int found = -1; // index of the first field with an initializer
|
||||||
|
for (int j = i; j < i + unionSize; ++j)
|
||||||
|
{
|
||||||
|
if (!elements->tdata()[j])
|
||||||
|
continue;
|
||||||
|
if (found >= 0)
|
||||||
|
{
|
||||||
|
VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration();
|
||||||
|
VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration();
|
||||||
|
error(loc, "%s cannot have initializers for fields %s and %s in same union",
|
||||||
|
ad->toChars(),
|
||||||
|
v1->toChars(), v->toChars());
|
||||||
|
goto Lno;
|
||||||
|
}
|
||||||
|
found = j;
|
||||||
|
}
|
||||||
|
if (found == -1)
|
||||||
|
{
|
||||||
|
error(loc, "no initializer for union that contains field %s",
|
||||||
|
vd->toChars());
|
||||||
|
goto Lno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += unionSize;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
e = new StructLiteralExp(loc, sd, elements);
|
||||||
|
e->type = sd->type;
|
||||||
|
return e;
|
||||||
|
|
||||||
|
Lno:
|
||||||
|
delete elements;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
//printf("StructInitializer::toCBuffer()\n");
|
||||||
|
buf->writebyte('{');
|
||||||
|
for (size_t i = 0; i < field.dim; i++)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
buf->writebyte(',');
|
||||||
|
Identifier *id = field.tdata()[i];
|
||||||
|
if (id)
|
||||||
|
{
|
||||||
|
buf->writestring(id->toChars());
|
||||||
|
buf->writebyte(':');
|
||||||
|
}
|
||||||
|
Initializer *iz = value.tdata()[i];
|
||||||
|
if (iz)
|
||||||
|
iz->toCBuffer(buf, hgs);
|
||||||
|
}
|
||||||
|
buf->writebyte('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************** ArrayInitializer ************************************/
|
||||||
|
|
||||||
|
ArrayInitializer::ArrayInitializer(Loc loc)
|
||||||
|
: Initializer(loc)
|
||||||
|
{
|
||||||
|
dim = 0;
|
||||||
|
type = NULL;
|
||||||
|
sem = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Initializer *ArrayInitializer::syntaxCopy()
|
||||||
|
{
|
||||||
|
//printf("ArrayInitializer::syntaxCopy()\n");
|
||||||
|
|
||||||
|
ArrayInitializer *ai = new ArrayInitializer(loc);
|
||||||
|
|
||||||
|
assert(index.dim == value.dim);
|
||||||
|
ai->index.setDim(index.dim);
|
||||||
|
ai->value.setDim(value.dim);
|
||||||
|
for (size_t i = 0; i < ai->value.dim; i++)
|
||||||
|
{ Expression *e = index.tdata()[i];
|
||||||
|
if (e)
|
||||||
|
e = e->syntaxCopy();
|
||||||
|
ai->index.tdata()[i] = e;
|
||||||
|
|
||||||
|
Initializer *init = value.tdata()[i];
|
||||||
|
init = init->syntaxCopy();
|
||||||
|
ai->value.tdata()[i] = init;
|
||||||
|
}
|
||||||
|
return ai;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArrayInitializer::addInit(Expression *index, Initializer *value)
|
||||||
|
{
|
||||||
|
this->index.push(index);
|
||||||
|
this->value.push(value);
|
||||||
|
dim = 0;
|
||||||
|
type = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret)
|
||||||
|
{ unsigned i;
|
||||||
|
unsigned length;
|
||||||
|
const unsigned amax = 0x80000000;
|
||||||
|
|
||||||
|
//printf("ArrayInitializer::semantic(%s)\n", t->toChars());
|
||||||
|
if (sem) // if semantic() already run
|
||||||
|
return this;
|
||||||
|
sem = 1;
|
||||||
|
type = t;
|
||||||
|
t = t->toBasetype();
|
||||||
|
switch (t->ty)
|
||||||
|
{
|
||||||
|
case Tpointer:
|
||||||
|
case Tsarray:
|
||||||
|
case Tarray:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error(loc, "cannot use array to initialize %s", type->toChars());
|
||||||
|
goto Lerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = 0;
|
||||||
|
for (i = 0; i < index.dim; i++)
|
||||||
|
{
|
||||||
|
Expression *idx = index.tdata()[i];
|
||||||
|
if (idx)
|
||||||
|
{ idx = idx->semantic(sc);
|
||||||
|
idx = idx->optimize(WANTvalue | WANTinterpret);
|
||||||
|
index.tdata()[i] = idx;
|
||||||
|
length = idx->toInteger();
|
||||||
|
}
|
||||||
|
|
||||||
|
Initializer *val = value.tdata()[i];
|
||||||
|
val = val->semantic(sc, t->nextOf(), needInterpret);
|
||||||
|
value.tdata()[i] = val;
|
||||||
|
length++;
|
||||||
|
if (length == 0)
|
||||||
|
{ error(loc, "array dimension overflow");
|
||||||
|
goto Lerr;
|
||||||
|
}
|
||||||
|
if (length > dim)
|
||||||
|
dim = length;
|
||||||
|
}
|
||||||
|
if (t->ty == Tsarray)
|
||||||
|
{
|
||||||
|
dinteger_t edim = ((TypeSArray *)t)->dim->toInteger();
|
||||||
|
if (dim > edim)
|
||||||
|
{
|
||||||
|
error(loc, "array initializer has %u elements, but array length is %jd", dim, edim);
|
||||||
|
goto Lerr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((unsigned long) dim * t->nextOf()->size() >= amax)
|
||||||
|
{ error(loc, "array dimension %u exceeds max of %u", dim, amax / t->nextOf()->size());
|
||||||
|
goto Lerr;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
|
||||||
|
Lerr:
|
||||||
|
return new ExpInitializer(loc, new ErrorExp());
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************
|
||||||
|
* If possible, convert array initializer to array literal.
|
||||||
|
* Otherwise return NULL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Expression *ArrayInitializer::toExpression()
|
||||||
|
{ Expressions *elements;
|
||||||
|
|
||||||
|
//printf("ArrayInitializer::toExpression(), dim = %d\n", dim);
|
||||||
|
//static int i; if (++i == 2) halt();
|
||||||
|
|
||||||
|
size_t edim;
|
||||||
|
Type *t = NULL;
|
||||||
|
if (type)
|
||||||
|
{
|
||||||
|
if (type == Type::terror)
|
||||||
|
return new ErrorExp();
|
||||||
|
|
||||||
|
t = type->toBasetype();
|
||||||
|
switch (t->ty)
|
||||||
|
{
|
||||||
|
case Tsarray:
|
||||||
|
edim = ((TypeSArray *)t)->dim->toInteger();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tpointer:
|
||||||
|
case Tarray:
|
||||||
|
edim = dim;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
edim = value.dim;
|
||||||
|
for (size_t i = 0, j = 0; i < value.dim; i++, j++)
|
||||||
|
{
|
||||||
|
if (index.tdata()[i])
|
||||||
|
j = index.tdata()[i]->toInteger();
|
||||||
|
if (j >= edim)
|
||||||
|
edim = j + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elements = new Expressions();
|
||||||
|
elements->setDim(edim);
|
||||||
|
elements->zero();
|
||||||
|
for (size_t i = 0, j = 0; i < value.dim; i++, j++)
|
||||||
|
{
|
||||||
|
if (index.tdata()[i])
|
||||||
|
j = (index.tdata()[i])->toInteger();
|
||||||
|
assert(j < edim);
|
||||||
|
Initializer *iz = value.tdata()[i];
|
||||||
|
if (!iz)
|
||||||
|
goto Lno;
|
||||||
|
Expression *ex = iz->toExpression();
|
||||||
|
if (!ex)
|
||||||
|
{
|
||||||
|
goto Lno;
|
||||||
|
}
|
||||||
|
elements->tdata()[j] = ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill in any missing elements with the default initializer
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Expression *init = NULL;
|
||||||
|
for (size_t i = 0; i < edim; i++)
|
||||||
|
{
|
||||||
|
if (!elements->tdata()[i])
|
||||||
|
{
|
||||||
|
if (!type)
|
||||||
|
goto Lno;
|
||||||
|
if (!init)
|
||||||
|
init = ((TypeNext *)t)->next->defaultInit();
|
||||||
|
elements->tdata()[i] = init;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression *e = new ArrayLiteralExp(loc, elements);
|
||||||
|
e->type = type;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lno:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************
|
||||||
|
* If possible, convert array initializer to associative array initializer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Expression *ArrayInitializer::toAssocArrayLiteral()
|
||||||
|
{
|
||||||
|
Expression *e;
|
||||||
|
|
||||||
|
//printf("ArrayInitializer::toAssocArrayInitializer()\n");
|
||||||
|
//static int i; if (++i == 2) halt();
|
||||||
|
Expressions *keys = new Expressions();
|
||||||
|
keys->setDim(value.dim);
|
||||||
|
Expressions *values = new Expressions();
|
||||||
|
values->setDim(value.dim);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < value.dim; i++)
|
||||||
|
{
|
||||||
|
e = index.tdata()[i];
|
||||||
|
if (!e)
|
||||||
|
goto Lno;
|
||||||
|
keys->tdata()[i] = e;
|
||||||
|
|
||||||
|
Initializer *iz = value.tdata()[i];
|
||||||
|
if (!iz)
|
||||||
|
goto Lno;
|
||||||
|
e = iz->toExpression();
|
||||||
|
if (!e)
|
||||||
|
goto Lno;
|
||||||
|
values->tdata()[i] = e;
|
||||||
|
}
|
||||||
|
e = new AssocArrayLiteralExp(loc, keys, values);
|
||||||
|
return e;
|
||||||
|
|
||||||
|
Lno:
|
||||||
|
delete keys;
|
||||||
|
delete values;
|
||||||
|
error(loc, "not an associative array initializer");
|
||||||
|
return new ErrorExp();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArrayInitializer::isAssociativeArray()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < value.dim; i++)
|
||||||
|
{
|
||||||
|
if (index.tdata()[i])
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *ArrayInitializer::inferType(Scope *sc)
|
||||||
|
{
|
||||||
|
//printf("ArrayInitializer::inferType() %s\n", toChars());
|
||||||
|
assert(0);
|
||||||
|
return NULL;
|
||||||
|
#if 0
|
||||||
|
type = Type::terror;
|
||||||
|
for (size_t i = 0; i < value.dim; i++)
|
||||||
|
{
|
||||||
|
if (index.data[i])
|
||||||
|
goto Laa;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < value.dim; i++)
|
||||||
|
{
|
||||||
|
Initializer *iz = (Initializer *)value.data[i];
|
||||||
|
if (iz)
|
||||||
|
{ Type *t = iz->inferType(sc);
|
||||||
|
if (i == 0)
|
||||||
|
{ /* BUG: This gets the type from the first element.
|
||||||
|
* Fix to use all the elements to figure out the type.
|
||||||
|
*/
|
||||||
|
t = new TypeSArray(t, new IntegerExp(value.dim));
|
||||||
|
t = t->semantic(loc, sc);
|
||||||
|
type = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
|
||||||
|
Laa:
|
||||||
|
/* It's possibly an associative array initializer.
|
||||||
|
* BUG: inferring type from first member.
|
||||||
|
*/
|
||||||
|
Initializer *iz = (Initializer *)value.data[0];
|
||||||
|
Expression *indexinit = (Expression *)index.data[0];
|
||||||
|
if (iz && indexinit)
|
||||||
|
{ Type *t = iz->inferType(sc);
|
||||||
|
indexinit = indexinit->semantic(sc);
|
||||||
|
Type *indext = indexinit->type;
|
||||||
|
t = new TypeAArray(t, indext);
|
||||||
|
type = t->semantic(loc, sc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error(loc, "cannot infer type from this array initializer");
|
||||||
|
return type;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
buf->writebyte('[');
|
||||||
|
for (size_t i = 0; i < index.dim; i++)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
buf->writebyte(',');
|
||||||
|
Expression *ex = index.tdata()[i];
|
||||||
|
if (ex)
|
||||||
|
{
|
||||||
|
ex->toCBuffer(buf, hgs);
|
||||||
|
buf->writebyte(':');
|
||||||
|
}
|
||||||
|
Initializer *iz = value.tdata()[i];
|
||||||
|
if (iz)
|
||||||
|
iz->toCBuffer(buf, hgs);
|
||||||
|
}
|
||||||
|
buf->writebyte(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************** ExpInitializer ************************************/
|
||||||
|
|
||||||
|
ExpInitializer::ExpInitializer(Loc loc, Expression *exp)
|
||||||
|
: Initializer(loc)
|
||||||
|
{
|
||||||
|
this->exp = exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Initializer *ExpInitializer::syntaxCopy()
|
||||||
|
{
|
||||||
|
return new ExpInitializer(loc, exp->syntaxCopy());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool arrayHasNonConstPointers(Expressions *elems);
|
||||||
|
|
||||||
|
bool hasNonConstPointers(Expression *e)
|
||||||
|
{
|
||||||
|
if (e->op == TOKnull)
|
||||||
|
return false;
|
||||||
|
if (e->op == TOKstructliteral)
|
||||||
|
{
|
||||||
|
StructLiteralExp *se = (StructLiteralExp *)e;
|
||||||
|
return arrayHasNonConstPointers(se->elements);
|
||||||
|
}
|
||||||
|
if (e->op == TOKarrayliteral)
|
||||||
|
{
|
||||||
|
if (!e->type->nextOf()->hasPointers())
|
||||||
|
return false;
|
||||||
|
ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
|
||||||
|
return arrayHasNonConstPointers(ae->elements);
|
||||||
|
}
|
||||||
|
if (e->op == TOKassocarrayliteral)
|
||||||
|
{
|
||||||
|
AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
|
||||||
|
if (ae->type->nextOf()->hasPointers() &&
|
||||||
|
arrayHasNonConstPointers(ae->values))
|
||||||
|
return true;
|
||||||
|
if (((TypeAArray *)ae->type)->index->hasPointers())
|
||||||
|
return arrayHasNonConstPointers(ae->keys);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (e->type->ty== Tpointer && e->type->nextOf()->ty != Tfunction)
|
||||||
|
{
|
||||||
|
#if IN_LLVM
|
||||||
|
// address of a global is OK
|
||||||
|
if (e->op == TOKaddress || e->op == TOKcast)
|
||||||
|
return false;
|
||||||
|
if (e->op == TOKadd || e->op == TOKmin) {
|
||||||
|
BinExp *be = (BinExp*)e;
|
||||||
|
if (be->e1->type->ty == Tpointer || be->e2->type->ty == Tpointer)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (e->op == TOKsymoff) // address of a global is OK
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
if (e->op == TOKint64) // cast(void *)int is OK
|
||||||
|
return false;
|
||||||
|
if (e->op == TOKstring) // "abc".ptr is OK
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool arrayHasNonConstPointers(Expressions *elems)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < elems->dim; i++)
|
||||||
|
{
|
||||||
|
if (!elems->tdata()[i])
|
||||||
|
continue;
|
||||||
|
if (hasNonConstPointers(elems->tdata()[i]))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret)
|
||||||
|
{
|
||||||
|
//printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars());
|
||||||
|
exp = exp->semantic(sc);
|
||||||
|
exp = resolveProperties(sc, exp);
|
||||||
|
int wantOptimize = needInterpret ? WANTinterpret|WANTvalue : WANTvalue;
|
||||||
|
|
||||||
|
int olderrors = global.errors;
|
||||||
|
exp = exp->optimize(wantOptimize);
|
||||||
|
if (!global.gag && olderrors != global.errors)
|
||||||
|
return this; // Failed, suppress duplicate error messages
|
||||||
|
|
||||||
|
if (exp->op == TOKtype)
|
||||||
|
error("initializer must be an expression, not '%s'", exp->toChars());
|
||||||
|
|
||||||
|
// Make sure all pointers are constants
|
||||||
|
if (needInterpret && hasNonConstPointers(exp))
|
||||||
|
{
|
||||||
|
exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *tb = t->toBasetype();
|
||||||
|
|
||||||
|
/* Look for case of initializing a static array with a too-short
|
||||||
|
* string literal, such as:
|
||||||
|
* char[5] foo = "abc";
|
||||||
|
* Allow this by doing an explicit cast, which will lengthen the string
|
||||||
|
* literal.
|
||||||
|
*/
|
||||||
|
if (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray)
|
||||||
|
{ StringExp *se = (StringExp *)exp;
|
||||||
|
|
||||||
|
if (!se->committed && se->type->ty == Tsarray &&
|
||||||
|
((TypeSArray *)se->type)->dim->toInteger() <
|
||||||
|
((TypeSArray *)t)->dim->toInteger())
|
||||||
|
{
|
||||||
|
exp = se->castTo(sc, t);
|
||||||
|
goto L1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for the case of statically initializing an array
|
||||||
|
// with a single member.
|
||||||
|
if (tb->ty == Tsarray &&
|
||||||
|
!tb->nextOf()->equals(exp->type->toBasetype()->nextOf()) &&
|
||||||
|
exp->implicitConvTo(tb->nextOf())
|
||||||
|
)
|
||||||
|
{
|
||||||
|
t = tb->nextOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
exp = exp->implicitCastTo(sc, t);
|
||||||
|
L1:
|
||||||
|
exp = exp->optimize(wantOptimize);
|
||||||
|
//printf("-ExpInitializer::semantic(): "); exp->print();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *ExpInitializer::inferType(Scope *sc)
|
||||||
|
{
|
||||||
|
//printf("ExpInitializer::inferType() %s\n", toChars());
|
||||||
|
if (exp->op == TOKfunction && ((FuncExp *)exp)->td)
|
||||||
|
{
|
||||||
|
exp->error("cannot infer type from ambiguous function literal %s", exp->toChars());
|
||||||
|
return Type::terror;
|
||||||
|
}
|
||||||
|
|
||||||
|
exp = exp->semantic(sc);
|
||||||
|
exp = resolveProperties(sc, exp);
|
||||||
|
|
||||||
|
// Give error for overloaded function addresses
|
||||||
|
if (exp->op == TOKsymoff)
|
||||||
|
{ SymOffExp *se = (SymOffExp *)exp;
|
||||||
|
if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique())
|
||||||
|
exp->error("cannot infer type from overloaded function symbol %s", exp->toChars());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give error for overloaded function addresses
|
||||||
|
if (exp->op == TOKdelegate)
|
||||||
|
{ DelegateExp *se = (DelegateExp *)exp;
|
||||||
|
if (
|
||||||
|
se->func->isFuncDeclaration() &&
|
||||||
|
!se->func->isFuncDeclaration()->isUnique())
|
||||||
|
exp->error("cannot infer type from overloaded function symbol %s", exp->toChars());
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *t = exp->type;
|
||||||
|
if (!t)
|
||||||
|
t = Initializer::inferType(sc);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression *ExpInitializer::toExpression()
|
||||||
|
{
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExpInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
||||||
|
{
|
||||||
|
exp->toCBuffer(buf, hgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+149
@@ -0,0 +1,149 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2007 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef INIT_H
|
||||||
|
#define INIT_H
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "arraytypes.h"
|
||||||
|
|
||||||
|
struct Identifier;
|
||||||
|
struct Expression;
|
||||||
|
struct Scope;
|
||||||
|
struct Type;
|
||||||
|
struct dt_t;
|
||||||
|
struct AggregateDeclaration;
|
||||||
|
struct VoidInitializer;
|
||||||
|
struct StructInitializer;
|
||||||
|
struct ArrayInitializer;
|
||||||
|
struct ExpInitializer;
|
||||||
|
struct HdrGenState;
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
namespace llvm {
|
||||||
|
class StructType;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct Initializer : Object
|
||||||
|
{
|
||||||
|
Loc loc;
|
||||||
|
|
||||||
|
Initializer(Loc loc);
|
||||||
|
virtual Initializer *syntaxCopy();
|
||||||
|
// needInterpret is WANTinterpret if must be a manifest constant, 0 if not.
|
||||||
|
virtual Initializer *semantic(Scope *sc, Type *t, int needInterpret);
|
||||||
|
virtual Type *inferType(Scope *sc);
|
||||||
|
virtual Expression *toExpression() = 0;
|
||||||
|
virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0;
|
||||||
|
char *toChars();
|
||||||
|
|
||||||
|
static Initializers *arraySyntaxCopy(Initializers *ai);
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
virtual dt_t *toDt();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
virtual VoidInitializer *isVoidInitializer() { return NULL; }
|
||||||
|
virtual StructInitializer *isStructInitializer() { return NULL; }
|
||||||
|
virtual ArrayInitializer *isArrayInitializer() { return NULL; }
|
||||||
|
virtual ExpInitializer *isExpInitializer() { return NULL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VoidInitializer : Initializer
|
||||||
|
{
|
||||||
|
Type *type; // type that this will initialize to
|
||||||
|
|
||||||
|
VoidInitializer(Loc loc);
|
||||||
|
Initializer *syntaxCopy();
|
||||||
|
Initializer *semantic(Scope *sc, Type *t, int needInterpret);
|
||||||
|
Expression *toExpression();
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
dt_t *toDt();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
virtual VoidInitializer *isVoidInitializer() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StructInitializer : Initializer
|
||||||
|
{
|
||||||
|
Identifiers field; // of Identifier *'s
|
||||||
|
Initializers value; // parallel array of Initializer *'s
|
||||||
|
|
||||||
|
VarDeclarations vars; // parallel array of VarDeclaration *'s
|
||||||
|
AggregateDeclaration *ad; // which aggregate this is for
|
||||||
|
|
||||||
|
StructInitializer(Loc loc);
|
||||||
|
Initializer *syntaxCopy();
|
||||||
|
void addInit(Identifier *field, Initializer *value);
|
||||||
|
Initializer *semantic(Scope *sc, Type *t, int needInterpret);
|
||||||
|
Expression *toExpression();
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
dt_t *toDt();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
StructInitializer *isStructInitializer() { return this; }
|
||||||
|
#if IN_LLVM
|
||||||
|
llvm::StructType *ltype;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ArrayInitializer : Initializer
|
||||||
|
{
|
||||||
|
Expressions index; // indices
|
||||||
|
Initializers value; // of Initializer *'s
|
||||||
|
unsigned dim; // length of array being initialized
|
||||||
|
Type *type; // type that array will be used to initialize
|
||||||
|
int sem; // !=0 if semantic() is run
|
||||||
|
|
||||||
|
ArrayInitializer(Loc loc);
|
||||||
|
Initializer *syntaxCopy();
|
||||||
|
void addInit(Expression *index, Initializer *value);
|
||||||
|
Initializer *semantic(Scope *sc, Type *t, int needInterpret);
|
||||||
|
int isAssociativeArray();
|
||||||
|
Type *inferType(Scope *sc);
|
||||||
|
Expression *toExpression();
|
||||||
|
Expression *toAssocArrayLiteral();
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
dt_t *toDt();
|
||||||
|
dt_t *toDtBit(); // for bit arrays
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ArrayInitializer *isArrayInitializer() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExpInitializer : Initializer
|
||||||
|
{
|
||||||
|
Expression *exp;
|
||||||
|
|
||||||
|
ExpInitializer(Loc loc, Expression *exp);
|
||||||
|
Initializer *syntaxCopy();
|
||||||
|
Initializer *semantic(Scope *sc, Type *t, int needInterpret);
|
||||||
|
Type *inferType(Scope *sc);
|
||||||
|
Expression *toExpression();
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
|
||||||
|
#if IN_DMD
|
||||||
|
dt_t *toDt();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
virtual ExpInitializer *isExpInitializer() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+1831
File diff suppressed because it is too large
Load Diff
+6586
File diff suppressed because it is too large
Load Diff
+1105
File diff suppressed because it is too large
Load Diff
+149
@@ -0,0 +1,149 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by KennyTM
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DMD_SXNUM_H
|
||||||
|
#define DMD_SXNUM_H
|
||||||
|
|
||||||
|
#include "mars.h" // for uinteger_t
|
||||||
|
struct Type;
|
||||||
|
struct Expression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
This class represents a "sign-extended number", i.e. a 65-bit number, which can
|
||||||
|
represent all built-in integer types in D. This class is mainly used for
|
||||||
|
performing value-range propagation only, therefore all arithmetic are done with
|
||||||
|
saturation, not wrapping as usual.
|
||||||
|
*/
|
||||||
|
struct SignExtendedNumber
|
||||||
|
{
|
||||||
|
/// The lower 64-bit of the number.
|
||||||
|
uinteger_t value;
|
||||||
|
/// The sign (i.e. the most significant bit) of the number.
|
||||||
|
bool negative;
|
||||||
|
|
||||||
|
/// Create an uninitialized sign-extended number.
|
||||||
|
SignExtendedNumber() {}
|
||||||
|
|
||||||
|
/// Create a sign-extended number from an unsigned 64-bit number.
|
||||||
|
SignExtendedNumber(uinteger_t value_)
|
||||||
|
: value(value_), negative(false) {}
|
||||||
|
/// Create a sign-extended number from the lower 64-bit and the sign bit.
|
||||||
|
SignExtendedNumber(uinteger_t value_, bool negative_)
|
||||||
|
: value(value_), negative(negative_) {}
|
||||||
|
|
||||||
|
/// Create a sign-extended number from a signed 64-bit number.
|
||||||
|
static SignExtendedNumber fromInteger(uinteger_t value_);
|
||||||
|
|
||||||
|
/// Get the minimum or maximum value of a sign-extended number.
|
||||||
|
static SignExtendedNumber extreme(bool minimum);
|
||||||
|
static SignExtendedNumber max();
|
||||||
|
static SignExtendedNumber min() { return SignExtendedNumber(0, true); }
|
||||||
|
|
||||||
|
/// Check if the sign-extended number is minimum or zero.
|
||||||
|
bool isMinimum() const { return negative && value == 0; }
|
||||||
|
|
||||||
|
/// Compare two sign-extended number.
|
||||||
|
bool operator==(const SignExtendedNumber&) const;
|
||||||
|
bool operator!=(const SignExtendedNumber& a) const { return !(*this == a); }
|
||||||
|
bool operator<(const SignExtendedNumber&) const;
|
||||||
|
bool operator>(const SignExtendedNumber& a) const { return a < *this; }
|
||||||
|
bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); }
|
||||||
|
bool operator>=(const SignExtendedNumber& a) const { return !(*this < a); }
|
||||||
|
|
||||||
|
/// Compute the saturated negation of a sign-extended number.
|
||||||
|
SignExtendedNumber operator-() const;
|
||||||
|
|
||||||
|
/// Compute the saturated sum of two sign-extended number.
|
||||||
|
SignExtendedNumber operator+(const SignExtendedNumber&) const;
|
||||||
|
/// Compute the saturated difference of two sign-extended number.
|
||||||
|
SignExtendedNumber operator-(const SignExtendedNumber& a) const;
|
||||||
|
/// Compute the saturated product of two sign-extended number.
|
||||||
|
SignExtendedNumber operator*(const SignExtendedNumber&) const;
|
||||||
|
/// Compute the saturated quotient of two sign-extended number.
|
||||||
|
SignExtendedNumber operator/(const SignExtendedNumber&) const;
|
||||||
|
/// Compute the saturated modulus of two sign-extended number.
|
||||||
|
SignExtendedNumber operator%(const SignExtendedNumber&) const;
|
||||||
|
|
||||||
|
/// Increase the sign-extended number by 1 (saturated).
|
||||||
|
SignExtendedNumber& operator++();
|
||||||
|
|
||||||
|
/// Compute the saturated shifts of two sign-extended number.
|
||||||
|
SignExtendedNumber operator<<(const SignExtendedNumber&) const;
|
||||||
|
SignExtendedNumber operator>>(const SignExtendedNumber&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
This class represents a range of integers, denoted by its lower and upper bounds
|
||||||
|
(inclusive).
|
||||||
|
*/
|
||||||
|
struct IntRange
|
||||||
|
{
|
||||||
|
SignExtendedNumber imin, imax;
|
||||||
|
|
||||||
|
/// Create an uninitialized range.
|
||||||
|
IntRange() {}
|
||||||
|
|
||||||
|
/// Create a range consisting of a single number.
|
||||||
|
IntRange(const SignExtendedNumber& a)
|
||||||
|
: imin(a), imax(a) {}
|
||||||
|
/// Create a range with the lower and upper bounds.
|
||||||
|
IntRange(const SignExtendedNumber& lower, const SignExtendedNumber& upper)
|
||||||
|
: imin(lower), imax(upper) {}
|
||||||
|
|
||||||
|
/// Create the tightest range containing all valid integers in the specified
|
||||||
|
/// type.
|
||||||
|
static IntRange fromType(Type *type);
|
||||||
|
/// Create the tightest range containing all valid integers in the type with
|
||||||
|
/// a forced signedness.
|
||||||
|
static IntRange fromType(Type *type, bool isUnsigned);
|
||||||
|
|
||||||
|
|
||||||
|
/// Create the tightest range containing all specified numbers.
|
||||||
|
static IntRange fromNumbers2(const SignExtendedNumber numbers[2]);
|
||||||
|
static IntRange fromNumbers4(const SignExtendedNumber numbers[4]);
|
||||||
|
|
||||||
|
/// Create the widest range possible.
|
||||||
|
static IntRange widest();
|
||||||
|
|
||||||
|
/// Cast the integer range to a signed type with the given size mask.
|
||||||
|
IntRange& castSigned(uinteger_t mask);
|
||||||
|
/// Cast the integer range to an unsigned type with the given size mask.
|
||||||
|
IntRange& castUnsigned(uinteger_t mask);
|
||||||
|
/// Cast the integer range to the dchar type.
|
||||||
|
IntRange& castDchar();
|
||||||
|
|
||||||
|
/// Cast the integer range to a specific type.
|
||||||
|
IntRange& cast(Type *type);
|
||||||
|
/// Cast the integer range to a specific type, forcing it to be unsigned.
|
||||||
|
IntRange& castUnsigned(Type *type);
|
||||||
|
|
||||||
|
/// Check if this range contains another range.
|
||||||
|
bool contains(const IntRange& a) const;
|
||||||
|
|
||||||
|
/// Check if this range contains 0.
|
||||||
|
bool containsZero() const;
|
||||||
|
|
||||||
|
/// Compute the range of the negated absolute values of the original range.
|
||||||
|
IntRange absNeg() const;
|
||||||
|
|
||||||
|
/// Compute the union of two ranges.
|
||||||
|
IntRange unionWith(const IntRange& other) const;
|
||||||
|
void unionOrAssign(const IntRange& other, bool& union_);
|
||||||
|
|
||||||
|
/// Dump the content of the integer range to the console.
|
||||||
|
const IntRange& dump(const char* funcName, Expression *e) const;
|
||||||
|
|
||||||
|
/// Split the range into two nonnegative- and negative-only subintervals.
|
||||||
|
void splitBySign(IntRange& negRange, bool& hasNegRange,
|
||||||
|
IntRange& nonNegRange, bool& hasNonNegRange) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+195
@@ -0,0 +1,195 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "irstate.h"
|
||||||
|
|
||||||
|
IRState::IRState(IRState *irs, Statement *s)
|
||||||
|
{
|
||||||
|
prev = irs;
|
||||||
|
statement = s;
|
||||||
|
symbol = NULL;
|
||||||
|
breakBlock = NULL;
|
||||||
|
contBlock = NULL;
|
||||||
|
switchBlock = NULL;
|
||||||
|
defaultBlock = NULL;
|
||||||
|
ident = NULL;
|
||||||
|
ehidden = NULL;
|
||||||
|
startaddress = NULL;
|
||||||
|
if (irs)
|
||||||
|
{
|
||||||
|
m = irs->m;
|
||||||
|
shidden = irs->shidden;
|
||||||
|
sclosure = irs->sclosure;
|
||||||
|
sthis = irs->sthis;
|
||||||
|
blx = irs->blx;
|
||||||
|
deferToObj = irs->deferToObj;
|
||||||
|
#if DMDV2
|
||||||
|
varsInScope = irs->varsInScope;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m = NULL;
|
||||||
|
shidden = NULL;
|
||||||
|
sclosure = NULL;
|
||||||
|
sthis = NULL;
|
||||||
|
blx = NULL;
|
||||||
|
deferToObj = NULL;
|
||||||
|
#if DMDV2
|
||||||
|
varsInScope = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IRState::IRState(IRState *irs, Dsymbol *s)
|
||||||
|
{
|
||||||
|
prev = irs;
|
||||||
|
statement = NULL;
|
||||||
|
symbol = s;
|
||||||
|
breakBlock = NULL;
|
||||||
|
contBlock = NULL;
|
||||||
|
switchBlock = NULL;
|
||||||
|
defaultBlock = NULL;
|
||||||
|
ident = NULL;
|
||||||
|
ehidden = NULL;
|
||||||
|
startaddress = NULL;
|
||||||
|
if (irs)
|
||||||
|
{
|
||||||
|
m = irs->m;
|
||||||
|
shidden = irs->shidden;
|
||||||
|
sclosure = irs->sclosure;
|
||||||
|
sthis = irs->sthis;
|
||||||
|
blx = irs->blx;
|
||||||
|
deferToObj = irs->deferToObj;
|
||||||
|
varsInScope = irs->varsInScope;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m = NULL;
|
||||||
|
shidden = NULL;
|
||||||
|
sclosure = NULL;
|
||||||
|
sthis = NULL;
|
||||||
|
blx = NULL;
|
||||||
|
deferToObj = NULL;
|
||||||
|
varsInScope = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IRState::IRState(Module *m, Dsymbol *s)
|
||||||
|
{
|
||||||
|
prev = NULL;
|
||||||
|
statement = NULL;
|
||||||
|
this->m = m;
|
||||||
|
symbol = s;
|
||||||
|
breakBlock = NULL;
|
||||||
|
contBlock = NULL;
|
||||||
|
switchBlock = NULL;
|
||||||
|
defaultBlock = NULL;
|
||||||
|
ident = NULL;
|
||||||
|
ehidden = NULL;
|
||||||
|
shidden = NULL;
|
||||||
|
sclosure = NULL;
|
||||||
|
sthis = NULL;
|
||||||
|
blx = NULL;
|
||||||
|
deferToObj = NULL;
|
||||||
|
startaddress = NULL;
|
||||||
|
varsInScope = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
block *IRState::getBreakBlock(Identifier *ident)
|
||||||
|
{
|
||||||
|
IRState *bc;
|
||||||
|
|
||||||
|
for (bc = this; bc; bc = bc->prev)
|
||||||
|
{
|
||||||
|
if (ident)
|
||||||
|
{
|
||||||
|
if (bc->prev && bc->prev->ident == ident)
|
||||||
|
return bc->breakBlock;
|
||||||
|
}
|
||||||
|
else if (bc->breakBlock)
|
||||||
|
return bc->breakBlock;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
block *IRState::getContBlock(Identifier *ident)
|
||||||
|
{
|
||||||
|
IRState *bc;
|
||||||
|
|
||||||
|
for (bc = this; bc; bc = bc->prev)
|
||||||
|
{
|
||||||
|
if (ident)
|
||||||
|
{
|
||||||
|
if (bc->prev && bc->prev->ident == ident)
|
||||||
|
return bc->contBlock;
|
||||||
|
}
|
||||||
|
else if (bc->contBlock)
|
||||||
|
return bc->contBlock;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
block *IRState::getSwitchBlock()
|
||||||
|
{
|
||||||
|
IRState *bc;
|
||||||
|
|
||||||
|
for (bc = this; bc; bc = bc->prev)
|
||||||
|
{
|
||||||
|
if (bc->switchBlock)
|
||||||
|
return bc->switchBlock;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
block *IRState::getDefaultBlock()
|
||||||
|
{
|
||||||
|
IRState *bc;
|
||||||
|
|
||||||
|
for (bc = this; bc; bc = bc->prev)
|
||||||
|
{
|
||||||
|
if (bc->defaultBlock)
|
||||||
|
return bc->defaultBlock;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncDeclaration *IRState::getFunc()
|
||||||
|
{
|
||||||
|
IRState *bc;
|
||||||
|
|
||||||
|
for (bc = this; bc->prev; bc = bc->prev)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return (FuncDeclaration *)(bc->symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* Return !=0 if do array bounds checking
|
||||||
|
*/
|
||||||
|
int IRState::arrayBoundsCheck()
|
||||||
|
{
|
||||||
|
int result = global.params.useArrayBounds;
|
||||||
|
|
||||||
|
if (result == 1)
|
||||||
|
{ // For safe functions only
|
||||||
|
result = 0;
|
||||||
|
FuncDeclaration *fd = getFunc();
|
||||||
|
if (fd)
|
||||||
|
{ Type *t = fd->type;
|
||||||
|
if (t->ty == Tfunction && ((TypeFunction *)t)->trust == TRUSTsafe)
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
|
||||||
|
#ifndef DMD_CONTEXT_H
|
||||||
|
#define DMD_CONTEXT_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
struct Module;
|
||||||
|
struct Statement;
|
||||||
|
struct block;
|
||||||
|
struct Dsymbol;
|
||||||
|
struct Identifier;
|
||||||
|
struct Symbol;
|
||||||
|
struct FuncDeclaration;
|
||||||
|
struct Blockx;
|
||||||
|
struct elem;
|
||||||
|
#include "arraytypes.h"
|
||||||
|
|
||||||
|
struct IRState
|
||||||
|
{
|
||||||
|
IRState *prev;
|
||||||
|
Statement *statement;
|
||||||
|
Module *m; // module
|
||||||
|
Dsymbol *symbol;
|
||||||
|
Identifier *ident;
|
||||||
|
Symbol *shidden; // hidden parameter to function
|
||||||
|
Symbol *sthis; // 'this' parameter to function (member and nested)
|
||||||
|
Symbol *sclosure; // pointer to closure instance
|
||||||
|
Blockx *blx;
|
||||||
|
Dsymbols *deferToObj; // array of Dsymbol's to run toObjFile(int multiobj) on later
|
||||||
|
elem *ehidden; // transmit hidden pointer to CallExp::toElem()
|
||||||
|
Symbol *startaddress;
|
||||||
|
VarDeclarations *varsInScope; // variables that are in scope that will need destruction later
|
||||||
|
|
||||||
|
block *breakBlock;
|
||||||
|
block *contBlock;
|
||||||
|
block *switchBlock;
|
||||||
|
block *defaultBlock;
|
||||||
|
|
||||||
|
IRState(IRState *irs, Statement *s);
|
||||||
|
IRState(IRState *irs, Dsymbol *s);
|
||||||
|
IRState(Module *m, Dsymbol *s);
|
||||||
|
|
||||||
|
block *getBreakBlock(Identifier *ident);
|
||||||
|
block *getContBlock(Identifier *ident);
|
||||||
|
block *getSwitchBlock();
|
||||||
|
block *getDefaultBlock();
|
||||||
|
FuncDeclaration *getFunc();
|
||||||
|
int arrayBoundsCheck();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DMD_CONTEXT_H */
|
||||||
+462
@@ -0,0 +1,462 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
// This implements the JSON capability.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "rmem.h"
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "dsymbol.h"
|
||||||
|
#include "macro.h"
|
||||||
|
#include "template.h"
|
||||||
|
#include "lexer.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "enum.h"
|
||||||
|
#include "id.h"
|
||||||
|
#include "module.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "hdrgen.h"
|
||||||
|
#include "json.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "attrib.h"
|
||||||
|
#include "cond.h"
|
||||||
|
|
||||||
|
const char Pname[] = "name";
|
||||||
|
const char Pkind[] = "kind";
|
||||||
|
const char Pfile[] = "file";
|
||||||
|
const char Pline[] = "line";
|
||||||
|
const char Ptype[] = "type";
|
||||||
|
const char Pcomment[] = "comment";
|
||||||
|
const char Pmembers[] = "members";
|
||||||
|
const char Pprotection[] = "protection";
|
||||||
|
const char* Pprotectionnames[] = {NULL, "none", "private", "package", "protected", "public", "export"};
|
||||||
|
|
||||||
|
void JsonRemoveComma(OutBuffer *buf);
|
||||||
|
|
||||||
|
void json_generate(Modules *modules)
|
||||||
|
{ OutBuffer buf;
|
||||||
|
|
||||||
|
buf.writestring("[\n");
|
||||||
|
for (size_t i = 0; i < modules->dim; i++)
|
||||||
|
{ Module *m = modules->tdata()[i];
|
||||||
|
if (global.params.verbose)
|
||||||
|
printf("json gen %s\n", m->toChars());
|
||||||
|
m->toJsonBuffer(&buf);
|
||||||
|
buf.writestring(",\n");
|
||||||
|
}
|
||||||
|
JsonRemoveComma(&buf);
|
||||||
|
buf.writestring("]\n");
|
||||||
|
|
||||||
|
// Write buf to file
|
||||||
|
char *arg = global.params.xfilename;
|
||||||
|
if (!arg || !*arg)
|
||||||
|
{ // Generate lib file name from first obj name
|
||||||
|
char *n = global.params.objfiles->tdata()[0];
|
||||||
|
|
||||||
|
n = FileName::name(n);
|
||||||
|
FileName *fn = FileName::forceExt(n, global.json_ext);
|
||||||
|
arg = fn->toChars();
|
||||||
|
}
|
||||||
|
else if (arg[0] == '-' && arg[1] == 0)
|
||||||
|
{ // Write to stdout; assume it succeeds
|
||||||
|
int n = fwrite(buf.data, 1, buf.offset, stdout);
|
||||||
|
assert(n == buf.offset); // keep gcc happy about return values
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if (!FileName::absolute(arg))
|
||||||
|
// arg = FileName::combine(dir, arg);
|
||||||
|
FileName *jsonfilename = FileName::defaultExt(arg, global.json_ext);
|
||||||
|
File *jsonfile = new File(jsonfilename);
|
||||||
|
assert(jsonfile);
|
||||||
|
jsonfile->setbuffer(buf.data, buf.offset);
|
||||||
|
jsonfile->ref = 1;
|
||||||
|
char *pt = FileName::path(jsonfile->toChars());
|
||||||
|
if (*pt)
|
||||||
|
FileName::ensurePathExists(pt);
|
||||||
|
mem.free(pt);
|
||||||
|
jsonfile->writev();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* Encode string into buf, and wrap it in double quotes.
|
||||||
|
*/
|
||||||
|
void JsonString(OutBuffer *buf, const char *s)
|
||||||
|
{
|
||||||
|
buf->writeByte('\"');
|
||||||
|
for (; *s; s++)
|
||||||
|
{
|
||||||
|
unsigned char c = (unsigned char) *s;
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '\n':
|
||||||
|
buf->writestring("\\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
buf->writestring("\\r");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\t':
|
||||||
|
buf->writestring("\\t");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\"':
|
||||||
|
buf->writestring("\\\"");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\\':
|
||||||
|
buf->writestring("\\\\");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '/':
|
||||||
|
buf->writestring("\\/");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\b':
|
||||||
|
buf->writestring("\\b");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\f':
|
||||||
|
buf->writestring("\\f");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (c < 0x20)
|
||||||
|
buf->printf("\\u%04x", c);
|
||||||
|
else
|
||||||
|
// Note that UTF-8 chars pass through here just fine
|
||||||
|
buf->writeByte(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf->writeByte('\"');
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonProperty(OutBuffer *buf, const char *name, const char *value)
|
||||||
|
{
|
||||||
|
JsonString(buf, name);
|
||||||
|
buf->writestring(" : ");
|
||||||
|
JsonString(buf, value);
|
||||||
|
buf->writestring(",\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonProperty(OutBuffer *buf, const char *name, int value)
|
||||||
|
{
|
||||||
|
JsonString(buf, name);
|
||||||
|
buf->writestring(" : ");
|
||||||
|
buf->printf("%d", value);
|
||||||
|
buf->writestring(",\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonRemoveComma(OutBuffer *buf)
|
||||||
|
{
|
||||||
|
if (buf->offset >= 2 &&
|
||||||
|
buf->data[buf->offset - 2] == ',' &&
|
||||||
|
buf->data[buf->offset - 1] == '\n')
|
||||||
|
buf->offset -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dsymbol::toJsonBuffer(OutBuffer *buf)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Module::toJsonBuffer(OutBuffer *buf)
|
||||||
|
{
|
||||||
|
buf->writestring("{\n");
|
||||||
|
|
||||||
|
if (md)
|
||||||
|
JsonProperty(buf, Pname, md->toChars());
|
||||||
|
|
||||||
|
JsonProperty(buf, Pkind, kind());
|
||||||
|
|
||||||
|
JsonProperty(buf, Pfile, srcfile->toChars());
|
||||||
|
|
||||||
|
if (comment)
|
||||||
|
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||||
|
|
||||||
|
JsonString(buf, Pmembers);
|
||||||
|
buf->writestring(" : [\n");
|
||||||
|
|
||||||
|
size_t offset = buf->offset;
|
||||||
|
for (size_t i = 0; i < members->dim; i++)
|
||||||
|
{ Dsymbol *s = members->tdata()[i];
|
||||||
|
if (offset != buf->offset)
|
||||||
|
{ buf->writestring(",\n");
|
||||||
|
offset = buf->offset;
|
||||||
|
}
|
||||||
|
s->toJsonBuffer(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonRemoveComma(buf);
|
||||||
|
buf->writestring("]\n");
|
||||||
|
|
||||||
|
buf->writestring("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttribDeclaration::toJsonBuffer(OutBuffer *buf)
|
||||||
|
{
|
||||||
|
//printf("AttribDeclaration::toJsonBuffer()\n");
|
||||||
|
|
||||||
|
Dsymbols *d = include(NULL, NULL);
|
||||||
|
|
||||||
|
if (d)
|
||||||
|
{
|
||||||
|
size_t offset = buf->offset;
|
||||||
|
for (unsigned i = 0; i < d->dim; i++)
|
||||||
|
{ Dsymbol *s = d->tdata()[i];
|
||||||
|
//printf("AttribDeclaration::toJsonBuffer %s\n", s->toChars());
|
||||||
|
if (offset != buf->offset)
|
||||||
|
{ buf->writestring(",\n");
|
||||||
|
offset = buf->offset;
|
||||||
|
}
|
||||||
|
s->toJsonBuffer(buf);
|
||||||
|
}
|
||||||
|
JsonRemoveComma(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ConditionalDeclaration::toJsonBuffer(OutBuffer *buf)
|
||||||
|
{
|
||||||
|
//printf("ConditionalDeclaration::toJsonBuffer()\n");
|
||||||
|
if (condition->inc)
|
||||||
|
{
|
||||||
|
AttribDeclaration::toJsonBuffer(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InvariantDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||||
|
void DtorDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||||
|
void StaticCtorDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||||
|
void StaticDtorDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||||
|
void ClassInfoDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||||
|
void ModuleInfoDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||||
|
void TypeInfoDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||||
|
void UnitTestDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||||
|
#if DMDV2
|
||||||
|
void PostBlitDeclaration::toJsonBuffer(OutBuffer *buf) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Declaration::toJsonBuffer(OutBuffer *buf)
|
||||||
|
{
|
||||||
|
//printf("Declaration::toJsonBuffer()\n");
|
||||||
|
buf->writestring("{\n");
|
||||||
|
|
||||||
|
JsonProperty(buf, Pname, toChars());
|
||||||
|
JsonProperty(buf, Pkind, kind());
|
||||||
|
|
||||||
|
if (prot())
|
||||||
|
JsonProperty(buf, Pprotection, Pprotectionnames[prot()]);
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
JsonProperty(buf, Ptype, type->toChars());
|
||||||
|
|
||||||
|
if (comment)
|
||||||
|
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||||
|
|
||||||
|
if (loc.linnum)
|
||||||
|
JsonProperty(buf, Pline, loc.linnum);
|
||||||
|
|
||||||
|
TypedefDeclaration *td = isTypedefDeclaration();
|
||||||
|
if (td)
|
||||||
|
{
|
||||||
|
JsonProperty(buf, "base", td->basetype->toChars());
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonRemoveComma(buf);
|
||||||
|
buf->writestring("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AggregateDeclaration::toJsonBuffer(OutBuffer *buf)
|
||||||
|
{
|
||||||
|
//printf("AggregateDeclaration::toJsonBuffer()\n");
|
||||||
|
buf->writestring("{\n");
|
||||||
|
|
||||||
|
JsonProperty(buf, Pname, toChars());
|
||||||
|
JsonProperty(buf, Pkind, kind());
|
||||||
|
|
||||||
|
if (prot())
|
||||||
|
JsonProperty(buf, Pprotection, Pprotectionnames[prot()]);
|
||||||
|
|
||||||
|
if (comment)
|
||||||
|
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||||
|
|
||||||
|
if (loc.linnum)
|
||||||
|
JsonProperty(buf, Pline, loc.linnum);
|
||||||
|
|
||||||
|
ClassDeclaration *cd = isClassDeclaration();
|
||||||
|
if (cd)
|
||||||
|
{
|
||||||
|
if (cd->baseClass)
|
||||||
|
{
|
||||||
|
JsonProperty(buf, "base", cd->baseClass->toChars());
|
||||||
|
}
|
||||||
|
if (cd->interfaces_dim)
|
||||||
|
{
|
||||||
|
JsonString(buf, "interfaces");
|
||||||
|
buf->writestring(" : [\n");
|
||||||
|
size_t offset = buf->offset;
|
||||||
|
for (size_t i = 0; i < cd->interfaces_dim; i++)
|
||||||
|
{ BaseClass *b = cd->interfaces[i];
|
||||||
|
if (offset != buf->offset)
|
||||||
|
{ buf->writestring(",\n");
|
||||||
|
offset = buf->offset;
|
||||||
|
}
|
||||||
|
JsonString(buf, b->base->toChars());
|
||||||
|
}
|
||||||
|
JsonRemoveComma(buf);
|
||||||
|
buf->writestring("],\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (members)
|
||||||
|
{
|
||||||
|
JsonString(buf, Pmembers);
|
||||||
|
buf->writestring(" : [\n");
|
||||||
|
size_t offset = buf->offset;
|
||||||
|
for (size_t i = 0; i < members->dim; i++)
|
||||||
|
{ Dsymbol *s = members->tdata()[i];
|
||||||
|
if (offset != buf->offset)
|
||||||
|
{ buf->writestring(",\n");
|
||||||
|
offset = buf->offset;
|
||||||
|
}
|
||||||
|
s->toJsonBuffer(buf);
|
||||||
|
}
|
||||||
|
JsonRemoveComma(buf);
|
||||||
|
buf->writestring("]\n");
|
||||||
|
}
|
||||||
|
JsonRemoveComma(buf);
|
||||||
|
|
||||||
|
buf->writestring("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemplateDeclaration::toJsonBuffer(OutBuffer *buf)
|
||||||
|
{
|
||||||
|
//printf("TemplateDeclaration::toJsonBuffer()\n");
|
||||||
|
|
||||||
|
buf->writestring("{\n");
|
||||||
|
|
||||||
|
JsonProperty(buf, Pname, toChars());
|
||||||
|
JsonProperty(buf, Pkind, kind());
|
||||||
|
|
||||||
|
if (prot())
|
||||||
|
JsonProperty(buf, Pprotection, Pprotectionnames[prot()]);
|
||||||
|
|
||||||
|
if (comment)
|
||||||
|
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||||
|
|
||||||
|
if (loc.linnum)
|
||||||
|
JsonProperty(buf, Pline, loc.linnum);
|
||||||
|
|
||||||
|
JsonString(buf, Pmembers);
|
||||||
|
buf->writestring(" : [\n");
|
||||||
|
size_t offset = buf->offset;
|
||||||
|
for (size_t i = 0; i < members->dim; i++)
|
||||||
|
{ Dsymbol *s = members->tdata()[i];
|
||||||
|
if (offset != buf->offset)
|
||||||
|
{ buf->writestring(",\n");
|
||||||
|
offset = buf->offset;
|
||||||
|
}
|
||||||
|
s->toJsonBuffer(buf);
|
||||||
|
}
|
||||||
|
JsonRemoveComma(buf);
|
||||||
|
buf->writestring("]\n");
|
||||||
|
|
||||||
|
buf->writestring("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnumDeclaration::toJsonBuffer(OutBuffer *buf)
|
||||||
|
{
|
||||||
|
//printf("EnumDeclaration::toJsonBuffer()\n");
|
||||||
|
if (isAnonymous())
|
||||||
|
{
|
||||||
|
if (members)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < members->dim; i++)
|
||||||
|
{
|
||||||
|
Dsymbol *s = members->tdata()[i];
|
||||||
|
s->toJsonBuffer(buf);
|
||||||
|
buf->writestring(",\n");
|
||||||
|
}
|
||||||
|
JsonRemoveComma(buf);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->writestring("{\n");
|
||||||
|
|
||||||
|
JsonProperty(buf, Pname, toChars());
|
||||||
|
JsonProperty(buf, Pkind, kind());
|
||||||
|
|
||||||
|
if (prot())
|
||||||
|
JsonProperty(buf, Pprotection, Pprotectionnames[prot()]);
|
||||||
|
|
||||||
|
if (comment)
|
||||||
|
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||||
|
|
||||||
|
if (loc.linnum)
|
||||||
|
JsonProperty(buf, Pline, loc.linnum);
|
||||||
|
|
||||||
|
if (memtype)
|
||||||
|
JsonProperty(buf, "base", memtype->toChars());
|
||||||
|
|
||||||
|
if (members)
|
||||||
|
{
|
||||||
|
JsonString(buf, Pmembers);
|
||||||
|
buf->writestring(" : [\n");
|
||||||
|
size_t offset = buf->offset;
|
||||||
|
for (size_t i = 0; i < members->dim; i++)
|
||||||
|
{ Dsymbol *s = members->tdata()[i];
|
||||||
|
if (offset != buf->offset)
|
||||||
|
{ buf->writestring(",\n");
|
||||||
|
offset = buf->offset;
|
||||||
|
}
|
||||||
|
s->toJsonBuffer(buf);
|
||||||
|
}
|
||||||
|
JsonRemoveComma(buf);
|
||||||
|
buf->writestring("]\n");
|
||||||
|
}
|
||||||
|
JsonRemoveComma(buf);
|
||||||
|
|
||||||
|
buf->writestring("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnumMember::toJsonBuffer(OutBuffer *buf)
|
||||||
|
{
|
||||||
|
//printf("EnumMember::toJsonBuffer()\n");
|
||||||
|
buf->writestring("{\n");
|
||||||
|
|
||||||
|
JsonProperty(buf, Pname, toChars());
|
||||||
|
JsonProperty(buf, Pkind, kind());
|
||||||
|
|
||||||
|
if (prot())
|
||||||
|
JsonProperty(buf, Pprotection, Pprotectionnames[prot()]);
|
||||||
|
|
||||||
|
if (comment)
|
||||||
|
JsonProperty(buf, Pcomment, (const char *)comment);
|
||||||
|
|
||||||
|
if (loc.linnum)
|
||||||
|
JsonProperty(buf, Pline, loc.linnum);
|
||||||
|
|
||||||
|
JsonRemoveComma(buf);
|
||||||
|
buf->writestring("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2008 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_JSON_H
|
||||||
|
#define DMD_JSON_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include "arraytypes.h"
|
||||||
|
|
||||||
|
void json_generate(Modules *);
|
||||||
|
|
||||||
|
#endif /* DMD_JSON_H */
|
||||||
|
|
||||||
+3216
File diff suppressed because it is too large
Load Diff
+321
@@ -0,0 +1,321 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2010 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_LEXER_H
|
||||||
|
#define DMD_LEXER_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "mars.h"
|
||||||
|
|
||||||
|
struct StringTable;
|
||||||
|
struct Identifier;
|
||||||
|
struct Module;
|
||||||
|
|
||||||
|
/* Tokens:
|
||||||
|
( )
|
||||||
|
[ ]
|
||||||
|
{ }
|
||||||
|
< > <= >= == != === !==
|
||||||
|
<< >> <<= >>= >>> >>>=
|
||||||
|
+ - += -=
|
||||||
|
* / % *= /= %=
|
||||||
|
& | ^ &= |= ^=
|
||||||
|
= ! ~ @
|
||||||
|
^^ ^^=
|
||||||
|
++ --
|
||||||
|
. -> : , =>
|
||||||
|
? && ||
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum TOK
|
||||||
|
{
|
||||||
|
TOKreserved,
|
||||||
|
|
||||||
|
// Other
|
||||||
|
TOKlparen, TOKrparen,
|
||||||
|
TOKlbracket, TOKrbracket,
|
||||||
|
TOKlcurly, TOKrcurly,
|
||||||
|
TOKcolon, TOKneg,
|
||||||
|
TOKsemicolon, TOKdotdotdot,
|
||||||
|
TOKeof, TOKcast,
|
||||||
|
TOKnull, TOKassert,
|
||||||
|
TOKtrue, TOKfalse,
|
||||||
|
TOKarray, TOKcall,
|
||||||
|
TOKaddress,
|
||||||
|
TOKtype, TOKthrow,
|
||||||
|
TOKnew, TOKdelete,
|
||||||
|
TOKstar, TOKsymoff,
|
||||||
|
TOKvar, TOKdotvar,
|
||||||
|
TOKdotti, TOKdotexp,
|
||||||
|
TOKdottype, TOKslice,
|
||||||
|
TOKarraylength, TOKversion,
|
||||||
|
TOKmodule, TOKdollar,
|
||||||
|
TOKtemplate, TOKdottd,
|
||||||
|
TOKdeclaration, TOKtypeof,
|
||||||
|
TOKpragma, TOKdsymbol,
|
||||||
|
TOKtypeid, TOKuadd,
|
||||||
|
TOKremove,
|
||||||
|
TOKnewanonclass, TOKcomment,
|
||||||
|
TOKarrayliteral, TOKassocarrayliteral,
|
||||||
|
TOKstructliteral,
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
TOKlt, TOKgt,
|
||||||
|
TOKle, TOKge,
|
||||||
|
TOKequal, TOKnotequal,
|
||||||
|
TOKidentity, TOKnotidentity,
|
||||||
|
TOKindex, TOKis,
|
||||||
|
TOKtobool,
|
||||||
|
|
||||||
|
// 60
|
||||||
|
// NCEG floating point compares
|
||||||
|
// !<>= <> <>= !> !>= !< !<= !<>
|
||||||
|
TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue,
|
||||||
|
|
||||||
|
TOKshl, TOKshr,
|
||||||
|
TOKshlass, TOKshrass,
|
||||||
|
TOKushr, TOKushrass,
|
||||||
|
TOKcat, TOKcatass, // ~ ~=
|
||||||
|
TOKadd, TOKmin, TOKaddass, TOKminass,
|
||||||
|
TOKmul, TOKdiv, TOKmod,
|
||||||
|
TOKmulass, TOKdivass, TOKmodass,
|
||||||
|
TOKand, TOKor, TOKxor,
|
||||||
|
TOKandass, TOKorass, TOKxorass,
|
||||||
|
TOKassign, TOKnot, TOKtilde,
|
||||||
|
TOKplusplus, TOKminusminus, TOKconstruct, TOKblit,
|
||||||
|
TOKdot, TOKarrow, TOKcomma,
|
||||||
|
TOKquestion, TOKandand, TOKoror,
|
||||||
|
TOKpreplusplus, TOKpreminusminus,
|
||||||
|
|
||||||
|
// 106
|
||||||
|
// Numeric literals
|
||||||
|
TOKint32v, TOKuns32v,
|
||||||
|
TOKint64v, TOKuns64v,
|
||||||
|
TOKfloat32v, TOKfloat64v, TOKfloat80v,
|
||||||
|
TOKimaginary32v, TOKimaginary64v, TOKimaginary80v,
|
||||||
|
|
||||||
|
// Char constants
|
||||||
|
TOKcharv, TOKwcharv, TOKdcharv,
|
||||||
|
|
||||||
|
// Leaf operators
|
||||||
|
TOKidentifier, TOKstring,
|
||||||
|
TOKthis, TOKsuper,
|
||||||
|
TOKhalt, TOKtuple,
|
||||||
|
TOKerror,
|
||||||
|
|
||||||
|
// Basic types
|
||||||
|
TOKvoid,
|
||||||
|
TOKint8, TOKuns8,
|
||||||
|
TOKint16, TOKuns16,
|
||||||
|
TOKint32, TOKuns32,
|
||||||
|
TOKint64, TOKuns64,
|
||||||
|
TOKfloat32, TOKfloat64, TOKfloat80,
|
||||||
|
TOKimaginary32, TOKimaginary64, TOKimaginary80,
|
||||||
|
TOKcomplex32, TOKcomplex64, TOKcomplex80,
|
||||||
|
TOKchar, TOKwchar, TOKdchar, TOKbit, TOKbool,
|
||||||
|
TOKcent, TOKucent,
|
||||||
|
|
||||||
|
// 152
|
||||||
|
// Aggregates
|
||||||
|
TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport,
|
||||||
|
TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction,
|
||||||
|
TOKmixin,
|
||||||
|
|
||||||
|
TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport,
|
||||||
|
TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile,
|
||||||
|
TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy,
|
||||||
|
TOKauto, TOKpackage, TOKmanifest, TOKimmutable,
|
||||||
|
|
||||||
|
// Statements
|
||||||
|
TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch,
|
||||||
|
TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith,
|
||||||
|
TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally,
|
||||||
|
TOKasm, TOKforeach, TOKforeach_reverse,
|
||||||
|
TOKscope,
|
||||||
|
TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success,
|
||||||
|
|
||||||
|
// Contracts
|
||||||
|
TOKbody, TOKinvariant,
|
||||||
|
|
||||||
|
// Testing
|
||||||
|
TOKunittest,
|
||||||
|
|
||||||
|
// Added after 1.0
|
||||||
|
TOKargTypes,
|
||||||
|
TOKref,
|
||||||
|
TOKmacro,
|
||||||
|
#if DMDV2
|
||||||
|
TOKtraits,
|
||||||
|
TOKoverloadset,
|
||||||
|
TOKpure,
|
||||||
|
TOKnothrow,
|
||||||
|
TOKtls,
|
||||||
|
TOKgshared,
|
||||||
|
TOKline,
|
||||||
|
TOKfile,
|
||||||
|
TOKshared,
|
||||||
|
TOKat,
|
||||||
|
TOKpow,
|
||||||
|
TOKpowass,
|
||||||
|
TOKgoesto,
|
||||||
|
TOKvector,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// LDC specific
|
||||||
|
#if IN_LLVM
|
||||||
|
TOKgep,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TOKMAX
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TOKwild TOKinout
|
||||||
|
|
||||||
|
#define BASIC_TYPES \
|
||||||
|
TOKwchar: case TOKdchar: \
|
||||||
|
case TOKbit: case TOKbool: case TOKchar: \
|
||||||
|
case TOKint8: case TOKuns8: \
|
||||||
|
case TOKint16: case TOKuns16: \
|
||||||
|
case TOKint32: case TOKuns32: \
|
||||||
|
case TOKint64: case TOKuns64: \
|
||||||
|
case TOKfloat32: case TOKfloat64: case TOKfloat80: \
|
||||||
|
case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: \
|
||||||
|
case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: \
|
||||||
|
case TOKvoid
|
||||||
|
|
||||||
|
#define BASIC_TYPES_X(t) \
|
||||||
|
TOKvoid: t = Type::tvoid; goto LabelX; \
|
||||||
|
case TOKint8: t = Type::tint8; goto LabelX; \
|
||||||
|
case TOKuns8: t = Type::tuns8; goto LabelX; \
|
||||||
|
case TOKint16: t = Type::tint16; goto LabelX; \
|
||||||
|
case TOKuns16: t = Type::tuns16; goto LabelX; \
|
||||||
|
case TOKint32: t = Type::tint32; goto LabelX; \
|
||||||
|
case TOKuns32: t = Type::tuns32; goto LabelX; \
|
||||||
|
case TOKint64: t = Type::tint64; goto LabelX; \
|
||||||
|
case TOKuns64: t = Type::tuns64; goto LabelX; \
|
||||||
|
case TOKfloat32: t = Type::tfloat32; goto LabelX; \
|
||||||
|
case TOKfloat64: t = Type::tfloat64; goto LabelX; \
|
||||||
|
case TOKfloat80: t = Type::tfloat80; goto LabelX; \
|
||||||
|
case TOKimaginary32: t = Type::timaginary32; goto LabelX; \
|
||||||
|
case TOKimaginary64: t = Type::timaginary64; goto LabelX; \
|
||||||
|
case TOKimaginary80: t = Type::timaginary80; goto LabelX; \
|
||||||
|
case TOKcomplex32: t = Type::tcomplex32; goto LabelX; \
|
||||||
|
case TOKcomplex64: t = Type::tcomplex64; goto LabelX; \
|
||||||
|
case TOKcomplex80: t = Type::tcomplex80; goto LabelX; \
|
||||||
|
case TOKbool: t = Type::tbool; goto LabelX; \
|
||||||
|
case TOKchar: t = Type::tchar; goto LabelX; \
|
||||||
|
case TOKwchar: t = Type::twchar; goto LabelX; \
|
||||||
|
case TOKdchar: t = Type::tdchar; goto LabelX; \
|
||||||
|
LabelX
|
||||||
|
|
||||||
|
struct Token
|
||||||
|
{
|
||||||
|
Token *next;
|
||||||
|
unsigned char *ptr; // pointer to first character of this token within buffer
|
||||||
|
enum TOK value;
|
||||||
|
unsigned char *blockComment; // doc comment string prior to this token
|
||||||
|
unsigned char *lineComment; // doc comment for previous token
|
||||||
|
union
|
||||||
|
{
|
||||||
|
// Integers
|
||||||
|
d_int32 int32value;
|
||||||
|
d_uns32 uns32value;
|
||||||
|
d_int64 int64value;
|
||||||
|
d_uns64 uns64value;
|
||||||
|
|
||||||
|
// Floats
|
||||||
|
#ifdef IN_GCC
|
||||||
|
// real_t float80value; // can't use this in a union!
|
||||||
|
#else
|
||||||
|
d_float80 float80value;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct
|
||||||
|
{ unsigned char *ustring; // UTF8 string
|
||||||
|
unsigned len;
|
||||||
|
unsigned char postfix; // 'c', 'w', 'd'
|
||||||
|
};
|
||||||
|
|
||||||
|
Identifier *ident;
|
||||||
|
};
|
||||||
|
#ifdef IN_GCC
|
||||||
|
real_t float80value; // can't use this in a union!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char *tochars[TOKMAX];
|
||||||
|
static void *operator new(size_t sz);
|
||||||
|
|
||||||
|
int isKeyword();
|
||||||
|
void print();
|
||||||
|
const char *toChars();
|
||||||
|
static const char *toChars(enum TOK);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Lexer
|
||||||
|
{
|
||||||
|
static StringTable stringtable;
|
||||||
|
static OutBuffer stringbuffer;
|
||||||
|
static Token *freelist;
|
||||||
|
|
||||||
|
Loc loc; // for error messages
|
||||||
|
|
||||||
|
unsigned char *base; // pointer to start of buffer
|
||||||
|
unsigned char *end; // past end of buffer
|
||||||
|
unsigned char *p; // current character
|
||||||
|
Token token;
|
||||||
|
Module *mod;
|
||||||
|
int doDocComment; // collect doc comment information
|
||||||
|
int anyToken; // !=0 means seen at least one token
|
||||||
|
int commentToken; // !=0 means comments are TOKcomment's
|
||||||
|
|
||||||
|
Lexer(Module *mod,
|
||||||
|
unsigned char *base, unsigned begoffset, unsigned endoffset,
|
||||||
|
int doDocComment, int commentToken);
|
||||||
|
|
||||||
|
static void initKeywords();
|
||||||
|
static Identifier *idPool(const char *s);
|
||||||
|
static Identifier *uniqueId(const char *s);
|
||||||
|
static Identifier *uniqueId(const char *s, int num);
|
||||||
|
|
||||||
|
TOK nextToken();
|
||||||
|
TOK peekNext();
|
||||||
|
TOK peekNext2();
|
||||||
|
void scan(Token *t);
|
||||||
|
Token *peek(Token *t);
|
||||||
|
Token *peekPastParen(Token *t);
|
||||||
|
unsigned escapeSequence();
|
||||||
|
TOK wysiwygStringConstant(Token *t, int tc);
|
||||||
|
TOK hexStringConstant(Token *t);
|
||||||
|
#if DMDV2
|
||||||
|
TOK delimitedStringConstant(Token *t);
|
||||||
|
TOK tokenStringConstant(Token *t);
|
||||||
|
#endif
|
||||||
|
TOK escapeStringConstant(Token *t, int wide);
|
||||||
|
TOK charConstant(Token *t, int wide);
|
||||||
|
void stringPostfix(Token *t);
|
||||||
|
unsigned wchar(unsigned u);
|
||||||
|
TOK number(Token *t);
|
||||||
|
TOK inreal(Token *t);
|
||||||
|
void error(const char *format, ...) IS_PRINTF(2);
|
||||||
|
void error(Loc loc, const char *format, ...) IS_PRINTF(3);
|
||||||
|
void verror(Loc loc, const char *format, va_list ap);
|
||||||
|
void pragma();
|
||||||
|
unsigned decodeUTF();
|
||||||
|
void getDocComment(Token *t, unsigned lineComment);
|
||||||
|
|
||||||
|
static int isValidIdentifier(char *p);
|
||||||
|
static unsigned char *combineComments(unsigned char *c1, unsigned char *c2);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DMD_LEXER_H */
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2008 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_LIB_H
|
||||||
|
#define DMD_LIB_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
struct ObjModule;
|
||||||
|
|
||||||
|
struct ObjSymbol
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
ObjModule *om;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "arraytypes.h"
|
||||||
|
|
||||||
|
typedef ArrayBase<ObjModule> ObjModules;
|
||||||
|
typedef ArrayBase<ObjSymbol> ObjSymbols;
|
||||||
|
|
||||||
|
struct Library
|
||||||
|
{
|
||||||
|
File *libfile;
|
||||||
|
ObjModules objmodules; // ObjModule[]
|
||||||
|
ObjSymbols objsymbols; // ObjSymbol[]
|
||||||
|
|
||||||
|
StringTable tab;
|
||||||
|
|
||||||
|
Library();
|
||||||
|
void setFilename(char *dir, char *filename);
|
||||||
|
void addObject(const char *module_name, void *buf, size_t buflen);
|
||||||
|
void addLibrary(void *buf, size_t buflen);
|
||||||
|
void write();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addSymbol(ObjModule *om, char *name, int pickAny = 0);
|
||||||
|
void scanObjModule(ObjModule *om);
|
||||||
|
unsigned short numDictPages(unsigned padding);
|
||||||
|
int FillDict(unsigned char *bucketsP, unsigned short uNumPages);
|
||||||
|
void WriteLibToBuffer(OutBuffer *libbuf);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DMD_LIB_H */
|
||||||
|
|
||||||
+449
@@ -0,0 +1,449 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2006 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
/* Simple macro text processor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "rmem.h"
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
#include "macro.h"
|
||||||
|
|
||||||
|
#define isidstart(c) (isalpha(c) || (c) == '_')
|
||||||
|
#define isidchar(c) (isalnum(c) || (c) == '_')
|
||||||
|
|
||||||
|
unsigned char *memdup(unsigned char *p, size_t len)
|
||||||
|
{
|
||||||
|
return (unsigned char *)memcpy(mem.malloc(len), p, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
Macro::Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen)
|
||||||
|
{
|
||||||
|
next = NULL;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
this->name = name;
|
||||||
|
this->namelen = namelen;
|
||||||
|
|
||||||
|
this->text = text;
|
||||||
|
this->textlen = textlen;
|
||||||
|
#else
|
||||||
|
this->name = name;
|
||||||
|
this->namelen = namelen;
|
||||||
|
|
||||||
|
this->text = text;
|
||||||
|
this->textlen = textlen;
|
||||||
|
#endif
|
||||||
|
inuse = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Macro *Macro::search(unsigned char *name, size_t namelen)
|
||||||
|
{ Macro *table;
|
||||||
|
|
||||||
|
//printf("Macro::search(%.*s)\n", namelen, name);
|
||||||
|
for (table = this; table; table = table->next)
|
||||||
|
{
|
||||||
|
if (table->namelen == namelen &&
|
||||||
|
memcmp(table->name, name, namelen) == 0)
|
||||||
|
{
|
||||||
|
//printf("\tfound %d\n", table->textlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
Macro *Macro::define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen)
|
||||||
|
{
|
||||||
|
//printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text);
|
||||||
|
|
||||||
|
Macro *table;
|
||||||
|
|
||||||
|
//assert(ptable);
|
||||||
|
for (table = *ptable; table; table = table->next)
|
||||||
|
{
|
||||||
|
if (table->namelen == namelen &&
|
||||||
|
memcmp(table->name, name, namelen) == 0)
|
||||||
|
{
|
||||||
|
table->text = text;
|
||||||
|
table->textlen = textlen;
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table = new Macro(name, namelen, text, textlen);
|
||||||
|
table->next = *ptable;
|
||||||
|
*ptable = table;
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************
|
||||||
|
* Given buffer p[0..end], extract argument marg[0..marglen].
|
||||||
|
* Params:
|
||||||
|
* n 0: get entire argument
|
||||||
|
* 1..9: get nth argument
|
||||||
|
* -1: get 2nd through end
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned extractArgN(unsigned char *p, unsigned end, unsigned char **pmarg, unsigned *pmarglen, int n)
|
||||||
|
{
|
||||||
|
/* Scan forward for matching right parenthesis.
|
||||||
|
* Nest parentheses.
|
||||||
|
* Skip over $( and $)
|
||||||
|
* Skip over "..." and '...' strings inside HTML tags.
|
||||||
|
* Skip over <!-- ... --> comments.
|
||||||
|
* Skip over previous macro insertions
|
||||||
|
* Set marglen.
|
||||||
|
*/
|
||||||
|
unsigned parens = 1;
|
||||||
|
unsigned char instring = 0;
|
||||||
|
unsigned incomment = 0;
|
||||||
|
unsigned intag = 0;
|
||||||
|
unsigned inexp = 0;
|
||||||
|
unsigned argn = 0;
|
||||||
|
|
||||||
|
unsigned v = 0;
|
||||||
|
|
||||||
|
Largstart:
|
||||||
|
#if 1
|
||||||
|
// Skip first space, if any, to find the start of the macro argument
|
||||||
|
if (v < end && isspace(p[v]))
|
||||||
|
v++;
|
||||||
|
#else
|
||||||
|
// Skip past spaces to find the start of the macro argument
|
||||||
|
for (; v < end && isspace(p[v]); v++)
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
*pmarg = p + v;
|
||||||
|
|
||||||
|
for (; v < end; v++)
|
||||||
|
{ unsigned char c = p[v];
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ',':
|
||||||
|
if (!inexp && !instring && !incomment && parens == 1)
|
||||||
|
{
|
||||||
|
argn++;
|
||||||
|
if (argn == 1 && n == -1)
|
||||||
|
{ v++;
|
||||||
|
goto Largstart;
|
||||||
|
}
|
||||||
|
if (argn == n)
|
||||||
|
break;
|
||||||
|
if (argn + 1 == n)
|
||||||
|
{ v++;
|
||||||
|
goto Largstart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '(':
|
||||||
|
if (!inexp && !instring && !incomment)
|
||||||
|
parens++;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case ')':
|
||||||
|
if (!inexp && !instring && !incomment && --parens == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
if (!inexp && !incomment && intag)
|
||||||
|
{
|
||||||
|
if (c == instring)
|
||||||
|
instring = 0;
|
||||||
|
else if (!instring)
|
||||||
|
instring = c;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '<':
|
||||||
|
if (!inexp && !instring && !incomment)
|
||||||
|
{
|
||||||
|
if (v + 6 < end &&
|
||||||
|
p[v + 1] == '!' &&
|
||||||
|
p[v + 2] == '-' &&
|
||||||
|
p[v + 3] == '-')
|
||||||
|
{
|
||||||
|
incomment = 1;
|
||||||
|
v += 3;
|
||||||
|
}
|
||||||
|
else if (v + 2 < end &&
|
||||||
|
isalpha(p[v + 1]))
|
||||||
|
intag = 1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '>':
|
||||||
|
if (!inexp)
|
||||||
|
intag = 0;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
if (!inexp &&
|
||||||
|
!instring &&
|
||||||
|
incomment &&
|
||||||
|
v + 2 < end &&
|
||||||
|
p[v + 1] == '-' &&
|
||||||
|
p[v + 2] == '>')
|
||||||
|
{
|
||||||
|
incomment = 0;
|
||||||
|
v += 2;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 0xFF:
|
||||||
|
if (v + 1 < end)
|
||||||
|
{
|
||||||
|
if (p[v + 1] == '{')
|
||||||
|
inexp++;
|
||||||
|
else if (p[v + 1] == '}')
|
||||||
|
inexp--;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (argn == 0 && n == -1)
|
||||||
|
*pmarg = p + v;
|
||||||
|
*pmarglen = p + v - *pmarg;
|
||||||
|
//printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************
|
||||||
|
* Expand macro in place in buf.
|
||||||
|
* Only look at the text in buf from start to end.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Macro::expand(OutBuffer *buf, unsigned start, unsigned *pend,
|
||||||
|
unsigned char *arg, unsigned arglen)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, *pend, arglen, arg);
|
||||||
|
printf("Buf is: '%.*s'\n", *pend - start, buf->data + start);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int nest;
|
||||||
|
if (nest > 100) // limit recursive expansion
|
||||||
|
return;
|
||||||
|
nest++;
|
||||||
|
|
||||||
|
unsigned end = *pend;
|
||||||
|
assert(start <= end);
|
||||||
|
assert(end <= buf->offset);
|
||||||
|
|
||||||
|
/* First pass - replace $0
|
||||||
|
*/
|
||||||
|
arg = memdup(arg, arglen);
|
||||||
|
for (unsigned u = start; u + 1 < end; )
|
||||||
|
{
|
||||||
|
unsigned char *p = buf->data; // buf->data is not loop invariant
|
||||||
|
|
||||||
|
/* Look for $0, but not $$0, and replace it with arg.
|
||||||
|
*/
|
||||||
|
if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+'))
|
||||||
|
{
|
||||||
|
if (u > start && p[u - 1] == '$')
|
||||||
|
{ // Don't expand $$0, but replace it with $0
|
||||||
|
buf->remove(u - 1, 1);
|
||||||
|
end--;
|
||||||
|
u += 1; // now u is one past the closing '1'
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char c = p[u + 1];
|
||||||
|
int n = (c == '+') ? -1 : c - '0';
|
||||||
|
|
||||||
|
unsigned char *marg;
|
||||||
|
unsigned marglen;
|
||||||
|
extractArgN(arg, arglen, &marg, &marglen, n);
|
||||||
|
if (marglen == 0)
|
||||||
|
{ // Just remove macro invocation
|
||||||
|
//printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
|
||||||
|
buf->remove(u, 2);
|
||||||
|
end -= 2;
|
||||||
|
}
|
||||||
|
else if (c == '+')
|
||||||
|
{
|
||||||
|
// Replace '$+' with 'arg'
|
||||||
|
//printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
|
||||||
|
buf->remove(u, 2);
|
||||||
|
buf->insert(u, marg, marglen);
|
||||||
|
end += marglen - 2;
|
||||||
|
|
||||||
|
// Scan replaced text for further expansion
|
||||||
|
unsigned mend = u + marglen;
|
||||||
|
expand(buf, u, &mend, NULL, 0);
|
||||||
|
end += mend - (u + marglen);
|
||||||
|
u = mend;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Replace '$1' with '\xFF{arg\xFF}'
|
||||||
|
//printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg);
|
||||||
|
buf->data[u] = 0xFF;
|
||||||
|
buf->data[u + 1] = '{';
|
||||||
|
buf->insert(u + 2, marg, marglen);
|
||||||
|
buf->insert(u + 2 + marglen, "\xFF}", 2);
|
||||||
|
end += -2 + 2 + marglen + 2;
|
||||||
|
|
||||||
|
// Scan replaced text for further expansion
|
||||||
|
unsigned mend = u + 2 + marglen;
|
||||||
|
expand(buf, u + 2, &mend, NULL, 0);
|
||||||
|
end += mend - (u + 2 + marglen);
|
||||||
|
u = mend;
|
||||||
|
}
|
||||||
|
//printf("u = %d, end = %d\n", u, end);
|
||||||
|
//printf("#%.*s#\n", end, &buf->data[0]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
u++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Second pass - replace other macros
|
||||||
|
*/
|
||||||
|
for (unsigned u = start; u + 4 < end; )
|
||||||
|
{
|
||||||
|
unsigned char *p = buf->data; // buf->data is not loop invariant
|
||||||
|
|
||||||
|
/* A valid start of macro expansion is $(c, where c is
|
||||||
|
* an id start character, and not $$(c.
|
||||||
|
*/
|
||||||
|
if (p[u] == '$' && p[u + 1] == '(' && isidstart(p[u + 2]))
|
||||||
|
{
|
||||||
|
//printf("\tfound macro start '%c'\n", p[u + 2]);
|
||||||
|
unsigned char *name = p + u + 2;
|
||||||
|
unsigned namelen = 0;
|
||||||
|
|
||||||
|
unsigned char *marg;
|
||||||
|
unsigned marglen;
|
||||||
|
|
||||||
|
unsigned v;
|
||||||
|
/* Scan forward to find end of macro name and
|
||||||
|
* beginning of macro argument (marg).
|
||||||
|
*/
|
||||||
|
for (v = u + 2; v < end; v++)
|
||||||
|
{ unsigned char c = p[v];
|
||||||
|
|
||||||
|
if (!isidchar(c))
|
||||||
|
{ // We've gone past the end of the macro name.
|
||||||
|
namelen = v - (u + 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v += extractArgN(p + v, end - v, &marg, &marglen, 0);
|
||||||
|
assert(v <= end);
|
||||||
|
|
||||||
|
if (v < end)
|
||||||
|
{ // v is on the closing ')'
|
||||||
|
if (u > start && p[u - 1] == '$')
|
||||||
|
{ // Don't expand $$(NAME), but replace it with $(NAME)
|
||||||
|
buf->remove(u - 1, 1);
|
||||||
|
end--;
|
||||||
|
u = v; // now u is one past the closing ')'
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Macro *m = search(name, namelen);
|
||||||
|
if (m)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if (m->textlen && m->text[0] == ' ')
|
||||||
|
{ m->text++;
|
||||||
|
m->textlen--;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (m->inuse && marglen == 0)
|
||||||
|
{ // Remove macro invocation
|
||||||
|
buf->remove(u, v + 1 - u);
|
||||||
|
end -= v + 1 - u;
|
||||||
|
}
|
||||||
|
else if (m->inuse && arglen == marglen && memcmp(arg, marg, arglen) == 0)
|
||||||
|
{ // Recursive expansion; just leave in place
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text);
|
||||||
|
#if 1
|
||||||
|
marg = memdup(marg, marglen);
|
||||||
|
// Insert replacement text
|
||||||
|
buf->spread(v + 1, 2 + m->textlen + 2);
|
||||||
|
buf->data[v + 1] = 0xFF;
|
||||||
|
buf->data[v + 2] = '{';
|
||||||
|
memcpy(buf->data + v + 3, m->text, m->textlen);
|
||||||
|
buf->data[v + 3 + m->textlen] = 0xFF;
|
||||||
|
buf->data[v + 3 + m->textlen + 1] = '}';
|
||||||
|
|
||||||
|
end += 2 + m->textlen + 2;
|
||||||
|
|
||||||
|
// Scan replaced text for further expansion
|
||||||
|
m->inuse++;
|
||||||
|
unsigned mend = v + 1 + 2+m->textlen+2;
|
||||||
|
expand(buf, v + 1, &mend, marg, marglen);
|
||||||
|
end += mend - (v + 1 + 2+m->textlen+2);
|
||||||
|
m->inuse--;
|
||||||
|
|
||||||
|
buf->remove(u, v + 1 - u);
|
||||||
|
end -= v + 1 - u;
|
||||||
|
u += mend - (v + 1);
|
||||||
|
#else
|
||||||
|
// Insert replacement text
|
||||||
|
buf->insert(v + 1, m->text, m->textlen);
|
||||||
|
end += m->textlen;
|
||||||
|
|
||||||
|
// Scan replaced text for further expansion
|
||||||
|
m->inuse++;
|
||||||
|
unsigned mend = v + 1 + m->textlen;
|
||||||
|
expand(buf, v + 1, &mend, marg, marglen);
|
||||||
|
end += mend - (v + 1 + m->textlen);
|
||||||
|
m->inuse--;
|
||||||
|
|
||||||
|
buf->remove(u, v + 1 - u);
|
||||||
|
end -= v + 1 - u;
|
||||||
|
u += mend - (v + 1);
|
||||||
|
#endif
|
||||||
|
mem.free(marg);
|
||||||
|
//printf("u = %d, end = %d\n", u, end);
|
||||||
|
//printf("#%.*s#\n", end - u, &buf->data[u]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Replace $(NAME) with nothing
|
||||||
|
buf->remove(u, v + 1 - u);
|
||||||
|
end -= (v + 1 - u);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u++;
|
||||||
|
}
|
||||||
|
mem.free(arg);
|
||||||
|
*pend = end;
|
||||||
|
nest--;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_MACRO_H
|
||||||
|
#define DMD_MACRO_H 1
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct Macro
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Macro *next; // next in list
|
||||||
|
|
||||||
|
unsigned char *name; // macro name
|
||||||
|
size_t namelen; // length of macro name
|
||||||
|
|
||||||
|
unsigned char *text; // macro replacement text
|
||||||
|
size_t textlen; // length of replacement text
|
||||||
|
|
||||||
|
int inuse; // macro is in use (don't expand)
|
||||||
|
|
||||||
|
Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen);
|
||||||
|
Macro *search(unsigned char *name, size_t namelen);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Macro *define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen);
|
||||||
|
|
||||||
|
void expand(OutBuffer *buf, unsigned start, unsigned *pend,
|
||||||
|
unsigned char *arg, unsigned arglen);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+303
@@ -0,0 +1,303 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2010 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
#include "init.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "attrib.h"
|
||||||
|
#include "template.h"
|
||||||
|
#include "id.h"
|
||||||
|
#include "module.h"
|
||||||
|
|
||||||
|
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
|
||||||
|
char *cpp_mangle(Dsymbol *s);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *mangle(Declaration *sthis)
|
||||||
|
{
|
||||||
|
OutBuffer buf;
|
||||||
|
char *id;
|
||||||
|
Dsymbol *s;
|
||||||
|
|
||||||
|
//printf("::mangle(%s)\n", sthis->toChars());
|
||||||
|
s = sthis;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
//printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent);
|
||||||
|
if (s->ident)
|
||||||
|
{
|
||||||
|
FuncDeclaration *fd = s->isFuncDeclaration();
|
||||||
|
if (s != sthis && fd)
|
||||||
|
{
|
||||||
|
id = mangle(fd);
|
||||||
|
buf.prependstring(id);
|
||||||
|
goto L1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
id = s->ident->toChars();
|
||||||
|
int len = strlen(id);
|
||||||
|
char tmp[sizeof(len) * 3 + 1];
|
||||||
|
buf.prependstring(id);
|
||||||
|
sprintf(tmp, "%d", len);
|
||||||
|
buf.prependstring(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
buf.prependstring("0");
|
||||||
|
s = s->parent;
|
||||||
|
} while (s);
|
||||||
|
|
||||||
|
// buf.prependstring("_D");
|
||||||
|
L1:
|
||||||
|
//printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null");
|
||||||
|
//printf("sthis->type = %s\n", sthis->type->toChars());
|
||||||
|
FuncDeclaration *fd = sthis->isFuncDeclaration();
|
||||||
|
if (fd && (fd->needThis() || fd->isNested()))
|
||||||
|
buf.writeByte(Type::needThisPrefix());
|
||||||
|
if (sthis->type->deco)
|
||||||
|
buf.writestring(sthis->type->deco);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (!fd->inferRetType)
|
||||||
|
printf("%s\n", fd->toChars());
|
||||||
|
#endif
|
||||||
|
assert(fd && fd->inferRetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
id = buf.toChars();
|
||||||
|
buf.data = NULL;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Declaration::mangle()
|
||||||
|
#if __DMC__
|
||||||
|
__out(result)
|
||||||
|
{
|
||||||
|
int len = strlen(result);
|
||||||
|
|
||||||
|
assert(len > 0);
|
||||||
|
//printf("mangle: '%s' => '%s'\n", toChars(), result);
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
assert(result[i] == '_' ||
|
||||||
|
result[i] == '@' ||
|
||||||
|
isalnum(result[i]) || result[i] & 0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__body
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
//printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", this, toChars(), parent ? parent->toChars() : "null", linkage);
|
||||||
|
if (!parent || parent->isModule() || linkage == LINKcpp) // if at global scope
|
||||||
|
{
|
||||||
|
// If it's not a D declaration, no mangling
|
||||||
|
switch (linkage)
|
||||||
|
{
|
||||||
|
case LINKd:
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
case LINKintrinsic:
|
||||||
|
#endif
|
||||||
|
case LINKc:
|
||||||
|
case LINKwindows:
|
||||||
|
case LINKpascal:
|
||||||
|
return ident->toChars();
|
||||||
|
|
||||||
|
case LINKcpp:
|
||||||
|
#if CPP_MANGLE
|
||||||
|
return cpp_mangle(this);
|
||||||
|
#else
|
||||||
|
// Windows C++ mangling is done by C++ back end
|
||||||
|
return ident->toChars();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case LINKdefault:
|
||||||
|
error("forward declaration");
|
||||||
|
return ident->toChars();
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stdmsg, "'%s', linkage = %d\n", toChars(), linkage);
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char *p = ::mangle(this);
|
||||||
|
OutBuffer buf;
|
||||||
|
buf.writestring("_D");
|
||||||
|
buf.writestring(p);
|
||||||
|
p = buf.toChars();
|
||||||
|
buf.data = NULL;
|
||||||
|
//printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d) = %s\n", this, toChars(), parent ? parent->toChars() : "null", linkage, p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *FuncDeclaration::mangle()
|
||||||
|
#if __DMC__
|
||||||
|
__out(result)
|
||||||
|
{
|
||||||
|
assert(strlen(result) > 0);
|
||||||
|
}
|
||||||
|
__body
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (isMain())
|
||||||
|
return (char *)"_Dmain";
|
||||||
|
|
||||||
|
if (isWinMain() || isDllMain() || ident == Id::tls_get_addr)
|
||||||
|
return ident->toChars();
|
||||||
|
|
||||||
|
assert(this);
|
||||||
|
return Declaration::mangle();
|
||||||
|
}
|
||||||
|
|
||||||
|
char *StructDeclaration::mangle()
|
||||||
|
{
|
||||||
|
//printf("StructDeclaration::mangle() '%s'\n", toChars());
|
||||||
|
return Dsymbol::mangle();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *TypedefDeclaration::mangle()
|
||||||
|
{
|
||||||
|
//printf("TypedefDeclaration::mangle() '%s'\n", toChars());
|
||||||
|
return Dsymbol::mangle();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *ClassDeclaration::mangle()
|
||||||
|
{
|
||||||
|
Dsymbol *parentsave = parent;
|
||||||
|
|
||||||
|
//printf("ClassDeclaration::mangle() %s.%s\n", parent->toChars(), toChars());
|
||||||
|
|
||||||
|
/* These are reserved to the compiler, so keep simple
|
||||||
|
* names for them.
|
||||||
|
*/
|
||||||
|
if (ident == Id::Exception)
|
||||||
|
{ if (parent->ident == Id::object)
|
||||||
|
parent = NULL;
|
||||||
|
}
|
||||||
|
else if (ident == Id::TypeInfo ||
|
||||||
|
// ident == Id::Exception ||
|
||||||
|
ident == Id::TypeInfo_Struct ||
|
||||||
|
ident == Id::TypeInfo_Class ||
|
||||||
|
ident == Id::TypeInfo_Typedef ||
|
||||||
|
ident == Id::TypeInfo_Tuple ||
|
||||||
|
this == object ||
|
||||||
|
this == classinfo ||
|
||||||
|
#if !MODULEINFO_IS_STRUCT
|
||||||
|
this == Module::moduleinfo ||
|
||||||
|
#endif
|
||||||
|
memcmp(ident->toChars(), "TypeInfo_", 9) == 0
|
||||||
|
)
|
||||||
|
parent = NULL;
|
||||||
|
|
||||||
|
char *id = Dsymbol::mangle();
|
||||||
|
parent = parentsave;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *TemplateInstance::mangle()
|
||||||
|
{
|
||||||
|
OutBuffer buf;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printf("TemplateInstance::mangle() %p %s", this, toChars());
|
||||||
|
if (parent)
|
||||||
|
printf(" parent = %s %s", parent->kind(), parent->toChars());
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
char *id = ident ? ident->toChars() : toChars();
|
||||||
|
if (!tempdecl)
|
||||||
|
error("is not defined");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Dsymbol *par = isnested || isTemplateMixin() ? parent : tempdecl->parent;
|
||||||
|
if (par)
|
||||||
|
{
|
||||||
|
char *p = par->mangle();
|
||||||
|
if (p[0] == '_' && p[1] == 'D')
|
||||||
|
p += 2;
|
||||||
|
buf.writestring(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.printf("%zu%s", strlen(id), id);
|
||||||
|
id = buf.toChars();
|
||||||
|
buf.data = NULL;
|
||||||
|
//printf("TemplateInstance::mangle() %s = %s\n", toChars(), id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
char *TemplateMixin::mangle()
|
||||||
|
{
|
||||||
|
OutBuffer buf;
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printf("TemplateMixin::mangle() %s", toChars());
|
||||||
|
if (parent)
|
||||||
|
printf(" parent = %s %s", parent->kind(), parent->toChars());
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
id = ident ? ident->toChars() : toChars();
|
||||||
|
if (parent)
|
||||||
|
{
|
||||||
|
char *p = parent->mangle();
|
||||||
|
if (p[0] == '_' && p[1] == 'D')
|
||||||
|
p += 2;
|
||||||
|
buf.writestring(p);
|
||||||
|
}
|
||||||
|
buf.printf("%zu%s", strlen(id), id);
|
||||||
|
id = buf.toChars();
|
||||||
|
buf.data = NULL;
|
||||||
|
//printf("TemplateMixin::mangle() %s = %s\n", toChars(), id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *Dsymbol::mangle()
|
||||||
|
{
|
||||||
|
OutBuffer buf;
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printf("Dsymbol::mangle() '%s'", toChars());
|
||||||
|
if (parent)
|
||||||
|
printf(" parent = %s %s", parent->kind(), parent->toChars());
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
id = ident ? ident->toChars() : toChars();
|
||||||
|
if (parent)
|
||||||
|
{
|
||||||
|
char *p = parent->mangle();
|
||||||
|
if (p[0] == '_' && p[1] == 'D')
|
||||||
|
p += 2;
|
||||||
|
buf.writestring(p);
|
||||||
|
}
|
||||||
|
buf.printf("%zu%s", strlen(id), id);
|
||||||
|
id = buf.toChars();
|
||||||
|
buf.data = NULL;
|
||||||
|
//printf("Dsymbol::mangle() %s = %s\n", toChars(), id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+1605
File diff suppressed because it is too large
Load Diff
+503
@@ -0,0 +1,503 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_MARS_H
|
||||||
|
#define DMD_MARS_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
It is very important to use version control macros correctly - the
|
||||||
|
idea is that host and target are independent. If these are done
|
||||||
|
correctly, cross compilers can be built.
|
||||||
|
The host compiler and host operating system are also different,
|
||||||
|
and are predefined by the host compiler. The ones used in
|
||||||
|
dmd are:
|
||||||
|
|
||||||
|
Macros defined by the compiler, not the code:
|
||||||
|
|
||||||
|
Compiler:
|
||||||
|
__DMC__ Digital Mars compiler
|
||||||
|
_MSC_VER Microsoft compiler
|
||||||
|
__GNUC__ Gnu compiler
|
||||||
|
__clang__ Clang compiler
|
||||||
|
|
||||||
|
Host operating system:
|
||||||
|
_WIN32 Microsoft NT, Windows 95, Windows 98, Win32s,
|
||||||
|
Windows 2000, Win XP, Vista
|
||||||
|
_WIN64 Windows for AMD64
|
||||||
|
linux Linux
|
||||||
|
__APPLE__ Mac OSX
|
||||||
|
__FreeBSD__ FreeBSD
|
||||||
|
__OpenBSD__ OpenBSD
|
||||||
|
__sun&&__SVR4 Solaris, OpenSolaris (yes, both macros are necessary)
|
||||||
|
|
||||||
|
For the target systems, there are the target operating system and
|
||||||
|
the target object file format:
|
||||||
|
|
||||||
|
Target operating system:
|
||||||
|
TARGET_WINDOS Covers 32 bit windows and 64 bit windows
|
||||||
|
TARGET_LINUX Covers 32 and 64 bit linux
|
||||||
|
TARGET_OSX Covers 32 and 64 bit Mac OSX
|
||||||
|
TARGET_FREEBSD Covers 32 and 64 bit FreeBSD
|
||||||
|
TARGET_OPENBSD Covers 32 and 64 bit OpenBSD
|
||||||
|
TARGET_SOLARIS Covers 32 and 64 bit Solaris
|
||||||
|
TARGET_NET Covers .Net
|
||||||
|
|
||||||
|
It is expected that the compiler for each platform will be able
|
||||||
|
to generate 32 and 64 bit code from the same compiler binary.
|
||||||
|
|
||||||
|
Target object module format:
|
||||||
|
OMFOBJ Intel Object Module Format, used on Windows
|
||||||
|
ELFOBJ Elf Object Module Format, used on linux, FreeBSD, OpenBSD and Solaris
|
||||||
|
MACHOBJ Mach-O Object Module Format, used on Mac OSX
|
||||||
|
|
||||||
|
There are currently no macros for byte endianness order.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#ifdef DEBUG
|
||||||
|
#undef assert
|
||||||
|
#define assert(e) (static_cast<void>((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt())))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define UNITTEST 1
|
||||||
|
#endif
|
||||||
|
void unittests();
|
||||||
|
|
||||||
|
#ifndef IS_PRINTF
|
||||||
|
# ifdef __GNUC__
|
||||||
|
# define IS_PRINTF(FMTARG) __attribute((__format__ (__printf__, (FMTARG), (FMTARG)+1) ))
|
||||||
|
# else
|
||||||
|
# define IS_PRINTF(FMTARG)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IN_GCC
|
||||||
|
/* Changes for the GDC compiler by David Friedman */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DMDV1 0
|
||||||
|
#define DMDV2 1 // Version 2.0 features
|
||||||
|
#define BREAKABI 1 // 0 if not ready to break the ABI just yet
|
||||||
|
#define STRUCTTHISREF DMDV2 // if 'this' for struct is a reference, not a pointer
|
||||||
|
#define SNAN_DEFAULT_INIT DMDV2 // if floats are default initialized to signalling NaN
|
||||||
|
#define SARRAYVALUE DMDV2 // static arrays are value types
|
||||||
|
#define MODULEINFO_IS_STRUCT DMDV2 // if ModuleInfo is a struct rather than a class
|
||||||
|
|
||||||
|
// Set if C++ mangling is done by the front end
|
||||||
|
#define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS))
|
||||||
|
|
||||||
|
/* Other targets are TARGET_LINUX, TARGET_OSX, TARGET_FREEBSD, TARGET_OPENBSD and
|
||||||
|
* TARGET_SOLARIS, which are
|
||||||
|
* set on the command line via the compiler makefile.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
#ifndef TARGET_WINDOS
|
||||||
|
#define TARGET_WINDOS 1 // Windows dmd generates Windows targets
|
||||||
|
#endif
|
||||||
|
#ifndef OMFOBJ
|
||||||
|
#define OMFOBJ TARGET_WINDOS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
|
||||||
|
#ifndef ELFOBJ
|
||||||
|
#define ELFOBJ 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TARGET_OSX
|
||||||
|
#ifndef MACHOBJ
|
||||||
|
#define MACHOBJ 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct OutBuffer;
|
||||||
|
|
||||||
|
// Can't include arraytypes.h here, need to declare these directly.
|
||||||
|
template <typename TYPE> struct ArrayBase;
|
||||||
|
typedef ArrayBase<struct Identifier> Identifiers;
|
||||||
|
typedef ArrayBase<char> Strings;
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
enum ARCH
|
||||||
|
{
|
||||||
|
ARCHinvalid,
|
||||||
|
ARCHx86,
|
||||||
|
ARCHx86_64,
|
||||||
|
ARCHppc,
|
||||||
|
ARCHppc_64,
|
||||||
|
ARCHarm,
|
||||||
|
ARCHthumb
|
||||||
|
};
|
||||||
|
enum OUTPUTFLAG
|
||||||
|
{
|
||||||
|
OUTPUTFLAGno,
|
||||||
|
OUTPUTFLAGdefault, // for the .o default
|
||||||
|
OUTPUTFLAGset // for -output
|
||||||
|
};
|
||||||
|
|
||||||
|
enum OS
|
||||||
|
{
|
||||||
|
OSinvalid,
|
||||||
|
OSLinux,
|
||||||
|
OSHaiku,
|
||||||
|
OSWindows,
|
||||||
|
OSMacOSX,
|
||||||
|
OSFreeBSD,
|
||||||
|
OSSolaris,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef unsigned char ubyte;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Put command line switches in here
|
||||||
|
struct Param
|
||||||
|
{
|
||||||
|
bool obj; // write object file
|
||||||
|
bool link; // perform link
|
||||||
|
bool verbose; // verbose compile
|
||||||
|
bool vtls; // identify thread local variables
|
||||||
|
ubyte symdebug; // insert debug symbolic information
|
||||||
|
#if !IN_LLVM
|
||||||
|
// LDC uses a different mechanism
|
||||||
|
bool optimize; // run optimizer
|
||||||
|
char optimizeLevel; // optimization level
|
||||||
|
#endif
|
||||||
|
ARCH cpu; // target CPU
|
||||||
|
OS os;
|
||||||
|
bool alwaysframe; // always emit standard stack frame
|
||||||
|
char map; // generate linker .map file
|
||||||
|
bool isLE; // generate little endian code
|
||||||
|
bool is64bit; // generate 64 bit code
|
||||||
|
bool useDeprecated; // allow use of deprecated features
|
||||||
|
bool useAssert; // generate runtime code for assert()'s
|
||||||
|
bool useInvariants; // generate class invariant checks
|
||||||
|
bool useIn; // generate precondition checks
|
||||||
|
bool useOut; // generate postcondition checks
|
||||||
|
bool useArrayBounds; // generate array bounds checks
|
||||||
|
bool useSwitchError; // check for switches without a default
|
||||||
|
bool useUnitTests; // generate unittest code
|
||||||
|
bool useInline; // inline expand functions
|
||||||
|
ubyte warnings; // enable warnings
|
||||||
|
ubyte Dversion; // D version number
|
||||||
|
bool ignoreUnsupportedPragmas; // rather than error on them
|
||||||
|
bool enforcePropertySyntax;
|
||||||
|
|
||||||
|
char *argv0; // program name
|
||||||
|
Strings *imppath; // array of char*'s of where to look for import modules
|
||||||
|
Strings *fileImppath; // array of char*'s of where to look for file import modules
|
||||||
|
char *objdir; // .obj file output directory
|
||||||
|
char *objname; // .obj file output name
|
||||||
|
|
||||||
|
bool doDocComments; // process embedded documentation comments
|
||||||
|
char *docdir; // write documentation file to docdir directory
|
||||||
|
char *docname; // write documentation file to docname
|
||||||
|
Strings *ddocfiles; // macro include files for Ddoc
|
||||||
|
|
||||||
|
bool doHdrGeneration; // process embedded documentation comments
|
||||||
|
char *hdrdir; // write 'header' file to docdir directory
|
||||||
|
char *hdrname; // write 'header' file to docname
|
||||||
|
|
||||||
|
bool doXGeneration; // write JSON file
|
||||||
|
char *xfilename; // write JSON file to xfilename
|
||||||
|
|
||||||
|
unsigned debuglevel; // debug level
|
||||||
|
Strings *debugids; // debug identifiers
|
||||||
|
|
||||||
|
unsigned versionlevel; // version level
|
||||||
|
Strings *versionids; // version identifiers
|
||||||
|
|
||||||
|
bool dump_source;
|
||||||
|
|
||||||
|
Strings *defaultlibnames; // default libraries for non-debug builds
|
||||||
|
Strings *debuglibnames; // default libraries for debug builds
|
||||||
|
|
||||||
|
char *moduleDepsFile; // filename for deps output
|
||||||
|
OutBuffer *moduleDeps; // contents to be written to deps file
|
||||||
|
|
||||||
|
// Hidden debug switches
|
||||||
|
bool debuga;
|
||||||
|
bool debugb;
|
||||||
|
bool debugc;
|
||||||
|
bool debugf;
|
||||||
|
bool debugr;
|
||||||
|
bool debugw;
|
||||||
|
bool debugx;
|
||||||
|
bool debugy;
|
||||||
|
|
||||||
|
bool run; // run resulting executable
|
||||||
|
|
||||||
|
// Linker stuff
|
||||||
|
Strings *objfiles;
|
||||||
|
Strings *linkswitches;
|
||||||
|
Strings *libfiles;
|
||||||
|
char *deffile;
|
||||||
|
char *resfile;
|
||||||
|
char *exefile;
|
||||||
|
char *mapfile;
|
||||||
|
#if IN_LLVM
|
||||||
|
// LDC stuff
|
||||||
|
OUTPUTFLAG output_ll;
|
||||||
|
OUTPUTFLAG output_bc;
|
||||||
|
OUTPUTFLAG output_s;
|
||||||
|
OUTPUTFLAG output_o;
|
||||||
|
bool llvmAnnotate;
|
||||||
|
bool useInlineAsm;
|
||||||
|
bool verbose_cg;
|
||||||
|
bool useAvailableExternally;
|
||||||
|
|
||||||
|
// target stuff
|
||||||
|
const char* llvmArch;
|
||||||
|
const char *targetTriple;
|
||||||
|
const char *dataLayout;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Global
|
||||||
|
{
|
||||||
|
const char *mars_ext;
|
||||||
|
const char *sym_ext;
|
||||||
|
const char *obj_ext;
|
||||||
|
#if IN_LLVM
|
||||||
|
#if _WIN32
|
||||||
|
char *obj_ext_alt;
|
||||||
|
#endif
|
||||||
|
char *ll_ext;
|
||||||
|
char *bc_ext;
|
||||||
|
char *s_ext;
|
||||||
|
#endif
|
||||||
|
const char *lib_ext;
|
||||||
|
const char *dll_ext;
|
||||||
|
const char *doc_ext; // for Ddoc generated files
|
||||||
|
const char *ddoc_ext; // for Ddoc macro include files
|
||||||
|
const char *hdr_ext; // for D 'header' import files
|
||||||
|
const char *json_ext; // for JSON files
|
||||||
|
const char *map_ext; // for .map files
|
||||||
|
const char *copyright;
|
||||||
|
const char *written;
|
||||||
|
Strings *path; // Array of char*'s which form the import lookup path
|
||||||
|
Strings *filePath; // Array of char*'s which form the file import lookup path
|
||||||
|
int structalign;
|
||||||
|
const char *version;
|
||||||
|
#if IN_LLVM
|
||||||
|
char *ldc_version;
|
||||||
|
char *llvm_version;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Param params;
|
||||||
|
unsigned errors; // number of errors reported so far
|
||||||
|
unsigned warnings; // number of warnings reported so far
|
||||||
|
unsigned gag; // !=0 means gag reporting of errors & warnings
|
||||||
|
unsigned gaggedErrors; // number of errors reported while gagged
|
||||||
|
|
||||||
|
// Start gagging. Return the current number of gagged errors
|
||||||
|
unsigned startGagging();
|
||||||
|
|
||||||
|
/* End gagging, restoring the old gagged state.
|
||||||
|
* Return true if errors occured while gagged.
|
||||||
|
*/
|
||||||
|
bool endGagging(unsigned oldGagged);
|
||||||
|
|
||||||
|
Global();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Global global;
|
||||||
|
|
||||||
|
/* Set if Windows Structured Exception Handling C extensions are supported.
|
||||||
|
* Apparently, VC has dropped support for these?
|
||||||
|
*/
|
||||||
|
#define WINDOWS_SEH (_WIN32 && __DMC__)
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
typedef _Complex long double complex_t;
|
||||||
|
#else
|
||||||
|
#ifndef IN_GCC
|
||||||
|
#include "complex_t.h"
|
||||||
|
#endif
|
||||||
|
#ifdef __APPLE__
|
||||||
|
//#include "complex.h"//This causes problems with include the c++ <complex> and not the C "complex.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Be careful not to care about sign when using dinteger_t
|
||||||
|
//typedef uint64_t integer_t;
|
||||||
|
typedef uint64_t dinteger_t; // use this instead of integer_t to
|
||||||
|
// avoid conflicts with system #include's
|
||||||
|
|
||||||
|
// Signed and unsigned variants
|
||||||
|
typedef int64_t sinteger_t;
|
||||||
|
typedef uint64_t uinteger_t;
|
||||||
|
|
||||||
|
typedef int8_t d_int8;
|
||||||
|
typedef uint8_t d_uns8;
|
||||||
|
typedef int16_t d_int16;
|
||||||
|
typedef uint16_t d_uns16;
|
||||||
|
typedef int32_t d_int32;
|
||||||
|
typedef uint32_t d_uns32;
|
||||||
|
typedef int64_t d_int64;
|
||||||
|
typedef uint64_t d_uns64;
|
||||||
|
|
||||||
|
typedef float d_float32;
|
||||||
|
typedef double d_float64;
|
||||||
|
typedef long double d_float80;
|
||||||
|
|
||||||
|
typedef d_uns8 d_char;
|
||||||
|
typedef d_uns16 d_wchar;
|
||||||
|
typedef d_uns32 d_dchar;
|
||||||
|
|
||||||
|
#ifdef IN_GCC
|
||||||
|
#include "d-gcc-real.h"
|
||||||
|
#else
|
||||||
|
typedef long double real_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Modify OutBuffer::writewchar to write the correct size of wchar
|
||||||
|
#if _WIN32
|
||||||
|
#define writewchar writeword
|
||||||
|
#else
|
||||||
|
// This needs a configuration test...
|
||||||
|
#define writewchar write4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IN_GCC
|
||||||
|
#include "d-gcc-complex_t.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Module;
|
||||||
|
|
||||||
|
//typedef unsigned Loc; // file location
|
||||||
|
struct Loc
|
||||||
|
{
|
||||||
|
const char *filename;
|
||||||
|
unsigned linnum;
|
||||||
|
|
||||||
|
Loc()
|
||||||
|
{
|
||||||
|
linnum = 0;
|
||||||
|
filename = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loc(int x)
|
||||||
|
{
|
||||||
|
linnum = x;
|
||||||
|
filename = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loc(Module *mod, unsigned linnum);
|
||||||
|
|
||||||
|
char *toChars();
|
||||||
|
bool equals(const Loc& loc);
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef GCC_SAFE_DMD
|
||||||
|
#define TRUE 1
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define INTERFACE_OFFSET 0 // if 1, put classinfo as first entry
|
||||||
|
// in interface vtbl[]'s
|
||||||
|
#define INTERFACE_VIRTUAL 0 // 1 means if an interface appears
|
||||||
|
// in the inheritance graph multiple
|
||||||
|
// times, only one is used
|
||||||
|
|
||||||
|
enum LINK
|
||||||
|
{
|
||||||
|
LINKdefault,
|
||||||
|
LINKd,
|
||||||
|
LINKc,
|
||||||
|
LINKcpp,
|
||||||
|
LINKwindows,
|
||||||
|
LINKpascal,
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
LINKintrinsic,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DYNCAST
|
||||||
|
{
|
||||||
|
DYNCAST_OBJECT,
|
||||||
|
DYNCAST_EXPRESSION,
|
||||||
|
DYNCAST_DSYMBOL,
|
||||||
|
DYNCAST_TYPE,
|
||||||
|
DYNCAST_IDENTIFIER,
|
||||||
|
DYNCAST_TUPLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MATCH
|
||||||
|
{
|
||||||
|
MATCHnomatch, // no match
|
||||||
|
MATCHconvert, // match with conversions
|
||||||
|
#if DMDV2
|
||||||
|
MATCHconst, // match with conversion to const
|
||||||
|
#endif
|
||||||
|
MATCHexact // exact match
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef uint64_t StorageClass;
|
||||||
|
|
||||||
|
|
||||||
|
void warning(Loc loc, const char *format, ...) IS_PRINTF(2);
|
||||||
|
void error(Loc loc, const char *format, ...) IS_PRINTF(2);
|
||||||
|
void errorSupplemental(Loc loc, const char *format, ...);
|
||||||
|
void verror(Loc loc, const char *format, va_list);
|
||||||
|
void vwarning(Loc loc, const char *format, va_list);
|
||||||
|
void verrorSupplemental(Loc loc, const char *format, va_list);
|
||||||
|
void fatal();
|
||||||
|
void err_nomem();
|
||||||
|
#if IN_LLVM
|
||||||
|
void inifile(char *argv0, const char *inifile);
|
||||||
|
#else
|
||||||
|
int runLINK();
|
||||||
|
void deleteExeFile();
|
||||||
|
int runProgram();
|
||||||
|
const char *inifile(const char *argv0, const char *inifile);
|
||||||
|
#endif
|
||||||
|
void halt();
|
||||||
|
#if !IN_LLVM
|
||||||
|
void util_progress();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*** Where to send error messages ***/
|
||||||
|
#if IN_GCC || IN_LLVM
|
||||||
|
#define stdmsg stderr
|
||||||
|
#else
|
||||||
|
#define stdmsg stderr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !IN_LLVM
|
||||||
|
struct Dsymbol;
|
||||||
|
struct Library;
|
||||||
|
struct File;
|
||||||
|
void obj_start(char *srcfile);
|
||||||
|
void obj_end(Library *library, File *objfile);
|
||||||
|
void obj_append(Dsymbol *s);
|
||||||
|
void obj_write_deferred(Library *library);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *importHint(const char *s);
|
||||||
|
|
||||||
|
#endif /* DMD_MARS_H */
|
||||||
+1365
File diff suppressed because it is too large
Load Diff
+232
@@ -0,0 +1,232 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2008 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_MODULE_H
|
||||||
|
#define DMD_MODULE_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "dsymbol.h"
|
||||||
|
|
||||||
|
struct ModuleInfoDeclaration;
|
||||||
|
struct ClassDeclaration;
|
||||||
|
struct ModuleDeclaration;
|
||||||
|
struct Macro;
|
||||||
|
struct Escape;
|
||||||
|
struct VarDeclaration;
|
||||||
|
struct Library;
|
||||||
|
|
||||||
|
// Back end
|
||||||
|
#if IN_LLVM
|
||||||
|
class Ir;
|
||||||
|
struct DValue;
|
||||||
|
typedef DValue elem;
|
||||||
|
namespace llvm {
|
||||||
|
class LLVMContext;
|
||||||
|
class Module;
|
||||||
|
class GlobalVariable;
|
||||||
|
class StructType;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef IN_GCC
|
||||||
|
union tree_node; typedef union tree_node elem;
|
||||||
|
#else
|
||||||
|
struct elem;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Package : ScopeDsymbol
|
||||||
|
{
|
||||||
|
Package(Identifier *ident);
|
||||||
|
const char *kind();
|
||||||
|
|
||||||
|
static DsymbolTable *resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg);
|
||||||
|
|
||||||
|
Package *isPackage() { return this; }
|
||||||
|
|
||||||
|
virtual void semantic(Scope *sc) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Module : Package
|
||||||
|
{
|
||||||
|
static Module *rootModule;
|
||||||
|
static DsymbolTable *modules; // symbol table of all modules
|
||||||
|
static Modules amodules; // array of all modules
|
||||||
|
static Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them
|
||||||
|
static unsigned dprogress; // progress resolving the deferred list
|
||||||
|
static void init();
|
||||||
|
|
||||||
|
static AggregateDeclaration *moduleinfo;
|
||||||
|
|
||||||
|
const char *arg; // original argument name
|
||||||
|
ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration
|
||||||
|
File *srcfile; // input source file
|
||||||
|
File *objfile; // output .obj file
|
||||||
|
File *hdrfile; // 'header' file
|
||||||
|
File *symfile; // output symbol file
|
||||||
|
File *docfile; // output documentation file
|
||||||
|
|
||||||
|
unsigned errors; // if any errors in file
|
||||||
|
unsigned numlines; // number of lines in source file
|
||||||
|
int isHtml; // if it is an HTML file
|
||||||
|
int isDocFile; // if it is a documentation input file, not D source
|
||||||
|
int needmoduleinfo;
|
||||||
|
#ifdef IN_GCC
|
||||||
|
int strictlyneedmoduleinfo;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int selfimports; // 0: don't know, 1: does not, 2: does
|
||||||
|
int selfImports(); // returns !=0 if module imports itself
|
||||||
|
|
||||||
|
int insearch;
|
||||||
|
Identifier *searchCacheIdent;
|
||||||
|
Dsymbol *searchCacheSymbol; // cached value of search
|
||||||
|
int searchCacheFlags; // cached flags
|
||||||
|
|
||||||
|
int semanticstarted; // has semantic() been started?
|
||||||
|
int semanticRun; // has semantic() been done?
|
||||||
|
int root; // != 0 if this is a 'root' module,
|
||||||
|
// i.e. a module that will be taken all the
|
||||||
|
// way to an object file
|
||||||
|
Module *importedFrom; // module from command line we're imported from,
|
||||||
|
// i.e. a module that will be taken all the
|
||||||
|
// way to an object file
|
||||||
|
|
||||||
|
Dsymbols *decldefs; // top level declarations for this Module
|
||||||
|
|
||||||
|
Modules aimports; // all imported modules
|
||||||
|
|
||||||
|
ModuleInfoDeclaration *vmoduleinfo;
|
||||||
|
|
||||||
|
unsigned debuglevel; // debug level
|
||||||
|
Strings *debugids; // debug identifiers
|
||||||
|
Strings *debugidsNot; // forward referenced debug identifiers
|
||||||
|
|
||||||
|
unsigned versionlevel; // version level
|
||||||
|
Strings *versionids; // version identifiers
|
||||||
|
Strings *versionidsNot; // forward referenced version identifiers
|
||||||
|
|
||||||
|
Macro *macrotable; // document comment macros
|
||||||
|
Escape *escapetable; // document comment escapes
|
||||||
|
bool safe; // TRUE if module is marked as 'safe'
|
||||||
|
|
||||||
|
size_t nameoffset; // offset of module name from start of ModuleInfo
|
||||||
|
size_t namelen; // length of module name in characters
|
||||||
|
|
||||||
|
int doDocComment; // enable generating doc comments for this module
|
||||||
|
int doHdrGen; // enable generating header file for this module
|
||||||
|
|
||||||
|
Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen);
|
||||||
|
~Module();
|
||||||
|
|
||||||
|
static Module *load(Loc loc, Identifiers *packages, Identifier *ident);
|
||||||
|
|
||||||
|
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
|
||||||
|
void toJsonBuffer(OutBuffer *buf);
|
||||||
|
const char *kind();
|
||||||
|
#if !IN_LLVM
|
||||||
|
void setDocfile(); // set docfile member
|
||||||
|
#endif
|
||||||
|
void read(Loc loc); // read file
|
||||||
|
#if IN_LLVM
|
||||||
|
void parse(bool gen_docs = false); // syntactic parse
|
||||||
|
#elif IN_GCC
|
||||||
|
void parse(bool dump_source = false); // syntactic parse
|
||||||
|
#else
|
||||||
|
void parse(); // syntactic parse
|
||||||
|
#endif
|
||||||
|
void importAll(Scope *sc);
|
||||||
|
void semantic(Scope* unused_sc = NULL); // semantic analysis
|
||||||
|
void semantic2(Scope* unused_sc = NULL); // pass 2 semantic analysis
|
||||||
|
void semantic3(Scope* unused_sc = NULL); // pass 3 semantic analysis
|
||||||
|
void inlineScan(); // scan for functions to inline
|
||||||
|
#if !IN_LLVM
|
||||||
|
void setHdrfile(); // set hdrfile member
|
||||||
|
#endif
|
||||||
|
void genhdrfile(); // generate D import file
|
||||||
|
// void gensymfile();
|
||||||
|
void gendocfile();
|
||||||
|
int needModuleInfo();
|
||||||
|
Dsymbol *search(Loc loc, Identifier *ident, int flags);
|
||||||
|
Dsymbol *symtabInsert(Dsymbol *s);
|
||||||
|
void deleteObjFile();
|
||||||
|
void addDeferredSemantic(Dsymbol *s);
|
||||||
|
static void runDeferredSemantic();
|
||||||
|
static void clearCache();
|
||||||
|
int imports(Module *m);
|
||||||
|
|
||||||
|
// Back end
|
||||||
|
#if IN_DMD
|
||||||
|
int doppelganger; // sub-module
|
||||||
|
Symbol *cov; // private uint[] __coverage;
|
||||||
|
unsigned *covb; // bit array of valid code line numbers
|
||||||
|
|
||||||
|
Symbol *sictor; // module order independent constructor
|
||||||
|
Symbol *sctor; // module constructor
|
||||||
|
Symbol *sdtor; // module destructor
|
||||||
|
Symbol *ssharedctor; // module shared constructor
|
||||||
|
Symbol *sshareddtor; // module shared destructor
|
||||||
|
Symbol *stest; // module unit test
|
||||||
|
|
||||||
|
Symbol *sfilename; // symbol for filename
|
||||||
|
|
||||||
|
Symbol *massert; // module assert function
|
||||||
|
Symbol *toModuleAssert(); // get module assert function
|
||||||
|
|
||||||
|
Symbol *munittest; // module unittest failure function
|
||||||
|
Symbol *toModuleUnittest(); // get module unittest failure function
|
||||||
|
|
||||||
|
Symbol *marray; // module array bounds function
|
||||||
|
Symbol *toModuleArray(); // get module array bounds function
|
||||||
|
|
||||||
|
|
||||||
|
static Symbol *gencritsec();
|
||||||
|
elem *toEfilename();
|
||||||
|
|
||||||
|
Symbol *toSymbol();
|
||||||
|
#endif
|
||||||
|
void genmoduleinfo();
|
||||||
|
|
||||||
|
#if IN_LLVM
|
||||||
|
// LDC
|
||||||
|
llvm::Module* genLLVMModule(llvm::LLVMContext& context, Ir* sir);
|
||||||
|
void buildTargetFiles(bool singleObj);
|
||||||
|
File* buildFilePath(const char* forcename, const char* path, const char* ext);
|
||||||
|
Module *isModule() { return this; }
|
||||||
|
llvm::GlobalVariable* moduleInfoSymbol();
|
||||||
|
|
||||||
|
bool llvmForceLogging;
|
||||||
|
llvm::GlobalVariable* moduleInfoVar;
|
||||||
|
llvm::StructType* moduleInfoType;
|
||||||
|
|
||||||
|
// array ops emitted in this module already
|
||||||
|
AA *arrayfuncs;
|
||||||
|
|
||||||
|
bool isRoot;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ModuleDeclaration
|
||||||
|
{
|
||||||
|
Identifier *id;
|
||||||
|
Identifiers *packages; // array of Identifier's representing packages
|
||||||
|
bool safe;
|
||||||
|
|
||||||
|
ModuleDeclaration(Identifiers *packages, Identifier *id, bool safe);
|
||||||
|
|
||||||
|
char *toChars();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DMD_MODULE_H */
|
||||||
+9323
File diff suppressed because it is too large
Load Diff
+1067
File diff suppressed because it is too large
Load Diff
+1612
File diff suppressed because it is too large
Load Diff
+1219
File diff suppressed because it is too large
Load Diff
+6709
File diff suppressed because it is too large
Load Diff
+187
@@ -0,0 +1,187 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef DMD_PARSE_H
|
||||||
|
#define DMD_PARSE_H
|
||||||
|
|
||||||
|
#ifdef __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif /* __DMC__ */
|
||||||
|
|
||||||
|
#include "arraytypes.h"
|
||||||
|
#include "lexer.h"
|
||||||
|
#include "enum.h"
|
||||||
|
|
||||||
|
struct Type;
|
||||||
|
struct TypeQualified;
|
||||||
|
struct Expression;
|
||||||
|
struct Declaration;
|
||||||
|
struct Statement;
|
||||||
|
struct Import;
|
||||||
|
struct Initializer;
|
||||||
|
struct FuncDeclaration;
|
||||||
|
struct CtorDeclaration;
|
||||||
|
struct PostBlitDeclaration;
|
||||||
|
struct DtorDeclaration;
|
||||||
|
struct StaticCtorDeclaration;
|
||||||
|
struct StaticDtorDeclaration;
|
||||||
|
struct SharedStaticCtorDeclaration;
|
||||||
|
struct SharedStaticDtorDeclaration;
|
||||||
|
struct ConditionalDeclaration;
|
||||||
|
struct InvariantDeclaration;
|
||||||
|
struct UnitTestDeclaration;
|
||||||
|
struct NewDeclaration;
|
||||||
|
struct DeleteDeclaration;
|
||||||
|
struct Condition;
|
||||||
|
struct Module;
|
||||||
|
struct ModuleDeclaration;
|
||||||
|
struct TemplateDeclaration;
|
||||||
|
struct TemplateInstance;
|
||||||
|
struct StaticAssert;
|
||||||
|
|
||||||
|
/************************************
|
||||||
|
* These control how parseStatement() works.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum ParseStatementFlags
|
||||||
|
{
|
||||||
|
PSsemi = 1, // empty ';' statements are allowed, but deprecated
|
||||||
|
PSscope = 2, // start a new scope
|
||||||
|
PScurly = 4, // { } statement is required
|
||||||
|
PScurlyscope = 8, // { } starts a new scope
|
||||||
|
PSsemi_ok = 0x10, // empty ';' are really ok
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Parser : Lexer
|
||||||
|
{
|
||||||
|
ModuleDeclaration *md;
|
||||||
|
enum LINK linkage;
|
||||||
|
Loc endloc; // set to location of last right curly
|
||||||
|
int inBrackets; // inside [] of array index or slice
|
||||||
|
Loc lookingForElse; // location of lonely if looking for an else
|
||||||
|
|
||||||
|
Parser(Module *module, unsigned char *base, unsigned length, int doDocComment);
|
||||||
|
|
||||||
|
Dsymbols *parseModule();
|
||||||
|
Dsymbols *parseDeclDefs(int once);
|
||||||
|
Dsymbols *parseAutoDeclarations(StorageClass storageClass, unsigned char *comment);
|
||||||
|
Dsymbols *parseBlock();
|
||||||
|
void composeStorageClass(StorageClass stc);
|
||||||
|
StorageClass parseAttribute();
|
||||||
|
StorageClass parsePostfix();
|
||||||
|
Expression *parseConstraint();
|
||||||
|
TemplateDeclaration *parseTemplateDeclaration(int ismixin);
|
||||||
|
TemplateParameters *parseTemplateParameterList(int flag = 0);
|
||||||
|
Dsymbol *parseMixin();
|
||||||
|
Objects *parseTemplateArgumentList();
|
||||||
|
Objects *parseTemplateArgumentList2();
|
||||||
|
Objects *parseTemplateArgument();
|
||||||
|
StaticAssert *parseStaticAssert();
|
||||||
|
TypeQualified *parseTypeof();
|
||||||
|
Type *parseVector();
|
||||||
|
enum LINK parseLinkage();
|
||||||
|
Condition *parseDebugCondition();
|
||||||
|
Condition *parseVersionCondition();
|
||||||
|
Condition *parseStaticIfCondition();
|
||||||
|
Dsymbol *parseCtor();
|
||||||
|
PostBlitDeclaration *parsePostBlit();
|
||||||
|
DtorDeclaration *parseDtor();
|
||||||
|
StaticCtorDeclaration *parseStaticCtor();
|
||||||
|
StaticDtorDeclaration *parseStaticDtor();
|
||||||
|
SharedStaticCtorDeclaration *parseSharedStaticCtor();
|
||||||
|
SharedStaticDtorDeclaration *parseSharedStaticDtor();
|
||||||
|
InvariantDeclaration *parseInvariant();
|
||||||
|
UnitTestDeclaration *parseUnitTest();
|
||||||
|
NewDeclaration *parseNew();
|
||||||
|
DeleteDeclaration *parseDelete();
|
||||||
|
Parameters *parseParameters(int *pvarargs, TemplateParameters **tpl = NULL);
|
||||||
|
EnumDeclaration *parseEnum();
|
||||||
|
Dsymbol *parseAggregate();
|
||||||
|
BaseClasses *parseBaseClasses();
|
||||||
|
Import *parseImport(Dsymbols *decldefs, int isstatic);
|
||||||
|
Type *parseType(Identifier **pident = NULL, TemplateParameters **tpl = NULL);
|
||||||
|
Type *parseBasicType();
|
||||||
|
Type *parseBasicType2(Type *t);
|
||||||
|
Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL, StorageClass storage_class = 0, int* pdisable = NULL);
|
||||||
|
Dsymbols *parseDeclarations(StorageClass storage_class, unsigned char *comment);
|
||||||
|
void parseContracts(FuncDeclaration *f);
|
||||||
|
void checkDanglingElse(Loc elseloc);
|
||||||
|
Statement *parseStatement(int flags);
|
||||||
|
Initializer *parseInitializer();
|
||||||
|
Expression *parseDefaultInitExp();
|
||||||
|
void check(Loc loc, enum TOK value);
|
||||||
|
void check(enum TOK value);
|
||||||
|
void check(enum TOK value, const char *string);
|
||||||
|
void checkParens(enum TOK value, Expression *e);
|
||||||
|
int isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt);
|
||||||
|
int isBasicType(Token **pt);
|
||||||
|
int isDeclarator(Token **pt, int *haveId, enum TOK endtok);
|
||||||
|
int isParameters(Token **pt);
|
||||||
|
int isExpression(Token **pt);
|
||||||
|
int isTemplateInstance(Token *t, Token **pt);
|
||||||
|
int skipParens(Token *t, Token **pt);
|
||||||
|
int skipAttributes(Token *t, Token **pt);
|
||||||
|
|
||||||
|
Expression *parseExpression();
|
||||||
|
Expression *parsePrimaryExp();
|
||||||
|
Expression *parseUnaryExp();
|
||||||
|
Expression *parsePostExp(Expression *e);
|
||||||
|
Expression *parseMulExp();
|
||||||
|
Expression *parseAddExp();
|
||||||
|
Expression *parseShiftExp();
|
||||||
|
#if DMDV1
|
||||||
|
Expression *parseRelExp();
|
||||||
|
Expression *parseEqualExp();
|
||||||
|
#endif
|
||||||
|
Expression *parseCmpExp();
|
||||||
|
Expression *parseAndExp();
|
||||||
|
Expression *parseXorExp();
|
||||||
|
Expression *parseOrExp();
|
||||||
|
Expression *parseAndAndExp();
|
||||||
|
Expression *parseOrOrExp();
|
||||||
|
Expression *parseCondExp();
|
||||||
|
Expression *parseAssignExp();
|
||||||
|
|
||||||
|
Expressions *parseArguments();
|
||||||
|
|
||||||
|
Expression *parseNewExp(Expression *thisexp);
|
||||||
|
|
||||||
|
void addComment(Dsymbol *s, unsigned char *blockComment);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Operator precedence - greater values are higher precedence
|
||||||
|
|
||||||
|
enum PREC
|
||||||
|
{
|
||||||
|
PREC_zero,
|
||||||
|
PREC_expr,
|
||||||
|
PREC_assign,
|
||||||
|
PREC_cond,
|
||||||
|
PREC_oror,
|
||||||
|
PREC_andand,
|
||||||
|
PREC_or,
|
||||||
|
PREC_xor,
|
||||||
|
PREC_and,
|
||||||
|
PREC_equal,
|
||||||
|
PREC_rel,
|
||||||
|
PREC_shift,
|
||||||
|
PREC_add,
|
||||||
|
PREC_mul,
|
||||||
|
PREC_pow,
|
||||||
|
PREC_unary,
|
||||||
|
PREC_primary,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum PREC precedence[TOKMAX];
|
||||||
|
|
||||||
|
void initPrecedence();
|
||||||
|
|
||||||
|
#endif /* DMD_PARSE_H */
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
The D Programming Language
|
||||||
|
Compiler Front End Source
|
||||||
|
Copyright (c) 1999-2009, by Digital Mars
|
||||||
|
http://www.digitalmars.com
|
||||||
|
All Rights Reserved
|
||||||
|
|
||||||
|
|
||||||
|
This is the source code to the front end Digital Mars D compiler.
|
||||||
|
It covers the lexical analysis, parsing, and semantic analysis
|
||||||
|
of the D Programming Language defined in the documents at
|
||||||
|
http://www.digitalmars.com/d/
|
||||||
|
|
||||||
|
These sources are free, they are redistributable and modifiable
|
||||||
|
under the terms of the GNU General Public License (attached as gpl.txt),
|
||||||
|
or the Artistic License (attached as artistic.txt).
|
||||||
|
|
||||||
|
The optimizer and code generator sources are
|
||||||
|
covered under a separate license, backendlicense.txt.
|
||||||
|
|
||||||
|
It does not apply to anything else distributed by Digital Mars,
|
||||||
|
including D compiler executables.
|
||||||
|
|
||||||
|
-Walter Bright
|
||||||
+188
@@ -0,0 +1,188 @@
|
|||||||
|
/**
|
||||||
|
* Implementation of associative arrays.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "aav.h"
|
||||||
|
|
||||||
|
static const size_t prime_list[] = {
|
||||||
|
31UL,
|
||||||
|
97UL, 389UL,
|
||||||
|
1543UL, 6151UL,
|
||||||
|
24593UL, 98317UL,
|
||||||
|
393241UL, 1572869UL,
|
||||||
|
6291469UL, 25165843UL,
|
||||||
|
100663319UL, 402653189UL,
|
||||||
|
1610612741UL, 4294967291UL,
|
||||||
|
};
|
||||||
|
|
||||||
|
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* binit[4]; // initial value of b[]
|
||||||
|
};
|
||||||
|
|
||||||
|
static const AA bbinit = { NULL, };
|
||||||
|
|
||||||
|
/****************************************************
|
||||||
|
* Determine number of entries in associative array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
size_t _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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Value* _aaGet(AA** paa, Key key)
|
||||||
|
{
|
||||||
|
//printf("paa = %p\n", paa);
|
||||||
|
|
||||||
|
if (!*paa)
|
||||||
|
{ AA *a = new AA();
|
||||||
|
*a = bbinit;
|
||||||
|
a->b = a->binit;
|
||||||
|
a->b_length = sizeof(a->binit) / sizeof(a->binit[0]);
|
||||||
|
*paa = a;
|
||||||
|
assert((*paa)->b_length == 4);
|
||||||
|
}
|
||||||
|
//printf("paa = %p, *paa = %p\n", paa, *paa);
|
||||||
|
|
||||||
|
assert((*paa)->b_length);
|
||||||
|
size_t i = (size_t)key % (*paa)->b_length;
|
||||||
|
aaA** pe = &(*paa)->b[i];
|
||||||
|
aaA *e;
|
||||||
|
while ((e = *pe) != NULL)
|
||||||
|
{
|
||||||
|
if (key == e->key)
|
||||||
|
return &e->value;
|
||||||
|
pe = &e->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found, create new elem
|
||||||
|
//printf("create new one\n");
|
||||||
|
e = new aaA();
|
||||||
|
e->next = NULL;
|
||||||
|
e->key = key;
|
||||||
|
e->value = NULL;
|
||||||
|
*pe = e;
|
||||||
|
|
||||||
|
size_t nodes = ++(*paa)->nodes;
|
||||||
|
//printf("length = %d, nodes = %d\n", paa.a.b.length, nodes);
|
||||||
|
if (nodes > (*paa)->b_length * 4)
|
||||||
|
{
|
||||||
|
//printf("rehash\n");
|
||||||
|
_aaRehash(paa);
|
||||||
|
}
|
||||||
|
|
||||||
|
return &e->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************
|
||||||
|
* Get value in associative array indexed by key.
|
||||||
|
* Returns NULL if it is not already there.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Value _aaGetRvalue(AA* aa, Key key)
|
||||||
|
{
|
||||||
|
//printf("_aaGetRvalue(key = %p)\n", key);
|
||||||
|
if (!aa)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size_t len = aa->b_length;
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
size_t i = (size_t)key % len;
|
||||||
|
aaA* e = aa->b[i];
|
||||||
|
while (e)
|
||||||
|
{
|
||||||
|
if (key == e->key)
|
||||||
|
return e->value;
|
||||||
|
e = e->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL; // not found
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************
|
||||||
|
* Rehash an array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _aaRehash(AA** paa)
|
||||||
|
{
|
||||||
|
//printf("Rehash\n");
|
||||||
|
if (*paa)
|
||||||
|
{
|
||||||
|
AA newb = bbinit;
|
||||||
|
AA *aa = *paa;
|
||||||
|
size_t len = _aaLen(*paa);
|
||||||
|
if (len)
|
||||||
|
{ size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(prime_list)/sizeof(prime_list[0]) - 1; i++)
|
||||||
|
{
|
||||||
|
if (len <= prime_list[i])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len = prime_list[i];
|
||||||
|
newb.b = new aaA*[len];
|
||||||
|
memset(newb.b, 0, len * sizeof(aaA*));
|
||||||
|
newb.b_length = len;
|
||||||
|
|
||||||
|
for (size_t k = 0; k < aa->b_length; k++)
|
||||||
|
{ aaA *e = aa->b[k];
|
||||||
|
while (e)
|
||||||
|
{ aaA* enext = e->next;
|
||||||
|
size_t j = (size_t)e->key % len;
|
||||||
|
e->next = newb.b[j];
|
||||||
|
newb.b[j] = e;
|
||||||
|
e = enext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (aa->b != aa->binit)
|
||||||
|
delete[] aa->b;
|
||||||
|
|
||||||
|
newb.nodes = aa->nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
**paa = newb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if UNITTEST
|
||||||
|
|
||||||
|
void unittest_aa()
|
||||||
|
{
|
||||||
|
AA* aa = NULL;
|
||||||
|
Value v = _aaGetRvalue(aa, NULL);
|
||||||
|
assert(!v);
|
||||||
|
Value *pv = _aaGet(&aa, NULL);
|
||||||
|
assert(pv);
|
||||||
|
*pv = (void *)3;
|
||||||
|
v = _aaGetRvalue(aa, NULL);
|
||||||
|
assert(v == (void *)3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
typedef void* Value;
|
||||||
|
typedef void* Key;
|
||||||
|
|
||||||
|
struct AA;
|
||||||
|
|
||||||
|
size_t _aaLen(AA* aa);
|
||||||
|
Value* _aaGet(AA** aa, Key key);
|
||||||
|
Value _aaGetRvalue(AA* aa, Key key);
|
||||||
|
void _aaRehash(AA** paa);
|
||||||
|
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2010 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#if (defined (__SVR4) && defined (__sun))
|
||||||
|
#include <alloca.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _MSC_VER || __MINGW32__
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IN_GCC
|
||||||
|
#include "gdc_alloca.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "port.h"
|
||||||
|
#include "root.h"
|
||||||
|
#include "dchar.h"
|
||||||
|
#include "rmem.h"
|
||||||
|
|
||||||
|
|
||||||
|
/********************************* Array ****************************/
|
||||||
|
|
||||||
|
Array::Array()
|
||||||
|
{
|
||||||
|
data = SMALLARRAYCAP ? &smallarray[0] : NULL;
|
||||||
|
dim = 0;
|
||||||
|
allocdim = SMALLARRAYCAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
Array::~Array()
|
||||||
|
{
|
||||||
|
if (data != &smallarray[0])
|
||||||
|
mem.free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Array::mark()
|
||||||
|
{ unsigned u;
|
||||||
|
|
||||||
|
mem.mark(data);
|
||||||
|
for (u = 0; u < dim; u++)
|
||||||
|
mem.mark(data[u]); // BUG: what if arrays of Object's?
|
||||||
|
}
|
||||||
|
|
||||||
|
void Array::reserve(unsigned nentries)
|
||||||
|
{
|
||||||
|
//printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", dim, allocdim, nentries);
|
||||||
|
if (allocdim - dim < nentries)
|
||||||
|
{
|
||||||
|
if (allocdim == 0)
|
||||||
|
{ // Not properly initialized, someone memset it to zero
|
||||||
|
if (nentries <= SMALLARRAYCAP)
|
||||||
|
{ allocdim = SMALLARRAYCAP;
|
||||||
|
data = SMALLARRAYCAP ? &smallarray[0] : NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ allocdim = nentries;
|
||||||
|
data = (void **)mem.malloc(allocdim * sizeof(*data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (allocdim == SMALLARRAYCAP)
|
||||||
|
{
|
||||||
|
allocdim = dim + nentries;
|
||||||
|
data = (void **)mem.malloc(allocdim * sizeof(*data));
|
||||||
|
memcpy(data, &smallarray[0], dim * sizeof(*data));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ allocdim = dim + nentries;
|
||||||
|
data = (void **)mem.realloc(data, allocdim * sizeof(*data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Array::setDim(unsigned newdim)
|
||||||
|
{
|
||||||
|
if (dim < newdim)
|
||||||
|
{
|
||||||
|
reserve(newdim - dim);
|
||||||
|
}
|
||||||
|
dim = newdim;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Array::fixDim()
|
||||||
|
{
|
||||||
|
if (dim != allocdim)
|
||||||
|
{
|
||||||
|
if (allocdim >= SMALLARRAYCAP)
|
||||||
|
{
|
||||||
|
if (dim <= SMALLARRAYCAP)
|
||||||
|
{
|
||||||
|
memcpy(&smallarray[0], data, dim * sizeof(*data));
|
||||||
|
mem.free(data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
data = (void **)mem.realloc(data, dim * sizeof(*data));
|
||||||
|
}
|
||||||
|
allocdim = dim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Array::push(void *ptr)
|
||||||
|
{
|
||||||
|
reserve(1);
|
||||||
|
data[dim++] = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Array::pop()
|
||||||
|
{
|
||||||
|
return data[--dim];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Array::shift(void *ptr)
|
||||||
|
{
|
||||||
|
reserve(1);
|
||||||
|
memmove(data + 1, data, dim * sizeof(*data));
|
||||||
|
data[0] = ptr;
|
||||||
|
dim++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Array::insert(unsigned index, void *ptr)
|
||||||
|
{
|
||||||
|
reserve(1);
|
||||||
|
memmove(data + index + 1, data + index, (dim - index) * sizeof(*data));
|
||||||
|
data[index] = ptr;
|
||||||
|
dim++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Array::insert(unsigned index, Array *a)
|
||||||
|
{
|
||||||
|
if (a)
|
||||||
|
{ unsigned d;
|
||||||
|
|
||||||
|
d = a->dim;
|
||||||
|
reserve(d);
|
||||||
|
if (dim != index)
|
||||||
|
memmove(data + index + d, data + index, (dim - index) * sizeof(*data));
|
||||||
|
memcpy(data + index, a->data, d * sizeof(*data));
|
||||||
|
dim += d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************
|
||||||
|
* Append array a to this array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Array::append(Array *a)
|
||||||
|
{
|
||||||
|
insert(dim, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Array::remove(unsigned i)
|
||||||
|
{
|
||||||
|
if (dim - i - 1)
|
||||||
|
memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0]));
|
||||||
|
dim--;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Array::toChars()
|
||||||
|
{
|
||||||
|
unsigned len;
|
||||||
|
unsigned u;
|
||||||
|
char **buf;
|
||||||
|
char *str;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
buf = (char **)malloc(dim * sizeof(char *));
|
||||||
|
assert(buf);
|
||||||
|
len = 2;
|
||||||
|
for (u = 0; u < dim; u++)
|
||||||
|
{
|
||||||
|
buf[u] = ((Object *)data[u])->toChars();
|
||||||
|
len += strlen(buf[u]) + 1;
|
||||||
|
}
|
||||||
|
str = (char *)mem.malloc(len);
|
||||||
|
|
||||||
|
str[0] = '[';
|
||||||
|
p = str + 1;
|
||||||
|
for (u = 0; u < dim; u++)
|
||||||
|
{
|
||||||
|
if (u)
|
||||||
|
*p++ = ',';
|
||||||
|
len = strlen(buf[u]);
|
||||||
|
memcpy(p,buf[u],len);
|
||||||
|
p += len;
|
||||||
|
}
|
||||||
|
*p++ = ']';
|
||||||
|
*p = 0;
|
||||||
|
free(buf);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Array::zero()
|
||||||
|
{
|
||||||
|
memset(data,0,dim * sizeof(data[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Array::tos()
|
||||||
|
{
|
||||||
|
return dim ? data[dim - 1] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
#if _WIN32
|
||||||
|
__cdecl
|
||||||
|
#endif
|
||||||
|
Array_sort_compare(const void *x, const void *y)
|
||||||
|
{
|
||||||
|
Object *ox = *(Object **)x;
|
||||||
|
Object *oy = *(Object **)y;
|
||||||
|
|
||||||
|
return ox->compare(oy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Array::sort()
|
||||||
|
{
|
||||||
|
if (dim)
|
||||||
|
{
|
||||||
|
qsort(data, dim, sizeof(Object *), Array_sort_compare);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Array *Array::copy()
|
||||||
|
{
|
||||||
|
Array *a = new Array();
|
||||||
|
|
||||||
|
a->setDim(dim);
|
||||||
|
memcpy(a->data, data, dim * sizeof(void *));
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,325 @@
|
|||||||
|
|
||||||
|
#define _MT 1
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <process.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
static unsigned __stdcall startthread(void *p);
|
||||||
|
|
||||||
|
struct FileData
|
||||||
|
{
|
||||||
|
File *file;
|
||||||
|
int result;
|
||||||
|
HANDLE event;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AsyncRead
|
||||||
|
{
|
||||||
|
static AsyncRead *create(size_t nfiles);
|
||||||
|
void addFile(File *file);
|
||||||
|
void start();
|
||||||
|
int read(size_t i);
|
||||||
|
static void dispose(AsyncRead *);
|
||||||
|
|
||||||
|
HANDLE hThread;
|
||||||
|
|
||||||
|
size_t filesdim;
|
||||||
|
size_t filesmax;
|
||||||
|
FileData files[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
AsyncRead *AsyncRead::create(size_t nfiles)
|
||||||
|
{
|
||||||
|
AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) +
|
||||||
|
(nfiles - 1) * sizeof(FileData));
|
||||||
|
aw->filesmax = nfiles;
|
||||||
|
return aw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncRead::addFile(File *file)
|
||||||
|
{
|
||||||
|
//printf("addFile(file = %p)\n", file);
|
||||||
|
//printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax);
|
||||||
|
assert(filesdim < filesmax);
|
||||||
|
files[filesdim].file = file;
|
||||||
|
files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
ResetEvent(files[filesdim].event);
|
||||||
|
filesdim++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncRead::start()
|
||||||
|
{
|
||||||
|
//printf("aw->filesdim = %p %d\n", this, filesdim);
|
||||||
|
if (filesdim)
|
||||||
|
{
|
||||||
|
unsigned threadaddr;
|
||||||
|
hThread = (HANDLE) _beginthreadex(NULL,
|
||||||
|
0,
|
||||||
|
&startthread,
|
||||||
|
this,
|
||||||
|
0,
|
||||||
|
(unsigned *)&threadaddr);
|
||||||
|
|
||||||
|
if (hThread)
|
||||||
|
{
|
||||||
|
SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int AsyncRead::read(size_t i)
|
||||||
|
{
|
||||||
|
FileData *f = &files[i];
|
||||||
|
WaitForSingleObject(f->event, INFINITE);
|
||||||
|
Sleep(0); // give up time slice
|
||||||
|
return f->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncRead::dispose(AsyncRead *aw)
|
||||||
|
{
|
||||||
|
free(aw);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned __stdcall startthread(void *p)
|
||||||
|
{
|
||||||
|
AsyncRead *aw = (AsyncRead *)p;
|
||||||
|
|
||||||
|
//printf("aw->filesdim = %p %d\n", aw, aw->filesdim);
|
||||||
|
for (size_t i = 0; i < aw->filesdim; i++)
|
||||||
|
{ FileData *f = &aw->files[i];
|
||||||
|
|
||||||
|
f->result = f->file->read();
|
||||||
|
SetEvent(f->event);
|
||||||
|
}
|
||||||
|
_endthreadex(EXIT_SUCCESS);
|
||||||
|
return EXIT_SUCCESS; // if skidding
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif linux // Posix
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
void *startthread(void *arg);
|
||||||
|
|
||||||
|
void err_abort(int status, const char *msg)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "fatal error = %d, %s\n", status, msg);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FileData
|
||||||
|
{
|
||||||
|
File *file;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
pthread_cond_t cond;
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AsyncRead
|
||||||
|
{
|
||||||
|
static AsyncRead *create(size_t nfiles);
|
||||||
|
void addFile(File *file);
|
||||||
|
void start();
|
||||||
|
int read(size_t i);
|
||||||
|
static void dispose(AsyncRead *);
|
||||||
|
|
||||||
|
size_t filesdim;
|
||||||
|
size_t filesmax;
|
||||||
|
FileData files[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
AsyncRead *AsyncRead::create(size_t nfiles)
|
||||||
|
{
|
||||||
|
AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) +
|
||||||
|
(nfiles - 1) * sizeof(FileData));
|
||||||
|
aw->filesmax = nfiles;
|
||||||
|
return aw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncRead::addFile(File *file)
|
||||||
|
{
|
||||||
|
//printf("addFile(file = %p)\n", file);
|
||||||
|
//printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax);
|
||||||
|
assert(filesdim < filesmax);
|
||||||
|
FileData *f = &files[filesdim];
|
||||||
|
f->file = file;
|
||||||
|
|
||||||
|
int status = pthread_mutex_init(&f->mutex, NULL);
|
||||||
|
if (status != 0)
|
||||||
|
err_abort(status, "init mutex");
|
||||||
|
status = pthread_cond_init(&f->cond, NULL);
|
||||||
|
if (status != 0)
|
||||||
|
err_abort(status, "init cond");
|
||||||
|
|
||||||
|
filesdim++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncRead::start()
|
||||||
|
{
|
||||||
|
//printf("aw->filesdim = %p %d\n", this, filesdim);
|
||||||
|
if (filesdim)
|
||||||
|
{
|
||||||
|
pthread_t thread_id;
|
||||||
|
int status = pthread_create(&thread_id,
|
||||||
|
NULL,
|
||||||
|
&startthread,
|
||||||
|
this);
|
||||||
|
if (status != 0)
|
||||||
|
err_abort(status, "create thread");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int AsyncRead::read(size_t i)
|
||||||
|
{
|
||||||
|
FileData *f = &files[i];
|
||||||
|
|
||||||
|
// Wait for the event
|
||||||
|
int status = pthread_mutex_lock(&f->mutex);
|
||||||
|
if (status != 0)
|
||||||
|
err_abort(status, "lock mutex");
|
||||||
|
while (f->value == 0)
|
||||||
|
{
|
||||||
|
status = pthread_cond_wait(&f->cond, &f->mutex);
|
||||||
|
if (status != 0)
|
||||||
|
err_abort(status, "wait on condition");
|
||||||
|
}
|
||||||
|
status = pthread_mutex_unlock(&f->mutex);
|
||||||
|
if (status != 0)
|
||||||
|
err_abort(status, "unlock mutex");
|
||||||
|
|
||||||
|
return f->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncRead::dispose(AsyncRead *aw)
|
||||||
|
{
|
||||||
|
//printf("AsyncRead::dispose()\n");
|
||||||
|
for (int i = 0; i < aw->filesdim; i++)
|
||||||
|
{
|
||||||
|
FileData *f = &aw->files[i];
|
||||||
|
int status = pthread_cond_destroy(&f->cond);
|
||||||
|
if (status != 0)
|
||||||
|
err_abort(status, "cond destroy");
|
||||||
|
status = pthread_mutex_destroy(&f->mutex);
|
||||||
|
if (status != 0)
|
||||||
|
err_abort(status, "mutex destroy");
|
||||||
|
}
|
||||||
|
free(aw);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *startthread(void *p)
|
||||||
|
{
|
||||||
|
AsyncRead *aw = (AsyncRead *)p;
|
||||||
|
|
||||||
|
//printf("startthread: aw->filesdim = %p %d\n", aw, aw->filesdim);
|
||||||
|
size_t dim = aw->filesdim;
|
||||||
|
for (size_t i = 0; i < dim; i++)
|
||||||
|
{ FileData *f = &aw->files[i];
|
||||||
|
|
||||||
|
f->result = f->file->read();
|
||||||
|
|
||||||
|
// Set event
|
||||||
|
int status = pthread_mutex_lock(&f->mutex);
|
||||||
|
if (status != 0)
|
||||||
|
err_abort(status, "lock mutex");
|
||||||
|
f->value = 1;
|
||||||
|
status = pthread_cond_signal(&f->cond);
|
||||||
|
if (status != 0)
|
||||||
|
err_abort(status, "signal condition");
|
||||||
|
status = pthread_mutex_unlock(&f->mutex);
|
||||||
|
if (status != 0)
|
||||||
|
err_abort(status, "unlock mutex");
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL; // end thread
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
struct FileData
|
||||||
|
{
|
||||||
|
File *file;
|
||||||
|
int result;
|
||||||
|
//HANDLE event;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AsyncRead
|
||||||
|
{
|
||||||
|
static AsyncRead *create(size_t nfiles);
|
||||||
|
void addFile(File *file);
|
||||||
|
void start();
|
||||||
|
int read(size_t i);
|
||||||
|
static void dispose(AsyncRead *);
|
||||||
|
|
||||||
|
//HANDLE hThread;
|
||||||
|
|
||||||
|
size_t filesdim;
|
||||||
|
size_t filesmax;
|
||||||
|
FileData files[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
AsyncRead *AsyncRead::create(size_t nfiles)
|
||||||
|
{
|
||||||
|
AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) +
|
||||||
|
(nfiles - 1) * sizeof(FileData));
|
||||||
|
aw->filesmax = nfiles;
|
||||||
|
return aw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncRead::addFile(File *file)
|
||||||
|
{
|
||||||
|
//printf("addFile(file = %p)\n", file);
|
||||||
|
//printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax);
|
||||||
|
assert(filesdim < filesmax);
|
||||||
|
files[filesdim].file = file;
|
||||||
|
//files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
//ResetEvent(files[filesdim].event);
|
||||||
|
filesdim++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncRead::start()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int AsyncRead::read(size_t i)
|
||||||
|
{
|
||||||
|
FileData *f = &files[i];
|
||||||
|
f->result = f->file->read();
|
||||||
|
return f->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncRead::dispose(AsyncRead *aw)
|
||||||
|
{
|
||||||
|
free(aw);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 2009-2009 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef ASYNC_H
|
||||||
|
#define ASYNC_H
|
||||||
|
|
||||||
|
#if __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
* Simple interface to read files asynchronously in another
|
||||||
|
* thread.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct AsyncRead
|
||||||
|
{
|
||||||
|
static AsyncRead *create(size_t nfiles);
|
||||||
|
void addFile(File *file);
|
||||||
|
void start();
|
||||||
|
int read(size_t i);
|
||||||
|
static void dispose(AsyncRead *);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,482 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2006 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "dchar.h"
|
||||||
|
#include "rmem.h"
|
||||||
|
|
||||||
|
#if M_UNICODE
|
||||||
|
|
||||||
|
// Converts a char string to Unicode
|
||||||
|
|
||||||
|
dchar *Dchar::dup(char *p)
|
||||||
|
{
|
||||||
|
dchar *s;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
return NULL;
|
||||||
|
len = strlen(p);
|
||||||
|
s = (dchar *)mem.malloc((len + 1) * sizeof(dchar));
|
||||||
|
for (unsigned i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
s[i] = (dchar)(p[i] & 0xFF);
|
||||||
|
}
|
||||||
|
s[len] = 0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
dchar *Dchar::memchr(dchar *p, int c, int count)
|
||||||
|
{
|
||||||
|
int u;
|
||||||
|
|
||||||
|
for (u = 0; u < count; u++)
|
||||||
|
{
|
||||||
|
if (p[u] == c)
|
||||||
|
return p + u;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _WIN32 && __DMC__
|
||||||
|
__declspec(naked)
|
||||||
|
unsigned Dchar::calcHash(const dchar *str, unsigned len)
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
mov ECX,4[ESP]
|
||||||
|
mov EDX,8[ESP]
|
||||||
|
xor EAX,EAX
|
||||||
|
test EDX,EDX
|
||||||
|
je L92
|
||||||
|
|
||||||
|
LC8: cmp EDX,1
|
||||||
|
je L98
|
||||||
|
cmp EDX,2
|
||||||
|
je LAE
|
||||||
|
|
||||||
|
add EAX,[ECX]
|
||||||
|
// imul EAX,EAX,025h
|
||||||
|
lea EAX,[EAX][EAX*8]
|
||||||
|
add ECX,4
|
||||||
|
sub EDX,2
|
||||||
|
jmp LC8
|
||||||
|
|
||||||
|
L98: mov DX,[ECX]
|
||||||
|
and EDX,0FFFFh
|
||||||
|
add EAX,EDX
|
||||||
|
ret
|
||||||
|
|
||||||
|
LAE: add EAX,[ECX]
|
||||||
|
L92: ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
hash_t Dchar::calcHash(const dchar *str, size_t len)
|
||||||
|
{
|
||||||
|
unsigned hash = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
switch (len)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
hash += *(const uint16_t *)str;
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
hash += *(const uint32_t *)str;
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
default:
|
||||||
|
hash += *(const uint32_t *)str;
|
||||||
|
hash *= 37;
|
||||||
|
str += 2;
|
||||||
|
len -= 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hash_t Dchar::icalcHash(const dchar *str, size_t len)
|
||||||
|
{
|
||||||
|
hash_t hash = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
switch (len)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
hash += *(const uint16_t *)str | 0x20;
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
hash += *(const uint32_t *)str | 0x200020;
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
default:
|
||||||
|
hash += *(const uint32_t *)str | 0x200020;
|
||||||
|
hash *= 37;
|
||||||
|
str += 2;
|
||||||
|
len -= 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif MCBS
|
||||||
|
|
||||||
|
hash_t Dchar::calcHash(const dchar *str, size_t len)
|
||||||
|
{
|
||||||
|
hash_t hash = 0;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
switch (len)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
hash *= 37;
|
||||||
|
hash += *(const uint8_t *)str;
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
hash *= 37;
|
||||||
|
hash += *(const uint16_t *)str;
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
hash *= 37;
|
||||||
|
hash += (*(const uint16_t *)str << 8) +
|
||||||
|
((const uint8_t *)str)[2];
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
default:
|
||||||
|
hash *= 37;
|
||||||
|
hash += *(const uint32_t *)str;
|
||||||
|
str += 4;
|
||||||
|
len -= 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif UTF8
|
||||||
|
|
||||||
|
// Specification is: http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335
|
||||||
|
|
||||||
|
char Dchar::mblen[256] =
|
||||||
|
{
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||||
|
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||||
|
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
|
4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
|
||||||
|
};
|
||||||
|
|
||||||
|
dchar *Dchar::dec(dchar *pstart, dchar *p)
|
||||||
|
{
|
||||||
|
while ((p[-1] & 0xC0) == 0x80)
|
||||||
|
p--;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Dchar::get(dchar *p)
|
||||||
|
{
|
||||||
|
unsigned c;
|
||||||
|
unsigned char *q = (unsigned char *)p;
|
||||||
|
|
||||||
|
c = q[0];
|
||||||
|
switch (mblen[c])
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
c = ((c - 0xC0) << 6) |
|
||||||
|
(q[1] - 0x80);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
c = ((c - 0xE0) << 12) |
|
||||||
|
((q[1] - 0x80) << 6) |
|
||||||
|
(q[2] - 0x80);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
c = ((c - 0xF0) << 18) |
|
||||||
|
((q[1] - 0x80) << 12) |
|
||||||
|
((q[2] - 0x80) << 6) |
|
||||||
|
(q[3] - 0x80);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
c = ((c - 0xF8) << 24) |
|
||||||
|
((q[1] - 0x80) << 18) |
|
||||||
|
((q[2] - 0x80) << 12) |
|
||||||
|
((q[3] - 0x80) << 6) |
|
||||||
|
(q[4] - 0x80);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
c = ((c - 0xFC) << 30) |
|
||||||
|
((q[1] - 0x80) << 24) |
|
||||||
|
((q[2] - 0x80) << 18) |
|
||||||
|
((q[3] - 0x80) << 12) |
|
||||||
|
((q[4] - 0x80) << 6) |
|
||||||
|
(q[5] - 0x80);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
dchar *Dchar::put(dchar *p, unsigned c)
|
||||||
|
{
|
||||||
|
if (c <= 0x7F)
|
||||||
|
{
|
||||||
|
*p++ = c;
|
||||||
|
}
|
||||||
|
else if (c <= 0x7FF)
|
||||||
|
{
|
||||||
|
p[0] = 0xC0 + (c >> 6);
|
||||||
|
p[1] = 0x80 + (c & 0x3F);
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
else if (c <= 0xFFFF)
|
||||||
|
{
|
||||||
|
p[0] = 0xE0 + (c >> 12);
|
||||||
|
p[1] = 0x80 + ((c >> 6) & 0x3F);
|
||||||
|
p[2] = 0x80 + (c & 0x3F);
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
else if (c <= 0x1FFFFF)
|
||||||
|
{
|
||||||
|
p[0] = 0xF0 + (c >> 18);
|
||||||
|
p[1] = 0x80 + ((c >> 12) & 0x3F);
|
||||||
|
p[2] = 0x80 + ((c >> 6) & 0x3F);
|
||||||
|
p[3] = 0x80 + (c & 0x3F);
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
else if (c <= 0x3FFFFFF)
|
||||||
|
{
|
||||||
|
p[0] = 0xF8 + (c >> 24);
|
||||||
|
p[1] = 0x80 + ((c >> 18) & 0x3F);
|
||||||
|
p[2] = 0x80 + ((c >> 12) & 0x3F);
|
||||||
|
p[3] = 0x80 + ((c >> 6) & 0x3F);
|
||||||
|
p[4] = 0x80 + (c & 0x3F);
|
||||||
|
p += 5;
|
||||||
|
}
|
||||||
|
else if (c <= 0x7FFFFFFF)
|
||||||
|
{
|
||||||
|
p[0] = 0xFC + (c >> 30);
|
||||||
|
p[1] = 0x80 + ((c >> 24) & 0x3F);
|
||||||
|
p[2] = 0x80 + ((c >> 18) & 0x3F);
|
||||||
|
p[3] = 0x80 + ((c >> 12) & 0x3F);
|
||||||
|
p[4] = 0x80 + ((c >> 6) & 0x3F);
|
||||||
|
p[5] = 0x80 + (c & 0x3F);
|
||||||
|
p += 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
assert(0); // not a UCS-4 character
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_t Dchar::calcHash(const dchar *str, size_t len)
|
||||||
|
{
|
||||||
|
hash_t hash = 0;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
switch (len)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
hash *= 37;
|
||||||
|
hash += *(const uint8_t *)str;
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
hash *= 37;
|
||||||
|
#if LITTLE_ENDIAN
|
||||||
|
hash += *(const uint16_t *)str;
|
||||||
|
#else
|
||||||
|
hash += str[0] * 256 + str[1];
|
||||||
|
#endif
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
hash *= 37;
|
||||||
|
#if LITTLE_ENDIAN
|
||||||
|
hash += (*(const uint16_t *)str << 8) +
|
||||||
|
((const uint8_t *)str)[2];
|
||||||
|
#else
|
||||||
|
hash += (str[0] * 256 + str[1]) * 256 + str[2];
|
||||||
|
#endif
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
default:
|
||||||
|
hash *= 37;
|
||||||
|
#if LITTLE_ENDIAN
|
||||||
|
hash += *(const uint32_t *)str;
|
||||||
|
#else
|
||||||
|
hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
str += 4;
|
||||||
|
len -= 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // ascii
|
||||||
|
|
||||||
|
hash_t Dchar::calcHash(const dchar *str, size_t len)
|
||||||
|
{
|
||||||
|
hash_t hash = 0;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
switch (len)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
hash *= 37;
|
||||||
|
hash += *(const uint8_t *)str;
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
hash *= 37;
|
||||||
|
#if LITTLE_ENDIAN
|
||||||
|
hash += *(const uint16_t *)str;
|
||||||
|
#else
|
||||||
|
hash += str[0] * 256 + str[1];
|
||||||
|
#endif
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
hash *= 37;
|
||||||
|
#if LITTLE_ENDIAN
|
||||||
|
hash += (*(const uint16_t *)str << 8) +
|
||||||
|
((const uint8_t *)str)[2];
|
||||||
|
#else
|
||||||
|
hash += (str[0] * 256 + str[1]) * 256 + str[2];
|
||||||
|
#endif
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
default:
|
||||||
|
hash *= 37;
|
||||||
|
#if LITTLE_ENDIAN
|
||||||
|
hash += *(const uint32_t *)str;
|
||||||
|
#else
|
||||||
|
hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3];
|
||||||
|
#endif
|
||||||
|
str += 4;
|
||||||
|
len -= 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_t Dchar::icalcHash(const dchar *str, size_t len)
|
||||||
|
{
|
||||||
|
hash_t hash = 0;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
switch (len)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
hash *= 37;
|
||||||
|
hash += *(const uint8_t *)str | 0x20;
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
hash *= 37;
|
||||||
|
hash += *(const uint16_t *)str | 0x2020;
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
hash *= 37;
|
||||||
|
hash += ((*(const uint16_t *)str << 8) +
|
||||||
|
((const uint8_t *)str)[2]) | 0x202020;
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
default:
|
||||||
|
hash *= 37;
|
||||||
|
hash += *(const uint32_t *)str | 0x20202020;
|
||||||
|
str += 4;
|
||||||
|
len -= 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Print out values to hardcode into Dchar::mblen[]
|
||||||
|
int c;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
for (c = 0; c < 256; c++)
|
||||||
|
{
|
||||||
|
s = 1;
|
||||||
|
if (c >= 0xC0 && c <= 0xDF)
|
||||||
|
s = 2;
|
||||||
|
if (c >= 0xE0 && c <= 0xEF)
|
||||||
|
s = 3;
|
||||||
|
if (c >= 0xF0 && c <= 0xF7)
|
||||||
|
s = 4;
|
||||||
|
if (c >= 0xF8 && c <= 0xFB)
|
||||||
|
s = 5;
|
||||||
|
if (c >= 0xFC && c <= 0xFD)
|
||||||
|
s = 6;
|
||||||
|
|
||||||
|
printf("%d", s);
|
||||||
|
if ((c & 15) == 15)
|
||||||
|
printf(",\n");
|
||||||
|
else
|
||||||
|
printf(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DCHAR_H
|
||||||
|
#define DCHAR_H
|
||||||
|
|
||||||
|
#if __GNUC__ && !_WIN32
|
||||||
|
#include "gnuc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
// Disable useless warnings about unreferenced functions
|
||||||
|
#pragma warning (disable : 4514)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#include "root.h"
|
||||||
|
typedef size_t hash_t;
|
||||||
|
|
||||||
|
#undef TEXT
|
||||||
|
|
||||||
|
// NOTE: All functions accepting pointer arguments must not be NULL
|
||||||
|
|
||||||
|
#if M_UNICODE
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
typedef wchar_t dchar;
|
||||||
|
#define TEXT(x) L##x
|
||||||
|
|
||||||
|
#define Dchar_mbmax 1
|
||||||
|
|
||||||
|
struct Dchar
|
||||||
|
{
|
||||||
|
static dchar *inc(dchar *p) { return p + 1; }
|
||||||
|
static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; }
|
||||||
|
static int len(const dchar *p) { return wcslen(p); }
|
||||||
|
static dchar get(dchar *p) { return *p; }
|
||||||
|
static dchar getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1]; }
|
||||||
|
static dchar *put(dchar *p, dchar c) { *p = c; return p + 1; }
|
||||||
|
static int cmp(dchar *s1, dchar *s2)
|
||||||
|
{
|
||||||
|
#if __DMC__
|
||||||
|
if (!*s1 && !*s2) // wcscmp is broken
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
return wcscmp(s1, s2);
|
||||||
|
#if 0
|
||||||
|
return (*s1 == *s2)
|
||||||
|
? wcscmp(s1, s2)
|
||||||
|
: ((int)*s1 - (int)*s2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars * sizeof(dchar)); }
|
||||||
|
static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
|
||||||
|
static int isAlpha(dchar c) { return iswalpha(c); }
|
||||||
|
static int isUpper(dchar c) { return iswupper(c); }
|
||||||
|
static int isLower(dchar c) { return iswlower(c); }
|
||||||
|
static int isLocaleUpper(dchar c) { return isUpper(c); }
|
||||||
|
static int isLocaleLower(dchar c) { return isLower(c); }
|
||||||
|
static int toLower(dchar c) { return isUpper(c) ? towlower(c) : c; }
|
||||||
|
static int toLower(dchar *p) { return toLower(*p); }
|
||||||
|
static int toUpper(dchar c) { return isLower(c) ? towupper(c) : c; }
|
||||||
|
static dchar *dup(dchar *p) { return ::_wcsdup(p); } // BUG: out of memory?
|
||||||
|
static dchar *dup(char *p);
|
||||||
|
static dchar *chr(dchar *p, unsigned c) { return wcschr(p, (dchar)c); }
|
||||||
|
static dchar *rchr(dchar *p, unsigned c) { return wcsrchr(p, (dchar)c); }
|
||||||
|
static dchar *memchr(dchar *p, int c, int count);
|
||||||
|
static dchar *cpy(dchar *s1, dchar *s2) { return wcscpy(s1, s2); }
|
||||||
|
static dchar *str(dchar *s1, dchar *s2) { return wcsstr(s1, s2); }
|
||||||
|
static hash_t calcHash(const dchar *str, size_t len);
|
||||||
|
|
||||||
|
// Case insensitive versions
|
||||||
|
static int icmp(dchar *s1, dchar *s2) { return wcsicmp(s1, s2); }
|
||||||
|
static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::wcsnicmp(s1, s2, nchars); }
|
||||||
|
static hash_t icalcHash(const dchar *str, size_t len);
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif MCBS
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <mbstring.h>
|
||||||
|
|
||||||
|
typedef char dchar;
|
||||||
|
#define TEXT(x) x
|
||||||
|
|
||||||
|
#define Dchar_mbmax MB_LEN_MAX
|
||||||
|
|
||||||
|
#elif UTF8
|
||||||
|
|
||||||
|
typedef char dchar;
|
||||||
|
#define TEXT(x) x
|
||||||
|
|
||||||
|
#define Dchar_mbmax 6
|
||||||
|
|
||||||
|
struct Dchar
|
||||||
|
{
|
||||||
|
static char mblen[256];
|
||||||
|
|
||||||
|
static dchar *inc(dchar *p) { return p + mblen[*p & 0xFF]; }
|
||||||
|
static dchar *dec(dchar *pstart, dchar *p);
|
||||||
|
static int len(const dchar *p) { return strlen(p); }
|
||||||
|
static int get(dchar *p);
|
||||||
|
static int getprev(dchar *pstart, dchar *p)
|
||||||
|
{ return *dec(pstart, p) & 0xFF; }
|
||||||
|
static dchar *put(dchar *p, unsigned c);
|
||||||
|
static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); }
|
||||||
|
static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); }
|
||||||
|
static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
|
||||||
|
static int isAlpha(dchar c) { return c <= 0x7F ? isalpha(c) : 0; }
|
||||||
|
static int isUpper(dchar c) { return c <= 0x7F ? isupper(c) : 0; }
|
||||||
|
static int isLower(dchar c) { return c <= 0x7F ? islower(c) : 0; }
|
||||||
|
static int isLocaleUpper(dchar c) { return isUpper(c); }
|
||||||
|
static int isLocaleLower(dchar c) { return isLower(c); }
|
||||||
|
static int toLower(dchar c) { return isUpper(c) ? tolower(c) : c; }
|
||||||
|
static int toLower(dchar *p) { return toLower(*p); }
|
||||||
|
static int toUpper(dchar c) { return isLower(c) ? toupper(c) : c; }
|
||||||
|
static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory?
|
||||||
|
static dchar *chr(dchar *p, int c) { return strchr(p, c); }
|
||||||
|
static dchar *rchr(dchar *p, int c) { return strrchr(p, c); }
|
||||||
|
static dchar *memchr(dchar *p, int c, int count)
|
||||||
|
{ return (dchar *)::memchr(p, c, count); }
|
||||||
|
static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); }
|
||||||
|
static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); }
|
||||||
|
static hash_t calcHash(const dchar *str, size_t len);
|
||||||
|
|
||||||
|
// Case insensitive versions
|
||||||
|
static int icmp(dchar *s1, dchar *s2) { return _mbsicmp(s1, s2); }
|
||||||
|
static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::_mbsnicmp(s1, s2, nchars); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef GCC_SAFE_DMD
|
||||||
|
#include <ctype.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef char dchar;
|
||||||
|
#define TEXT(x) x
|
||||||
|
|
||||||
|
#define Dchar_mbmax 1
|
||||||
|
|
||||||
|
struct Dchar
|
||||||
|
{
|
||||||
|
static dchar *inc(dchar *p) { return p + 1; }
|
||||||
|
static dchar *dec(dchar *pstart, dchar *p) { return p - 1; }
|
||||||
|
static int len(const dchar *p) { return strlen(p); }
|
||||||
|
static int get(dchar *p) { return *p & 0xFF; }
|
||||||
|
static int getprev(dchar *pstart, dchar *p) { return p[-1] & 0xFF; }
|
||||||
|
static dchar *put(dchar *p, unsigned c) { *p = c; return p + 1; }
|
||||||
|
static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); }
|
||||||
|
static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); }
|
||||||
|
static int isDigit(dchar c) { return '0' <= c && c <= '9'; }
|
||||||
|
#ifndef GCC_SAFE_DMD
|
||||||
|
static int isAlpha(dchar c) { return isalpha((unsigned char)c); }
|
||||||
|
static int isUpper(dchar c) { return isupper((unsigned char)c); }
|
||||||
|
static int isLower(dchar c) { return islower((unsigned char)c); }
|
||||||
|
static int isLocaleUpper(dchar c) { return isupper((unsigned char)c); }
|
||||||
|
static int isLocaleLower(dchar c) { return islower((unsigned char)c); }
|
||||||
|
static int toLower(dchar c) { return isupper((unsigned char)c) ? tolower(c) : c; }
|
||||||
|
static int toLower(dchar *p) { return toLower(*p); }
|
||||||
|
static int toUpper(dchar c) { return islower((unsigned char)c) ? toupper(c) : c; }
|
||||||
|
static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory?
|
||||||
|
#endif
|
||||||
|
static dchar *chr(dchar *p, int c) { return strchr(p, c); }
|
||||||
|
static dchar *rchr(dchar *p, int c) { return strrchr(p, c); }
|
||||||
|
static dchar *memchr(dchar *p, int c, int count)
|
||||||
|
{ return (dchar *)::memchr(p, c, count); }
|
||||||
|
static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); }
|
||||||
|
static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); }
|
||||||
|
static hash_t calcHash(const dchar *str, size_t len);
|
||||||
|
|
||||||
|
// Case insensitive versions
|
||||||
|
#ifdef __GNUC__
|
||||||
|
static int icmp(dchar *s1, dchar *s2) { return strcasecmp(s1, s2); }
|
||||||
|
#else
|
||||||
|
static int icmp(dchar *s1, dchar *s2) { return stricmp(s1, s2); }
|
||||||
|
#endif
|
||||||
|
static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::memicmp(s1, s2, nchars); }
|
||||||
|
static hash_t icalcHash(const dchar *str, size_t len);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,499 @@
|
|||||||
|
|
||||||
|
|
||||||
|
// Copyright (c) 2000-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "rmem.h"
|
||||||
|
#include "gc/gc.h"
|
||||||
|
//#include "printf.h"
|
||||||
|
|
||||||
|
/* This implementation of the storage allocator uses the Digital Mars gc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Mem mem;
|
||||||
|
|
||||||
|
//static int nuncollectable;
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
void gc_init();
|
||||||
|
GC *gc_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::init()
|
||||||
|
{
|
||||||
|
gc_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Mem::strdup(const char *s)
|
||||||
|
{
|
||||||
|
return gc_get()->strdup(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Mem::malloc(size_t size)
|
||||||
|
{
|
||||||
|
if (gc) // if cached allocator
|
||||||
|
{
|
||||||
|
// PRINTF("Using cached gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line);
|
||||||
|
// GC::file = NULL;
|
||||||
|
// GC::line = 0;
|
||||||
|
return ((GC *)gc)->malloc(size);
|
||||||
|
}
|
||||||
|
if (this == &mem) // don't cache global mem
|
||||||
|
{
|
||||||
|
// PRINTF("Using global gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line);
|
||||||
|
// GC::file = NULL;
|
||||||
|
// GC::line = 0;
|
||||||
|
return gc_get()->malloc(size);
|
||||||
|
}
|
||||||
|
// PRINTF("Generating cached gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line);
|
||||||
|
gc = gc_get();
|
||||||
|
return gc->malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Mem::malloc_uncollectable(size_t size)
|
||||||
|
{ void *p;
|
||||||
|
|
||||||
|
p = ::malloc(size);
|
||||||
|
if (!p)
|
||||||
|
error();
|
||||||
|
addroots((char *)p, (char *)p + size);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
++nuncollectable;
|
||||||
|
WPRINTF(L"malloc_uncollectable(%u) = %x, n=%d\n", size, p, nuncollectable);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Mem::calloc(size_t size, size_t n)
|
||||||
|
{
|
||||||
|
return gc_get()->calloc(size, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Mem::realloc(void *p, size_t size)
|
||||||
|
{
|
||||||
|
return gc_get()->realloc(p, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::free(void *p)
|
||||||
|
{
|
||||||
|
gc_get()->free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::free_uncollectable(void *p)
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
{ removeroots((char *)p);
|
||||||
|
::free(p);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
--nuncollectable;
|
||||||
|
WPRINTF(L"free_uncollectable(%x) n=%d\n", p, nuncollectable);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
gc_get()->fullcollect();
|
||||||
|
|
||||||
|
GCStats stats;
|
||||||
|
|
||||||
|
getStats(&stats);
|
||||||
|
WPRINTF(L"poolsize = %x, usedsize = %x, freelistsize = %x\n",
|
||||||
|
stats.poolsize, stats.usedsize, stats.freelistsize);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Mem::mallocdup(void *o, size_t size)
|
||||||
|
{
|
||||||
|
return gc_get()->mallocdup(o, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::check(void *p)
|
||||||
|
{
|
||||||
|
if (gc)
|
||||||
|
gc->check(p);
|
||||||
|
else
|
||||||
|
gc_get()->check(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::error()
|
||||||
|
{
|
||||||
|
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__
|
||||||
|
assert(0);
|
||||||
|
#endif
|
||||||
|
printf("Error: out of memory\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::fullcollect()
|
||||||
|
{
|
||||||
|
gc_get()->fullcollect();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
GCStats stats;
|
||||||
|
|
||||||
|
gc_get()->getStats(&stats);
|
||||||
|
WPRINTF(L"Thread %x ", Thread::getId());
|
||||||
|
WPRINTF(L"poolsize=x%x, usedsize=x%x, freelistsize=x%x, freeblocks=%d, pageblocks=%d\n",
|
||||||
|
stats.poolsize, stats.usedsize, stats.freelistsize, stats.freeblocks, stats.pageblocks);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mem::fullcollectNoStack()
|
||||||
|
{
|
||||||
|
gc_get()->fullcollectNoStack();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
GCStats stats;
|
||||||
|
|
||||||
|
gc_get()->getStats(&stats);
|
||||||
|
WPRINTF(L"Thread %x ", Thread::getId());
|
||||||
|
WPRINTF(L"poolsize=x%x, usedsize=x%x, freelistsize=x%x, freeblocks=%d, pageblocks=%d\n",
|
||||||
|
stats.poolsize, stats.usedsize, stats.freelistsize, stats.freeblocks, stats.pageblocks);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mem::mark(void *pointer)
|
||||||
|
{
|
||||||
|
(void) pointer; // for VC /W4 compatibility
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mem::addroots(char* pStart, char* pEnd)
|
||||||
|
{
|
||||||
|
gc_get()->addRange(pStart, pEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mem::removeroots(char* pStart)
|
||||||
|
{
|
||||||
|
gc_get()->removeRange(pStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mem::setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData)
|
||||||
|
{
|
||||||
|
(void)pClientData;
|
||||||
|
gc_get()->setFinalizer(pObj, pFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mem::setStackBottom(void *stackbottom)
|
||||||
|
{
|
||||||
|
gc_get()->setStackBottom(stackbottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GC *Mem::getThreadGC()
|
||||||
|
{
|
||||||
|
return gc_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* =================================================== */
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
void * operator new(size_t m_size)
|
||||||
|
{
|
||||||
|
//PRINTF("Call to global operator new(%d), file = '%s', line = %d\n", m_size, GC::file ? GC::file : "(null)", GC::line);
|
||||||
|
GC::file = NULL;
|
||||||
|
GC::line = 0;
|
||||||
|
return mem.malloc(m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete(void *p)
|
||||||
|
{
|
||||||
|
//WPRINTF(L"Call to global operator delete\n");
|
||||||
|
mem.free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* operator new[](size_t size)
|
||||||
|
{
|
||||||
|
return operator new(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete[](void *pv)
|
||||||
|
{
|
||||||
|
operator delete(pv);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void * Mem::operator new(size_t m_size)
|
||||||
|
{ void *p;
|
||||||
|
|
||||||
|
p = gc_get()->malloc(m_size);
|
||||||
|
//printf("Mem::operator new(%d) = %p\n", m_size, p);
|
||||||
|
if (!p)
|
||||||
|
mem.error();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void * Mem::operator new(size_t m_size, Mem *mem)
|
||||||
|
{ void *p;
|
||||||
|
|
||||||
|
p = mem->malloc(m_size);
|
||||||
|
//printf("Mem::operator new(%d) = %p\n", m_size, p);
|
||||||
|
if (!p)
|
||||||
|
::mem.error();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void * Mem::operator new(size_t m_size, GC *gc)
|
||||||
|
{ void *p;
|
||||||
|
|
||||||
|
// if (!gc)
|
||||||
|
// WPRINTF(L"gc is NULL\n");
|
||||||
|
p = gc->malloc(m_size);
|
||||||
|
//printf("Mem::operator new(%d) = %p\n", m_size, p);
|
||||||
|
if (!p)
|
||||||
|
::mem.error();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::operator delete(void *p)
|
||||||
|
{
|
||||||
|
// printf("Mem::operator delete(%p)\n", p);
|
||||||
|
gc_get()->free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
|
||||||
|
/* The following section of code exists to find the right
|
||||||
|
* garbage collector for this thread. There is one independent instance
|
||||||
|
* of the collector per thread.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ===================== linux ================================ */
|
||||||
|
|
||||||
|
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#define LOG 0 // log thread creation / destruction
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
|
// Key identifying the thread-specific data
|
||||||
|
static pthread_key_t gc_key;
|
||||||
|
|
||||||
|
/* "Once" variable ensuring that the key for gc_alloc will be allocated
|
||||||
|
* exactly once.
|
||||||
|
*/
|
||||||
|
static pthread_once_t gc_alloc_key_once = PTHREAD_ONCE_INIT;
|
||||||
|
|
||||||
|
/* Forward functions */
|
||||||
|
static void gc_alloc_key();
|
||||||
|
static void gc_alloc_destroy_gc(void * accu);
|
||||||
|
|
||||||
|
|
||||||
|
void gc_init()
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
WPRINTF(L"Thread %lx: gc_init()\n", pthread_self());
|
||||||
|
#endif
|
||||||
|
pthread_once(&gc_alloc_key_once, gc_alloc_key);
|
||||||
|
#if LOG
|
||||||
|
WPRINTF(L"Thread %lx: gc_init() return\n", pthread_self());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
GC *gc_get()
|
||||||
|
{
|
||||||
|
GC *gc;
|
||||||
|
|
||||||
|
// Get the thread-specific data associated with the key
|
||||||
|
gc = (GC *) pthread_getspecific(gc_key);
|
||||||
|
|
||||||
|
// It's initially NULL, meaning that we must allocate the buffer first.
|
||||||
|
if (gc == NULL)
|
||||||
|
{
|
||||||
|
GC_LOG();
|
||||||
|
gc = new GC();
|
||||||
|
gc->init();
|
||||||
|
|
||||||
|
// Store the buffer pointer in the thread-specific data.
|
||||||
|
pthread_setspecific(gc_key, (void *) gc);
|
||||||
|
#if LOG
|
||||||
|
WPRINTF(L"Thread %lx: allocating gc at %x\n", pthread_self(), gc);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return gc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to allocate the key for gc_alloc thread-specific data.
|
||||||
|
|
||||||
|
static void gc_alloc_key()
|
||||||
|
{
|
||||||
|
pthread_key_create(&gc_key, gc_alloc_destroy_gc);
|
||||||
|
#if LOG
|
||||||
|
WPRINTF(L"Thread %lx: allocated gc key %d\n", pthread_self(), gc_key);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to free the buffer when the thread exits.
|
||||||
|
// Called only when the thread-specific data is not NULL.
|
||||||
|
|
||||||
|
static void gc_alloc_destroy_gc(void *gc)
|
||||||
|
{
|
||||||
|
#if LOG
|
||||||
|
WPRINTF(L"Thread %x: freeing gc at %x\n", pthread_self(), gc);
|
||||||
|
#endif
|
||||||
|
delete (GC *)gc;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ===================== win32 ================================ */
|
||||||
|
|
||||||
|
#if !defined(linux) && defined(_WIN32)
|
||||||
|
|
||||||
|
#if 1 // single threaded version
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
|
static GC *gc;
|
||||||
|
|
||||||
|
void gc_init()
|
||||||
|
{
|
||||||
|
if (!gc)
|
||||||
|
{ gc = (GC *)::malloc(sizeof(GC));
|
||||||
|
gc->init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GC *gc_get()
|
||||||
|
{
|
||||||
|
return gc;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // multi threaded version
|
||||||
|
|
||||||
|
#include "mutex.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
|
/* This is the win32 version. It suffers from the bug that
|
||||||
|
* when the thread exits the data structure is not cleared,
|
||||||
|
* but the memory pool it points to is free'd.
|
||||||
|
* Thus, if a new thread comes along with the same thread id,
|
||||||
|
* the data will look initialized, but will point to garbage.
|
||||||
|
*
|
||||||
|
* What needs to happen is when a thread exits, the associated
|
||||||
|
* GC_context data struct is cleared.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct GC_context
|
||||||
|
{
|
||||||
|
ThreadId threadid; // identifier of current thread
|
||||||
|
GC *gc;
|
||||||
|
};
|
||||||
|
|
||||||
|
Mutex gc_mutex;
|
||||||
|
|
||||||
|
static GC_context array[64];
|
||||||
|
|
||||||
|
// Array of pointers to GC_context objects, one per threadid
|
||||||
|
GC_context *gccontext = array;
|
||||||
|
unsigned gccontext_allocdim = 64;
|
||||||
|
unsigned gccontext_dim;
|
||||||
|
|
||||||
|
ThreadId gc_cache_ti;
|
||||||
|
GC_context *gc_cache_cc;
|
||||||
|
|
||||||
|
extern "C" void gc_init()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" GC *gc_get()
|
||||||
|
{
|
||||||
|
/* This works by creating an array of GC_context's, one
|
||||||
|
* for each thread. We match up by thread id.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ThreadId ti;
|
||||||
|
GC_context *cc;
|
||||||
|
|
||||||
|
//PRINTF("gc_get()\n");
|
||||||
|
|
||||||
|
ti = Thread::getId();
|
||||||
|
gc_mutex.acquire();
|
||||||
|
|
||||||
|
// Used cached version if we can
|
||||||
|
if (ti == gc_cache_ti)
|
||||||
|
{
|
||||||
|
cc = gc_cache_cc;
|
||||||
|
//exception(L"getGC_context(): cache x%x", ti);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This does a linear search through gccontext[].
|
||||||
|
// A hash table might be faster if there are more
|
||||||
|
// than a dozen threads.
|
||||||
|
GC_context *ccp;
|
||||||
|
GC_context *ccptop = &gccontext[gccontext_dim];
|
||||||
|
for (ccp = gccontext; ccp < ccptop; ccp++)
|
||||||
|
{
|
||||||
|
cc = ccp;
|
||||||
|
if (cc->threadid == ti)
|
||||||
|
{
|
||||||
|
WPRINTF(L"getGC_context(): existing x%x", ti);
|
||||||
|
goto Lret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not allocate with garbage collector, as this must reside
|
||||||
|
// global to all threads.
|
||||||
|
|
||||||
|
assert(gccontext_dim < gccontext_allocdim);
|
||||||
|
cc = ccp;
|
||||||
|
memset(cc, 0, sizeof(*cc));
|
||||||
|
cc->threadid = ti;
|
||||||
|
cc->gc = new GC();
|
||||||
|
cc->gc->init();
|
||||||
|
|
||||||
|
gccontext_dim++;
|
||||||
|
WPRINTF(L"getGC_context(): new x%x\n", ti);
|
||||||
|
|
||||||
|
Lret:
|
||||||
|
// Cache for next time
|
||||||
|
gc_cache_ti = ti;
|
||||||
|
gc_cache_cc = cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
gc_mutex.release();
|
||||||
|
return cc->gc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
// Put functions in here missing from gnu C
|
||||||
|
|
||||||
|
#include "gnuc.h"
|
||||||
|
|
||||||
|
int memicmp(const char *s1, const char *s2, int n)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{ char c1 = s1[i];
|
||||||
|
char c2 = s2[i];
|
||||||
|
|
||||||
|
result = c1 - c2;
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
if ('A' <= c1 && c1 <= 'Z')
|
||||||
|
c1 += 'a' - 'A';
|
||||||
|
if ('A' <= c2 && c2 <= 'Z')
|
||||||
|
c2 += 'a' - 'A';
|
||||||
|
result = c1 - c2;
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stricmp(const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{ char c1 = *s1;
|
||||||
|
char c2 = *s2;
|
||||||
|
|
||||||
|
result = c1 - c2;
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
if ('A' <= c1 && c1 <= 'Z')
|
||||||
|
c1 += 'a' - 'A';
|
||||||
|
if ('A' <= c2 && c2 <= 'Z')
|
||||||
|
c2 += 'a' - 'A';
|
||||||
|
result = c1 - c2;
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!c1)
|
||||||
|
break;
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
#ifndef _GNUC_H
|
||||||
|
#define _GNUC_H 1
|
||||||
|
|
||||||
|
int memicmp(const char *s1, const char *s2, int n);
|
||||||
|
int stricmp(const char *s1, const char *s2);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
// lstring.c
|
||||||
|
|
||||||
|
// Copyright (c) 1999-2002 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "dchar.h"
|
||||||
|
#include "rmem.h"
|
||||||
|
#include "lstring.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER // prevent compiler internal crash
|
||||||
|
Lstring Lstring::zero;
|
||||||
|
#else
|
||||||
|
Lstring Lstring::zero = LSTRING_EMPTY();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Lstring *Lstring::ctor(const dchar *p, unsigned length)
|
||||||
|
{
|
||||||
|
Lstring *s;
|
||||||
|
|
||||||
|
s = alloc(length);
|
||||||
|
memcpy(s->string, p, length * sizeof(dchar));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lstring *Lstring::alloc(unsigned length)
|
||||||
|
{
|
||||||
|
Lstring *s;
|
||||||
|
|
||||||
|
s = (Lstring *)mem.malloc(size(length));
|
||||||
|
s->length = length;
|
||||||
|
s->string[length] = 0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lstring *Lstring::append(const Lstring *s)
|
||||||
|
{
|
||||||
|
Lstring *t;
|
||||||
|
|
||||||
|
if (!s->length)
|
||||||
|
return this;
|
||||||
|
t = alloc(length + s->length);
|
||||||
|
memcpy(t->string, string, length * sizeof(dchar));
|
||||||
|
memcpy(t->string + length, s->string, s->length * sizeof(dchar));
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lstring *Lstring::substring(int start, int end)
|
||||||
|
{
|
||||||
|
Lstring *t;
|
||||||
|
|
||||||
|
if (start == end)
|
||||||
|
return &zero;
|
||||||
|
t = alloc(end - start);
|
||||||
|
memcpy(t->string, string + start, (end - start) * sizeof(dchar));
|
||||||
|
return t;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
// lstring.h
|
||||||
|
// length-prefixed strings
|
||||||
|
|
||||||
|
// Copyright (c) 1999-2002 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef LSTRING_H
|
||||||
|
#define LSTRING_H 1
|
||||||
|
|
||||||
|
#include "dchar.h"
|
||||||
|
|
||||||
|
struct Lstring
|
||||||
|
{
|
||||||
|
unsigned length;
|
||||||
|
|
||||||
|
// Disable warning about nonstandard extension
|
||||||
|
#pragma warning (disable : 4200)
|
||||||
|
dchar string[];
|
||||||
|
|
||||||
|
static Lstring zero; // 0 length string
|
||||||
|
|
||||||
|
// No constructors because we want to be able to statically
|
||||||
|
// initialize Lstring's, and Lstrings are of variable size.
|
||||||
|
|
||||||
|
#if M_UNICODE
|
||||||
|
#define LSTRING(p,length) { length, L##p }
|
||||||
|
#else
|
||||||
|
#define LSTRING(p,length) { length, p }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC__
|
||||||
|
#define LSTRING_EMPTY() { 0 }
|
||||||
|
#else
|
||||||
|
#define LSTRING_EMPTY() LSTRING("", 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static Lstring *ctor(const dchar *p) { return ctor(p, Dchar::len(p)); }
|
||||||
|
static Lstring *ctor(const dchar *p, unsigned length);
|
||||||
|
static unsigned size(unsigned length) { return sizeof(Lstring) + (length + 1) * sizeof(dchar); }
|
||||||
|
static Lstring *alloc(unsigned length);
|
||||||
|
Lstring *clone();
|
||||||
|
|
||||||
|
unsigned len() { return length; }
|
||||||
|
|
||||||
|
dchar *toDchars() { return string; }
|
||||||
|
|
||||||
|
hash_t hash() { return Dchar::calcHash(string, length); }
|
||||||
|
hash_t ihash() { return Dchar::icalcHash(string, length); }
|
||||||
|
|
||||||
|
static int cmp(const Lstring *s1, const Lstring *s2)
|
||||||
|
{
|
||||||
|
int c = s2->length - s1->length;
|
||||||
|
return c ? c : Dchar::memcmp(s1->string, s2->string, s1->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int icmp(const Lstring *s1, const Lstring *s2)
|
||||||
|
{
|
||||||
|
int c = s2->length - s1->length;
|
||||||
|
return c ? c : Dchar::memicmp(s1->string, s2->string, s1->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Lstring *append(const Lstring *s);
|
||||||
|
Lstring *substring(int start, int end);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
// Compiler implementation of the D programming language
|
||||||
|
// Copyright (c) 2008-2009 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#pragma comment(lib,"shell32.lib")
|
||||||
|
|
||||||
|
void browse(const char *url)
|
||||||
|
{
|
||||||
|
ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if linux || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void browse(const char *url)
|
||||||
|
{
|
||||||
|
pid_t childpid;
|
||||||
|
const char *args[3];
|
||||||
|
|
||||||
|
const char *browser = getenv("BROWSER");
|
||||||
|
if (browser)
|
||||||
|
browser = strdup(browser);
|
||||||
|
else
|
||||||
|
browser = "x-www-browser";
|
||||||
|
|
||||||
|
args[0] = browser;
|
||||||
|
args[1] = url;
|
||||||
|
args[2] = NULL;
|
||||||
|
|
||||||
|
childpid = fork();
|
||||||
|
if (childpid == 0)
|
||||||
|
{
|
||||||
|
execvp(args[0], (char**)args);
|
||||||
|
perror(args[0]); // failed to execute
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __APPLE__
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void browse(const char *url)
|
||||||
|
{
|
||||||
|
pid_t childpid;
|
||||||
|
const char *args[5];
|
||||||
|
|
||||||
|
char *browser = getenv("BROWSER");
|
||||||
|
if (browser)
|
||||||
|
{ browser = strdup(browser);
|
||||||
|
args[0] = browser;
|
||||||
|
args[1] = url;
|
||||||
|
args[2] = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//browser = "/Applications/Safari.app/Contents/MacOS/Safari";
|
||||||
|
args[0] = "open";
|
||||||
|
args[1] = "-a";
|
||||||
|
args[2] = "/Applications/Safari.app";
|
||||||
|
args[3] = url;
|
||||||
|
args[4] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
childpid = fork();
|
||||||
|
if (childpid == 0)
|
||||||
|
{
|
||||||
|
execvp(args[0], (char**)args);
|
||||||
|
perror(args[0]); // failed to execute
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,796 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
|
||||||
|
#include "port.h"
|
||||||
|
#if __DMC__
|
||||||
|
#include <math.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <fp.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
double Port::nan = NAN;
|
||||||
|
double Port::infinity = INFINITY;
|
||||||
|
double Port::dbl_max = DBL_MAX;
|
||||||
|
double Port::dbl_min = DBL_MIN;
|
||||||
|
long double Port::ldbl_max = LDBL_MAX;
|
||||||
|
|
||||||
|
int Port::isNan(double r)
|
||||||
|
{
|
||||||
|
return ::isnan(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isNan(long double r)
|
||||||
|
{
|
||||||
|
return ::isnan(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isSignallingNan(double r)
|
||||||
|
{
|
||||||
|
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||||
|
* its significand, which is bit 51 of 0..63 for 64 bit doubles.
|
||||||
|
*/
|
||||||
|
return isNan(r) && !((((unsigned char*)&r)[6]) & 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isSignallingNan(long double r)
|
||||||
|
{
|
||||||
|
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||||
|
* its significand, which is bit 62 of 0..79 for 80 bit reals.
|
||||||
|
*/
|
||||||
|
return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isFinite(double r)
|
||||||
|
{
|
||||||
|
return ::isfinite(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isInfinity(double r)
|
||||||
|
{
|
||||||
|
return (::fpclassify(r) == FP_INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::Signbit(double r)
|
||||||
|
{
|
||||||
|
return ::signbit(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::floor(double d)
|
||||||
|
{
|
||||||
|
return ::floor(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::pow(double x, double y)
|
||||||
|
{
|
||||||
|
return ::pow(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
long double Port::fmodl(long double x, long double y)
|
||||||
|
{
|
||||||
|
return ::fmodl(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long Port::strtoull(const char *p, char **pend, int base)
|
||||||
|
{
|
||||||
|
return ::strtoull(p, pend, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Port::ull_to_string(char *buffer, ulonglong ull)
|
||||||
|
{
|
||||||
|
sprintf(buffer, "%llu", ull);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull)
|
||||||
|
{
|
||||||
|
swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::ull_to_double(ulonglong ull)
|
||||||
|
{
|
||||||
|
return (double) ull;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Port::list_separator()
|
||||||
|
{
|
||||||
|
// LOCALE_SLIST for Windows
|
||||||
|
return ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t *Port::wlist_separator()
|
||||||
|
{
|
||||||
|
// LOCALE_SLIST for Windows
|
||||||
|
return L",";
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Port::strupr(char *s)
|
||||||
|
{
|
||||||
|
return ::strupr(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
|
||||||
|
// Disable useless warnings about unreferenced functions
|
||||||
|
#pragma warning (disable : 4514)
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <limits> // for std::numeric_limits
|
||||||
|
|
||||||
|
static unsigned long nanarray[2]= { 0xFFFFFFFF, 0x7FFFFFFF };
|
||||||
|
//static unsigned long nanarray[2] = {0,0x7FF80000 };
|
||||||
|
double Port::nan = (*(double *)nanarray);
|
||||||
|
|
||||||
|
//static unsigned long infinityarray[2] = {0,0x7FF00000 };
|
||||||
|
static double zero = 0;
|
||||||
|
double Port::infinity = 1 / zero;
|
||||||
|
|
||||||
|
double Port::dbl_max = DBL_MAX;
|
||||||
|
double Port::dbl_min = DBL_MIN;
|
||||||
|
long double Port::ldbl_max = LDBL_MAX;
|
||||||
|
|
||||||
|
struct PortInitializer
|
||||||
|
{
|
||||||
|
PortInitializer();
|
||||||
|
};
|
||||||
|
|
||||||
|
static PortInitializer portinitializer;
|
||||||
|
|
||||||
|
PortInitializer::PortInitializer()
|
||||||
|
{
|
||||||
|
Port::infinity = std::numeric_limits<long double>::infinity();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isNan(double r)
|
||||||
|
{
|
||||||
|
return ::_isnan(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isNan(long double r)
|
||||||
|
{
|
||||||
|
return ::_isnan(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isSignallingNan(double r)
|
||||||
|
{
|
||||||
|
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||||
|
* its significand, which is bit 51 of 0..63 for 64 bit doubles.
|
||||||
|
*/
|
||||||
|
return isNan(r) && !((((unsigned char*)&r)[6]) & 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isSignallingNan(long double r)
|
||||||
|
{
|
||||||
|
/* MSVC doesn't have 80 bit long doubles
|
||||||
|
*/
|
||||||
|
return isSignallingNan((double) r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isFinite(double r)
|
||||||
|
{
|
||||||
|
return ::_finite(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isInfinity(double r)
|
||||||
|
{
|
||||||
|
return (::_fpclass(r) & (_FPCLASS_NINF | _FPCLASS_PINF));
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::Signbit(double r)
|
||||||
|
{
|
||||||
|
return (long)(((long *)&(r))[1] & 0x80000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::floor(double d)
|
||||||
|
{
|
||||||
|
return ::floor(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::pow(double x, double y)
|
||||||
|
{
|
||||||
|
if (y == 0)
|
||||||
|
return 1; // even if x is NAN
|
||||||
|
return ::pow(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
long double Port::fmodl(long double x, long double y)
|
||||||
|
{
|
||||||
|
return ::fmodl(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned _int64 Port::strtoull(const char *p, char **pend, int base)
|
||||||
|
{
|
||||||
|
unsigned _int64 number = 0;
|
||||||
|
int c;
|
||||||
|
int error;
|
||||||
|
#ifndef ULLONG_MAX
|
||||||
|
#define ULLONG_MAX ((unsigned _int64)~0I64)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (isspace((unsigned char)*p)) /* skip leading white space */
|
||||||
|
p++;
|
||||||
|
if (*p == '+')
|
||||||
|
p++;
|
||||||
|
switch (base)
|
||||||
|
{ case 0:
|
||||||
|
base = 10; /* assume decimal base */
|
||||||
|
if (*p == '0')
|
||||||
|
{ base = 8; /* could be octal */
|
||||||
|
p++;
|
||||||
|
switch (*p)
|
||||||
|
{ case 'x':
|
||||||
|
case 'X':
|
||||||
|
base = 16; /* hex */
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
#if BINARY
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
base = 2; /* binary */
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 16: /* skip over '0x' and '0X' */
|
||||||
|
if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
|
||||||
|
p += 2;
|
||||||
|
break;
|
||||||
|
#if BINARY
|
||||||
|
case 2: /* skip over '0b' and '0B' */
|
||||||
|
if (*p == '0' && (p[1] == 'b' || p[1] == 'B'))
|
||||||
|
p += 2;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
error = 0;
|
||||||
|
for (;;)
|
||||||
|
{ c = *p;
|
||||||
|
if (isdigit(c))
|
||||||
|
c -= '0';
|
||||||
|
else if (isalpha(c))
|
||||||
|
c = (c & ~0x20) - ('A' - 10);
|
||||||
|
else /* unrecognized character */
|
||||||
|
break;
|
||||||
|
if (c >= base) /* not in number base */
|
||||||
|
break;
|
||||||
|
if ((ULLONG_MAX - c) / base < number)
|
||||||
|
error = 1;
|
||||||
|
number = number * base + c;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (pend)
|
||||||
|
*pend = (char *)p;
|
||||||
|
if (error)
|
||||||
|
{ number = ULLONG_MAX;
|
||||||
|
errno = ERANGE;
|
||||||
|
}
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Port::ull_to_string(char *buffer, ulonglong ull)
|
||||||
|
{
|
||||||
|
_ui64toa(ull, buffer, 10);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull)
|
||||||
|
{
|
||||||
|
_ui64tow(ull, buffer, 10);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::ull_to_double(ulonglong ull)
|
||||||
|
{ double d;
|
||||||
|
|
||||||
|
if ((__int64) ull < 0)
|
||||||
|
{
|
||||||
|
// MSVC doesn't implement the conversion
|
||||||
|
d = (double) (__int64)(ull - 0x8000000000000000i64);
|
||||||
|
d += (double)(signed __int64)(0x7FFFFFFFFFFFFFFFi64) + 1.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
d = (double)(__int64)ull;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Port::list_separator()
|
||||||
|
{
|
||||||
|
// LOCALE_SLIST for Windows
|
||||||
|
return ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t *Port::wlist_separator()
|
||||||
|
{
|
||||||
|
// LOCALE_SLIST for Windows
|
||||||
|
return L",";
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Port::strupr(char *s)
|
||||||
|
{
|
||||||
|
return ::strupr(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __HAIKU__
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#if linux
|
||||||
|
#include <bits/nan.h>
|
||||||
|
#include <bits/mathdef.h>
|
||||||
|
#endif
|
||||||
|
#if __FreeBSD__ && __i386__
|
||||||
|
#include <ieeefp.h>
|
||||||
|
#endif
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
static double zero = 0;
|
||||||
|
double Port::nan = copysign(NAN, 1.0);
|
||||||
|
double Port::infinity = 1 / zero;
|
||||||
|
double Port::dbl_max = 1.7976931348623157e308;
|
||||||
|
double Port::dbl_min = 5e-324;
|
||||||
|
long double Port::ldbl_max = LDBL_MAX;
|
||||||
|
|
||||||
|
struct PortInitializer
|
||||||
|
{
|
||||||
|
PortInitializer();
|
||||||
|
};
|
||||||
|
|
||||||
|
static PortInitializer portinitializer;
|
||||||
|
|
||||||
|
PortInitializer::PortInitializer()
|
||||||
|
{
|
||||||
|
assert(!signbit(Port::nan));
|
||||||
|
|
||||||
|
#if __FreeBSD__ && __i386__
|
||||||
|
// LDBL_MAX comes out as infinity. Fix.
|
||||||
|
static unsigned char x[sizeof(long double)] =
|
||||||
|
{ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F };
|
||||||
|
Port::ldbl_max = *(long double *)&x[0];
|
||||||
|
// FreeBSD defaults to double precision. Switch to extended precision.
|
||||||
|
fpsetprec(FP_PE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef __HAIKU__
|
||||||
|
#endif
|
||||||
|
int Port::isNan(double r)
|
||||||
|
{
|
||||||
|
#if __APPLE__
|
||||||
|
return __inline_isnan(r);
|
||||||
|
#elif defined __HAIKU__ || __OpenBSD__
|
||||||
|
return isnan(r);
|
||||||
|
#else
|
||||||
|
#undef isnan
|
||||||
|
return ::isnan(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isNan(long double r)
|
||||||
|
{
|
||||||
|
#if __APPLE__
|
||||||
|
return __inline_isnan(r);
|
||||||
|
#elif defined __HAIKU__ || __OpenBSD__
|
||||||
|
return isnan(r);
|
||||||
|
#else
|
||||||
|
#undef isnan
|
||||||
|
return ::isnan(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isSignallingNan(double r)
|
||||||
|
{
|
||||||
|
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||||
|
* its significand, which is bit 51 of 0..63 for 64 bit doubles.
|
||||||
|
*/
|
||||||
|
return isNan(r) && !((((unsigned char*)&r)[6]) & 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isSignallingNan(long double r)
|
||||||
|
{
|
||||||
|
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||||
|
* its significand, which is bit 62 of 0..79 for 80 bit reals.
|
||||||
|
*/
|
||||||
|
return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef isfinite
|
||||||
|
int Port::isFinite(double r)
|
||||||
|
{
|
||||||
|
return ::finite(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined __HAIKU__
|
||||||
|
#endif
|
||||||
|
int Port::isInfinity(double r)
|
||||||
|
{
|
||||||
|
#if __APPLE__
|
||||||
|
return fpclassify(r) == FP_INFINITE;
|
||||||
|
#elif defined __HAIKU__ || __OpenBSD__
|
||||||
|
return isinf(r);
|
||||||
|
#else
|
||||||
|
#undef isinf
|
||||||
|
return ::isinf(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef signbit
|
||||||
|
int Port::Signbit(double r)
|
||||||
|
{
|
||||||
|
union { double d; long long ll; } u;
|
||||||
|
u.d = r;
|
||||||
|
return u.ll < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::floor(double d)
|
||||||
|
{
|
||||||
|
return ::floor(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::pow(double x, double y)
|
||||||
|
{
|
||||||
|
return ::pow(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
long double Port::fmodl(long double x, long double y)
|
||||||
|
{
|
||||||
|
#if __FreeBSD__ || __OpenBSD__
|
||||||
|
return ::fmod(x, y); // hack for now, fix later
|
||||||
|
#else
|
||||||
|
return ::fmodl(x, y);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long Port::strtoull(const char *p, char **pend, int base)
|
||||||
|
{
|
||||||
|
return ::strtoull(p, pend, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Port::ull_to_string(char *buffer, ulonglong ull)
|
||||||
|
{
|
||||||
|
sprintf(buffer, "%llu", ull);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull)
|
||||||
|
{
|
||||||
|
#if __OpenBSD__
|
||||||
|
assert(0);
|
||||||
|
#else
|
||||||
|
swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull);
|
||||||
|
#endif
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::ull_to_double(ulonglong ull)
|
||||||
|
{
|
||||||
|
return (double) ull;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Port::list_separator()
|
||||||
|
{
|
||||||
|
return ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t *Port::wlist_separator()
|
||||||
|
{
|
||||||
|
return L",";
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Port::strupr(char *s)
|
||||||
|
{
|
||||||
|
char *t = s;
|
||||||
|
|
||||||
|
while (*s)
|
||||||
|
{
|
||||||
|
*s = toupper(*s);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __sun&&__SVR4
|
||||||
|
|
||||||
|
#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more
|
||||||
|
#include <math.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <ieeefp.h>
|
||||||
|
|
||||||
|
static double zero = 0;
|
||||||
|
double Port::nan = NAN;
|
||||||
|
double Port::infinity = 1 / zero;
|
||||||
|
double Port::dbl_max = 1.7976931348623157e308;
|
||||||
|
double Port::dbl_min = 5e-324;
|
||||||
|
long double Port::ldbl_max = LDBL_MAX;
|
||||||
|
|
||||||
|
struct PortInitializer
|
||||||
|
{
|
||||||
|
PortInitializer();
|
||||||
|
};
|
||||||
|
|
||||||
|
static PortInitializer portinitializer;
|
||||||
|
|
||||||
|
PortInitializer::PortInitializer()
|
||||||
|
{
|
||||||
|
// gcc nan's have the sign bit set by default, so turn it off
|
||||||
|
// Need the volatile to prevent gcc from doing incorrect
|
||||||
|
// constant folding.
|
||||||
|
volatile long double foo;
|
||||||
|
foo = NAN;
|
||||||
|
if (signbit(foo)) // signbit sometimes, not always, set
|
||||||
|
foo = -foo; // turn off sign bit
|
||||||
|
Port::nan = foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isNan(double r)
|
||||||
|
{
|
||||||
|
return isnan(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isNan(long double r)
|
||||||
|
{
|
||||||
|
return isnan(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isSignallingNan(double r)
|
||||||
|
{
|
||||||
|
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||||
|
* its significand, which is bit 51 of 0..63 for 64 bit doubles.
|
||||||
|
*/
|
||||||
|
return isNan(r) && !((((unsigned char*)&r)[6]) & 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isSignallingNan(long double r)
|
||||||
|
{
|
||||||
|
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||||
|
* its significand, which is bit 62 of 0..79 for 80 bit reals.
|
||||||
|
*/
|
||||||
|
return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef isfinite
|
||||||
|
int Port::isFinite(double r)
|
||||||
|
{
|
||||||
|
return finite(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isInfinity(double r)
|
||||||
|
{
|
||||||
|
return isinf(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef signbit
|
||||||
|
int Port::Signbit(double r)
|
||||||
|
{
|
||||||
|
return (long)(((long *)&r)[1] & 0x80000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::floor(double d)
|
||||||
|
{
|
||||||
|
return ::floor(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::pow(double x, double y)
|
||||||
|
{
|
||||||
|
return ::pow(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long Port::strtoull(const char *p, char **pend, int base)
|
||||||
|
{
|
||||||
|
return ::strtoull(p, pend, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Port::ull_to_string(char *buffer, ulonglong ull)
|
||||||
|
{
|
||||||
|
sprintf(buffer, "%llu", ull);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull)
|
||||||
|
{
|
||||||
|
swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::ull_to_double(ulonglong ull)
|
||||||
|
{
|
||||||
|
return (double) ull;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Port::list_separator()
|
||||||
|
{
|
||||||
|
return ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t *Port::wlist_separator()
|
||||||
|
{
|
||||||
|
return L",";
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Port::strupr(char *s)
|
||||||
|
{
|
||||||
|
char *t = s;
|
||||||
|
|
||||||
|
while (*s)
|
||||||
|
{
|
||||||
|
*s = toupper(*s);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IN_GCC
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <bits/nan.h>
|
||||||
|
#include <bits/mathdef.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
static double zero = 0;
|
||||||
|
double Port::nan = NAN;
|
||||||
|
double Port::infinity = 1 / zero;
|
||||||
|
double Port::dbl_max = 1.7976931348623157e308;
|
||||||
|
double Port::dbl_min = 5e-324;
|
||||||
|
long double Port::ldbl_max = LDBL_MAX;
|
||||||
|
|
||||||
|
#include "d-gcc-real.h"
|
||||||
|
extern "C" bool real_isnan (const real_t *);
|
||||||
|
|
||||||
|
struct PortInitializer
|
||||||
|
{
|
||||||
|
PortInitializer();
|
||||||
|
};
|
||||||
|
|
||||||
|
static PortInitializer portinitializer;
|
||||||
|
|
||||||
|
PortInitializer::PortInitializer()
|
||||||
|
{
|
||||||
|
Port::infinity = real_t::getinfinity();
|
||||||
|
Port::nan = real_t::getnan(real_t::LongDouble);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef isnan
|
||||||
|
int Port::isNan(double r)
|
||||||
|
{
|
||||||
|
#if __APPLE__
|
||||||
|
return __inline_isnan(r);
|
||||||
|
#else
|
||||||
|
return ::isnan(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isNan(long double r)
|
||||||
|
{
|
||||||
|
return real_isnan(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isSignallingNan(double r)
|
||||||
|
{
|
||||||
|
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||||
|
* its significand, which is bit 51 of 0..63 for 64 bit doubles.
|
||||||
|
*/
|
||||||
|
return isNan(r) && !((((unsigned char*)&r)[6]) & 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Port::isSignallingNan(long double r)
|
||||||
|
{
|
||||||
|
/* A signalling NaN is a NaN with 0 as the most significant bit of
|
||||||
|
* its significand, which is bit 62 of 0..79 for 80 bit reals.
|
||||||
|
*/
|
||||||
|
return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef isfinite
|
||||||
|
int Port::isFinite(double r)
|
||||||
|
{
|
||||||
|
return ::finite(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef isinf
|
||||||
|
int Port::isInfinity(double r)
|
||||||
|
{
|
||||||
|
return ::isinf(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef signbit
|
||||||
|
int Port::Signbit(double r)
|
||||||
|
{
|
||||||
|
return (long)(((long *)&r)[1] & 0x80000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::floor(double d)
|
||||||
|
{
|
||||||
|
return ::floor(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::pow(double x, double y)
|
||||||
|
{
|
||||||
|
return ::pow(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long Port::strtoull(const char *p, char **pend, int base)
|
||||||
|
{
|
||||||
|
return ::strtoull(p, pend, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Port::ull_to_string(char *buffer, ulonglong ull)
|
||||||
|
{
|
||||||
|
sprintf(buffer, "%llu", ull);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull)
|
||||||
|
{
|
||||||
|
swprintf(buffer, L"%llu", ull);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Port::ull_to_double(ulonglong ull)
|
||||||
|
{
|
||||||
|
return (double) ull;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Port::list_separator()
|
||||||
|
{
|
||||||
|
return ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t *Port::wlist_separator()
|
||||||
|
{
|
||||||
|
return L",";
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Port::strupr(char *s)
|
||||||
|
{
|
||||||
|
char *t = s;
|
||||||
|
|
||||||
|
while (*s)
|
||||||
|
{
|
||||||
|
*s = toupper(*s);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2009 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
|
||||||
|
#ifndef PORT_H
|
||||||
|
#define PORT_H
|
||||||
|
|
||||||
|
// Portable wrapper around compiler/system specific things.
|
||||||
|
// The idea is to minimize #ifdef's in the app code.
|
||||||
|
|
||||||
|
#ifndef TYPEDEFS
|
||||||
|
#define TYPEDEFS
|
||||||
|
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
typedef __int64 longlong;
|
||||||
|
typedef unsigned __int64 ulonglong;
|
||||||
|
|
||||||
|
// According to VC 8.0 docs, long double is the same as double
|
||||||
|
#define strtold strtod
|
||||||
|
#define strtof strtod
|
||||||
|
|
||||||
|
#else
|
||||||
|
typedef long long longlong;
|
||||||
|
typedef unsigned long long ulonglong;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef double d_time;
|
||||||
|
|
||||||
|
struct Port
|
||||||
|
{
|
||||||
|
static double nan;
|
||||||
|
static double infinity;
|
||||||
|
static double dbl_max;
|
||||||
|
static double dbl_min;
|
||||||
|
static long double ldbl_max;
|
||||||
|
|
||||||
|
#if !defined __HAIKU__ || __OpenBSD__
|
||||||
|
#elif __GNUC__
|
||||||
|
// These conflict with macros in math.h, should rename them
|
||||||
|
#undef isnan
|
||||||
|
#undef isfinite
|
||||||
|
#undef isinfinity
|
||||||
|
#undef signbit
|
||||||
|
#endif
|
||||||
|
static int isNan(double);
|
||||||
|
static int isNan(long double);
|
||||||
|
|
||||||
|
static int isSignallingNan(double);
|
||||||
|
static int isSignallingNan(long double);
|
||||||
|
|
||||||
|
static int isFinite(double);
|
||||||
|
static int isInfinity(double);
|
||||||
|
static int Signbit(double);
|
||||||
|
|
||||||
|
static double floor(double);
|
||||||
|
static double pow(double x, double y);
|
||||||
|
|
||||||
|
static long double fmodl(long double x, long double y);
|
||||||
|
|
||||||
|
static ulonglong strtoull(const char *p, char **pend, int base);
|
||||||
|
|
||||||
|
static char *ull_to_string(char *buffer, ulonglong ull);
|
||||||
|
static wchar_t *ull_to_string(wchar_t *buffer, ulonglong ull);
|
||||||
|
|
||||||
|
// Convert ulonglong to double
|
||||||
|
static double ull_to_double(ulonglong ull);
|
||||||
|
|
||||||
|
// Get locale-dependent list separator
|
||||||
|
static const char *list_separator();
|
||||||
|
static const wchar_t *wlist_separator();
|
||||||
|
|
||||||
|
static char *strupr(char *);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
// Copyright (C) 1990-1998 by Symantec
|
||||||
|
// Copyright (C) 2000-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// Written by Walter Bright
|
||||||
|
/*
|
||||||
|
* This source file is made available for personal use
|
||||||
|
* only. The license is in /dmd/src/dmd/backendlicense.txt
|
||||||
|
* For any other uses, please contact Digital Mars.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <io.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* #include <stdlib.h>
|
||||||
|
* int response_expand(int *pargc,char ***pargv);
|
||||||
|
*
|
||||||
|
* Expand any response files in command line.
|
||||||
|
* Response files are arguments that look like:
|
||||||
|
* @NAME
|
||||||
|
* The name is first searched for in the environment. If it is not
|
||||||
|
* there, it is searched for as a file name.
|
||||||
|
* Arguments are separated by spaces, tabs, or newlines. These can be
|
||||||
|
* imbedded within arguments by enclosing the argument in '' or "".
|
||||||
|
* Recursively expands nested response files.
|
||||||
|
*
|
||||||
|
* To use, put the line:
|
||||||
|
* response_expand(&argc,&argv);
|
||||||
|
* as the first executable statement in main(int argc, char **argv).
|
||||||
|
* argc and argv are adjusted to be the new command line arguments
|
||||||
|
* after response file expansion.
|
||||||
|
*
|
||||||
|
* Digital Mars's MAKE program can be notified that a program can accept
|
||||||
|
* long command lines via environment variables by preceding the rule
|
||||||
|
* line for the program with a *.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 success
|
||||||
|
* !=0 failure (argc, argv unchanged)
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct Narg
|
||||||
|
{
|
||||||
|
int argc; /* arg count */
|
||||||
|
int argvmax; /* dimension of nargv[] */
|
||||||
|
char **argv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int addargp(struct Narg *n, char *p)
|
||||||
|
{
|
||||||
|
/* The 2 is to always allow room for a NULL argp at the end */
|
||||||
|
if (n->argc + 2 > n->argvmax)
|
||||||
|
{
|
||||||
|
n->argvmax = n->argc + 2;
|
||||||
|
char **ap = n->argv;
|
||||||
|
ap = (char **) realloc(ap,n->argvmax * sizeof(char *));
|
||||||
|
if (!ap)
|
||||||
|
{ if (n->argv)
|
||||||
|
free(n->argv);
|
||||||
|
memset(n, 0, sizeof(*n));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
n->argv = ap;
|
||||||
|
}
|
||||||
|
n->argv[n->argc++] = p;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int response_expand(int *pargc, char ***pargv)
|
||||||
|
{
|
||||||
|
struct Narg n;
|
||||||
|
int i;
|
||||||
|
char *cp;
|
||||||
|
int recurse = 0;
|
||||||
|
|
||||||
|
n.argc = 0;
|
||||||
|
n.argvmax = 0; /* dimension of n.argv[] */
|
||||||
|
n.argv = NULL;
|
||||||
|
for(i=0; i<*pargc; ++i)
|
||||||
|
{
|
||||||
|
cp = (*pargv)[i];
|
||||||
|
if (*cp == '@')
|
||||||
|
{
|
||||||
|
char *buffer;
|
||||||
|
char *bufend;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
cp++;
|
||||||
|
p = getenv(cp);
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
buffer = strdup(p);
|
||||||
|
if (!buffer)
|
||||||
|
goto noexpand;
|
||||||
|
bufend = buffer + strlen(buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long length;
|
||||||
|
int fd;
|
||||||
|
int nread;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
#if __DMC__
|
||||||
|
length = filesize(cp);
|
||||||
|
#else
|
||||||
|
struct stat statbuf;
|
||||||
|
if (stat(cp, &statbuf))
|
||||||
|
goto noexpand;
|
||||||
|
length = statbuf.st_size;
|
||||||
|
#endif
|
||||||
|
if (length & 0xF0000000) /* error or file too big */
|
||||||
|
goto noexpand;
|
||||||
|
len = length;
|
||||||
|
buffer = (char *)malloc(len + 1);
|
||||||
|
if (!buffer)
|
||||||
|
goto noexpand;
|
||||||
|
bufend = &buffer[len];
|
||||||
|
/* Read file into buffer */
|
||||||
|
#if _WIN32
|
||||||
|
fd = _open(cp,O_RDONLY|O_BINARY);
|
||||||
|
#else
|
||||||
|
fd = open(cp,O_RDONLY);
|
||||||
|
#endif
|
||||||
|
if (fd == -1)
|
||||||
|
goto noexpand;
|
||||||
|
nread = read(fd,buffer,len);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (nread != len)
|
||||||
|
goto noexpand;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The logic of this should match that in setargv()
|
||||||
|
|
||||||
|
for (p = buffer; p < bufend; p++)
|
||||||
|
{
|
||||||
|
char *d;
|
||||||
|
char c,lastc;
|
||||||
|
unsigned char instring;
|
||||||
|
int num_slashes,non_slashes;
|
||||||
|
|
||||||
|
switch (*p)
|
||||||
|
{
|
||||||
|
case 26: /* ^Z marks end of file */
|
||||||
|
goto L2;
|
||||||
|
|
||||||
|
case 0xD:
|
||||||
|
case 0:
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\n':
|
||||||
|
continue; // scan to start of argument
|
||||||
|
|
||||||
|
case '@':
|
||||||
|
recurse = 1;
|
||||||
|
default: /* start of new argument */
|
||||||
|
if (addargp(&n,p))
|
||||||
|
goto noexpand;
|
||||||
|
instring = 0;
|
||||||
|
c = 0;
|
||||||
|
num_slashes = 0;
|
||||||
|
for (d = p; 1; p++)
|
||||||
|
{
|
||||||
|
lastc = c;
|
||||||
|
if (p >= bufend)
|
||||||
|
goto Lend;
|
||||||
|
c = *p;
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '"':
|
||||||
|
/*
|
||||||
|
Yes this looks strange,but this is so that we are
|
||||||
|
MS Compatible, tests have shown that:
|
||||||
|
\\\\"foo bar" gets passed as \\foo bar
|
||||||
|
\\\\foo gets passed as \\\\foo
|
||||||
|
\\\"foo gets passed as \"foo
|
||||||
|
and \"foo gets passed as "foo in VC!
|
||||||
|
*/
|
||||||
|
non_slashes = num_slashes % 2;
|
||||||
|
num_slashes = num_slashes / 2;
|
||||||
|
for (; num_slashes > 0; num_slashes--)
|
||||||
|
{
|
||||||
|
d--;
|
||||||
|
*d = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (non_slashes)
|
||||||
|
{
|
||||||
|
*(d-1) = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
instring ^= 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 26:
|
||||||
|
Lend:
|
||||||
|
*d = 0; // terminate argument
|
||||||
|
goto L2;
|
||||||
|
|
||||||
|
case 0xD: // CR
|
||||||
|
c = lastc;
|
||||||
|
continue; // ignore
|
||||||
|
|
||||||
|
case '@':
|
||||||
|
recurse = 1;
|
||||||
|
goto Ladd;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
if (!instring)
|
||||||
|
{
|
||||||
|
case '\n':
|
||||||
|
case 0:
|
||||||
|
*d = 0; // terminate argument
|
||||||
|
goto Lnextarg;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Ladd:
|
||||||
|
if (c == '\\')
|
||||||
|
num_slashes++;
|
||||||
|
else
|
||||||
|
num_slashes = 0;
|
||||||
|
*d++ = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#ifdef _MBCS
|
||||||
|
if (_istlead (c)) {
|
||||||
|
*d++ = *++p;
|
||||||
|
if (*(d - 1) == '\0') {
|
||||||
|
d--;
|
||||||
|
goto Lnextarg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Lnextarg:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
L2:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
else if (addargp(&n,(*pargv)[i]))
|
||||||
|
goto noexpand;
|
||||||
|
}
|
||||||
|
if (n.argvmax == 0)
|
||||||
|
{
|
||||||
|
n.argvmax = 1;
|
||||||
|
n.argv = (char **) calloc(n.argvmax, sizeof(char *));
|
||||||
|
if (!n.argv)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
n.argv[n.argc] = NULL;
|
||||||
|
if (recurse)
|
||||||
|
{
|
||||||
|
/* Recursively expand @filename */
|
||||||
|
if (response_expand(&n.argc,&n.argv))
|
||||||
|
goto noexpand;
|
||||||
|
}
|
||||||
|
*pargc = n.argc;
|
||||||
|
*pargv = n.argv;
|
||||||
|
return 0; /* success */
|
||||||
|
|
||||||
|
noexpand: /* error */
|
||||||
|
free(n.argv);
|
||||||
|
/* BUG: any file buffers are not free'd */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
|
||||||
|
/* Copyright (c) 2000 Digital Mars */
|
||||||
|
/* All Rights Reserved */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
|
||||||
|
#include "../root/rmem.h"
|
||||||
|
#else
|
||||||
|
#include "rmem.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This implementation of the storage allocator uses the standard C allocation package.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Mem mem;
|
||||||
|
|
||||||
|
void Mem::init()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Mem::strdup(const char *s)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
p = ::strdup(s);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Mem::malloc(size_t size)
|
||||||
|
{ void *p;
|
||||||
|
|
||||||
|
if (!size)
|
||||||
|
p = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p = ::malloc(size);
|
||||||
|
if (!p)
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Mem::calloc(size_t size, size_t n)
|
||||||
|
{ void *p;
|
||||||
|
|
||||||
|
if (!size || !n)
|
||||||
|
p = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p = ::calloc(size, n);
|
||||||
|
if (!p)
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Mem::realloc(void *p, size_t size)
|
||||||
|
{
|
||||||
|
if (!size)
|
||||||
|
{ if (p)
|
||||||
|
{ ::free(p);
|
||||||
|
p = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!p)
|
||||||
|
{
|
||||||
|
p = ::malloc(size);
|
||||||
|
if (!p)
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
void *psave = p;
|
||||||
|
p = ::realloc(psave, size);
|
||||||
|
if (!p)
|
||||||
|
{ free(psave);
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::free(void *p)
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
::free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Mem::mallocdup(void *o, size_t size)
|
||||||
|
{ void *p;
|
||||||
|
|
||||||
|
if (!size)
|
||||||
|
p = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p = ::malloc(size);
|
||||||
|
if (!p)
|
||||||
|
error();
|
||||||
|
else
|
||||||
|
memcpy(p,o,size);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::error()
|
||||||
|
{
|
||||||
|
printf("Error: out of memory\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::fullcollect()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::mark(void *pointer)
|
||||||
|
{
|
||||||
|
(void) pointer; // necessary for VC /W4
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::setStackBottom(void *bottom)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mem::addroots(char* pStart, char* pEnd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* =================================================== */
|
||||||
|
|
||||||
|
void * operator new(size_t m_size)
|
||||||
|
{
|
||||||
|
void *p = malloc(m_size);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
printf("Error: out of memory\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete(void *p)
|
||||||
|
{
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (C) 2000-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
|
||||||
|
#ifndef ROOT_MEM_H
|
||||||
|
#define ROOT_MEM_H
|
||||||
|
|
||||||
|
#include <stddef.h> // for size_t
|
||||||
|
|
||||||
|
typedef void (*FINALIZERPROC)(void* pObj, void* pClientData);
|
||||||
|
|
||||||
|
struct GC; // thread specific allocator
|
||||||
|
|
||||||
|
struct Mem
|
||||||
|
{
|
||||||
|
GC *gc; // pointer to our thread specific allocator
|
||||||
|
Mem() { gc = NULL; }
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
// Derive from Mem to get these storage allocators instead of global new/delete
|
||||||
|
void * operator new(size_t m_size);
|
||||||
|
void * operator new(size_t m_size, Mem *mem);
|
||||||
|
void * operator new(size_t m_size, GC *gc);
|
||||||
|
void operator delete(void *p);
|
||||||
|
|
||||||
|
void * operator new[](size_t m_size);
|
||||||
|
void operator delete[](void *p);
|
||||||
|
|
||||||
|
char *strdup(const char *s);
|
||||||
|
void *malloc(size_t size);
|
||||||
|
void *malloc_uncollectable(size_t size);
|
||||||
|
void *calloc(size_t size, size_t n);
|
||||||
|
void *realloc(void *p, size_t size);
|
||||||
|
void free(void *p);
|
||||||
|
void free_uncollectable(void *p);
|
||||||
|
void *mallocdup(void *o, size_t size);
|
||||||
|
void error();
|
||||||
|
void check(void *p); // validate pointer
|
||||||
|
void fullcollect(); // do full garbage collection
|
||||||
|
void fullcollectNoStack(); // do full garbage collection, no scan stack
|
||||||
|
void mark(void *pointer);
|
||||||
|
void addroots(char* pStart, char* pEnd);
|
||||||
|
void removeroots(char* pStart);
|
||||||
|
void setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData);
|
||||||
|
void setStackBottom(void *bottom);
|
||||||
|
GC *getThreadGC(); // get apartment allocator for this thread
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Mem mem;
|
||||||
|
|
||||||
|
#endif /* ROOT_MEM_H */
|
||||||
+2095
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,417 @@
|
|||||||
|
|
||||||
|
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#ifndef ROOT_H
|
||||||
|
#define ROOT_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#ifdef DEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __DMC__
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef size_t hash_t;
|
||||||
|
|
||||||
|
#include "dchar.h"
|
||||||
|
|
||||||
|
char *wchar2ascii(wchar_t *);
|
||||||
|
int wcharIsAscii(wchar_t *);
|
||||||
|
char *wchar2ascii(wchar_t *, unsigned len);
|
||||||
|
int wcharIsAscii(wchar_t *, unsigned len);
|
||||||
|
|
||||||
|
int bstrcmp(unsigned char *s1, unsigned char *s2);
|
||||||
|
char *bstr2str(unsigned char *b);
|
||||||
|
void error(const char *format, ...);
|
||||||
|
void error(const wchar_t *format, ...);
|
||||||
|
void warning(const char *format, ...);
|
||||||
|
|
||||||
|
#ifndef TYPEDEFS
|
||||||
|
#define TYPEDEFS
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
#include <float.h> // for _isnan
|
||||||
|
#include <malloc.h> // for alloca
|
||||||
|
// According to VC 8.0 docs, long double is the same as double
|
||||||
|
#define strtold strtod
|
||||||
|
#define strtof strtod
|
||||||
|
#define isnan _isnan
|
||||||
|
|
||||||
|
typedef __int64 longlong;
|
||||||
|
typedef unsigned __int64 ulonglong;
|
||||||
|
#else
|
||||||
|
typedef long long longlong;
|
||||||
|
typedef unsigned long long ulonglong;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
longlong randomx();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Root of our class library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct OutBuffer;
|
||||||
|
|
||||||
|
// Can't include arraytypes.h here, need to declare these directly.
|
||||||
|
template <typename TYPE> struct ArrayBase;
|
||||||
|
typedef ArrayBase<struct File> Files;
|
||||||
|
typedef ArrayBase<char> Strings;
|
||||||
|
|
||||||
|
|
||||||
|
struct Object
|
||||||
|
{
|
||||||
|
Object() { }
|
||||||
|
virtual ~Object() { }
|
||||||
|
|
||||||
|
virtual int equals(Object *o);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a hash code, useful for things like building hash tables of Objects.
|
||||||
|
*/
|
||||||
|
virtual hash_t hashCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return <0, ==0, or >0 if this is less than, equal to, or greater than obj.
|
||||||
|
* Useful for sorting Objects.
|
||||||
|
*/
|
||||||
|
virtual int compare(Object *obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pretty-print an Object. Useful for debugging the old-fashioned way.
|
||||||
|
*/
|
||||||
|
virtual void print();
|
||||||
|
|
||||||
|
virtual char *toChars();
|
||||||
|
virtual dchar *toDchars();
|
||||||
|
virtual void toBuffer(OutBuffer *buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used as a replacement for dynamic_cast. Returns a unique number
|
||||||
|
* defined by the library user. For Object, the return value is 0.
|
||||||
|
*/
|
||||||
|
virtual int dyncast();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks pointers for garbage collector by calling mem.mark() for all pointers into heap.
|
||||||
|
*/
|
||||||
|
/*virtual*/ // not used, disable for now
|
||||||
|
void mark();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct String : Object
|
||||||
|
{
|
||||||
|
int ref; // != 0 if this is a reference to someone else's string
|
||||||
|
char *str; // the string itself
|
||||||
|
|
||||||
|
String(char *str, int ref = 1);
|
||||||
|
|
||||||
|
~String();
|
||||||
|
|
||||||
|
static hash_t calcHash(const char *str, size_t len);
|
||||||
|
static hash_t calcHash(const char *str);
|
||||||
|
hash_t hashCode();
|
||||||
|
unsigned len();
|
||||||
|
int equals(Object *obj);
|
||||||
|
int compare(Object *obj);
|
||||||
|
char *toChars();
|
||||||
|
void print();
|
||||||
|
void mark();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FileName : String
|
||||||
|
{
|
||||||
|
FileName(char *str, int ref);
|
||||||
|
FileName(char *path, char *name);
|
||||||
|
hash_t hashCode();
|
||||||
|
int equals(Object *obj);
|
||||||
|
static int equals(const char *name1, const char *name2);
|
||||||
|
int compare(Object *obj);
|
||||||
|
static int compare(const char *name1, const char *name2);
|
||||||
|
static int absolute(const char *name);
|
||||||
|
static char *ext(const char *);
|
||||||
|
char *ext();
|
||||||
|
static char *removeExt(const char *str);
|
||||||
|
static char *name(const char *);
|
||||||
|
char *name();
|
||||||
|
static char *path(const char *);
|
||||||
|
static const char *replaceName(const char *path, const char *name);
|
||||||
|
|
||||||
|
static char *combine(const char *path, const char *name);
|
||||||
|
static Strings *splitPath(const char *path);
|
||||||
|
static FileName *defaultExt(const char *name, const char *ext);
|
||||||
|
static FileName *forceExt(const char *name, const char *ext);
|
||||||
|
int equalsExt(const char *ext);
|
||||||
|
|
||||||
|
void CopyTo(FileName *to);
|
||||||
|
static char *searchPath(Strings *path, const char *name, int cwd);
|
||||||
|
static char *safeSearchPath(Strings *path, const char *name);
|
||||||
|
static int exists(const char *name);
|
||||||
|
static void ensurePathExists(const char *path);
|
||||||
|
static char *canonicalName(const char *name);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct File : Object
|
||||||
|
{
|
||||||
|
int ref; // != 0 if this is a reference to someone else's buffer
|
||||||
|
unsigned char *buffer; // data for our file
|
||||||
|
unsigned len; // amount of data in buffer[]
|
||||||
|
void *touchtime; // system time to use for file
|
||||||
|
|
||||||
|
FileName *name; // name of our file
|
||||||
|
|
||||||
|
File(char *);
|
||||||
|
File(FileName *);
|
||||||
|
~File();
|
||||||
|
|
||||||
|
void mark();
|
||||||
|
|
||||||
|
char *toChars();
|
||||||
|
|
||||||
|
/* Read file, return !=0 if error
|
||||||
|
*/
|
||||||
|
|
||||||
|
int read();
|
||||||
|
|
||||||
|
/* Write file, either succeed or fail
|
||||||
|
* with error message & exit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void readv();
|
||||||
|
|
||||||
|
/* Read file, return !=0 if error
|
||||||
|
*/
|
||||||
|
|
||||||
|
int mmread();
|
||||||
|
|
||||||
|
/* Write file, either succeed or fail
|
||||||
|
* with error message & exit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void mmreadv();
|
||||||
|
|
||||||
|
/* Write file, return !=0 if error
|
||||||
|
*/
|
||||||
|
|
||||||
|
int write();
|
||||||
|
|
||||||
|
/* Write file, either succeed or fail
|
||||||
|
* with error message & exit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void writev();
|
||||||
|
|
||||||
|
/* Return !=0 if file exists.
|
||||||
|
* 0: file doesn't exist
|
||||||
|
* 1: normal file
|
||||||
|
* 2: directory
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Append to file, return !=0 if error
|
||||||
|
*/
|
||||||
|
|
||||||
|
int append();
|
||||||
|
|
||||||
|
/* Append to file, either succeed or fail
|
||||||
|
* with error message & exit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void appendv();
|
||||||
|
|
||||||
|
/* Return !=0 if file exists.
|
||||||
|
* 0: file doesn't exist
|
||||||
|
* 1: normal file
|
||||||
|
* 2: directory
|
||||||
|
*/
|
||||||
|
|
||||||
|
int exists();
|
||||||
|
|
||||||
|
/* Given wildcard filespec, return an array of
|
||||||
|
* matching File's.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static Files *match(char *);
|
||||||
|
static Files *match(FileName *);
|
||||||
|
|
||||||
|
// Compare file times.
|
||||||
|
// Return <0 this < f
|
||||||
|
// =0 this == f
|
||||||
|
// >0 this > f
|
||||||
|
int compareTime(File *f);
|
||||||
|
|
||||||
|
// Read system file statistics
|
||||||
|
void stat();
|
||||||
|
|
||||||
|
/* Set buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
void setbuffer(void *buffer, unsigned len)
|
||||||
|
{
|
||||||
|
this->buffer = (unsigned char *)buffer;
|
||||||
|
this->len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkoffset(size_t offset, size_t nbytes);
|
||||||
|
|
||||||
|
void remove(); // delete file
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OutBuffer : Object
|
||||||
|
{
|
||||||
|
unsigned char *data;
|
||||||
|
unsigned offset;
|
||||||
|
unsigned size;
|
||||||
|
|
||||||
|
OutBuffer();
|
||||||
|
~OutBuffer();
|
||||||
|
char *extractData();
|
||||||
|
void mark();
|
||||||
|
|
||||||
|
void reserve(unsigned nbytes);
|
||||||
|
void setsize(unsigned size);
|
||||||
|
void reset();
|
||||||
|
void write(const void *data, unsigned nbytes);
|
||||||
|
void writebstring(unsigned char *string);
|
||||||
|
void writestring(const char *string);
|
||||||
|
void writedstring(const char *string);
|
||||||
|
void writedstring(const wchar_t *string);
|
||||||
|
void prependstring(const char *string);
|
||||||
|
void writenl(); // write newline
|
||||||
|
void writeByte(unsigned b);
|
||||||
|
void writebyte(unsigned b) { writeByte(b); }
|
||||||
|
void writeUTF8(unsigned b);
|
||||||
|
void writedchar(unsigned b);
|
||||||
|
void prependbyte(unsigned b);
|
||||||
|
void writeword(unsigned w);
|
||||||
|
void writeUTF16(unsigned w);
|
||||||
|
void write4(unsigned w);
|
||||||
|
void write(OutBuffer *buf);
|
||||||
|
void write(Object *obj);
|
||||||
|
void fill0(unsigned nbytes);
|
||||||
|
void align(unsigned size);
|
||||||
|
void vprintf(const char *format, va_list args);
|
||||||
|
void printf(const char *format, ...);
|
||||||
|
#if M_UNICODE
|
||||||
|
void vprintf(const unsigned short *format, va_list args);
|
||||||
|
void printf(const unsigned short *format, ...);
|
||||||
|
#endif
|
||||||
|
void bracket(char left, char right);
|
||||||
|
unsigned bracket(unsigned i, const char *left, unsigned j, const char *right);
|
||||||
|
void spread(unsigned offset, unsigned nbytes);
|
||||||
|
unsigned insert(unsigned offset, const void *data, unsigned nbytes);
|
||||||
|
void remove(unsigned offset, unsigned nbytes);
|
||||||
|
char *toChars();
|
||||||
|
char *extractString();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Array : Object
|
||||||
|
{
|
||||||
|
unsigned dim;
|
||||||
|
void **data;
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned allocdim;
|
||||||
|
#define SMALLARRAYCAP 1
|
||||||
|
void *smallarray[SMALLARRAYCAP]; // inline storage for small arrays
|
||||||
|
|
||||||
|
public:
|
||||||
|
Array();
|
||||||
|
~Array();
|
||||||
|
//Array(const Array&);
|
||||||
|
void mark();
|
||||||
|
char *toChars();
|
||||||
|
|
||||||
|
void reserve(unsigned nentries);
|
||||||
|
void setDim(unsigned newdim);
|
||||||
|
void fixDim();
|
||||||
|
void push(void *ptr);
|
||||||
|
void *pop();
|
||||||
|
void shift(void *ptr);
|
||||||
|
void insert(unsigned index, void *ptr);
|
||||||
|
void insert(unsigned index, Array *a);
|
||||||
|
void append(Array *a);
|
||||||
|
void remove(unsigned i);
|
||||||
|
void zero();
|
||||||
|
void *tos();
|
||||||
|
void sort();
|
||||||
|
Array *copy();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TYPE>
|
||||||
|
struct ArrayBase : Array
|
||||||
|
{
|
||||||
|
TYPE **tdata()
|
||||||
|
{
|
||||||
|
return (TYPE **)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPE*& operator[] (size_t index)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(index < dim);
|
||||||
|
#endif
|
||||||
|
return ((TYPE **)data)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(size_t index, TYPE *v)
|
||||||
|
{
|
||||||
|
Array::insert(index, (void *)v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(size_t index, ArrayBase *a)
|
||||||
|
{
|
||||||
|
Array::insert(index, (Array *)a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(ArrayBase *a)
|
||||||
|
{
|
||||||
|
Array::append((Array *)a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void push(TYPE *a)
|
||||||
|
{
|
||||||
|
Array::push((void *)a);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayBase *copy()
|
||||||
|
{
|
||||||
|
return (ArrayBase *)Array::copy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Bits : Object
|
||||||
|
{
|
||||||
|
unsigned bitdim;
|
||||||
|
unsigned allocdim;
|
||||||
|
unsigned *data;
|
||||||
|
|
||||||
|
Bits();
|
||||||
|
~Bits();
|
||||||
|
void mark();
|
||||||
|
|
||||||
|
void resize(unsigned bitdim);
|
||||||
|
|
||||||
|
void set(unsigned bitnum);
|
||||||
|
void clear(unsigned bitnum);
|
||||||
|
int test(unsigned bitnum);
|
||||||
|
|
||||||
|
void set();
|
||||||
|
void clear();
|
||||||
|
void copy(Bits *from);
|
||||||
|
Bits *clone();
|
||||||
|
|
||||||
|
void sub(Bits *b);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#if __sun&&__SVR4
|
||||||
|
#include <alloca.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "speller.h"
|
||||||
|
|
||||||
|
const char idchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
|
||||||
|
|
||||||
|
/**************************************************
|
||||||
|
* Looks for correct spelling.
|
||||||
|
* Currently only looks a 'distance' of one from the seed[].
|
||||||
|
* This does an exhaustive search, so can potentially be very slow.
|
||||||
|
* Input:
|
||||||
|
* seed wrongly spelled word
|
||||||
|
* fp search function
|
||||||
|
* fparg argument to search function
|
||||||
|
* charset character set
|
||||||
|
* Returns:
|
||||||
|
* NULL no correct spellings found
|
||||||
|
* void* value returned by fp() for first possible correct spelling
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg,
|
||||||
|
const char *charset, size_t index)
|
||||||
|
{
|
||||||
|
if (!seedlen)
|
||||||
|
return NULL;
|
||||||
|
assert(seed[seedlen] == 0);
|
||||||
|
|
||||||
|
char tmp[30];
|
||||||
|
char *buf;
|
||||||
|
if (seedlen <= sizeof(tmp) - 2)
|
||||||
|
buf = tmp;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buf = (char *)alloca(seedlen + 2); // leave space for extra char
|
||||||
|
if (!buf)
|
||||||
|
return NULL; // no matches
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf, seed, index);
|
||||||
|
|
||||||
|
/* Delete at seed[index] */
|
||||||
|
if (index < seedlen)
|
||||||
|
{
|
||||||
|
memcpy(buf + index, seed + index + 1, seedlen - index);
|
||||||
|
assert(buf[seedlen - 1] == 0);
|
||||||
|
void *p = (*fp)(fparg, buf);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (charset && *charset)
|
||||||
|
{
|
||||||
|
/* Substitutions */
|
||||||
|
if (index < seedlen)
|
||||||
|
{
|
||||||
|
memcpy(buf, seed, seedlen + 1);
|
||||||
|
for (const char *s = charset; *s; s++)
|
||||||
|
{
|
||||||
|
buf[index] = *s;
|
||||||
|
|
||||||
|
//printf("sub buf = '%s'\n", buf);
|
||||||
|
void *p = (*fp)(fparg, buf);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
assert(buf[seedlen] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insertions */
|
||||||
|
memcpy (buf + index + 1, seed + index, seedlen + 1 - index);
|
||||||
|
|
||||||
|
for (const char *s = charset; *s; s++)
|
||||||
|
{
|
||||||
|
buf[index] = *s;
|
||||||
|
|
||||||
|
//printf("ins buf = '%s'\n", buf);
|
||||||
|
void *p = (*fp)(fparg, buf);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
assert(buf[seedlen + 1] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL; // didn't find any corrections
|
||||||
|
}
|
||||||
|
|
||||||
|
void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg,
|
||||||
|
const char *charset, int flag)
|
||||||
|
{
|
||||||
|
if (!seedlen)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char tmp[30];
|
||||||
|
char *buf;
|
||||||
|
if (seedlen <= sizeof(tmp) - 2)
|
||||||
|
buf = tmp;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buf = (char *)alloca(seedlen + 2); // leave space for extra char
|
||||||
|
if (!buf)
|
||||||
|
return NULL; // no matches
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deletions */
|
||||||
|
memcpy(buf, seed + 1, seedlen);
|
||||||
|
for (size_t i = 0; i < seedlen; i++)
|
||||||
|
{
|
||||||
|
//printf("del buf = '%s'\n", buf);
|
||||||
|
void *p;
|
||||||
|
if (flag)
|
||||||
|
p = spellerY(buf, seedlen - 1, fp, fparg, charset, i);
|
||||||
|
else
|
||||||
|
p = (*fp)(fparg, buf);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
|
||||||
|
buf[i] = seed[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transpositions */
|
||||||
|
if (!flag)
|
||||||
|
{
|
||||||
|
memcpy(buf, seed, seedlen + 1);
|
||||||
|
for (size_t i = 0; i + 1 < seedlen; i++)
|
||||||
|
{
|
||||||
|
// swap [i] and [i + 1]
|
||||||
|
buf[i] = seed[i + 1];
|
||||||
|
buf[i + 1] = seed[i];
|
||||||
|
|
||||||
|
//printf("tra buf = '%s'\n", buf);
|
||||||
|
void *p = (*fp)(fparg, buf);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
|
||||||
|
buf[i] = seed[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (charset && *charset)
|
||||||
|
{
|
||||||
|
/* Substitutions */
|
||||||
|
memcpy(buf, seed, seedlen + 1);
|
||||||
|
for (size_t i = 0; i < seedlen; i++)
|
||||||
|
{
|
||||||
|
for (const char *s = charset; *s; s++)
|
||||||
|
{
|
||||||
|
buf[i] = *s;
|
||||||
|
|
||||||
|
//printf("sub buf = '%s'\n", buf);
|
||||||
|
void *p;
|
||||||
|
if (flag)
|
||||||
|
p = spellerY(buf, seedlen, fp, fparg, charset, i + 1);
|
||||||
|
else
|
||||||
|
p = (*fp)(fparg, buf);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
buf[i] = seed[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insertions */
|
||||||
|
memcpy(buf + 1, seed, seedlen + 1);
|
||||||
|
for (size_t i = 0; i <= seedlen; i++) // yes, do seedlen+1 iterations
|
||||||
|
{
|
||||||
|
for (const char *s = charset; *s; s++)
|
||||||
|
{
|
||||||
|
buf[i] = *s;
|
||||||
|
|
||||||
|
//printf("ins buf = '%s'\n", buf);
|
||||||
|
void *p;
|
||||||
|
if (flag)
|
||||||
|
p = spellerY(buf, seedlen + 1, fp, fparg, charset, i + 1);
|
||||||
|
else
|
||||||
|
p = (*fp)(fparg, buf);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
buf[i] = seed[i]; // going past end of seed[] is ok, as we hit the 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL; // didn't find any corrections
|
||||||
|
}
|
||||||
|
|
||||||
|
void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset)
|
||||||
|
{
|
||||||
|
size_t seedlen = strlen(seed);
|
||||||
|
for (int distance = 0; distance < 2; distance++)
|
||||||
|
{ void *p = spellerX(seed, seedlen, fp, fparg, charset, distance);
|
||||||
|
if (p)
|
||||||
|
return p;
|
||||||
|
// if (seedlen > 10)
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
return NULL; // didn't find it
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if UNITTEST
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
void *speller_test(void *fparg, const char *s)
|
||||||
|
{
|
||||||
|
//printf("speller_test(%s, %s)\n", fparg, s);
|
||||||
|
if (strcmp((char *)fparg, s) == 0)
|
||||||
|
return fparg;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unittest_speller()
|
||||||
|
{
|
||||||
|
static const char *cases[][3] =
|
||||||
|
{
|
||||||
|
{ "hello", "hell", "y" },
|
||||||
|
{ "hello", "hel", "y" },
|
||||||
|
{ "hello", "ello", "y" },
|
||||||
|
{ "hello", "llo", "y" },
|
||||||
|
{ "hello", "hellox", "y" },
|
||||||
|
{ "hello", "helloxy", "y" },
|
||||||
|
{ "hello", "xhello", "y" },
|
||||||
|
{ "hello", "xyhello", "y" },
|
||||||
|
{ "hello", "ehllo", "y" },
|
||||||
|
{ "hello", "helol", "y" },
|
||||||
|
{ "hello", "abcd", "n" },
|
||||||
|
//{ "ehllo", "helol", "y" },
|
||||||
|
{ "hello", "helxxlo", "y" },
|
||||||
|
{ "hello", "ehlxxlo", "n" },
|
||||||
|
{ "hello", "heaao", "y" },
|
||||||
|
{ "_123456789_123456789_123456789_123456789", "_123456789_123456789_123456789_12345678", "y" },
|
||||||
|
};
|
||||||
|
//printf("unittest_speller()\n");
|
||||||
|
const void *p = speller("hello", &speller_test, (void *)"hell", idchars);
|
||||||
|
assert(p != NULL);
|
||||||
|
for (int i = 0; i < sizeof(cases)/sizeof(cases[0]); i++)
|
||||||
|
{
|
||||||
|
//printf("case [%d]\n", i);
|
||||||
|
void *p = speller(cases[i][0], &speller_test, (void *)cases[i][1], idchars);
|
||||||
|
if (p)
|
||||||
|
assert(cases[i][2][0] == 'y');
|
||||||
|
else
|
||||||
|
assert(cases[i][2][0] == 'n');
|
||||||
|
}
|
||||||
|
//printf("unittest_speller() success\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
typedef void *(fp_speller_t)(void *, const char *);
|
||||||
|
|
||||||
|
extern const char idchars[];
|
||||||
|
|
||||||
|
void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset);
|
||||||
|
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "rmem.h"
|
||||||
|
#include "dchar.h"
|
||||||
|
#include "lstring.h"
|
||||||
|
#include "stringtable.h"
|
||||||
|
|
||||||
|
void StringTable::init(unsigned size)
|
||||||
|
{
|
||||||
|
table = (void **)mem.calloc(size, sizeof(void *));
|
||||||
|
tabledim = size;
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringTable::~StringTable()
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
// Zero out dangling pointers to help garbage collector.
|
||||||
|
// Should zero out StringEntry's too.
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
table[i] = NULL;
|
||||||
|
|
||||||
|
mem.free(table);
|
||||||
|
table = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StringEntry
|
||||||
|
{
|
||||||
|
StringEntry *left;
|
||||||
|
StringEntry *right;
|
||||||
|
hash_t hash;
|
||||||
|
|
||||||
|
StringValue value;
|
||||||
|
|
||||||
|
static StringEntry *alloc(const dchar *s, unsigned len);
|
||||||
|
};
|
||||||
|
|
||||||
|
StringEntry *StringEntry::alloc(const dchar *s, unsigned len)
|
||||||
|
{
|
||||||
|
StringEntry *se;
|
||||||
|
|
||||||
|
se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) - sizeof(Lstring) + Lstring::size(len));
|
||||||
|
se->value.lstring.length = len;
|
||||||
|
se->hash = Dchar::calcHash(s,len);
|
||||||
|
memcpy(se->value.lstring.string, s, len * sizeof(dchar));
|
||||||
|
return se;
|
||||||
|
}
|
||||||
|
|
||||||
|
void **StringTable::search(const dchar *s, unsigned len)
|
||||||
|
{
|
||||||
|
hash_t hash;
|
||||||
|
unsigned u;
|
||||||
|
int cmp;
|
||||||
|
StringEntry **se;
|
||||||
|
|
||||||
|
//printf("StringTable::search(%p,%d)\n",s,len);
|
||||||
|
hash = Dchar::calcHash(s,len);
|
||||||
|
u = hash % tabledim;
|
||||||
|
se = (StringEntry **)&table[u];
|
||||||
|
//printf("\thash = %d, u = %d\n",hash,u);
|
||||||
|
while (*se)
|
||||||
|
{
|
||||||
|
cmp = (*se)->hash - hash;
|
||||||
|
if (cmp == 0)
|
||||||
|
{
|
||||||
|
cmp = (*se)->value.lstring.len() - len;
|
||||||
|
if (cmp == 0)
|
||||||
|
{
|
||||||
|
cmp = Dchar::memcmp(s,(*se)->value.lstring.toDchars(),len);
|
||||||
|
if (cmp == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cmp < 0)
|
||||||
|
se = &(*se)->left;
|
||||||
|
else
|
||||||
|
se = &(*se)->right;
|
||||||
|
}
|
||||||
|
//printf("\treturn %p, %p\n",se, (*se));
|
||||||
|
return (void **)se;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringValue *StringTable::lookup(const dchar *s, unsigned len)
|
||||||
|
{ StringEntry *se;
|
||||||
|
|
||||||
|
se = *(StringEntry **)search(s,len);
|
||||||
|
if (se)
|
||||||
|
return &se->value;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringValue *StringTable::update(const dchar *s, unsigned len)
|
||||||
|
{ StringEntry **pse;
|
||||||
|
StringEntry *se;
|
||||||
|
|
||||||
|
pse = (StringEntry **)search(s,len);
|
||||||
|
se = *pse;
|
||||||
|
if (!se) // not in table: so create new entry
|
||||||
|
{
|
||||||
|
se = StringEntry::alloc(s, len);
|
||||||
|
*pse = se;
|
||||||
|
}
|
||||||
|
return &se->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringValue *StringTable::insert(const dchar *s, unsigned len)
|
||||||
|
{ StringEntry **pse;
|
||||||
|
StringEntry *se;
|
||||||
|
|
||||||
|
pse = (StringEntry **)search(s,len);
|
||||||
|
se = *pse;
|
||||||
|
if (se)
|
||||||
|
return NULL; // error: already in table
|
||||||
|
else
|
||||||
|
{
|
||||||
|
se = StringEntry::alloc(s, len);
|
||||||
|
*pse = se;
|
||||||
|
}
|
||||||
|
return &se->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (c) 1999-2011 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef STRINGTABLE_H
|
||||||
|
#define STRINGTABLE_H
|
||||||
|
|
||||||
|
#if __SC__
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "dchar.h"
|
||||||
|
#include "lstring.h"
|
||||||
|
|
||||||
|
struct StringValue
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{ int intvalue;
|
||||||
|
void *ptrvalue;
|
||||||
|
dchar *string;
|
||||||
|
};
|
||||||
|
Lstring lstring;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringTable
|
||||||
|
{
|
||||||
|
void **table;
|
||||||
|
unsigned count;
|
||||||
|
unsigned tabledim;
|
||||||
|
|
||||||
|
void init(unsigned size = 37);
|
||||||
|
~StringTable();
|
||||||
|
|
||||||
|
StringValue *lookup(const dchar *s, unsigned len);
|
||||||
|
StringValue *insert(const dchar *s, unsigned len);
|
||||||
|
StringValue *update(const dchar *s, unsigned len);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void **search(const dchar *s, unsigned len);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+403
@@ -0,0 +1,403 @@
|
|||||||
|
|
||||||
|
// Copyright (c) 1999-2010 by Digital Mars
|
||||||
|
// All Rights Reserved
|
||||||
|
// written by Walter Bright
|
||||||
|
// http://www.digitalmars.com
|
||||||
|
// License for redistribution is by either the Artistic License
|
||||||
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
||||||
|
// See the included readme.txt for details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "root.h"
|
||||||
|
#include "speller.h"
|
||||||
|
|
||||||
|
#include "mars.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "identifier.h"
|
||||||
|
#include "attrib.h"
|
||||||
|
#include "dsymbol.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "module.h"
|
||||||
|
#include "id.h"
|
||||||
|
#include "lexer.h"
|
||||||
|
|
||||||
|
Scope *Scope::freelist = NULL;
|
||||||
|
|
||||||
|
void *Scope::operator new(size_t size)
|
||||||
|
{
|
||||||
|
if (freelist)
|
||||||
|
{
|
||||||
|
Scope *s = freelist;
|
||||||
|
freelist = s->enclosing;
|
||||||
|
//printf("freelist %p\n", s);
|
||||||
|
assert(s->flags & SCOPEfree);
|
||||||
|
s->flags &= ~SCOPEfree;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *p = ::operator new(size);
|
||||||
|
//printf("new %p\n", p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope::Scope()
|
||||||
|
{ // Create root scope
|
||||||
|
|
||||||
|
//printf("Scope::Scope() %p\n", this);
|
||||||
|
this->module = NULL;
|
||||||
|
this->scopesym = NULL;
|
||||||
|
this->sd = NULL;
|
||||||
|
this->enclosing = NULL;
|
||||||
|
this->parent = NULL;
|
||||||
|
this->sw = NULL;
|
||||||
|
this->enclosingFinally = NULL;
|
||||||
|
this->enclosingScopeExit = NULL;
|
||||||
|
this->tinst = NULL;
|
||||||
|
this->sbreak = NULL;
|
||||||
|
this->scontinue = NULL;
|
||||||
|
this->fes = NULL;
|
||||||
|
this->structalign = global.structalign;
|
||||||
|
this->func = NULL;
|
||||||
|
this->slabel = NULL;
|
||||||
|
this->linkage = LINKd;
|
||||||
|
this->protection = PROTpublic;
|
||||||
|
this->explicitProtection = 0;
|
||||||
|
this->stc = 0;
|
||||||
|
this->offset = 0;
|
||||||
|
this->inunion = 0;
|
||||||
|
this->incontract = 0;
|
||||||
|
this->nofree = 0;
|
||||||
|
this->noctor = 0;
|
||||||
|
this->noaccesscheck = 0;
|
||||||
|
this->mustsemantic = 0;
|
||||||
|
this->intypeof = 0;
|
||||||
|
this->parameterSpecialization = 0;
|
||||||
|
this->ignoreTemplates = 0;
|
||||||
|
this->callSuper = 0;
|
||||||
|
this->flags = 0;
|
||||||
|
this->anonAgg = NULL;
|
||||||
|
this->lastdc = NULL;
|
||||||
|
this->lastoffset = 0;
|
||||||
|
this->docbuf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope::Scope(Scope *enclosing)
|
||||||
|
{
|
||||||
|
//printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this);
|
||||||
|
assert(!(enclosing->flags & SCOPEfree));
|
||||||
|
this->module = enclosing->module;
|
||||||
|
this->func = enclosing->func;
|
||||||
|
this->parent = enclosing->parent;
|
||||||
|
this->scopesym = NULL;
|
||||||
|
this->sd = NULL;
|
||||||
|
this->sw = enclosing->sw;
|
||||||
|
this->enclosingFinally = enclosing->enclosingFinally;
|
||||||
|
this->enclosingScopeExit = enclosing->enclosingScopeExit;
|
||||||
|
this->tinst = enclosing->tinst;
|
||||||
|
this->sbreak = enclosing->sbreak;
|
||||||
|
this->scontinue = enclosing->scontinue;
|
||||||
|
this->fes = enclosing->fes;
|
||||||
|
this->structalign = enclosing->structalign;
|
||||||
|
this->enclosing = enclosing;
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (enclosing->enclosing)
|
||||||
|
assert(!(enclosing->enclosing->flags & SCOPEfree));
|
||||||
|
if (this == enclosing->enclosing)
|
||||||
|
{
|
||||||
|
printf("this = %p, enclosing = %p, enclosing->enclosing = %p\n", this, enclosing, enclosing->enclosing);
|
||||||
|
}
|
||||||
|
assert(this != enclosing->enclosing);
|
||||||
|
#endif
|
||||||
|
this->slabel = NULL;
|
||||||
|
this->linkage = enclosing->linkage;
|
||||||
|
this->protection = enclosing->protection;
|
||||||
|
this->explicitProtection = enclosing->explicitProtection;
|
||||||
|
this->stc = enclosing->stc;
|
||||||
|
this->offset = 0;
|
||||||
|
this->inunion = enclosing->inunion;
|
||||||
|
this->incontract = enclosing->incontract;
|
||||||
|
this->nofree = 0;
|
||||||
|
this->noctor = enclosing->noctor;
|
||||||
|
this->noaccesscheck = enclosing->noaccesscheck;
|
||||||
|
this->mustsemantic = enclosing->mustsemantic;
|
||||||
|
this->intypeof = enclosing->intypeof;
|
||||||
|
this->parameterSpecialization = enclosing->parameterSpecialization;
|
||||||
|
this->ignoreTemplates = enclosing->ignoreTemplates;
|
||||||
|
this->callSuper = enclosing->callSuper;
|
||||||
|
this->flags = 0;
|
||||||
|
this->anonAgg = NULL;
|
||||||
|
this->lastdc = NULL;
|
||||||
|
this->lastoffset = 0;
|
||||||
|
this->docbuf = enclosing->docbuf;
|
||||||
|
assert(this != enclosing);
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope *Scope::createGlobal(Module *module)
|
||||||
|
{
|
||||||
|
Scope *sc;
|
||||||
|
|
||||||
|
sc = new Scope();
|
||||||
|
sc->module = module;
|
||||||
|
sc->scopesym = new ScopeDsymbol();
|
||||||
|
sc->scopesym->symtab = new DsymbolTable();
|
||||||
|
|
||||||
|
// Add top level package as member of this global scope
|
||||||
|
Dsymbol *m = module;
|
||||||
|
while (m->parent)
|
||||||
|
m = m->parent;
|
||||||
|
m->addMember(NULL, sc->scopesym, 1);
|
||||||
|
m->parent = NULL; // got changed by addMember()
|
||||||
|
|
||||||
|
// Create the module scope underneath the global scope
|
||||||
|
sc = sc->push(module);
|
||||||
|
sc->parent = module;
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope *Scope::push()
|
||||||
|
{
|
||||||
|
//printf("Scope::push()\n");
|
||||||
|
Scope *s = new Scope(this);
|
||||||
|
assert(this != s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope *Scope::push(ScopeDsymbol *ss)
|
||||||
|
{
|
||||||
|
//printf("Scope::push(%s)\n", ss->toChars());
|
||||||
|
Scope *s = push();
|
||||||
|
s->scopesym = ss;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope *Scope::pop()
|
||||||
|
{
|
||||||
|
//printf("Scope::pop() %p nofree = %d\n", this, nofree);
|
||||||
|
Scope *enc = enclosing;
|
||||||
|
|
||||||
|
if (enclosing)
|
||||||
|
enclosing->callSuper |= callSuper;
|
||||||
|
|
||||||
|
if (!nofree)
|
||||||
|
{ enclosing = freelist;
|
||||||
|
freelist = this;
|
||||||
|
flags |= SCOPEfree;
|
||||||
|
}
|
||||||
|
|
||||||
|
return enc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scope::mergeCallSuper(Loc loc, unsigned cs)
|
||||||
|
{
|
||||||
|
// This does a primitive flow analysis to support the restrictions
|
||||||
|
// regarding when and how constructors can appear.
|
||||||
|
// It merges the results of two paths.
|
||||||
|
// The two paths are callSuper and cs; the result is merged into callSuper.
|
||||||
|
|
||||||
|
if (cs != callSuper)
|
||||||
|
{ int a;
|
||||||
|
int b;
|
||||||
|
|
||||||
|
callSuper |= cs & (CSXany_ctor | CSXlabel);
|
||||||
|
if (cs & CSXreturn)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (callSuper & CSXreturn)
|
||||||
|
{
|
||||||
|
callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0;
|
||||||
|
b = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0;
|
||||||
|
if (a != b)
|
||||||
|
error(loc, "one path skips constructor");
|
||||||
|
callSuper |= cs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym)
|
||||||
|
{ Dsymbol *s;
|
||||||
|
Scope *sc;
|
||||||
|
|
||||||
|
//printf("Scope::search(%p, '%s')\n", this, ident->toChars());
|
||||||
|
if (ident == Id::empty)
|
||||||
|
{
|
||||||
|
// Look for module scope
|
||||||
|
for (sc = this; sc; sc = sc->enclosing)
|
||||||
|
{
|
||||||
|
assert(sc != sc->enclosing);
|
||||||
|
if (sc->scopesym)
|
||||||
|
{
|
||||||
|
s = sc->scopesym->isModule();
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
//printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars());
|
||||||
|
if (pscopesym)
|
||||||
|
*pscopesym = sc->scopesym;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (sc = this; sc; sc = sc->enclosing)
|
||||||
|
{
|
||||||
|
assert(sc != sc->enclosing);
|
||||||
|
if (sc->scopesym)
|
||||||
|
{
|
||||||
|
//printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind());
|
||||||
|
s = sc->scopesym->search(loc, ident, 0);
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
if ((global.params.warnings ||
|
||||||
|
global.params.Dversion > 1) &&
|
||||||
|
ident == Id::length &&
|
||||||
|
sc->scopesym->isArrayScopeSymbol() &&
|
||||||
|
sc->enclosing &&
|
||||||
|
sc->enclosing->search(loc, ident, NULL))
|
||||||
|
{
|
||||||
|
warning(s->loc, "array 'length' hides other 'length' name in outer scope");
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind());
|
||||||
|
if (pscopesym)
|
||||||
|
*pscopesym = sc->scopesym;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dsymbol *Scope::insert(Dsymbol *s)
|
||||||
|
{ Scope *sc;
|
||||||
|
|
||||||
|
for (sc = this; sc; sc = sc->enclosing)
|
||||||
|
{
|
||||||
|
//printf("\tsc = %p\n", sc);
|
||||||
|
if (sc->scopesym)
|
||||||
|
{
|
||||||
|
//printf("\t\tsc->scopesym = %p\n", sc->scopesym);
|
||||||
|
if (!sc->scopesym->symtab)
|
||||||
|
sc->scopesym->symtab = new DsymbolTable();
|
||||||
|
return sc->scopesym->symtabInsert(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************
|
||||||
|
* Search enclosing scopes for ClassDeclaration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ClassDeclaration *Scope::getClassScope()
|
||||||
|
{ Scope *sc;
|
||||||
|
|
||||||
|
for (sc = this; sc; sc = sc->enclosing)
|
||||||
|
{
|
||||||
|
ClassDeclaration *cd;
|
||||||
|
|
||||||
|
if (sc->scopesym)
|
||||||
|
{
|
||||||
|
cd = sc->scopesym->isClassDeclaration();
|
||||||
|
if (cd)
|
||||||
|
return cd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************
|
||||||
|
* Search enclosing scopes for ClassDeclaration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
AggregateDeclaration *Scope::getStructClassScope()
|
||||||
|
{ Scope *sc;
|
||||||
|
|
||||||
|
for (sc = this; sc; sc = sc->enclosing)
|
||||||
|
{
|
||||||
|
AggregateDeclaration *ad;
|
||||||
|
|
||||||
|
if (sc->scopesym)
|
||||||
|
{
|
||||||
|
ad = sc->scopesym->isClassDeclaration();
|
||||||
|
if (ad)
|
||||||
|
return ad;
|
||||||
|
else
|
||||||
|
{ ad = sc->scopesym->isStructDeclaration();
|
||||||
|
if (ad)
|
||||||
|
return ad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************
|
||||||
|
* For TemplateDeclarations, we need to remember the Scope
|
||||||
|
* where it was declared. So mark the Scope as not
|
||||||
|
* to be free'd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Scope::setNoFree()
|
||||||
|
{ Scope *sc;
|
||||||
|
//int i = 0;
|
||||||
|
|
||||||
|
//printf("Scope::setNoFree(this = %p)\n", this);
|
||||||
|
for (sc = this; sc; sc = sc->enclosing)
|
||||||
|
{
|
||||||
|
//printf("\tsc = %p\n", sc);
|
||||||
|
sc->nofree = 1;
|
||||||
|
|
||||||
|
assert(!(flags & SCOPEfree));
|
||||||
|
//assert(sc != sc->enclosing);
|
||||||
|
//assert(!sc->enclosing || sc != sc->enclosing->enclosing);
|
||||||
|
//if (++i == 10)
|
||||||
|
//assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************
|
||||||
|
* Given the failed search attempt, try to find
|
||||||
|
* one with a close spelling.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *scope_search_fp(void *arg, const char *seed)
|
||||||
|
{
|
||||||
|
//printf("scope_search_fp('%s')\n", seed);
|
||||||
|
|
||||||
|
/* If not in the lexer's string table, it certainly isn't in the symbol table.
|
||||||
|
* Doing this first is a lot faster.
|
||||||
|
*/
|
||||||
|
size_t len = strlen(seed);
|
||||||
|
if (!len)
|
||||||
|
return NULL;
|
||||||
|
StringValue *sv = Lexer::stringtable.lookup(seed, len);
|
||||||
|
if (!sv)
|
||||||
|
return NULL;
|
||||||
|
Identifier *id = (Identifier *)sv->ptrvalue;
|
||||||
|
assert(id);
|
||||||
|
|
||||||
|
Scope *sc = (Scope *)arg;
|
||||||
|
Module::clearCache();
|
||||||
|
Dsymbol *s = sc->search(0, id, NULL);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dsymbol *Scope::search_correct(Identifier *ident)
|
||||||
|
{
|
||||||
|
if (global.gag)
|
||||||
|
return NULL; // don't do it for speculative compiles; too time consuming
|
||||||
|
|
||||||
|
return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user