diff -uNr dmd-0.172/dmd/src/dmd/arraytypes.h dmd-0.173/dmd/src/dmd/arraytypes.h --- dmd-0.172/dmd/src/dmd/arraytypes.h 2006-10-05 17:06:06.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/arraytypes.h 2006-10-26 00:30:42.000000000 +0200 @@ -40,4 +40,6 @@ struct FuncDeclarations : Array { }; +struct Arguments : Array { }; + #endif diff -uNr dmd-0.172/dmd/src/dmd/cast.c dmd-0.173/dmd/src/dmd/cast.c --- dmd-0.172/dmd/src/dmd/cast.c 2006-10-16 23:15:30.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/cast.c 2006-10-28 18:36:16.000000000 +0200 @@ -503,6 +503,7 @@ { Expression *e; Type *tb; + //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars()); #if 0 printf("Expression::castTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); @@ -866,6 +867,18 @@ return e; } + +Expression *TupleExp::castTo(Scope *sc, Type *t) +{ + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + e = e->castTo(sc, t); + exps->data[i] = (void *)e; + } + return this; +} + + Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) { Type *typeb = type->toBasetype(); diff -uNr dmd-0.172/dmd/src/dmd/class.c dmd-0.173/dmd/src/dmd/class.c --- dmd-0.172/dmd/src/dmd/class.c 2006-10-18 10:32:28.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/class.c 2006-10-25 21:24:38.000000000 +0200 @@ -398,14 +398,14 @@ isnested = 1; if (storage_class & STCstatic) error("static class cannot inherit from nested class %s", baseClass->toChars()); - if (toParent() != baseClass->toParent()) + if (toParent2() != baseClass->toParent2()) error("super class %s is nested within %s, not %s", baseClass->toChars(), - baseClass->toParent()->toChars(), - toParent()->toChars()); + baseClass->toParent2()->toChars(), + toParent2()->toChars()); } else if (!(storage_class & STCstatic)) - { Dsymbol *s = toParent(); + { Dsymbol *s = toParent2(); if (s) { ClassDeclaration *cd = s->isClassDeclaration(); diff -uNr dmd-0.172/dmd/src/dmd/complex_t.h dmd-0.173/dmd/src/dmd/complex_t.h --- dmd-0.172/dmd/src/dmd/complex_t.h 2006-10-05 17:03:42.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/complex_t.h 2006-10-25 14:31:22.000000000 +0200 @@ -8,6 +8,9 @@ // 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 */ @@ -68,4 +71,4 @@ return x.im; } - +#endif diff -uNr dmd-0.172/dmd/src/dmd/constfold.c dmd-0.173/dmd/src/dmd/constfold.c --- dmd-0.172/dmd/src/dmd/constfold.c 2006-04-12 10:49:22.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/constfold.c 2006-10-28 12:32:42.000000000 +0200 @@ -1,5 +1,6 @@ -// Copyright (c) 1999-2005 by Digital Mars +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com diff -uNr dmd-0.172/dmd/src/dmd/declaration.c dmd-0.173/dmd/src/dmd/declaration.c --- dmd-0.172/dmd/src/dmd/declaration.c 2006-10-07 19:13:38.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/declaration.c 2006-11-01 15:36:02.000000000 +0100 @@ -1,4 +1,5 @@ +// Compiler implementation of the D programming language // Copyright (c) 1999-2006 by Digital Mars // All Rights Reserved // written by Walter Bright @@ -78,6 +79,72 @@ return protection; } +/********************************* TupleDeclaration ****************************/ + +TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) + : Declaration(id) +{ + this->type = NULL; + this->objects = objects; + this->isexp = 0; + this->tupletype = NULL; +} + +Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); + return NULL; +} + +char *TupleDeclaration::kind() +{ + return "tuple"; +} + +Type *TupleDeclaration::getType() +{ + /* If this tuple represents a type, return that type + */ + + //printf("TupleDeclaration::getType() %s\n", toChars()); + if (isexp) + return NULL; + if (!tupletype) + { + /* It's only a type tuple if all the Object's are types + */ + for (size_t i = 0; i < objects->dim; i++) + { Object *o = (Object *)objects->data[i]; + + if (o->dyncast() != DYNCAST_TYPE) + { + //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); + return NULL; + } + } + + /* We know it's a type tuple, so build the TypeTuple + */ + Arguments *args = new Arguments(); + args->setDim(objects->dim); + OutBuffer buf; + for (size_t i = 0; i < objects->dim; i++) + { Type *t = (Type *)objects->data[i]; + + //printf("type = %s\n", t->toChars()); + buf.printf("_%s_%d", ident->toChars(), i); + char *name = (char *)buf.extractData(); + Identifier *id = new Identifier(name, TOKidentifier); + Argument *arg = new Argument(In, t, id, NULL); + args->data[i] = (void *)arg; + } + + tupletype = new TypeTuple(args); + } + + return tupletype; +} + /********************************* TypedefDeclaration ****************************/ TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) diff -uNr dmd-0.172/dmd/src/dmd/declaration.h dmd-0.173/dmd/src/dmd/declaration.h --- dmd-0.172/dmd/src/dmd/declaration.h 2006-10-07 19:04:48.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/declaration.h 2006-10-28 22:52:48.000000000 +0200 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2005 by Digital Mars +// Copyright (c) 1999-2006 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com @@ -29,6 +29,7 @@ struct FuncDeclaration; struct ExpInitializer; struct StructDeclaration; +struct TupleType; enum PROT; enum LINK; @@ -115,6 +116,23 @@ /**************************************************************/ +struct TupleDeclaration : Declaration +{ + Objects *objects; + int isexp; // 1: expression tuple + + TypeTuple *tupletype; // !=NULL if this is a type tuple + + TupleDeclaration(Loc loc, Identifier *ident, Objects *objects); + Dsymbol *syntaxCopy(Dsymbol *); + char *kind(); + Type *getType(); + + TupleDeclaration *isTupleDeclaration() { return this; } +}; + +/**************************************************************/ + struct TypedefDeclaration : Declaration { Type *basetype; @@ -473,10 +491,10 @@ }; struct CtorDeclaration : FuncDeclaration -{ Array *arguments; +{ Arguments *arguments; int varargs; - CtorDeclaration(Loc loc, Loc endloc, Array *arguments, int varargs); + CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -566,10 +584,10 @@ }; struct NewDeclaration : FuncDeclaration -{ Array *arguments; +{ Arguments *arguments; int varargs; - NewDeclaration(Loc loc, Loc endloc, Array *arguments, int varargs); + NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -583,9 +601,9 @@ struct DeleteDeclaration : FuncDeclaration -{ Array *arguments; +{ Arguments *arguments; - DeleteDeclaration(Loc loc, Loc endloc, Array *arguments); + DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); diff -uNr dmd-0.172/dmd/src/dmd/delegatize.c dmd-0.173/dmd/src/dmd/delegatize.c --- dmd-0.172/dmd/src/dmd/delegatize.c 2006-10-16 01:14:00.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/delegatize.c 2006-10-28 00:36:46.000000000 +0200 @@ -104,7 +104,7 @@ void DeclarationExp::scanForNestedRef(Scope *sc) { - printf("DeclarationExp::scanForNestedRef() %s\n", toChars()); + //printf("DeclarationExp::scanForNestedRef() %s\n", toChars()); //assert(0); } @@ -170,6 +170,12 @@ } +void TupleExp::scanForNestedRef(Scope *sc) +{ + arrayExpressionScanForNestedRef(sc, exps); +} + + void ArrayExp::scanForNestedRef(Scope *sc) { e1->scanForNestedRef(sc); diff -uNr dmd-0.172/dmd/src/dmd/doc.c dmd-0.173/dmd/src/dmd/doc.c --- dmd-0.172/dmd/src/dmd/doc.c 2006-08-10 01:55:58.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/doc.c 2006-10-27 23:29:38.000000000 +0200 @@ -1474,10 +1474,10 @@ { TypeFunction *tf = (TypeFunction *)f->type; - if (tf->arguments) + if (tf->parameters) { - for (int k = 0; k < tf->arguments->dim; k++) - { Argument *arg = (Argument *)tf->arguments->data[k]; + for (size_t k = 0; k < tf->parameters->dim; k++) + { Argument *arg = (Argument *)tf->parameters->data[k]; if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) { diff -uNr dmd-0.172/dmd/src/dmd/dsymbol.c dmd-0.173/dmd/src/dmd/dsymbol.c --- dmd-0.172/dmd/src/dmd/dsymbol.c 2006-10-16 01:08:16.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/dsymbol.c 2006-10-28 11:07:10.000000000 +0200 @@ -204,11 +204,26 @@ { Dsymbol *s = this; + //printf("Dsymbol::pastMixin() %s\n", toChars()); while (s && s->isTemplateMixin()) s = s->parent; return s; } +/********************************** + * Use this instead of toParent() when looking for the + * 'this' pointer of the enclosing function/class. + */ + +Dsymbol *Dsymbol::toParent2() +{ + Dsymbol *s = parent; + while (s && s->isTemplateInstance()) + s = s->parent; + return s; +} + + int Dsymbol::isAnonymous() { return ident ? 0 : 1; @@ -706,6 +721,7 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) { + //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); if (ident == Id::length || ident == Id::dollar) { VarDeclaration **pvar; Expression *ce; @@ -738,6 +754,14 @@ v->init = new ExpInitializer(0, e); v->storage_class |= STCconst; } + else if (ce->op == TOKtuple) + { /* It is for an expression tuple, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCconst; + } *pvar = v; } return (*pvar); diff -uNr dmd-0.172/dmd/src/dmd/dsymbol.h dmd-0.173/dmd/src/dmd/dsymbol.h --- dmd-0.172/dmd/src/dmd/dsymbol.h 2006-10-05 17:00:48.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/dsymbol.h 2006-10-25 21:11:26.000000000 +0200 @@ -25,6 +25,7 @@ struct Scope; struct DsymbolTable; struct Declaration; +struct TupleDeclaration; struct TypedefDeclaration; struct AliasDeclaration; struct AggregateDeclaration; @@ -107,6 +108,7 @@ Module *getModule(); Dsymbol *pastMixin(); Dsymbol *toParent(); + Dsymbol *toParent2(); int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() @@ -170,6 +172,7 @@ virtual TemplateInstance *isTemplateInstance() { return NULL; } virtual TemplateMixin *isTemplateMixin() { return NULL; } virtual Declaration *isDeclaration() { return NULL; } + virtual TupleDeclaration *isTupleDeclaration() { return NULL; } virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } virtual AliasDeclaration *isAliasDeclaration() { return NULL; } virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; } diff -uNr dmd-0.172/dmd/src/dmd/expression.c dmd-0.173/dmd/src/dmd/expression.c --- dmd-0.172/dmd/src/dmd/expression.c 2006-10-16 23:14:00.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/expression.c 2006-11-01 17:50:50.000000000 +0100 @@ -14,10 +14,6 @@ #include #include -#if __GNUC__ -extern "C" long double strtold(const char *p,char **endp); -#endif - #if _WIN32 && __DMC__ extern "C" char * __cdecl __locale_decpoint; #endif @@ -278,15 +274,40 @@ * Perform semantic() on an array of Expressions. */ -void arrayExpressionSemantic(Expressions *a, Scope *sc) +void arrayExpressionSemantic(Expressions *exps, Scope *sc) { - if (a) + if (exps) { - for (int i = 0; i < a->dim; i++) - { Expression *e = (Expression *)a->data[i]; + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; e = e->semantic(sc); - a->data[i] = (void *)e; + exps->data[i] = (void *)e; + } + } +} + +/**************************************** + * Expand tuples. + */ + +void expandTuples(Expressions *exps) +{ + if (exps) + { + for (size_t i = 0; i < exps->dim; i++) + { Expression *arg = (Expression *)exps->data[i]; + + // Inline expand all the tuples + while (arg->op == TOKtuple) + { TupleExp *te = (TupleExp *)arg; + + exps->remove(i); // remove arg + exps->insert(i, te->exps); // replace with tuple contents + if (i == exps->dim) + return; // empty tuple, no more arguments + arg = (Expression *)exps->data[i]; + } } } } @@ -295,12 +316,14 @@ * Preprocess arguments to function. */ -void preFunctionArguments(Loc loc, Scope *sc, Expressions *arguments) +void preFunctionArguments(Loc loc, Scope *sc, Expressions *exps) { - if (arguments) + if (exps) { - for (int i = 0; i < arguments->dim; i++) - { Expression *arg = (Expression *)arguments->data[i]; + expandTuples(exps); + + for (size_t i = 0; i < exps->dim; i++) + { Expression *arg = (Expression *)exps->data[i]; if (!arg->type) { @@ -313,7 +336,7 @@ } arg = resolveProperties(sc, arg); - arguments->data[i] = (void *) arg; + exps->data[i] = (void *) arg; //arg->rvalue(); #if 0 @@ -321,7 +344,7 @@ { arg = new AddrExp(arg->loc, arg); arg = arg->semantic(sc); - arguments->data[i] = (void *) arg; + exps->data[i] = (void *) arg; } #endif } @@ -340,44 +363,41 @@ void functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments) { - unsigned nargs; - unsigned nproto; unsigned n; int done; Type *tb; //printf("functionArguments()\n"); assert(arguments); - nargs = arguments ? arguments->dim : 0; - nproto = tf->arguments ? tf->arguments->dim : 0; + size_t nargs = arguments ? arguments->dim : 0; + size_t nparams = Argument::dim(tf->parameters); - if (nargs > nproto && tf->varargs == 0) - error(loc, "expected %d arguments, not %d\n", nproto, nargs); + if (nargs > nparams && tf->varargs == 0) + error(loc, "expected %d arguments, not %d\n", nparams, nargs); - n = (nargs > nproto) ? nargs : nproto; // maximum + n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) done = 0; - for (int i = 0; i < n; i++) + for (size_t i = 0; i < n; i++) { Expression *arg; - Argument *p; if (i < nargs) arg = (Expression *)arguments->data[i]; else arg = NULL; - if (i < nproto) + if (i < nparams) { - Argument *p = (Argument *)tf->arguments->data[i]; + Argument *p = Argument::getNth(tf->parameters, i); if (!arg) { if (!p->defaultArg) { - if (tf->varargs == 2 && i + 1 == nproto) + if (tf->varargs == 2 && i + 1 == nparams) goto L2; - error(loc, "expected %d arguments, not %d\n", nproto, nargs); + error(loc, "expected %d arguments, not %d\n", nparams, nargs); break; } arg = p->defaultArg->copy(); @@ -385,13 +405,13 @@ nargs++; } - if (tf->varargs == 2 && i + 1 == nproto) + if (tf->varargs == 2 && i + 1 == nparams) { //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); if (arg->implicitConvTo(p->type)) { - if (nargs != nproto) - error(loc, "expected %d arguments, not %d\n", nproto, nargs); + if (nargs != nparams) + error(loc, "expected %d arguments, not %d\n", nparams, nargs); goto L1; } L2: @@ -426,13 +446,13 @@ Expression *c = new DeclarationExp(0, v); c->type = v->type; - for (int u = i; u < nargs; u++) + for (size_t u = i; u < nargs; u++) { Expression *a = (Expression *)arguments->data[u]; if (tret && !tb->next->equals(a->type)) a = a->toDelegate(sc, tret); Expression *e = new VarExp(loc, v); - e = new IndexExp(loc, e, new IntegerExp(u + 1 - nproto)); + e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); e = new AssignExp(loc, e, a); if (c) c = new CommaExp(loc, c, e); @@ -450,7 +470,7 @@ */ Expressions *args = new Expressions(); args->setDim(nargs - i); - for (int u = i; u < nargs; u++) + for (size_t u = i; u < nargs; u++) args->data[u - i] = arguments->data[u]; arg = new NewExp(loc, NULL, NULL, p->type, args); break; @@ -540,8 +560,8 @@ { Expression *e; - e = createTypeInfoArray(sc, (Expression **)&arguments->data[nproto], - arguments->dim - nproto); + e = createTypeInfoArray(sc, (Expression **)&arguments->data[nparams], + arguments->dim - nparams); arguments->insert(0, e); } } @@ -568,11 +588,10 @@ */ void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) -{ int i; - +{ if (arguments) { - for (i = 0; i < arguments->dim; i++) + for (size_t i = 0; i < arguments->dim; i++) { Expression *arg = (Expression *)arguments->data[i]; if (i) @@ -1533,6 +1552,26 @@ // ArrayScopeSymbol::search() doesn't have access to sc. s->semantic(sc); } + // Look to see if f is really a function template + FuncDeclaration *f = s->isFuncDeclaration(); + if (f && f->parent) + { TemplateInstance *ti = f->parent->isTemplateInstance(); + + if (ti && + !ti->isTemplateMixin() && + (ti->idents.data[ti->idents.dim - 1] == f->ident || + ti->toAlias()->ident == f->ident) + && + ti->tempdecl && ti->tempdecl->onemember) + { + TemplateDeclaration *tempdecl = ti->tempdecl; + if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl->overroot; // then get the start + e = new TemplateExp(loc, tempdecl); + e = e->semantic(sc); + return e; + } + } e = new DsymbolExp(loc, s); } return e->semantic(sc); @@ -1732,6 +1771,29 @@ return new TypeExp(loc, t); } + TupleDeclaration *tup = s->isTupleDeclaration(); + if (tup) + { Expressions *exps = new Expressions(); + + exps->reserve(tup->objects->dim); + for (size_t i = 0; i < tup->objects->dim; i++) + { Object *o = (Object *)tup->objects->data[i]; + if (o->dyncast() != DYNCAST_EXPRESSION) + { + error("%s is not an expression", o->toChars()); + } + else + { + Expression *e = (Expression *)o; + e = e->syntaxCopy(); + exps->push(e); + } + } + e = new TupleExp(loc, exps); + e = e->semantic(sc); + return e; + } + TemplateInstance *ti = s->isTemplateInstance(); if (ti && !global.errors) { if (!ti->semanticdone) @@ -1752,6 +1814,7 @@ return e; } +Lerr: error("%s '%s' is not a variable", s->kind(), s->toChars()); type = Type::terror; return this; @@ -1822,7 +1885,7 @@ return this; Lerr: - error("'this' is only allowed in non-static member functions"); + error("'this' is only allowed in non-static member functions, not %s", sc->parent->toChars()); type = Type::tint32; return this; } @@ -2264,8 +2327,13 @@ // Run semantic() on each element for (int i = 0; i < elements->dim; i++) { e = (Expression *)elements->data[i]; - e = e->semantic(sc); + elements->data[i] = (void *)e; + } + expandTuples(elements); + for (int i = 0; i < elements->dim; i++) + { e = (Expression *)elements->data[i]; + if (!e->type) error("%s has no value", e->toChars()); e = resolveProperties(sc, e); @@ -2980,6 +3048,96 @@ } +/******************************** TupleExp **************************/ + +TupleExp::TupleExp(Loc loc, Expressions *exps) + : Expression(loc, TOKtuple, sizeof(TupleExp)) +{ + //printf("TupleExp(this = %p)\n", this); + this->exps = exps; + this->type = NULL; +} + +int TupleExp::equals(Object *o) +{ TupleExp *ne; + + if (this == o) + return 1; + if (((Expression *)o)->op == TOKtuple) + { + TupleExp *te = (TupleExp *)o; + if (exps->dim != te->exps->dim) + return 0; + for (size_t i = 0; i < exps->dim; i++) + { Expression *e1 = (Expression *)exps->data[i]; + Expression *e2 = (Expression *)te->exps->data[i]; + + if (!e1->equals(e2)) + return 0; + } + return 1; + } + return 0; +} + +Expression *TupleExp::syntaxCopy() +{ + return new TupleExp(loc, arraySyntaxCopy(exps)); +} + +Expression *TupleExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("TupleExp::semantic(%s)\n", toChars()); +#endif + if (type) + return this; + + // Run semantic() on each argument + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + e = e->semantic(sc); + if (!e->type) + { error("%s has no value", e->toChars()); + e->type = Type::terror; + } + exps->data[i] = (void *)e; + } + + expandTuples(exps); + type = new TypeTuple(exps); + return this; +} + +void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("tuple("); + argsToCBuffer(buf, exps, hgs); + buf->writestring(")"); +} + +int TupleExp::checkSideEffect(int flag) +{ int f = 0; + + for (int i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + f |= e->checkSideEffect(2); + } + if (flag == 0 && f == 0) + Expression::checkSideEffect(0); + return f; +} + +void TupleExp::checkEscape() +{ + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + e->checkEscape(); + } +} + /******************************** FuncExp *********************************/ FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd) @@ -3725,6 +3883,14 @@ eleft = NULL; eright = e1; } + + if (e1->op == TOKtuple && ident == Id::length) + { + TupleExp *te = (TupleExp *)e1; + e = new IntegerExp(loc, te->exps->dim, Type::tsize_t); + return e; + } + if (eright->op == TOKimport) // also used for template alias's { Dsymbol *s; @@ -4249,10 +4415,10 @@ /************************************************************/ -CallExp::CallExp(Loc loc, Expression *e, Expressions *arguments) +CallExp::CallExp(Loc loc, Expression *e, Expressions *exps) : UnaExp(loc, TOKcall, sizeof(CallExp), e) { - this->arguments = arguments; + this->arguments = exps; } CallExp::CallExp(Loc loc, Expression *e) @@ -4294,6 +4460,7 @@ FuncDeclaration *f; int i; Type *t1; + int istemp; #if LOGSEMANTIC printf("CallExp::semantic('%s')\n", toChars()); @@ -4357,6 +4524,7 @@ } } + istemp = 0; Lagain: f = NULL; if (e1->op == TOKthis || e1->op == TOKsuper) @@ -4657,6 +4825,31 @@ f = ve->var->isFuncDeclaration(); assert(f); + + // Look to see if f is really a function template + if (0 && !istemp && f->parent) + { TemplateInstance *ti = f->parent->isTemplateInstance(); + + if (ti && + (ti->idents.data[ti->idents.dim - 1] == f->ident || + ti->toAlias()->ident == f->ident) + && + ti->tempdecl) + { + /* This is so that one can refer to the enclosing + * template, even if it has the same name as a member + * of the template, if it has a !(arguments) + */ + TemplateDeclaration *tempdecl = ti->tempdecl; + if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl->overroot; // then get the start + e1 = new TemplateExp(loc, tempdecl); + istemp = 1; +printf("istemp\n"); + goto Lagain; + } + } + f = f->overloadResolve(loc, arguments); checkDeprecated(sc, f); @@ -5105,13 +5298,16 @@ if (type) return this; UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - to = to->semantic(loc, sc); - - e = op_overload(sc); - if (e) + if (e1->type) // if not a tuple { - return e->implicitCastTo(sc, to); + e1 = resolveProperties(sc, e1); + to = to->semantic(loc, sc); + + e = op_overload(sc); + if (e) + { + return e->implicitCastTo(sc, to); + } } return e1->castTo(sc, to); } @@ -5218,10 +5414,19 @@ } goto Lerror; } + else if (t->ty == Ttuple) + { + if (!lwr && !upr) + return e1; + if (!lwr || !upr) + { error("need upper and lower bound to slice tuple"); + goto Lerror; + } + } else goto Lerror; - if (t->ty == Tsarray || t->ty == Tarray) + if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) { sym = new ArrayScopeSymbol(this); sym->parent = sc->scopesym; @@ -5239,9 +5444,37 @@ upr = upr->implicitCastTo(sc, Type::tindex); } - if (t->ty == Tsarray || t->ty == Tarray) + if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) sc->pop(); + if (t->ty == Ttuple) + { TupleExp *te = (TupleExp *)e1; + lwr = lwr->optimize(WANTvalue); + upr = upr->optimize(WANTvalue); + size_t length = te->exps->dim; + uinteger_t i1 = lwr->toUInteger(); + uinteger_t i2 = upr->toUInteger(); + + if (i1 <= i2 && i2 <= length) + { Expressions *exps = new Expressions; + size_t j1 = (size_t) i1; + size_t j2 = (size_t) i2; + exps->setDim(j2 - j1); + for (size_t i = 0; i < j2 - j1; i++) + { Expression *e = (Expression *)te->exps->data[j1 + i]; + exps->data[i] = (void *)e; + } + e = new TupleExp(loc, exps); + e = e->semantic(sc); + } + else + { + error("string slice [%llu .. %llu] is out of bounds", i1, i2); + e = e1; + } + return e; + } + type = t->next->arrayOf(); return e; @@ -5344,7 +5577,6 @@ #endif UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); - assert(arguments && arguments->dim); t1 = e1->type->toBasetype(); if (t1->ty != Tclass && t1->ty != Tstruct) @@ -5356,7 +5588,7 @@ } // Run semantic() on each argument - for (int i = 0; i < arguments->dim; i++) + for (size_t i = 0; i < arguments->dim; i++) { e = (Expression *)arguments->data[i]; e = e->semantic(sc); @@ -5365,6 +5597,9 @@ arguments->data[i] = (void *)e; } + expandTuples(arguments); + assert(arguments && arguments->dim); + e = op_overload(sc); if (!e) { error("no [] operator overload for type %s", e1->type->toChars()); @@ -5489,7 +5724,7 @@ t1 = e1->type->toBasetype(); - if (t1->ty == Tsarray || t1->ty == Tarray) + if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) { // Create scope for 'length' variable sym = new ArrayScopeSymbol(this); sym->parent = sc->scopesym; @@ -5504,7 +5739,7 @@ } e2 = resolveProperties(sc, e2); - if (t1->ty == Tsarray || t1->ty == Tarray) + if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) sc = sc->pop(); switch (t1->ty) @@ -5518,11 +5753,6 @@ case Tsarray: { e2 = e2->implicitCastTo(sc, Type::tindex); - if (t1->next->toBasetype()->ty == Tbit) - { - e->type = t1->next; - break; - } TypeSArray *tsa = (TypeSArray *)t1; @@ -5551,6 +5781,25 @@ break; } + case Ttuple: + { TupleExp *te = (TupleExp *)e1; + e2 = e2->implicitCastTo(sc, Type::tindex); + e2 = e2->optimize(WANTvalue); + uinteger_t index = e2->toUInteger(); + uinteger_t length = te->exps->dim; + if (index < length) + { + e = (Expression *)te->exps->data[(size_t)index]; + } + else + { + error("array index [%llu] is outside array bounds [0 .. %llu]", + index, length); + e = e1; + } + break; + } + default: error("%s must be an array or pointer type, not %s", e1->toChars(), e1->type->toChars()); diff -uNr dmd-0.172/dmd/src/dmd/expression.h dmd-0.173/dmd/src/dmd/expression.h --- dmd-0.172/dmd/src/dmd/expression.h 2006-10-16 23:14:00.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/expression.h 2006-10-28 08:42:02.000000000 +0200 @@ -57,9 +57,10 @@ Expression *resolveProperties(Scope *sc, Expression *e); void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d); Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid); -void inferApplyArgTypes(enum TOK op, Array *arguments, Expression *aggr); +void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr); void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); +void expandTuples(Expressions *exps); struct Expression : Object { @@ -306,6 +307,28 @@ dt_t **toDt(dt_t **pdt); }; +// Tuple + +struct TupleExp : Expression +{ + Expressions *exps; + + TupleExp(Loc loc, Expressions *exps); + Expression *syntaxCopy(); + int equals(Object *o); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + void checkEscape(); + int checkSideEffect(int flag); + Expression *optimize(int result); + Expression *castTo(Scope *sc, Type *t); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); +}; + struct ArrayLiteralExp : Expression { Expressions *elements; @@ -668,9 +691,9 @@ struct CallExp : UnaExp { - Expressions *arguments; // Array of Expression's + Expressions *arguments; // function arguments - CallExp(Loc loc, Expression *e, Expressions *arguments); + CallExp(Loc loc, Expression *e, Expressions *exps); CallExp(Loc loc, Expression *e); CallExp(Loc loc, Expression *e, Expression *earg1); CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2); diff -uNr dmd-0.172/dmd/src/dmd/func.c dmd-0.173/dmd/src/dmd/func.c --- dmd-0.172/dmd/src/dmd/func.c 2006-10-17 21:40:24.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/func.c 2006-10-29 00:42:48.000000000 +0200 @@ -1,4 +1,5 @@ +// Compiler implementation of the D programming language // Copyright (c) 1999-2006 by Digital Mars // All Rights Reserved // written by Walter Bright @@ -98,6 +99,8 @@ printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); if (isFuncLiteralDeclaration()) printf("\tFuncLiteralDeclaration()\n"); + printf("sc->parent = %s\n", sc->parent->toChars()); + printf("type: %s\n", type->toChars()); #endif if (type->next) @@ -108,10 +111,14 @@ error("%s must be a function", toChars()); } f = (TypeFunction *)(type); + size_t nparams = Argument::dim(f->parameters); linkage = sc->linkage; -// parent = sc->scopesym; - parent = sc->parent; +// if (!parent) + { + //parent = sc->scopesym; + parent = sc->parent; + } protection = sc->protection; storage_class |= sc->stc; //printf("function storage_class = x%x\n", storage_class); @@ -449,27 +456,25 @@ if (isMain()) { // Check parameters to see if they are either () or (char[][] args) - if (f->arguments) + switch (nparams) { - switch (f->arguments->dim) - { - case 0: - break; - - case 1: - { - Argument *arg0 = (Argument *)f->arguments->data[0]; - if (arg0->type->ty != Tarray || - arg0->type->next->ty != Tarray || - arg0->type->next->next->ty != Tchar) - goto Lmainerr; - break; - } + case 0: + break; - default: + case 1: + { + Argument *arg0 = Argument::getNth(f->parameters, 0); + if (arg0->type->ty != Tarray || + arg0->type->next->ty != Tarray || + arg0->type->next->next->ty != Tchar) goto Lmainerr; + break; } + + default: + goto Lmainerr; } + if (f->next->ty != Tint32 && f->next->ty != Tvoid) error("must return int or void, not %s", f->next->toChars()); if (f->varargs) @@ -505,6 +510,7 @@ if (!type || type->ty != Tfunction) return; f = (TypeFunction *)(type); + size_t nparams = Argument::dim(f->parameters); // Check the 'throws' clause if (fthrows) @@ -554,7 +560,7 @@ if (isFuncLiteralDeclaration() && isNested()) { error("literals cannot be class members"); - ad = NULL; + return; } else { @@ -610,23 +616,22 @@ } // Declare all the function parameters as variables - if (f->arguments) - { int i; - + if (nparams) + { // parameters[] has all the tuples removed, as the back end + // doesn't know about tuples parameters = new Array(); - parameters->reserve(f->arguments->dim); - for (i = 0; i < f->arguments->dim; i++) - { Argument *arg; - VarDeclaration *v; - - arg = (Argument *)f->arguments->data[i]; + parameters->reserve(nparams); + for (size_t i = 0; i < nparams; i++) + { + Argument *arg = Argument::getNth(f->parameters, i); if (!arg->ident) error("no identifier for parameter %d of %s", i + 1, toChars()); else { - v = new VarDeclaration(0, arg->type, arg->ident, NULL); + VarDeclaration *v = new VarDeclaration(0, arg->type, arg->ident, NULL); + //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); v->storage_class |= STCparameter; - if (f->varargs == 2 && i + 1 == f->arguments->dim) + if (f->varargs == 2 && i + 1 == nparams) v->storage_class |= STCvariadic; switch (arg->inout) { case In: v->storage_class |= STCin; break; @@ -646,6 +651,36 @@ } } + // Declare the tuple symbols and put them in the symbol table, + // but not in parameters[] + if (f->parameters) + { + for (size_t i = 0; i < f->parameters->dim; i++) + { Argument *arg = (Argument *)f->parameters->data[i]; + + if (arg->type->ty == Ttuple) + { TypeTuple *t = (TypeTuple *)arg->type; + size_t dim = Argument::dim(t->arguments); + Objects *exps = new Objects(); + exps->setDim(dim); + for (size_t j = 0; j < dim; j++) + { Argument *arg = Argument::getNth(t->arguments, j); + VarDeclaration *v = sc2->search(0, arg->ident, NULL)->isVarDeclaration(); + assert(v); + Expression *e = new VarExp(0, v); + exps->data[j] = (void *)e; + } + TupleDeclaration *v = new TupleDeclaration(0, arg->ident, exps); + //printf("declaring tuple %s\n", v->toChars()); + v->isexp = 1; + if (!sc2->insert(v)) + error("parameter %s.%s is already defined", toChars(), v->toChars()); + localsymtab->insert(v); + v->parent = this; + } + } + } + sc2->incontract++; if (frequire) @@ -1307,8 +1342,8 @@ tf = (TypeFunction *)type; //printf("tf = %s, args = %s\n", tf->deco, ((Expression *)arguments->data[0])->type->deco); - error(loc, "%s does not match argument types (%s)", - Argument::argsTypesToChars(tf->arguments, tf->varargs), + error(loc, "%s does not match parameter types (%s)", + Argument::argsTypesToChars(tf->parameters, tf->varargs), buf.toChars()); return m.anyf; // as long as it's not a FuncAliasDeclaration } @@ -1320,8 +1355,8 @@ error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", buf.toChars(), - m.lastf->toPrettyChars(), Argument::argsTypesToChars(t1->arguments, t1->varargs), - m.nextf->toPrettyChars(), Argument::argsTypesToChars(t2->arguments, t2->varargs)); + m.lastf->toPrettyChars(), Argument::argsTypesToChars(t1->parameters, t1->varargs), + m.nextf->toPrettyChars(), Argument::argsTypesToChars(t2->parameters, t2->varargs)); #else error(loc, "overloads %s and %s both match argument list for %s", m.lastf->type->toChars(), @@ -1403,12 +1438,12 @@ Dsymbol *fdparent; //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars()); - fdparent = fd->toParent(); + fdparent = fd->toParent2(); if (fdparent == this) return -1; s = this; level = 0; - while (fd != s && fdparent != s->toParent()) + while (fd != s && fdparent != s->toParent2()) { //printf("\ts = '%s'\n", s->toChars()); FuncDeclaration *thisfd = s->isFuncDeclaration(); @@ -1427,7 +1462,7 @@ goto Lerr; } - s = s->toParent(); + s = s->toParent2(); assert(s); level++; } @@ -1525,7 +1560,7 @@ //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); //printf("\ttoParent() = '%s'\n", toParent()->toChars()); return ((storage_class & STCstatic) == 0) && - (toParent()->isFuncDeclaration() != NULL); + (toParent2()->isFuncDeclaration() != NULL); } int FuncDeclaration::needThis() @@ -1683,7 +1718,7 @@ /********************************* CtorDeclaration ****************************/ -CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Array *arguments, int varargs) +CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL) { this->arguments = arguments; @@ -2142,7 +2177,7 @@ /********************************* NewDeclaration ****************************/ -NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Array *arguments, int varargs) +NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) { this->arguments = arguments; @@ -2181,16 +2216,17 @@ type = new TypeFunction(arguments, tret, varargs, LINKd); type = type->semantic(loc, sc); + assert(type->ty == Tfunction); // Check that there is at least one argument of type uint TypeFunction *tf = (TypeFunction *)type; - if (!tf->arguments || tf->arguments->dim < 1) + if (Argument::dim(tf->parameters) < 1) { error("at least one argument of type uint expected"); } else { - Argument *a = (Argument *)tf->arguments->data[0]; + Argument *a = Argument::getNth(tf->parameters, 0); if (!a->type->equals(Type::tuns32)) error("first argument must be type uint, not %s", a->type->toChars()); } @@ -2228,7 +2264,7 @@ /********************************* DeleteDeclaration ****************************/ -DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Array *arguments) +DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments) : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) { this->arguments = arguments; @@ -2264,16 +2300,17 @@ type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); type = type->semantic(loc, sc); + assert(type->ty == Tfunction); // Check that there is only one argument of type void* TypeFunction *tf = (TypeFunction *)type; - if (!tf->arguments || tf->arguments->dim != 1) + if (Argument::dim(tf->parameters) != 1) { error("one argument of type void* expected"); } else { - Argument *a = (Argument *)tf->arguments->data[0]; + Argument *a = Argument::getNth(tf->parameters, 0); if (!a->type->equals(Type::tvoid->pointerTo())) error("one argument of type void* expected, not %s", a->type->toChars()); } diff -uNr dmd-0.172/dmd/src/dmd/html.c dmd-0.173/dmd/src/dmd/html.c --- dmd-0.172/dmd/src/dmd/html.c 2006-09-25 13:18:50.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/html.c 2006-10-25 14:23:24.000000000 +0200 @@ -25,10 +25,6 @@ #include "root.h" #include "../mars/mars.h" -#if __GNUC__ -int memicmp(const char *s1, const char *s2, int n); -#endif - extern int HtmlNamedEntity(unsigned char *p, int length); /********************************** diff -uNr dmd-0.172/dmd/src/dmd/html.h dmd-0.173/dmd/src/dmd/html.h --- dmd-0.172/dmd/src/dmd/html.h 2006-10-05 17:05:58.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/html.h 2006-10-25 14:31:48.000000000 +0200 @@ -8,6 +8,9 @@ // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. +#ifndef DMD_HTML_H +#define DMD_HTML_H 1 + struct OutBuffer; struct Html @@ -36,3 +39,5 @@ int charEntity(); static int namedEntity(unsigned char *p, int length); }; + +#endif diff -uNr dmd-0.172/dmd/src/dmd/inline.c dmd-0.173/dmd/src/dmd/inline.c --- dmd-0.172/dmd/src/dmd/inline.c 2006-09-10 01:11:12.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/inline.c 2006-10-28 19:42:02.000000000 +0200 @@ -52,10 +52,23 @@ int CompoundStatement::inlineCost(InlineCostState *ics) { int cost = 0; - for (int i = 0; i < statements->dim; i++) - { Statement *s; + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + cost += s->inlineCost(ics); + if (cost >= COST_MAX) + break; + } + } + return cost; +} - s = (Statement *) statements->data[i]; +int UnrolledLoopStatement::inlineCost(InlineCostState *ics) +{ int cost = 0; + + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; if (s) { cost += s->inlineCost(ics); @@ -154,6 +167,11 @@ return 1; } +int TupleExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, exps); +} + int ArrayLiteralExp::inlineCost(InlineCostState *ics) { return 1 + arrayInlineCost(ics, elements); @@ -281,14 +299,29 @@ Expression *e = NULL; //printf("CompoundStatement::doInline() %d\n", statements->dim); - for (int i = 0; i < statements->dim; i++) - { Statement *s; - Expression *e2; + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + Expression *e2 = s->doInline(ids); + e = Expression::combine(e, e2); + if (s->isReturnStatement()) + break; + } + } + return e; +} - s = (Statement *) statements->data[i]; +Expression *UnrolledLoopStatement::doInline(InlineDoState *ids) +{ + Expression *e = NULL; + + //printf("UnrolledLoopStatement::doInline() %d\n", statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; if (s) { - e2 = s->doInline(ids); + Expression *e2 = s->doInline(ids); e = Expression::combine(e, e2); if (s->isReturnStatement()) break; @@ -592,6 +625,16 @@ } +Expression *TupleExp::doInline(InlineDoState *ids) +{ + TupleExp *ce; + + ce = (TupleExp *)copy(); + ce->exps = arrayExpressiondoInline(exps, ids); + return ce; +} + + Expression *ArrayLiteralExp::doInline(InlineDoState *ids) { ArrayLiteralExp *ce; @@ -652,10 +695,18 @@ Statement *CompoundStatement::inlineScan(InlineScanState *iss) { - for (int i = 0; i < statements->dim; i++) - { Statement *s; + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + statements->data[i] = (void *)s->inlineScan(iss); + } + return this; +} - s = (Statement *) statements->data[i]; +Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss) +{ + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; if (s) statements->data[i] = (void *)s->inlineScan(iss); } @@ -945,6 +996,16 @@ } +Expression *TupleExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("TupleExp::inlineScan()\n"); + arrayInlineScan(iss, exps); + + return e; +} + + Expression *ArrayLiteralExp::inlineScan(InlineScanState *iss) { Expression *e = this; diff -uNr dmd-0.172/dmd/src/dmd/lexer.c dmd-0.173/dmd/src/dmd/lexer.c --- dmd-0.172/dmd/src/dmd/lexer.c 2006-10-14 14:13:38.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/lexer.c 2006-10-28 00:12:12.000000000 +0200 @@ -28,7 +28,6 @@ #if __GNUC__ #include -extern "C" long double strtold(const char *p,char **endp); #endif #if _WIN32 @@ -51,7 +50,6 @@ extern "C" char * __cdecl __locale_decpoint; #endif -extern int isUniAlpha(unsigned u); extern int HtmlNamedEntity(unsigned char *p, int length); #define LS 0x2028 // UTF line separator @@ -2720,4 +2718,5 @@ Token::tochars[TOKarrayliteral] = "arrayliteral"; Token::tochars[TOKstring] = "string"; Token::tochars[TOKdsymbol] = "symbol"; + Token::tochars[TOKtuple] = "tuple"; } diff -uNr dmd-0.172/dmd/src/dmd/lexer.h dmd-0.173/dmd/src/dmd/lexer.h --- dmd-0.172/dmd/src/dmd/lexer.h 2006-10-14 14:11:10.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/lexer.h 2006-10-28 00:11:52.000000000 +0200 @@ -108,7 +108,7 @@ // Leaf operators TOKidentifier, TOKstring, TOKthis, TOKsuper, - TOKhalt, + TOKhalt, TOKtuple, // Basic types TOKvoid, diff -uNr dmd-0.172/dmd/src/dmd/mars.c dmd-0.173/dmd/src/dmd/mars.c --- dmd-0.172/dmd/src/dmd/mars.c 2006-10-18 10:32:34.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/mars.c 2006-11-01 17:53:00.000000000 +0100 @@ -60,7 +60,7 @@ copyright = "Copyright (c) 1999-2006 by Digital Mars"; written = "written by Walter Bright"; - version = "v0.172"; + version = "v0.173"; global.structalign = 8; memset(¶ms, 0, sizeof(Param)); diff -uNr dmd-0.172/dmd/src/dmd/mars.h dmd-0.173/dmd/src/dmd/mars.h --- dmd-0.172/dmd/src/dmd/mars.h 2006-10-05 17:00:36.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/mars.h 2006-10-25 14:28:50.000000000 +0200 @@ -15,6 +15,8 @@ #pragma once #endif /* __DMC__ */ +#include + #ifdef IN_GCC /* Changes for the GDC compiler by David Friedman */ #endif @@ -136,21 +138,21 @@ #endif #endif -// Be careful not to care about sign with integer_t -typedef unsigned long long integer_t; +// Be careful not to care about sign when using integer_t +typedef uint64_t integer_t; // Signed and unsigned variants -typedef long long sinteger_t; -typedef unsigned long long uinteger_t; +typedef int64_t sinteger_t; +typedef uint64_t uinteger_t; -typedef signed char d_int8; -typedef unsigned char d_uns8; -typedef short d_int16; -typedef unsigned short d_uns16; -typedef int d_int32; -typedef unsigned d_uns32; -typedef long long d_int64; -typedef unsigned long long d_uns64; +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; @@ -231,6 +233,7 @@ DYNCAST_DSYMBOL, DYNCAST_TYPE, DYNCAST_IDENTIFIER, + DYNCAST_TUPLE, }; void error(Loc loc, const char *format, ...); diff -uNr dmd-0.172/dmd/src/dmd/mem.h dmd-0.173/dmd/src/dmd/mem.h --- dmd-0.172/dmd/src/dmd/mem.h 2004-03-27 00:11:52.000000000 +0100 +++ dmd-0.173/dmd/src/dmd/mem.h 2006-10-25 14:33:40.000000000 +0200 @@ -4,7 +4,7 @@ #ifndef ROOT_MEM_H #define ROOT_MEM_H -typedef unsigned size_t; +#include // for size_t typedef void (*FINALIZERPROC)(void* pObj, void* pClientData); diff -uNr dmd-0.172/dmd/src/dmd/mtype.c dmd-0.173/dmd/src/dmd/mtype.c --- dmd-0.172/dmd/src/dmd/mtype.c 2006-10-16 02:01:44.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/mtype.c 2006-10-29 00:45:26.000000000 +0200 @@ -182,6 +182,7 @@ mangleChar[Tinstance] = '@'; mangleChar[Terror] = '@'; mangleChar[Ttypeof] = '@'; + mangleChar[Ttuple] = '@'; for (i = 0; i < TMAX; i++) { if (!mangleChar[i]) @@ -2275,12 +2276,12 @@ /***************************** TypeFunction *****************************/ -TypeFunction::TypeFunction(Array *arguments, Type *treturn, int varargs, enum LINK linkage) +TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage) : Type(Tfunction, treturn) { //if (!treturn) *(char*)0=0; // assert(treturn); - this->arguments = arguments; + this->parameters = parameters; this->varargs = varargs; this->linkage = linkage; this->inuse = 0; @@ -2289,8 +2290,8 @@ Type *TypeFunction::syntaxCopy() { Type *treturn = next ? next->syntaxCopy() : NULL; - Array *args = Argument::arraySyntaxCopy(arguments); - Type *t = new TypeFunction(args, treturn, varargs, linkage); + Arguments *params = Argument::arraySyntaxCopy(parameters); + Type *t = new TypeFunction(params, treturn, varargs, linkage); return t; } @@ -2325,14 +2326,15 @@ if (t1->varargs != t2->varargs) goto Ldistinct; - if (t1->arguments && t2->arguments) + if (t1->parameters && t2->parameters) { - if (t1->arguments->dim != t2->arguments->dim) + size_t dim = Argument::dim(t1->parameters); + if (dim != Argument::dim(t2->parameters)) goto Ldistinct; - for (int i = 0; i < t1->arguments->dim; i++) - { Argument *arg1 = (Argument *)t1->arguments->data[i]; - Argument *arg2 = (Argument *)t2->arguments->data[i]; + for (size_t i = 0; i < dim; i++) + { Argument *arg1 = Argument::getNth(t1->parameters, i); + Argument *arg2 = Argument::getNth(t2->parameters, i); if (!arg1->type->equals(arg2->type)) goto Ldistinct; @@ -2340,7 +2342,7 @@ inoutmismatch = 1; } } - else if (t1->arguments != t2->arguments) + else if (t1->parameters != t2->parameters) goto Ldistinct; // The argument lists match @@ -2403,32 +2405,8 @@ assert(0); } buf->writeByte(mc); - // Write arguments - if (arguments) - { int i; - - for (i = 0; i < arguments->dim; i++) - { Argument *arg; - - arg = (Argument *)arguments->data[i]; - switch (arg->inout) - { case In: - break; - case Out: - buf->writeByte('J'); - break; - case InOut: - buf->writeByte('K'); - break; - case Lazy: - buf->writeByte('L'); - break; - default: - assert(0); - } - arg->type->toDecoBuffer(buf); - } - } + // Write argument types + Argument::argsToDecoBuffer(buf, parameters); buf->writeByte('Z' - varargs); // mark end of arg list next->toDecoBuffer(buf); inuse--; @@ -2468,7 +2446,7 @@ buf->writestring(ident->toHChars2()); } } - Argument::argsToCBuffer(buf, hgs, arguments, varargs); + Argument::argsToCBuffer(buf, hgs, parameters, varargs); if (next && (!ident || ident->toHChars2() == ident->toChars())) next->toCBuffer2(buf, NULL, hgs); } @@ -2500,14 +2478,13 @@ if (next->isauto() && !(sc->flags & SCOPEctor)) error(loc, "functions cannot return auto %s", next->toChars()); - if (arguments) - { int i; + if (parameters) + { size_t dim = Argument::dim(parameters); - for (i = 0; i < arguments->dim; i++) - { Argument *arg; + for (size_t i = 0; i < dim; i++) + { Argument *arg = Argument::getNth(parameters, i); Type *t; - arg = (Argument *)arguments->data[i]; arg->type = arg->type->semantic(loc,sc); t = arg->type->toBasetype(); if (arg->inout != In) @@ -2534,7 +2511,7 @@ return tvoid; } - if (varargs == 1 && linkage != LINKd && !(arguments && arguments->dim)) + if (varargs == 1 && linkage != LINKd && Argument::dim(parameters) == 0) error(loc, "variadic functions with non-D linkage must have at least one parameter"); /* Don't return merge(), because arg identifiers and default args @@ -2551,18 +2528,13 @@ * MATCHxxxx */ -int TypeFunction::callMatch(Array *args) +int TypeFunction::callMatch(Expressions *args) { - unsigned u; - unsigned nparams; - unsigned nargs; - int match; - //printf("TypeFunction::callMatch()\n"); - match = MATCHexact; // assume exact match + int match = MATCHexact; // assume exact match - nparams = arguments ? arguments->dim : 0; - nargs = args ? args->dim : 0; + size_t nparams = Argument::dim(parameters); + size_t nargs = args ? args->dim : 0; if (nparams == nargs) ; else if (nargs > nparams) @@ -2572,14 +2544,13 @@ match = MATCHconvert; // match ... with a "conversion" match level } - for (u = 0; u < nparams; u++) + for (size_t u = 0; u < nparams; u++) { int m; - Argument *p; Expression *arg; // BUG: what about out and inout? - p = (Argument *)arguments->data[u]; + Argument *p = Argument::getNth(parameters, u); assert(p); if (u >= nargs) { @@ -2674,15 +2645,11 @@ Type *TypeFunction::reliesOnTident() { - if (arguments) - { int i; - - for (i = 0; i < arguments->dim; i++) - { Argument *arg; - Type *t; - - arg = (Argument *)arguments->data[i]; - t = arg->type->reliesOnTident(); + if (parameters) + { + for (size_t i = 0; i < parameters->dim; i++) + { Argument *arg = (Argument *)parameters->data[i]; + Type *t = arg->type->reliesOnTident(); if (t) return t; } @@ -2730,7 +2697,7 @@ OutBuffer args; TypeFunction *tf = (TypeFunction *)next; - Argument::argsToCBuffer(&args, hgs, tf->arguments, tf->varargs); + Argument::argsToCBuffer(&args, hgs, tf->parameters, tf->varargs); buf->prependstring(args.toChars()); buf->prependstring(" delegate"); if (ident) @@ -3039,7 +3006,10 @@ //((TypeIdentifier *)t)->resolve(loc, scx, pe, &t, ps); } } - *pt = t->merge(); + if (t->ty == Ttuple) + *pt = t; + else + *pt = t->merge(); } if (!s) { @@ -3177,7 +3147,7 @@ resolve(loc, sc, &e, &t, &s); if (t) { - //printf("\tit's a type %s, %s\n", t->toChars(), t->deco); + //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco); if (t->ty == Ttypedef) { TypeTypedef *tt = (TypeTypedef *)t; @@ -3818,6 +3788,9 @@ char *TypeStruct::toChars() { //printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco); + TemplateInstance *ti = sym->parent->isTemplateInstance(); + if (ti && ti->toAlias() == sym) + return ti->toChars(); return sym->toChars(); } @@ -3877,7 +3850,7 @@ void TypeStruct::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) { buf->prependbyte(' '); - buf->prependstring(sym->toChars()); + buf->prependstring(toChars()); if (ident) buf->writestring(ident->toChars()); } @@ -4362,7 +4335,101 @@ return TRUE; } +/***************************** TypeTuple *****************************/ + +TypeTuple::TypeTuple(Arguments *arguments) + : Type(Ttuple, NULL) +{ + this->arguments = arguments; +} + +/**************** + * Form TypeTuple from the types of the expressions. + * Assume exps[] is already tuple expanded. + */ + +TypeTuple::TypeTuple(Expressions *exps) + : Type(Ttuple, NULL) +{ + Arguments *arguments = new Arguments; + if (exps) + { + arguments->setDim(exps->dim); + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + assert(e->type->ty != Ttuple); + Argument *arg = new Argument(None, e->type, NULL, NULL); + arguments->data[i] = (void *)arg; + } + } + this->arguments = arguments; +} + +Type *TypeTuple::syntaxCopy() +{ + Arguments *args = Argument::arraySyntaxCopy(arguments); + Type *t = new TypeTuple(args); + return t; +} + +Type *TypeTuple::semantic(Loc loc, Scope *sc) +{ +// if (!deco) +// deco = merge()->deco; + deco = "hello"; + + /* Don't return merge(), because a tuple with one type has the + * same deco as that type. + */ + return this; +} + +Type *TypeTuple::reliesOnTident() +{ + if (arguments) + { + for (size_t i = 0; i < arguments->dim; i++) + { + Argument *arg = (Argument *)arguments->data[i]; + Type *t = arg->type->reliesOnTident(); + if (t) + return t; + } + } + return NULL; +} + +void TypeTuple::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) +{ + OutBuffer buf2; + Argument::argsToCBuffer(&buf2, hgs, arguments, 0); + buf->prependstring(buf2.toChars()); + if (ident) + { buf->writeByte(' '); + buf->writestring(ident->toChars()); + } +} + +void TypeTuple::toDecoBuffer(OutBuffer *buf) +{ + //printf("TypeTuple::toDecoBuffer() this = %p\n", this); + Argument::argsToDecoBuffer(buf, arguments); +} +Expression *TypeTuple::getProperty(Loc loc, Identifier *ident) +{ Expression *e; + +#if LOGDOTEXP + printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars()); +#endif + if (ident == Id::length) + { + e = new IntegerExp(loc, arguments->dim, Type::tsize_t); + } + else + e = Type::getProperty(loc, ident); + return e; +} /***************************** Argument *****************************/ @@ -4383,14 +4450,14 @@ return a; } -Array *Argument::arraySyntaxCopy(Array *args) -{ Array *a = NULL; +Arguments *Argument::arraySyntaxCopy(Arguments *args) +{ Arguments *a = NULL; if (args) { - a = new Array(); + a = new Arguments(); a->setDim(args->dim); - for (int i = 0; i < a->dim; i++) + for (size_t i = 0; i < a->dim; i++) { Argument *arg = (Argument *)args->data[i]; arg = arg->syntaxCopy(); @@ -4400,7 +4467,7 @@ return a; } -char *Argument::argsTypesToChars(Array *args, int varargs) +char *Argument::argsTypesToChars(Arguments *args, int varargs) { OutBuffer *buf; buf = new OutBuffer(); @@ -4433,7 +4500,7 @@ return buf->toChars(); } -void Argument::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Array *arguments, int varargs) +void Argument::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs) { buf->writeByte('('); if (arguments) @@ -4472,6 +4539,21 @@ } +void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments) +{ + //printf("Argument::argsToDecoBuffer() this = %p\n", this); + + // Write argument types + if (arguments) + { + for (size_t i = 0; i < arguments->dim; i++) + { + Argument *arg = (Argument *)arguments->data[i]; + arg->toDecoBuffer(buf); + } + } +} + /**************************************************** * Determine if parameter is a lazy array of delegates. * If so, return the return type of those delegates. @@ -4491,9 +4573,7 @@ TypeDelegate *td = (TypeDelegate *)tel; TypeFunction *tf = (TypeFunction *)td->next; - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) + if (!tf->varargs && Argument::dim(tf->parameters) == 0) { return tf->next; // return type of delegate } @@ -4503,4 +4583,79 @@ return NULL; } +void Argument::toDecoBuffer(OutBuffer *buf) +{ + switch (inout) + { case In: + break; + case Out: + buf->writeByte('J'); + break; + case InOut: + buf->writeByte('K'); + break; + case Lazy: + buf->writeByte('L'); + break; + default: + assert(0); + } + type->toDecoBuffer(buf); +} + +/*************************************** + * Determine number of arguments, folding in tuples. + */ + +size_t Argument::dim(Arguments *args) +{ + size_t n = 0; + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { Argument *arg = (Argument *)args->data[i]; + if (arg->type->ty == Ttuple) + { TypeTuple *t = (TypeTuple *)arg->type; + n += dim(t->arguments); + } + else + n++; + } + } + return n; +} + +/*************************************** + * Get nth Argument, folding in tuples. + * Returns: + * Argument* nth Argument + * NULL not found, *pn gets incremented by the number + * of Arguments + */ + +Argument *Argument::getNth(Arguments *args, size_t nth, size_t *pn) +{ + if (!args) + return NULL; + + size_t n = 0; + for (size_t i = 0; i < args->dim; i++) + { Argument *arg = (Argument *)args->data[i]; + + if (arg->type->ty == Ttuple) + { TypeTuple *t = (TypeTuple *)arg->type; + arg = getNth(t->arguments, nth - n, &n); + if (arg) + return arg; + } + else if (n == nth) + return arg; + else + n++; + } + + if (pn) + *pn += n; + return NULL; +} diff -uNr dmd-0.172/dmd/src/dmd/mtype.h dmd-0.173/dmd/src/dmd/mtype.h --- dmd-0.172/dmd/src/dmd/mtype.h 2006-10-16 01:58:00.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/mtype.h 2006-10-28 10:06:22.000000000 +0200 @@ -92,6 +92,7 @@ Terror, Tinstance, Ttypeof, + Ttuple, TMAX }; @@ -397,14 +398,14 @@ struct TypeFunction : Type { - Array *arguments; // Array of Argument's + Arguments *parameters; // function parameters int varargs; // 1: T t, ...) style for variable number of arguments // 2: T t ...) style for variable number of arguments enum LINK linkage; // calling convention int inuse; - TypeFunction(Array *arguments, Type *treturn, int varargs, enum LINK linkage); + TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); void toDecoBuffer(OutBuffer *buf); @@ -413,7 +414,7 @@ TypeInfoDeclaration *getTypeInfoDeclaration(); Type *reliesOnTident(); - int callMatch(Array *toargs); + int callMatch(Expressions *toargs); type *toCtype(); enum RET retStyle(); @@ -614,6 +615,22 @@ Symbol *toSymbol(); }; +struct TypeTuple : Type +{ + Arguments *arguments; // types making up the tuple + + TypeTuple(Arguments *arguments); + TypeTuple(Expressions *exps); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + Type *reliesOnTident(); + void toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); + void toDecoBuffer(OutBuffer *buf); + Expression *getProperty(Loc loc, Identifier *ident); +}; + +/**************************************************************/ + enum InOut { None, In, Out, InOut, Lazy }; struct Argument : Object @@ -626,9 +643,13 @@ Argument(enum InOut inout, Type *type, Identifier *ident, Expression *defaultArg); Argument *syntaxCopy(); Type *isLazyArray(); - static Array *arraySyntaxCopy(Array *args); - static char *argsTypesToChars(Array *args, int varargs); - static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Array *arguments, int varargs); + void toDecoBuffer(OutBuffer *buf); + static Arguments *arraySyntaxCopy(Arguments *args); + static char *argsTypesToChars(Arguments *args, int varargs); + static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs); + static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments); + static size_t dim(Arguments *arguments); + static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL); }; extern int PTRSIZE; diff -uNr dmd-0.172/dmd/src/dmd/opover.c dmd-0.173/dmd/src/dmd/opover.c --- dmd-0.172/dmd/src/dmd/opover.c 2006-10-18 10:40:28.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/opover.c 2006-10-28 19:37:42.000000000 +0200 @@ -36,8 +36,8 @@ #include "template.h" static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id); -static void inferApplyArgTypesX(FuncDeclaration *fstart, Array *arguments); -static int inferApplyArgTypesY(TypeFunction *tf, Array *arguments); +static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments); +static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments); static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expressions *arguments); /******************************** Expression **************************/ @@ -487,7 +487,7 @@ * them from the aggregate type. */ -void inferApplyArgTypes(enum TOK op, Array *arguments, Expression *aggr) +void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr) { if (!arguments || !arguments->dim) return; @@ -514,14 +514,15 @@ { case Tarray: case Tsarray: + case Ttuple: if (arguments->dim == 2) { if (!arg->type) arg->type = Type::tsize_t; // key type arg = (Argument *)arguments->data[1]; } - if (!arg->type) - arg->type = tab->next; // value type + if (!arg->type && tab->ty != Ttuple) + arg->type = tab->next; // value type break; case Taarray: @@ -606,7 +607,7 @@ * analogous to func.overloadResolveX(). */ -static void inferApplyArgTypesX(FuncDeclaration *fstart, Array *arguments) +static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments) { Declaration *d; Declaration *next; @@ -656,13 +657,13 @@ * 1 no match for this function */ -static int inferApplyArgTypesY(TypeFunction *tf, Array *arguments) -{ unsigned nparams; +static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments) +{ size_t nparams; Argument *p; - if (!tf->arguments || tf->arguments->dim != 1) + if (Argument::dim(tf->parameters) != 1) goto Lnomatch; - p = (Argument *)tf->arguments->data[0]; + p = Argument::getNth(tf->parameters, 0); if (p->type->ty != Tdelegate) goto Lnomatch; tf = (TypeFunction *)p->type->next; @@ -671,18 +672,18 @@ /* We now have tf, the type of the delegate. Match it against * the arguments, filling in missing argument types. */ - if (!tf->arguments || tf->varargs) + nparams = Argument::dim(tf->parameters); + if (nparams == 0 || tf->varargs) goto Lnomatch; // not enough parameters - nparams = tf->arguments->dim; if (arguments->dim != nparams) goto Lnomatch; // not enough parameters - for (unsigned u = 0; u < nparams; u++) + for (size_t u = 0; u < nparams; u++) { - p = (Argument *)arguments->data[u]; - Argument *tp = (Argument *)tf->arguments->data[u]; - if (p->type) - { if (!p->type->equals(tp->type)) + Argument *arg = (Argument *)arguments->data[u]; + Argument *param = Argument::getNth(tf->parameters, u); + if (arg->type) + { if (!arg->type->equals(param->type)) { /* Cannot resolve argument types. Indicate an * error by setting the number of arguments to 0. @@ -692,7 +693,7 @@ } continue; } - p->type = tp->type; + arg->type = param->type; } Lmatch: return 0; diff -uNr dmd-0.172/dmd/src/dmd/optimize.c dmd-0.173/dmd/src/dmd/optimize.c --- dmd-0.172/dmd/src/dmd/optimize.c 2006-10-07 15:36:34.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/optimize.c 2006-10-28 15:50:42.000000000 +0200 @@ -1,4 +1,5 @@ +// Compiler implementation of the D programming language // Copyright (c) 1999-2006 by Digital Mars // All Rights Reserved // written by Walter Bright @@ -27,6 +28,17 @@ return this; } +Expression *TupleExp::optimize(int result) +{ + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + e = e->optimize(WANTvalue); + exps->data[i] = (void *)e; + } + return this; +} + Expression *ArrayLiteralExp::optimize(int result) { if (elements) @@ -349,10 +361,8 @@ if (i >= length) { error("array index %llu is out of bounds [0 .. %llu]", i, length); - i = 0; } - - if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) + else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; e = (Expression *)ale->elements->data[i]; e->type = type; diff -uNr dmd-0.172/dmd/src/dmd/parse.c dmd-0.173/dmd/src/dmd/parse.c --- dmd-0.172/dmd/src/dmd/parse.c 2006-10-16 01:53:32.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/parse.c 2006-10-26 00:44:12.000000000 +0200 @@ -696,7 +696,7 @@ CtorDeclaration *Parser::parseCtor() { CtorDeclaration *f; - Array *arguments; + Arguments *arguments; int varargs; Loc loc = this->loc; @@ -819,7 +819,7 @@ NewDeclaration *Parser::parseNew() { NewDeclaration *f; - Array *arguments; + Arguments *arguments; int varargs; Loc loc = this->loc; @@ -839,7 +839,7 @@ DeleteDeclaration *Parser::parseDelete() { DeleteDeclaration *f; - Array *arguments; + Arguments *arguments; int varargs; Loc loc = this->loc; @@ -856,9 +856,9 @@ * Parse parameter list. */ -Array *Parser::parseParameters(int *pvarargs) +Arguments *Parser::parseParameters(int *pvarargs) { - Array *arguments = new Array(); + Arguments *arguments = new Arguments(); int varargs = 0; int hasdefault = 0; @@ -1233,7 +1233,8 @@ // Get array of TemplateParameters if (token.value != TOKrparen) - { + { int variadic = 0; + while (1) { TemplateParameter *tp; Identifier *tp_ident = NULL; @@ -1244,6 +1245,11 @@ Expression *tp_defaultvalue = NULL; Token *t; + if (variadic) + { error("Variadic template parameter must be last one"); + variadic = 0; + } + // Get TemplateParameter // First, look ahead to see if it is a TypeParameter or a ValueParameter @@ -1294,6 +1300,14 @@ } tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); } + else if (token.value == TOKidentifier && t->value == TOKdotdotdot) + { // ident... + variadic = 1; + tp_ident = token.ident; + nextToken(); + nextToken(); + tp = new TemplateTupleParameter(loc, tp_ident); + } else { // ValueParameter tp_valtype = parseBasicType(); @@ -1768,7 +1782,7 @@ { // Handle delegate declaration: // t delegate(parameter list) // t function(parameter list) - Array *arguments; + Arguments *arguments; int varargs; enum TOK save = token.value; @@ -1859,7 +1873,7 @@ } #endif case TOKlparen: - { Array *arguments; + { Arguments *arguments; int varargs; Type **pt; @@ -2605,7 +2619,7 @@ case TOKforeach_reverse: { enum TOK op = token.value; - Array *arguments; + Arguments *arguments; Statement *d; Statement *body; @@ -2614,7 +2628,7 @@ nextToken(); check(TOKlparen); - arguments = new Array(); + arguments = new Arguments(); while (1) { @@ -3948,7 +3962,7 @@ /* function type(parameters) { body } * delegate type(parameters) { body } */ - Array *arguments; + Arguments *arguments; int varargs; FuncLiteralDeclaration *fd; Type *t; @@ -3957,7 +3971,7 @@ { t = NULL; varargs = 0; - arguments = new Array(); + arguments = new Arguments(); } else { diff -uNr dmd-0.172/dmd/src/dmd/parse.h dmd-0.173/dmd/src/dmd/parse.h --- dmd-0.172/dmd/src/dmd/parse.h 2006-10-05 17:05:06.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/parse.h 2006-10-26 00:39:32.000000000 +0200 @@ -73,7 +73,7 @@ UnitTestDeclaration *parseUnitTest(); NewDeclaration *parseNew(); DeleteDeclaration *parseDelete(); - Array *parseParameters(int *pvarargs); + Arguments *parseParameters(int *pvarargs); EnumDeclaration *parseEnum(); Dsymbol *parseAggregate(); BaseClasses *parseBaseClasses(); diff -uNr dmd-0.172/dmd/src/dmd/statement.c dmd-0.173/dmd/src/dmd/statement.c --- dmd-0.172/dmd/src/dmd/statement.c 2006-10-18 10:42:36.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/statement.c 2006-11-01 15:28:28.000000000 +0100 @@ -523,6 +523,128 @@ } +/**************************** UnrolledLoopStatement ***************************/ + +UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s) + : Statement(loc) +{ + statements = s; +} + +Statement *UnrolledLoopStatement::syntaxCopy() +{ + Statements *a = new Statements(); + a->setDim(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + if (s) + s = s->syntaxCopy(); + a->data[i] = s; + } + UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); + return cs; +} + + +Statement *UnrolledLoopStatement::semantic(Scope *sc) +{ + //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); + + sc->noctor++; + Scope *scd = sc->push(); + scd->sbreak = this; + scd->scontinue = this; + + for (size_t i = 0; i < statements->dim; i++) + { + Statement *s = (Statement *) statements->data[i]; + if (s) + { + s = s->semantic(scd); + statements->data[i] = s; + } + } + + scd->pop(); + sc->noctor--; + return this; +} + +void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("unrolled {"); + buf->writenl(); + + for (size_t i = 0; i < statements->dim; i++) + { Statement *s; + + s = (Statement *) statements->data[i]; + if (s) + s->toCBuffer(buf, hgs); + } + + buf->writeByte('}'); + buf->writenl(); +} + +int UnrolledLoopStatement::hasBreak() +{ + return TRUE; +} + +int UnrolledLoopStatement::hasContinue() +{ + return TRUE; +} + +int UnrolledLoopStatement::usesEH() +{ + for (size_t i = 0; i < statements->dim; i++) + { Statement *s; + + s = (Statement *) statements->data[i]; + if (s && s->usesEH()) + return TRUE; + } + return FALSE; +} + +int UnrolledLoopStatement::fallOffEnd() +{ int falloff = TRUE; + + //printf("UnrolledLoopStatement::fallOffEnd()\n"); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (!s) + continue; + + if (!falloff && global.params.warnings && !s->comeFrom()) + { + fprintf(stdmsg, "warning - "); + s->error("statement is not reachable"); + } + falloff = s->fallOffEnd(); + } + return falloff; +} + +int UnrolledLoopStatement::comeFrom() +{ int comefrom = FALSE; + + //printf("UnrolledLoopStatement::comeFrom()\n"); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (!s) + continue; + + comefrom |= s->comeFrom(); + } + return comefrom; +} + + /******************************** ScopeStatement ***************************/ ScopeStatement::ScopeStatement(Loc loc, Statement *s) @@ -874,7 +996,7 @@ /******************************** ForeachStatement ***************************/ -ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Array *arguments, +ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, Expression *aggr, Statement *body) : Statement(loc) { @@ -891,7 +1013,7 @@ Statement *ForeachStatement::syntaxCopy() { - Array *args = Argument::arraySyntaxCopy(arguments); + Arguments *args = Argument::arraySyntaxCopy(arguments); Expression *exp = aggr->syntaxCopy(); ForeachStatement *s = new ForeachStatement(loc, op, args, exp, body->syntaxCopy()); return s; @@ -931,6 +1053,80 @@ error("cannot uniquely infer foreach argument types"); return this; } + + Type *tab = aggr->type->toBasetype(); + + if (tab->ty == Ttuple) // don't generate new scope for tuple loops + { + if (dim < 1 || dim > 2) + { + error("only one (value) or two (key,value) arguments for tuple foreach"); + return s; + } + + TypeTuple *tuple = (TypeTuple *)tab; + Statements *statements = new Statements(); + //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); + size_t n; + TupleExp *te = NULL; + if (aggr->op == TOKtuple) + { te = (TupleExp *)aggr; + n = te->exps->dim; + } + else if (aggr->op == TOKtype) + { + n = Argument::dim(tuple->arguments); + } + else + assert(0); + for (size_t j = 0; j < n; j++) + { size_t k = (op == TOKforeach) ? j : n - 1 - j; + Expression *e; + if (te) + e = (Expression *)te->exps->data[k]; + else + e = Argument::getNth(tuple->arguments, k)->type->defaultInit(); + Argument *arg = (Argument *)arguments->data[0]; + Statements *st = new Statements(); + + if (dim == 2) + { // Declare key + if (arg->inout != In) + error("no storage class for %s", arg->ident->toChars()); + TY keyty = arg->type->ty; + if ((keyty != Tint32 && keyty != Tuns32) || + (global.params.isX86_64 && + keyty != Tint64 && keyty != Tuns64) + ) + { + error("foreach: key type must be int or uint, not %s", arg->type->toChars()); + } + Initializer *ie = new ExpInitializer(0, new IntegerExp(k)); + VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie); + DeclarationExp *de = new DeclarationExp(loc, var); + st->push(new ExpStatement(loc, de)); + arg = (Argument *)arguments->data[1]; // value + } + // Declare value + arg->type = e->type; + if (arg->inout != In) + error("no storage class for %s", arg->ident->toChars()); + Initializer *ie = new ExpInitializer(0, e); + VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie); + DeclarationExp *de = new DeclarationExp(loc, var); + st->push(new ExpStatement(loc, de)); + + st->push(body->syntaxCopy()); + s = new CompoundStatement(loc, st); + s = new ScopeStatement(loc, s); + statements->push(s); + } + + s = new UnrolledLoopStatement(loc, statements); + s = s->semantic(sc); + return s; + } + for (i = 0; i < dim; i++) { Argument *arg = (Argument *)arguments->data[i]; if (!arg->type) @@ -946,7 +1142,6 @@ sc->noctor++; - Type *tab = aggr->type->toBasetype(); switch (tab->ty) { case Tarray: @@ -1056,7 +1251,7 @@ case Tdelegate: Lapply: { FuncDeclaration *fdapply; - Expressions *args; + Arguments *args; Expression *ec; Expression *e; FuncLiteralDeclaration *fld; @@ -1084,7 +1279,7 @@ /* Turn body into the function literal: * int delegate(inout T arg) { body } */ - args = new Expressions(); + args = new Arguments(); for (i = 0; i < dim; i++) { Argument *arg = (Argument *)arguments->data[i]; @@ -1151,13 +1346,13 @@ else fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply"); ec = new VarExp(0, fdapply); - args = new Expressions(); - args->push(aggr); + Expressions *exps = new Expressions(); + exps->push(aggr); size_t keysize = taa->key->size(); keysize = (keysize + 3) & ~3; - args->push(new IntegerExp(0, keysize, Type::tint32)); - args->push(flde); - e = new CallExp(loc, ec, args); + exps->push(new IntegerExp(0, keysize, Type::tint32)); + exps->push(flde); + e = new CallExp(loc, ec, exps); e->type = Type::tindex; // don't run semantic() on e } else if (tab->ty == Tarray || tab->ty == Tsarray) @@ -1193,12 +1388,12 @@ fdapply = FuncDeclaration::genCfunc(Type::tindex, fdname); ec = new VarExp(0, fdapply); - args = new Expressions(); + Expressions *exps = new Expressions(); if (tab->ty == Tsarray) aggr = aggr->castTo(sc, tn->arrayOf()); - args->push(aggr); - args->push(flde); - e = new CallExp(loc, ec, args); + exps->push(aggr); + exps->push(flde); + e = new CallExp(loc, ec, exps); e->type = Type::tindex; // don't run semantic() on e } else if (tab->ty == Tdelegate) @@ -1206,9 +1401,9 @@ /* Call: * aggr(flde) */ - args = new Expressions(); - args->push(flde); - e = new CallExp(loc, aggr, args); + Expressions *exps = new Expressions(); + exps->push(flde); + e = new CallExp(loc, aggr, exps); e = e->semantic(sc); if (e->type != Type::tint32) error("opApply() function for %s must return an int", tab->toChars()); @@ -1221,9 +1416,9 @@ ec = new DotIdExp(loc, aggr, (op == TOKforeach_reverse) ? Id::applyReverse : Id::apply); - args = new Expressions(); - args->push(flde); - e = new CallExp(loc, ec, args); + Expressions *exps = new Expressions(); + exps->push(flde); + e = new CallExp(loc, ec, exps); e = e->semantic(sc); if (e->type != Type::tint32) error("opApply() function for %s must return an int", tab->toChars()); diff -uNr dmd-0.172/dmd/src/dmd/statement.h dmd-0.173/dmd/src/dmd/statement.h --- dmd-0.172/dmd/src/dmd/statement.h 2006-10-12 11:50:18.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/statement.h 2006-10-28 19:42:00.000000000 +0200 @@ -155,20 +155,29 @@ CompoundStatement *isCompoundStatement() { return this; } }; -#if 0 -// Same as CompoundStatement, but introduces a new scope - -struct BlockStatement : CompoundStatement +/* The purpose of this is so that continue will go to the next + * of the statements, and break will go to the end of the statements. + */ +struct UnrolledLoopStatement : Statement { - BlockStatement(Loc loc, Statements *s); - BlockStatement(Loc loc, Statement *s1, Statement *s2); + Statements *statements; + + UnrolledLoopStatement(Loc loc, Statements *statements); Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int fallOffEnd(); + int comeFrom(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); }; -#endif struct ScopeStatement : Statement { @@ -251,7 +260,7 @@ struct ForeachStatement : Statement { enum TOK op; // TOKforeach or TOKforeach_reverse - Array *arguments; // array of Argument*'s + Arguments *arguments; // array of Argument*'s Expression *aggr; Statement *body; @@ -263,7 +272,7 @@ Array cases; // put breaks, continues, gotos and returns here Array gotos; // forward referenced goto's go here - ForeachStatement(Loc loc, enum TOK op, Array *arguments, Expression *aggr, Statement *body); + ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, Expression *aggr, Statement *body); Statement *syntaxCopy(); Statement *semantic(Scope *sc); int hasBreak(); diff -uNr dmd-0.172/dmd/src/dmd/struct.c dmd-0.173/dmd/src/dmd/struct.c --- dmd-0.172/dmd/src/dmd/struct.c 2006-10-05 17:02:08.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/struct.c 2006-10-26 00:34:56.000000000 +0200 @@ -297,7 +297,7 @@ TypeFunction *tfeqptr; { - Array *arguments = new Array; + Arguments *arguments = new Arguments; Argument *arg = new Argument(In, handle, Id::p, NULL); arguments->push(arg); @@ -307,7 +307,7 @@ TypeFunction *tfeq; { - Array *arguments = new Array; + Arguments *arguments = new Arguments; Argument *arg = new Argument(In, type, NULL, NULL); arguments->push(arg); diff -uNr dmd-0.172/dmd/src/dmd/template.c dmd-0.173/dmd/src/dmd/template.c --- dmd-0.172/dmd/src/dmd/template.c 2006-10-07 01:41:30.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/template.c 2006-11-01 17:51:30.000000000 +0100 @@ -1,4 +1,5 @@ +// Compiler implementation of the D programming language // Copyright (c) 1999-2006 by Digital Mars // All Rights Reserved // written by Walter Bright @@ -66,6 +67,97 @@ return (Type *)o; } +static Tuple *isTuple(Object *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_TUPLE) + return NULL; + return (Tuple *)o; +} + +/****************************** + * If o1 matches o2, return 1. + * Else, return 0. + */ + +int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) +{ + Type *t1 = isType(o1); + Type *t2 = isType(o2); + Expression *e1 = isExpression(o1); + Expression *e2 = isExpression(o2); + Dsymbol *s1 = isDsymbol(o1); + Dsymbol *s2 = isDsymbol(o2); + Tuple *v1 = isTuple(o1); + Tuple *v2 = isTuple(o2); + + /* A proper implementation of the various equals() overrides + * should make it possible to just do o1->equals(o2), but + * we'll do that another day. + */ + + if (t1) + { + /* if t1 is an instance of ti, then give error + * about recursive expansions. + */ + Dsymbol *s = t1->toDsymbol(sc); + if (s && s->parent) + { TemplateInstance *ti1 = s->parent->isTemplateInstance(); + if (ti1 && ti1->tempdecl == tempdecl) + { + for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) + { + if (sc1->scopesym == ti1) + { + error("recursive template expansion for template argument %s", t1->toChars()); + return 1; // fake a match + } + } + } + } + + if (!t2 || !t1->equals(t2)) + goto L1; + } + else if (e1) + { +#if 0 + if (e1 && e2) + { + printf("match %d\n", e1->equals(e2)); + e1->print(); + e2->print(); + } +#endif + if (!e2 || !e1->equals(e2)) + goto L1; + } + else if (s1) + { + //printf("test1: %p %s, %p %s\n", s1, s1->toChars(), s2, s2->toChars()); + if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) + goto L1; + } + else if (v1) + { + if (!v2) + goto L1; + if (v1->objects.dim != v2->objects.dim) + goto L1; + for (size_t i = 0; i < v1->objects.dim; i++) + { + if (!match((Object *)v1->objects.data[i], + (Object *)v2->objects.data[i], + tempdecl, sc)) + goto L1; + } + } + return 1; // match +L1: + return 0; // nomatch; +} + /* ======================== TemplateDeclaration ============================= */ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs) @@ -254,24 +346,30 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, Objects *dedtypes, int flag) { MATCH m; - int dim = dedtypes->dim; + int dedtypes_dim = dedtypes->dim; #if LOG printf("+TemplateDeclaration::matchWithInstance(this = %p, ti = %p, flag = %d)\n", this, ti, flag); #endif - dedtypes->zero(); +#if 0 + printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim); + if (ti->tiargs->dim) + printf("ti->tiargs->dim = %d, [0] = %p\n", + ti->tiargs->dim, + ti->tiargs->data[0]); +#endif + dedtypes->zero(); -//printf("dedtypes->dim = %d, parameters->dim = %d\n", dim, parameters->dim); -//if (ti->tiargs->dim) -//printf("ti->tiargs->dim = %d, [0] = %p\n", ti->tiargs->dim, ti->tiargs->data[0]); + int parameters_dim = parameters->dim; + int variadic = isVariadic() != NULL; // If more arguments than parameters, no match - if (ti->tiargs->dim > parameters->dim) + if (ti->tiargs->dim > parameters_dim && !variadic) return MATCHnomatch; - assert(dim == parameters->dim); - assert(dim >= ti->tiargs->dim); + assert(dedtypes_dim == parameters_dim); + assert(dedtypes_dim >= ti->tiargs->dim || variadic); // Set up scope for parameters assert((size_t)scope > 0x10000); @@ -281,20 +379,11 @@ // Attempt type deduction m = MATCHexact; - for (int i = 0; i < dim; i++) + for (int i = 0; i < dedtypes_dim; i++) { MATCH m2; TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - Object *oarg; Declaration *sparam; - if (i < ti->tiargs->dim) - oarg = (Object *)ti->tiargs->data[i]; - else - { // Look for default argument instead - oarg = tp->defaultArg(paramscope); - if (!oarg) - goto Lnomatch; - } #if 0 printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); @@ -302,7 +391,8 @@ printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); #endif - m2 = tp->matchArg(paramscope, oarg, i, parameters, dedtypes, &sparam); + m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); + if (m2 == MATCHnomatch) { //printf("\tmatchArg() for parameter %i failed\n", i); goto Lnomatch; @@ -320,7 +410,7 @@ if (!flag) { // Any parameter left without a type gets the type of its corresponding arg - for (int i = 0; i < dim; i++) + for (int i = 0; i < dedtypes_dim; i++) { if (!dedtypes->data[i]) { assert(i < ti->tiargs->dim); @@ -336,7 +426,7 @@ printf("instance %s\n", ti->toChars()); if (m) { - for (int i = 0; i < dim; i++) + for (int i = 0; i < dedtypes_dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; Object *oarg; @@ -406,7 +496,11 @@ { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - ti.tiargs->data[i] = tp->dummyArg(); + void *p = tp->dummyArg(); + if (p) + ti.tiargs->data[i] = p; + else + ti.tiargs->setDim(i); } // Temporary Array to hold deduced types @@ -416,11 +510,18 @@ // Attempt a type deduction if (td2->matchWithInstance(&ti, &dedtypes, 1)) { + /* A non-variadic template is more specialized than a + * variadic one. + */ + if (isVariadic() && !td2->isVariadic()) + goto L1; + #if LOG_LEASTAS printf(" matches, so is least as specialized\n"); #endif return 1; } + L1: #if LOG_LEASTAS printf(" doesn't match, so is not as specialized\n"); #endif @@ -442,14 +543,23 @@ { size_t i; size_t nfparams; + size_t nfparams2; size_t nfargs; size_t nargsi; MATCH match = MATCHexact; FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); TypeFunction *fdtype; + TemplateTupleParameter *tp; Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T - //printf("TemplateDeclaration::deduceMatch() %s\n", toChars()); +#if 0 + printf("\nTemplateDeclaration::deduceMatch() %s\n", toChars()); + for (i = 0; i < fargs->dim; i++) + { Expression *e = (Expression *)fargs->data[i]; + printf("\tfarg[%d] = %s\n", i, e->toChars()); + } +#endif + assert((size_t)scope > 0x10000); dedargs->setDim(parameters->dim); @@ -474,12 +584,11 @@ memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data)); for (i = 0; i < nargsi; i++) - { Object *oarg = (Object *)dedargs->data[i]; - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; MATCH m; Declaration *sparam; - m = tp->matchArg(paramscope, oarg, i, parameters, &dedtypes, &sparam); + m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); if (m == MATCHnomatch) goto Lnomatch; if (m < match) @@ -494,10 +603,57 @@ assert(fd->type->ty == Tfunction); fdtype = (TypeFunction *)fd->type; - nfparams = fdtype->arguments->dim; // number of function parameters + nfparams = Argument::dim(fdtype->parameters); // number of function parameters + nfparams2 = nfparams; nfargs = fargs->dim; // number of function arguments - if (nfparams == nfargs) + /* Check for match of function arguments with variadic template + * parameter, such as: + * + * template Foo(T, A...) { void Foo(T t, A a); } + * void main() { Foo(1,2,3); } + */ + tp = isVariadic(); + if (tp) + { + if (fdtype->varargs) // variadic function doesn't + goto Lnomatch; // go with variadic template + if (nfparams == 0) // if no function parameters + { + Tuple *t = new Tuple(); + //printf("test1: t = %p\n", t); + dedargs->data[parameters->dim - 1] = (void *)t; + } + else if (nfargs < nfparams - 1) + goto Lnomatch; + else + { + /* See if 'A' of the template parameter matches 'A' + * of the type of the last function parameter. + */ + Argument *fparam = (Argument *)fdtype->parameters->data[nfparams - 1]; + if (fparam->type->ty != Tident) + goto Lnomatch; + TypeIdentifier *tid = (TypeIdentifier *)fparam->type; + if (!tp->ident->equals(tid->ident) || tid->idents.dim) + goto Lnomatch; + + /* The types of the function arguments [nfparams - 1 .. nfargs] + * now form the tuple argument. + */ + Tuple *t = new Tuple(); + dedargs->data[parameters->dim - 1] = (void *)t; + + int tuple_dim = nfargs - (nfparams - 1); + t->objects.setDim(tuple_dim); + for (i = 0; i < tuple_dim; i++) + { Expression *farg = (Expression *)fargs->data[nfparams - 1 + i]; + t->objects.data[i] = (void *)farg->type; + } + nfparams2--; // don't consider the last parameter for type deduction + } + } + else if (nfparams == nfargs) ; else if (nfargs > nfparams) { @@ -507,9 +663,9 @@ } // Loop through the function parameters - for (i = 0; i < nfparams; i++) + for (i = 0; i < nfparams2; i++) { - Argument *fparam = (Argument *)fdtype->arguments->data[i]; + Argument *fparam = Argument::getNth(fdtype->parameters, i); Expression *farg; MATCH m; @@ -534,9 +690,7 @@ TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype(); TypeFunction *tf = (TypeFunction *)td->next; - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) + if (!tf->varargs && Argument::dim(tf->parameters) == 0) { m = farg->type->deduceType(scope, tf->next, parameters, &dedtypes); if (!m && tf->next->toBasetype()->ty == Tvoid) @@ -573,6 +727,8 @@ Lmatch: + /* Fill in any missing arguments with their defaults. + */ for (i = nargsi; i < dedargs->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; @@ -596,11 +752,20 @@ } } +#if 0 + for (i = 0; i < dedargs->dim; i++) + { Type *t = (Type *)dedargs->data[i]; + printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); + } +#endif + paramscope->pop(); + //printf("\tmatch\n"); return match; Lnomatch: paramscope->pop(); + //printf("\tnomatch\n"); return MATCHnomatch; } @@ -615,6 +780,8 @@ Type *targ = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + Dsymbol *s; if (targ) @@ -637,6 +804,11 @@ v->storage_class = STCconst; s = v; } + else if (va) + { + //printf("\ttuple\n"); + s = new TupleDeclaration(loc, tp->ident, &va->objects); + } else { #ifdef DEBUG @@ -649,6 +821,19 @@ s->semantic(sc); } +/************************************** + * Determine if TemplateDeclaration is variadic. + */ + +TemplateTupleParameter *TemplateDeclaration::isVariadic() +{ size_t dim = parameters->dim; + TemplateTupleParameter *tp = NULL; + + if (dim) + tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter(); + return tp; +} + /************************************************* * Given function arguments, figure out which template function * to expand, and return that function. @@ -668,7 +853,23 @@ TemplateInstance *ti; FuncDeclaration *fd; - //printf("TemplateDeclaration::deduce() %s\n", toChars()); +#if 0 + printf("TemplateDeclaration::deduce() %s\n", toChars()); + printf(" targsi:\n"); + if (targsi) + { for (int i = 0; i < targsi->dim; i++) + { Object *arg = (Object *)targsi->data[i]; + printf("\t%s\n", arg->toChars()); + } + } + printf(" fargs:\n"); + for (int i = 0; i < fargs->dim; i++) + { Expression *arg = (Expression *)fargs->data[i]; + printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); + //printf("\tty = %d\n", arg->type->ty); + } +#endif + for (TemplateDeclaration *td = this; td; td = td->overnext) { if (!td->scope) @@ -991,13 +1192,16 @@ { TypeFunction *tp = (TypeFunction *)tparam; if (varargs != tp->varargs || - linkage != tp->linkage || - arguments->dim != tp->arguments->dim) + linkage != tp->linkage) return MATCHnomatch; - for (int i = 0; i < arguments->dim; i++) + + size_t dim = Argument::dim(this->parameters); + if (dim != Argument::dim(tp->parameters)) + return MATCHnomatch; + for (size_t i = 0; i < dim; i++) { - Argument *a = (Argument *)arguments->data[i]; - Argument *ap = (Argument *)tp->arguments->data[i]; + Argument *a = Argument::getNth(this->parameters, i); + Argument *ap = Argument::getNth(tp->parameters, i); if (a->inout != ap->inout || !a->type->deduceType(sc, ap->type, parameters, dedtypes)) return MATCHnomatch; @@ -1059,6 +1263,18 @@ //printf("\tthis->parent = %s, ", sym->parent->toChars()); print(); //printf("\ttparam = %d, ", tparam->ty); tparam->print(); + /* If this struct is a template struct, and we're matching + * it against a template instance, convert the struct type + * to a template instance, too, and try again. + */ + TemplateInstance *ti = sym->parent->isTemplateInstance(); + if (ti && ti->toAlias() == sym && + tparam && tparam->ty == Tinstance) + { + TypeInstance *t = new TypeInstance(0, ti); + return t->deduceType(sc, tparam, parameters, dedtypes); + } + // Extra check if (tparam && tparam->ty == Tstruct) { @@ -1134,6 +1350,11 @@ return NULL; } +TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter() +{ + return NULL; +} + /* ======================== TemplateTypeParameter =========================== */ // type-parameter @@ -1182,6 +1403,14 @@ #endif } +/**************************************** + * Determine if two TemplateParameters are the same + * as far as TemplateDeclaration overloading goes. + * Returns: + * 1 match + * 0 no match + */ + int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) { TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); @@ -1201,16 +1430,35 @@ return 0; } +/******************************************* + * Match to a particular TemplateParameter. + * Input: + * tiargs[] actual arguments to template instance + * parameters[] template parameters + * dedtypes[] deduced arguments to template instance + * *psparam set to symbol declared and initialized to dedtypes[i] + */ -MATCH TemplateTypeParameter::matchArg(Scope *sc, Object *oarg, +MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) { //printf("TemplateTypeParameter::matchArg()\n"); - Type *t; + Object *oarg; MATCH m = MATCHexact; - Type *ta = isType(oarg); + Type *ta; + + if (i < tiargs->dim) + oarg = (Object *)tiargs->data[i]; + else + { // Get default argument instead + oarg = defaultArg(sc); + if (!oarg) + goto Lnomatch; + } + + ta = isType(oarg); if (!ta) goto Lnomatch; @@ -1389,13 +1637,25 @@ } MATCH TemplateAliasParameter::matchArg(Scope *sc, - Object *oarg, int i, TemplateParameters *parameters, Objects *dedtypes, + Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) { Dsymbol *sa; + Object *oarg; + Expression *ea; //printf("TemplateAliasParameter::matchArg()\n"); - Expression *ea = isExpression(oarg); + + if (i < tiargs->dim) + oarg = (Object *)tiargs->data[i]; + else + { // Get default argument instead + oarg = defaultArg(sc); + if (!oarg) + goto Lnomatch; + } + + ea = isExpression(oarg); if (ea) { // Try to convert Expression to symbol if (ea->op == TOKvar) @@ -1598,15 +1858,27 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, - Object *oarg, int i, TemplateParameters *parameters, Objects *dedtypes, + Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) { //printf("TemplateValueParameter::matchArg()\n"); Initializer *init; Declaration *sparam; - Expression *ei = isExpression(oarg); MATCH m = MATCHexact; + Expression *ei; + Object *oarg; + + if (i < tiargs->dim) + oarg = (Object *)tiargs->data[i]; + else + { // Get default argument instead + oarg = defaultArg(sc); + if (!oarg) + goto Lnomatch; + } + + ei = isExpression(oarg); Type *vt; if (!ei && oarg) @@ -1725,6 +1997,136 @@ return e; } +/* ======================== TemplateTupleParameter ========================== */ + +// variadic-parameter + +TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident) + : TemplateParameter(loc, ident) +{ + this->ident = ident; +} + +TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter() +{ + return this; +} + +TemplateParameter *TemplateTupleParameter::syntaxCopy() +{ + TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident); + return tp; +} + +void TemplateTupleParameter::semantic(Scope *sc) +{ + TypeIdentifier *ti = new TypeIdentifier(loc, ident); + Declaration *sparam = new AliasDeclaration(loc, ident, ti); + if (!sc->insert(sparam)) + error(loc, "parameter '%s' multiply defined", ident->toChars()); +} + +int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateTupleParameter *tvp = tp->isTemplateTupleParameter(); + + if (tvp) + { + return 1; // match + } + +Lnomatch: + return 0; +} + +MATCH TemplateTupleParameter::matchArg(Scope *sc, + Objects *tiargs, int i, TemplateParameters *parameters, + Objects *dedtypes, + Declaration **psparam) +{ + //printf("TemplateTupleParameter::matchArg()\n"); + + /* The rest of the actual arguments (tiargs[]) form the match + * for the variadic parameter. + */ + assert(i + 1 == dedtypes->dim); // must be the last one + Tuple *ovar; + if (i + 1 == tiargs->dim && isTuple((Object *)tiargs->data[i])) + ovar = isTuple((Object *)tiargs->data[i]); + else + { + ovar = new Tuple(); + //printf("test3: ovar = %p\n", ovar); + if (i < tiargs->dim) + { + //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim); + ovar->objects.setDim(tiargs->dim - i); + for (size_t j = 0; j < ovar->objects.dim; j++) + ovar->objects.data[j] = tiargs->data[i + j]; + } + } + *psparam = new TupleDeclaration(loc, ident, &ovar->objects); + dedtypes->data[i] = (void *)ovar; + return MATCHexact; +} + + +void TemplateTupleParameter::print(Object *oarg, Object *oded) +{ + printf(" %s... [", ident->toChars()); + Tuple *v = isTuple(oded); + assert(v); + + //printf("|%d| ", v->objects.dim); + for (int i = 0; i < v->objects.dim; i++) + { + if (i) + printf(", "); + + Object *o = (Object *)v->objects.data[i]; + + Dsymbol *sa = isDsymbol(o); + if (sa) + printf("alias: %s", sa->toChars()); + + Type *ta = isType(o); + if (ta) + printf("type: %s", ta->toChars()); + + Expression *ea = isExpression(o); + if (ea) + printf("exp: %s", ea->toChars()); + + assert(!isTuple(o)); // no nested Tuple arguments + } + + printf("]\n"); +} + +void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(ident->toChars()); + buf->writestring("..."); +} + + +void *TemplateTupleParameter::dummyArg() +{ + return NULL; +} + + +Object *TemplateTupleParameter::specialization() +{ + return NULL; +} + + +Object *TemplateTupleParameter::defaultArg(Scope *sc) +{ + return NULL; +} + /* ======================== TemplateInstance ================================ */ TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) @@ -1744,6 +2146,7 @@ this->withsym = NULL; this->nest = 0; this->havetempdecl = 0; + this->isnested = 0; } @@ -1764,6 +2167,7 @@ this->withsym = NULL; this->nest = 0; this->havetempdecl = 1; + this->isnested = 0; assert((size_t)tempdecl->scope > 0x10000); } @@ -1866,7 +2270,7 @@ * implements the typeargs. If so, just refer to that one instead. */ - for (int i = 0; i < tempdecl->instances.dim; i++) + for (size_t i = 0; i < tempdecl->instances.dim; i++) { TemplateInstance *ti = (TemplateInstance *)tempdecl->instances.data[i]; #if LOG @@ -1874,64 +2278,11 @@ #endif assert(tdtypes.dim == ti->tdtypes.dim); - for (int j = 0; j < tdtypes.dim; j++) + for (size_t j = 0; j < tdtypes.dim; j++) { Object *o1 = (Object *)tdtypes.data[j]; Object *o2 = (Object *)ti->tdtypes.data[j]; - Type *t1 = isType(o1); - Type *t2 = isType(o2); - Expression *e1 = isExpression(o1); - Expression *e2 = isExpression(o2); - Dsymbol *s1 = isDsymbol(o1); - Dsymbol *s2 = isDsymbol(o2); - - /* A proper implementation of the various equals() overrides - * should make it possible to just do o1->equals(o2), but - * we'll do that another day. - */ - - if (t1) - { - /* if t1 is an instance of ti, then give error - * about recursive expansions. - */ - Dsymbol *s = t1->toDsymbol(sc); - if (s && s->parent) - { TemplateInstance *ti1 = s->parent->isTemplateInstance(); - if (ti1 && ti1->tempdecl == tempdecl) - { - for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) - { - if (sc1->scopesym == ti1) - { - error("recursive template expansion for template argument %s", t1->toChars()); - return; - } - } - } - } - - if (!t2 || !t1->equals(t2)) - goto L1; - } - else if (e1) - { -#if 0 - if (e1 && e2) - { - printf("match %d\n", e1->equals(e2)); - e1->print(); - e2->print(); - } -#endif - if (!e2 || !e1->equals(e2)) - goto L1; - } - else if (s1) - { - //printf("test1: %p %s, %p %s\n", s1, s1->toChars(), s2, s2->toChars()); - if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) - goto L1; - } + if (!match(o1, o2, tempdecl, sc)) + goto L1; } // It's a match @@ -1960,6 +2311,10 @@ ident = genIdent(); // need an identifier for name mangling purposes. + if (isnested) // isnested is set by genIdent() + parent = sc->parent; + //printf("parent = '%s'\n", parent->kind()); + // Add 'this' to the enclosing scope's members[] so the semantic routines // will get called on the instance members #if 1 @@ -2055,7 +2410,8 @@ #endif Scope *sc2; sc2 = scope->push(this); - sc2->parent = this; + //printf("test1: isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars()); + sc2->parent = /*isnested ? sc->parent :*/ this; #if _WIN32 __try @@ -2065,7 +2421,12 @@ { Dsymbol *s = (Dsymbol *)members->data[i]; //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); + //printf("test2: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); +// if (isnested) +// s->parent = sc->parent; + //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); s->semantic(sc2); + //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); sc2->module->runDeferredSemantic(); } #if _WIN32 @@ -2261,7 +2622,10 @@ // If more arguments than parameters, // then this is no match. if (td->parameters->dim < tiargs->dim) - continue; + { + if (!td->isVariadic()) + continue; + } dedtypes.setDim(td->parameters->dim); if (!td->scope) @@ -2363,22 +2727,30 @@ Identifier *TemplateInstance::genIdent() { OutBuffer buf; char *id; + Objects *args; //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); id = tempdecl->ident->toChars(); buf.printf("__T%d%s", strlen(id), id); - for (int i = 0; i < tiargs->dim; i++) - { Object *o = (Object *)tiargs->data[i]; + args = tiargs; + for (int i = 0; i < args->dim; i++) + { Object *o = (Object *)args->data[i]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); if (ta) { buf.writeByte('T'); if (ta->deco) buf.writestring(ta->deco); else + { +#ifdef DEBUG + printf("ta = %d, %s\n", ta->ty, ta->toChars()); +#endif assert(global.errors); + } } else if (ea) { sinteger_t v; @@ -2415,9 +2787,15 @@ Lsa: buf.writeByte('S'); Declaration *d = sa->isDeclaration(); - if (d && !d->isDataseg() && !d->isFuncDeclaration() && !isTemplateMixin()) - { - error("cannot use local '%s' as template parameter", d->toChars()); + if (d && !d->isDataseg() && + (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && + !isTemplateMixin()) + { + // if module level template + if (tempdecl->toParent()->isModule()) + isnested = 1; + else + error("cannot use local '%s' as template parameter", d->toChars()); } if (d && !d->type->deco) error("forward reference of %s", d->toChars()); @@ -2427,6 +2805,11 @@ buf.printf("%d%s", strlen(p), p); } } + else if (va) + { assert(i + 1 == args->dim); // must be last one + args = &va->objects; + i = -1; + } else assert(0); } @@ -2562,14 +2945,16 @@ else { nest++; - for (i = 0; i < tiargs->dim; i++) + Objects *args = tiargs; + for (i = 0; i < args->dim; i++) { if (i) buf->writeByte(','); - Object *oarg = (Object *)tiargs->data[i]; + Object *oarg = (Object *)args->data[i]; Type *t = isType(oarg); Expression *e = isExpression(oarg); Dsymbol *s = isDsymbol(oarg); + Tuple *v = isTuple(oarg); if (t) t->toCBuffer(buf, NULL, hgs); else if (e) @@ -2579,6 +2964,11 @@ char *p = s->ident ? s->ident->toChars() : s->toChars(); buf->writestring(p); } + else if (v) + { assert(i + 1 == args->dim); + args = &v->objects; + i = -1; + } else if (!oarg) { buf->writestring("NULL"); diff -uNr dmd-0.172/dmd/src/dmd/template.h dmd-0.173/dmd/src/dmd/template.h --- dmd-0.172/dmd/src/dmd/template.h 2006-10-16 01:12:02.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/template.h 2006-10-25 01:36:24.000000000 +0200 @@ -27,6 +27,7 @@ struct TemplateTypeParameter; struct TemplateValueParameter; struct TemplateAliasParameter; +struct TemplateTupleParameter; struct Type; struct TypeTypeof; struct Scope; @@ -36,6 +37,14 @@ struct HdrGenState; enum MATCH; +struct Tuple : Object +{ + Objects objects; + + int dyncast() { return DYNCAST_TUPLE; } // kludge for template.isType() +}; + + struct TemplateDeclaration : ScopeDsymbol { TemplateParameters *parameters; // array of TemplateParameter's @@ -66,6 +75,8 @@ void declareParameter(Scope *sc, TemplateParameter *tp, Object *o); TemplateDeclaration *isTemplateDeclaration() { return this; } + + TemplateTupleParameter *isVariadic(); }; struct TemplateParameter @@ -88,6 +99,7 @@ virtual TemplateTypeParameter *isTemplateTypeParameter(); virtual TemplateValueParameter *isTemplateValueParameter(); virtual TemplateAliasParameter *isTemplateAliasParameter(); + virtual TemplateTupleParameter *isTemplateTupleParameter(); virtual TemplateParameter *syntaxCopy() = 0; virtual void semantic(Scope *) = 0; @@ -102,7 +114,7 @@ /* Match actual argument against parameter. */ - virtual MATCH matchArg(Scope *sc, Object *oarg, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0; + virtual MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0; /* Create dummy argument based on parameter. */ @@ -127,7 +139,7 @@ Object *specialization(); Object *defaultArg(Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Object *oarg, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); }; @@ -153,7 +165,7 @@ Object *specialization(); Object *defaultArg(Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Object *oarg, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); }; @@ -180,7 +192,27 @@ Object *specialization(); Object *defaultArg(Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Object *oarg, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); + void *dummyArg(); +}; + +struct TemplateTupleParameter : TemplateParameter +{ + /* Syntax: + * ident ... + */ + + TemplateTupleParameter(Loc loc, Identifier *ident); + + TemplateTupleParameter *isTemplateTupleParameter(); + TemplateParameter *syntaxCopy(); + void semantic(Scope *); + void print(Object *oarg, Object *oded); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Object *specialization(); + Object *defaultArg(Scope *sc); + int overloadMatch(TemplateParameter *); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); }; @@ -200,13 +232,14 @@ TemplateDeclaration *tempdecl; // referenced by foo.bar.abc TemplateInstance *inst; // refer to existing instance - ScopeDsymbol *argsym; // argument symbol table + ScopeDsymbol *argsym; // argument symbol table AliasDeclaration *aliasdecl; // !=NULL if instance is an alias for its // sole member WithScopeSymbol *withsym; // if a member of a with statement int semanticdone; // has semantic() been done? int nest; // for recursion detection int havetempdecl; // 1 if used second constructor + int isnested; // if referencing local symbols #ifdef IN_GCC /* On some targets, it is necessary to know whether a symbol will be emitted in the output or not before the symbol diff -uNr dmd-0.172/dmd/src/dmd/tocsym.c dmd-0.173/dmd/src/dmd/tocsym.c --- dmd-0.172/dmd/src/dmd/tocsym.c 2006-08-26 00:38:12.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/tocsym.c 2006-10-27 23:46:50.000000000 +0200 @@ -80,6 +80,9 @@ Symbol *Dsymbol::toSymbol() { printf("Dsymbol::toSymbol() '%s', kind = '%s'\n", toChars(), kind()); +#ifdef DEBUG + *(char*)0=0; +#endif assert(0); // BUG: implement return NULL; } diff -uNr dmd-0.172/dmd/src/dmd/toobj.c dmd-0.173/dmd/src/dmd/toobj.c --- dmd-0.172/dmd/src/dmd/toobj.c 2006-10-06 15:19:08.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/toobj.c 2006-10-25 20:40:30.000000000 +0200 @@ -884,12 +884,12 @@ * in case multiple .obj files instantiate the same * template with the same types. */ - if (parent->isTemplateInstance()) + if (parent->isTemplateInstance() && !parent->isTemplateMixin()) { s->Sclass = SCcomdat; break; } - parent = parent->toParent(); + parent = parent->parent; } while (parent); } s->Sfl = FLdata; diff -uNr dmd-0.172/dmd/src/dmd/typinf.c dmd-0.173/dmd/src/dmd/typinf.c --- dmd-0.172/dmd/src/dmd/typinf.c 2006-10-07 21:27:42.000000000 +0200 +++ dmd-0.173/dmd/src/dmd/typinf.c 2006-10-26 00:48:44.000000000 +0200 @@ -383,7 +383,7 @@ TypeFunction *tfeqptr; { Scope sc; - Array *arguments = new Array; + Arguments *arguments = new Arguments; Argument *arg = new Argument(In, tc->pointerTo(), NULL, NULL); arguments->push(arg); diff -uNr dmd-0.172/dmd/src/phobos/internal/object.d dmd-0.173/dmd/src/phobos/internal/object.d --- dmd-0.172/dmd/src/phobos/internal/object.d 2006-10-18 00:18:36.000000000 +0200 +++ dmd-0.173/dmd/src/phobos/internal/object.d 2006-11-01 22:34:02.000000000 +0100 @@ -151,7 +151,7 @@ */ final void notifyRegister(void delegate(Object) dg) { - printf("notifyRegister(dg = %llx, o = %p)\n", dg, this); + //printf("notifyRegister(dg = %llx, o = %p)\n", dg, this); synchronized (this) { Monitor* m = cast(Monitor*)(cast(void**)this)[1]; @@ -208,7 +208,7 @@ extern (C) void _d_notify_release(Object o) { - printf("_d_notify_release(o = %p)\n", o); + //printf("_d_notify_release(o = %p)\n", o); Monitor* m = cast(Monitor*)(cast(void**)o)[1]; if (m.delegates.length) { @@ -222,7 +222,7 @@ foreach (dg; dgs) { if (dg) - { printf("calling dg = %llx (%p)\n", dg, o); + { //printf("calling dg = %llx (%p)\n", dg, o); dg(o); } } diff -uNr dmd-0.172/dmd/src/phobos/linux.mak dmd-0.173/dmd/src/phobos/linux.mak --- dmd-0.172/dmd/src/phobos/linux.mak 2006-10-18 00:18:36.000000000 +0200 +++ dmd-0.173/dmd/src/phobos/linux.mak 2006-11-01 22:34:00.000000000 +0100 @@ -58,6 +58,7 @@ socket.o socketstream.o stdarg.o stdio.o format.o \ perf.o openrj.o uni.o trace.o boxer.o \ demangle.o cover.o bitarray.o aApplyR.o \ + signals.o cpuid.o \ ti_wchar.o ti_uint.o ti_short.o ti_ushort.o \ ti_byte.o ti_ubyte.o ti_long.o ti_ulong.o ti_ptr.o \ ti_float.o ti_double.o ti_real.o ti_delegate.o \ @@ -92,10 +93,12 @@ std/regexp.d std/random.d std/stream.d std/process.d \ std/socket.d std/socketstream.d std/loader.d std/stdarg.d \ std/stdio.d std/format.d std/perf.d std/openrj.d std/uni.d \ - std/boxer.d std/cstream.d std/demangle.d std/cover.d std/bitarray.d + std/boxer.d std/cstream.d std/demangle.d std/cover.d std/bitarray.d \ + std/signals.d std/cpuid.d SRC_STD_C= std/c/process.d std/c/stdlib.d std/c/time.d std/c/stdio.d \ - std/c/math.d std/c/stdarg.d std/c/stddef.d std/c/fenv.d std/c/string.d + std/c/math.d std/c/stdarg.d std/c/stddef.d std/c/fenv.d std/c/string.d \ + std/d/locale.d SRC_TI= \ std/typeinfo/ti_wchar.d std/typeinfo/ti_uint.d \ @@ -319,6 +322,9 @@ cover.o : std/cover.d $(DMD) -c $(DFLAGS) std/cover.d +cpuid.o : std/cpuid.d + $(DMD) -c $(DFLAGS) std/cpuid.d + cstream.o : std/cstream.d $(DMD) -c $(DFLAGS) std/cstream.d @@ -382,6 +388,9 @@ regexp.o : std/regexp.d $(DMD) -c $(DFLAGS) std/regexp.d +signals.o : std/signals.d + $(DMD) -c $(DFLAGS) std/signals.d + socket.o : std/socket.d $(DMD) -c $(DFLAGS) std/socket.d diff -uNr dmd-0.172/dmd/src/phobos/std/c/locale.d dmd-0.173/dmd/src/phobos/std/c/locale.d --- dmd-0.172/dmd/src/phobos/std/c/locale.d 1970-01-01 01:00:00.000000000 +0100 +++ dmd-0.173/dmd/src/phobos/std/c/locale.d 2006-11-01 22:34:02.000000000 +0100 @@ -0,0 +1,151 @@ +/** + * C's <locale.h> + * License: Public Domain + * Standards: + * ISO/IEC 9899:1999 §7.11 + * Macros: + * WIKI=Phobos/StdCCType + */ +module std.c.locale; + +extern(C): + +/// Structure giving information about numeric and monetary notation. +struct lconv{ + /// The decimal-point character used to format nonmonetary quantities. + char* decimal_point; + + /** The character used to separate groups of digits before the + * decimal-point character in formatted nonmonetary quantities. + **/ + char* thousands_sep; + + /** A string whose elements indicate the size of each group of digits + * in formatted nonmonetary quantities. + **/ + char* grouping; + + /** The international currency symbol applicable to the current locale. + * The first three characters contain the alphabetic international + * currency symbol in accordance with those specified in ISO 4217. + * The fourth character (immediately preceding the null character) + * is the character used to separate the international currency symbol + * from the monetary quantity. + **/ + char* int_curr_symbol; + + /// The local currency symbol applicable to the current locale. + char* currency_symbol; + + /// The decimal-point used to format monetary quantities. + char* mon_decimal_point; + + /** The separator for groups of digits before the decimal-point in + * formatted monetary quantities. + **/ + char* mon_thousands_sep; + + /** A string whose elements indicate the size of each group of digits + * in formatted monetary quantities. + **/ + char* mon_grouping; + + /** The string used to indicate a nonnegative-valued formatted + * monetary quantity. + **/ + char* positive_sign; + + /** The string used to indicate a negative-valued formatted monetary + * quantity. + **/ + char* negative_sign; + + /** The number of fractional digits (those after the decimal-point) to + * be displayed in an internationally formatted monetary quantity. + **/ + char int_frac_digits; + + /** The number of fractional digits (those after the decimal-point) to + * be displayed in a locally formatted monetary quantity. + **/ + char frac_digits; + + /// 1 if currency_symbol precedes a positive value, 0 if succeeds. + char p_cs_precedes; + + /// 1 if a space separates currency_symbol from a positive value. + char p_sep_by_space; + + /// 1 if currency_symbol precedes a negative value, 0 if succeeds. + char n_cs_precedes; + + /// 1 if a space separates currency_symbol from a negative value. + char n_sep_by_space; + + /* Positive and negative sign positions: + 0 Parentheses surround the quantity and currency_symbol. + 1 The sign string precedes the quantity and currency_symbol. + 2 The sign string follows the quantity and currency_symbol. + 3 The sign string immediately precedes the currency_symbol. + 4 The sign string immediately follows the currency_symbol. */ + char p_sign_posn; + char n_sign_posn; + + /// 1 if int_curr_symbol precedes a positive value, 0 if succeeds. + char int_p_cs_precedes; + + /// 1 iff a space separates int_curr_symbol from a positive value. + char int_p_sep_by_space; + + /// 1 if int_curr_symbol precedes a negative value, 0 if succeeds. + char int_n_cs_precedes; + + /// 1 iff a space separates int_curr_symbol from a negative value. + char int_n_sep_by_space; + + /* Positive and negative sign positions: + 0 Parentheses surround the quantity and int_curr_symbol. + 1 The sign string precedes the quantity and int_curr_symbol. + 2 The sign string follows the quantity and int_curr_symbol. + 3 The sign string immediately precedes the int_curr_symbol. + 4 The sign string immediately follows the int_curr_symbol. */ + char int_p_sign_posn; + char int_n_sign_posn; +} + +/** Affects the behavior of C's character handling functions and C's multibyte + * and wide character functions. + **/ +const LC_CTYPE = 0; + +/** Affects the decimal-point character for C's formatted input/output functions + * and C's string conversion functions, as well as C's nonmonetary formatting + * information returned by the localeconv function. + **/ +const LC_NUMERIC = 1; + +/// Affects the behavior of the strftime and wcsftime functions. +const LC_TIME = 2; + +/// Affects the behavior of the strcoll and strxfrm functions. +const LC_COLLATE = 3; + +/** Affects the monetary formatting information returned by the localeconv + * function. + **/ +const LC_MONETARY = 4; + +/// The program’s entire locale. +const LC_ALL = 6; + +/** The setlocale function selects the appropriate portion of the program's + * locale as specified by the category and locale arguments. + **/ +char* setlocale(int category, char* locale); + +/** The localeconv function sets the components of an object with type + * lconv with values appropriate for the formatting of numeric quantities + * (monetary and otherwise) according to the rules of the current locale. + **/ +lconv* localeconv(); + diff -uNr dmd-0.172/dmd/src/phobos/std/cpuid.d dmd-0.173/dmd/src/phobos/std/cpuid.d --- dmd-0.172/dmd/src/phobos/std/cpuid.d 1970-01-01 01:00:00.000000000 +0100 +++ dmd-0.173/dmd/src/phobos/std/cpuid.d 2006-11-01 22:34:02.000000000 +0100 @@ -0,0 +1,399 @@ +/** + * Identify the characteristics of the host CPU. + * + * Implemented according to: + +- AP-485 Intel(C) Processor Identification and the CPUID Instruction + $(LINK http://www.intel.com/design/xeon/applnots/241618.htm) + +- Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2A: Instruction Set Reference, A-M + $(LINK http://developer.intel.com/design/pentium4/manuals/index_new.htm) + +- AMD CPUID Specification Publication # 25481 + $(LINK http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf) + +Example: +--- +import std.cpuid; +import std.stdio; + +void main() +{ + writefln(std.cpuid.toString()); +} +--- + +AUTHORS: Tomas Lindquist Olsen <tomas@famolsen.dk> + (slightly altered by Walter Bright) +COPYRIGHT: Public Domain + + * BUGS: Only works on x86 CPUs + * + * Macros: + * WIKI = Phobos/StdCpuid + * COPYRIGHT = Public Domain + */ + +module std.cpuid; + +import std.string; + +version(D_InlineAsm_X86) +{ + /// Returns everything as a printable string + char[] toString() + { + char[] feats; + if (mmx) feats ~= "MMX "; + if (fxsr) feats ~= "FXSR "; + if (sse) feats ~= "SSE "; + if (sse2) feats ~= "SSE2 "; + if (sse3) feats ~= "SSE3 "; + if (ssse3) feats ~= "SSSE3 "; + if (amd3dnow) feats ~= "3DNow! "; + if (amd3dnowExt) feats ~= "3DNow!+ "; + if (amdMmx) feats ~= "MMX+ "; + if (ia64) feats ~= "IA-64 "; + if (amd64) feats ~= "AMD64 "; + if (hyperThreading) feats ~= "HTT"; + + return format( + "Vendor string: %s\n", vendor, + "Processor string: %s\n", processor, + "Signature: Family=%d Model=%d Stepping=%d\n", family, model, stepping, + "Features: %s\n", feats, + "Multithreading: %d threads / %d cores\n", threadsPerCPU, coresPerCPU); + + } + + /// Returns vendor string + char[] vendor() {return vendorStr;} + /// Returns processor string + char[] processor() {return processorStr;} + + /// Is MMX supported? + bool mmx() {return (flags&MMX_BIT)!=0;} + /// Is FXSR supported? + bool fxsr() {return (flags&FXSR_BIT)!=0;} + /// Is SSE supported? + bool sse() {return (flags&SSE_BIT)!=0;} + /// Is SSE2 supported? + bool sse2() {return (flags&SSE2_BIT)!=0;} + /// Is SSE3 supported? + bool sse3() {return (misc&SSE3_BIT)!=0;} + /// Is SSSE3 supported? + bool ssse3() {return (misc&SSSE3_BIT)!=0;} + + /// Is AMD 3DNOW supported? + bool amd3dnow() {return (exflags&AMD_3DNOW_BIT)!=0;} + /// Is AMD 3DNOW Ext supported? + bool amd3dnowExt() {return (exflags&AMD_3DNOW_EXT_BIT)!=0;} + /// Is AMD MMX supported? + bool amdMmx() {return (exflags&AMD_MMX_BIT)!=0;} + + /// Is this an Intel Architecture IA64? + bool ia64() {return (flags&IA64_BIT)!=0;} + /// Is this an AMD 64? + bool amd64() {return (exflags&AMD64_BIT)!=0;} + + /// Is hyperthreading supported? + bool hyperThreading() {return (flags&HTT_BIT)!=0;} + /// Returns number of threads per CPU + uint threadsPerCPU() {return maxThreads;} + /// Returns number of cores in CPU + uint coresPerCPU() {return maxCores;} + + /// Is this an Intel processor? + bool intel() {return manufac==INTEL;} + /// Is this an AMD processor? + bool amd() {return manufac==AMD;} + + /// Returns stepping + uint stepping() {return _stepping;} + /// Returns model + uint model() {return _model;} + /// Returns family + uint family() {return _family;} + //uint processorType() {return (signature>>>12)&0x3;} + + static this() + { + getVendorString(); + getProcessorString(); + getFeatureFlags(); + + // stepping / family / model + _stepping = signature&0xF; + uint fbase = (signature>>>8)&0xF; + uint fex = (signature>>>20)&0xFF; + uint mbase = (signature>>>4)&0xF; + uint mex = (signature>>>16)&0xF; + + // vendor specific + void function() threadFn; + switch(vendorStr) + { + case "GenuineIntel": + manufac = INTEL; + threadFn = &getThreadingIntel; + if (fbase == 0xF) + _family = fbase+fex; + else + _family = fbase; + if (_family == 0x6 || _family == 0xF) + _model = mbase+(mex<<4); + else + _model = mbase; + break; + + case "AuthenticAMD": + manufac = AMD; + threadFn = &getThreadingAMD; + if (fbase < 0xF) + { + _family = fbase; + _model = mbase; + } + else + { + _family = fbase+fex; + _model = mbase+(mex<<4); + } + break; + + default: + manufac = OTHER; + } + + // threading details + if (hyperThreading && threadFn !is null) + { + threadFn(); + } + } + +private: + // feature flags + enum : uint + { + MMX_BIT = 1<<23, + FXSR_BIT = 1<<24, + SSE_BIT = 1<<25, + SSE2_BIT = 1<<26, + HTT_BIT = 1<<28, + IA64_BIT = 1<<30 + } + // feature flags misc + enum : uint + { + SSE3_BIT = 1, + SSSE3_BIT = 1<<9 + } + // extended feature flags + enum : uint + { + AMD_MMX_BIT = 1<<22, + AMD64_BIT = 1<<29, + AMD_3DNOW_EXT_BIT = 1<<30, + AMD_3DNOW_BIT = 1<<31 + } + // manufacturer + enum + { + OTHER, + INTEL, + AMD + } + + uint flags, misc, exflags, apic, signature; + uint _stepping, _model, _family; + + char[12] vendorStr = ""; + char[] processorStr = ""; + + uint maxThreads=1; + uint maxCores=1; + uint manufac=OTHER; + + /* ** + * fetches the cpu vendor string + */ + private void getVendorString() + { + char* dst = vendorStr; + // puts the vendor string into dst + asm + { + mov EAX, 0 ; + cpuid ; + mov EAX, dst ; + mov [EAX], EBX ; + mov [EAX+4], EDX ; + mov [EAX+8], ECX ; + } + } + + private void getProcessorString() + { + char[48] buffer; + char* dst = buffer; + // puts the processor string into dst + asm + { + mov EAX, 0x8000_0000 ; + cpuid ; + cmp EAX, 0x8000_0004 ; + jb PSLabel ; // no support + push EDI ; + mov EDI, dst ; + mov EAX, 0x8000_0002 ; + cpuid ; + mov [EDI], EAX ; + mov [EDI+4], EBX ; + mov [EDI+8], ECX ; + mov [EDI+12], EDX ; + mov EAX, 0x8000_0003 ; + cpuid ; + mov [EDI+16], EAX ; + mov [EDI+20], EBX ; + mov [EDI+24], ECX ; + mov [EDI+28], EDX ; + mov EAX, 0x8000_0004 ; + cpuid ; + mov [EDI+32], EAX ; + mov [EDI+36], EBX ; + mov [EDI+40], ECX ; + mov [EDI+44], EDX ; + pop EDI ; + PSLabel: ; + } + + if (buffer[0] == char.init) // no support + return; + + // seems many intel processors prepend whitespace + processorStr = std.string.strip(std.string.toString(dst)).dup; + } + + private void getFeatureFlags() + { + uint f,m,e,a,s; + asm + { + mov EAX, 0 ; + cpuid ; + cmp EAX, 1 ; + jb FeatLabel ; // no support + mov EAX, 1 ; + cpuid ; + mov f, EDX ; + mov m, ECX ; + mov a, EBX ; + mov s, EAX ; + + FeatLabel: ; + mov EAX, 0x8000_0000 ; + cpuid ; + cmp EAX, 0x8000_0001 ; + jb FeatLabel2 ; // no support + mov EAX, 0x8000_0001 ; + cpuid ; + mov e, EDX ; + + FeatLabel2: + ; + } + flags = f; + misc = m; + exflags = e; + apic = a; + signature = s; + } + + private void getThreadingIntel() + { + uint n; + ubyte b = 0; + asm + { + mov EAX, 0 ; + cpuid ; + cmp EAX, 4 ; + jb IntelSingle ; + mov EAX, 4 ; + mov ECX, 0 ; + cpuid ; + mov n, EAX ; + mov b, 1 ; + IntelSingle: ; + } + if (b != 0) + { + maxCores = ((n>>>26)&0x3F)+1; + maxThreads = (apic>>>16)&0xFF; + } + else + { + maxCores = maxThreads = 1; + } + } + + private void getThreadingAMD() + { + ubyte n; + ubyte b = 0; + asm + { + mov EAX, 0x8000_0000 ; + cpuid ; + cmp EAX, 0x8000_0008 ; + jb AMDSingle ; + mov EAX, 0x8000_0008 ; + cpuid ; + mov n, CL ; + mov b, 1 ; + AMDSingle: ; + } + if (b != 0) + { + maxCores = n+1; + maxThreads = (apic>>>16)&0xFF; + } + else + { + maxCores = maxThreads = 1; + } + } +} +else +{ + char[] toString() { return "unknown CPU\n"; } + + char[] vendor() {return "unknown vendor"; } + char[] processor() {return "unknown processor"; } + + bool mmx() {return false; } + bool fxsr() {return false; } + bool sse() {return false; } + bool sse2() {return false; } + bool sse3() {return false; } + bool ssse3() {return false; } + + bool amd3dnow() {return false; } + bool amd3dnowExt() {return false; } + bool amdMmx() {return false; } + + bool ia64() {return false; } + bool amd64() {return false; } + + bool hyperThreading() {return false; } + uint threadsPerCPU() {return 0; } + uint coresPerCPU() {return 0; } + + bool intel() {return false; } + bool amd() {return false; } + + uint stepping() {return 0; } + uint model() {return 0; } + uint family() {return 0; } +} diff -uNr dmd-0.172/dmd/src/phobos/std/signals.d dmd-0.173/dmd/src/phobos/std/signals.d --- dmd-0.172/dmd/src/phobos/std/signals.d 1970-01-01 01:00:00.000000000 +0100 +++ dmd-0.173/dmd/src/phobos/std/signals.d 2006-11-01 22:34:02.000000000 +0100 @@ -0,0 +1,289 @@ +// This is part of the Phobos runtime libary for the D programming language. + +/******************************** + * Signals and Slots are an implementation of the Observer Pattern. + * Essentially, when a Signal is emitted, a list of connected Observers + * (called slots) are called. + * + * There have been several D implementations of Signals and Slots. + * This version makes use of several new features in D, which make + * using it simpler and less error prone. In particular, it is no + * longer necessary to instrument the slots. + * + * References: + * $(LINK2 http://scottcollins.net/articles/a-deeper-look-at-signals-and-_slots.html, A Deeper Look at Signals and Slots)$(BR) + * $(LINK2 http://en.wikipedia.org/wiki/Observer_pattern, Observer pattern)$(BR) + * $(LINK2 http://en.wikipedia.org/wiki/Signals_and_slots, Wikipedia)$(BR) + * $(LINK2 http://boost.org/doc/html/signals.html, Boost Signals)$(BR) + * $(LINK2 http://doc.trolltech.com/4.1/signalsandslots.html, Qt)$(BR) + * + * There has been a great deal of discussion in the D newsgroups + * over this, and several implementations: + * + * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/announce/signal_slots_library_4825.html, signal slots library)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Signals_and_Slots_in_D_42387.html, Signals and Slots in D)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Dynamic_binding_--_Qt_s_Signals_and_Slots_vs_Objective-C_42260.html, Dynamic binding -- Qt's Signals and Slots vs Objective-C)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Dissecting_the_SS_42377.html, Dissecting the SS)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/dwt/about_harmonia_454.html, about harmonia)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/announce/1502.html, Another event handling module)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/41825.html, Suggestion: signal/slot mechanism)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/13251.html, Signals and slots?)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/10714.html, Signals and slots ready for evaluation)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/1393.html, Signals & Slots for Walter)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/28456.html, Signal/Slot mechanism?)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/19470.html, Modern Features?)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/16592.html, Delegates vs interfaces)$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/16583.html, The importance of component programming (properties, signals and slots, etc))$(BR) + * $(LINK2 http://www.digitalmars.com/d/archives/16368.html, signals and slots)$(BR) + * + * Bugs: + * Slots can only be delegates formed from class objects or + * interfaces to class objects. If a delegate to something else + * is passed to connect(), such as a struct member function, + * a nested function or a COM interface, undefined behavior + * will result. + * Macros: + * WIKI = Phobos/StdSignals + * Copyright: + * Public Domain + * Author: Walter Bright, Digital Mars, www.digitalmars.com + */ + +module std.signals; + +import std.stdio; +import std.c.stdlib; +import std.outofmemory; + +// Special function for internal use only. +// Use of this is where the slot had better be a delegate +// to an object or an interface that is part of an object. +extern (C) Object _d_toObject(void* p); + +//debug=signal; + +/************************ + * Mixin to create a signal within a class object. + * + * Different signals can be added to a class by naming the mixins. + * + * Example: +--- +import std.signals; + +class Observer +{ // our slot + void watch(char[] msg, int i) + { + writefln("Observed msg '%s' and value %s", msg, i); + } +} + +class Foo +{ + int value() { return _value; } + + int value(int v) + { + if (v != _value) + { _value = v; + // call all the connected slots with the two parameters + emit("setting new value", v); + } + return v; + } + + // Mix in all the code we need to make Foo into a signal + mixin Signal!(char[], int); + + private : + int _value; +} + +void main() +{ + Foo a = new Foo; + Observer o = new Observer; + + a.value = 3; // should not call o.watch() + a.connect(&o.watch); // o.watch is the slot + a.value = 4; // should call o.watch() + a.disconnect(&o.watch); // o.watch is no longer a slot + a.value = 5; // so should not call o.watch() + a.connect(&o.watch); // connect again + a.value = 6; // should call o.watch() + delete o; // destroying o should automatically disconnect it + a.value = 7; // should not call o.watch() +} +--- + * which should print: + *
+ * Observed msg 'setting new value' and value 4
+ * Observed msg 'setting new value' and value 6
+ * 
+ * + */ + +template Signal(T1...) +{ + /*** + * A slot is implemented as a delegate. + * The slot_t is the type of the delegate. + * The delegate must be to an instance of a class or an interface + * to a class instance. + * Delegates to struct instances or nested functions must not be + * used as slots. + */ + alias void delegate(T1) slot_t; + + /*** + * Call each of the connected slots, passing the argument(s) i to them. + */ + void emit( T1 i ) + { + foreach (slot; slots) + { if (slot) + slot(i); + } + } + + /*** + * Add a slot to the list of slots to be called when emit() is called. + */ + void connect(slot_t slot) + { + /* Do this: + * slots ~= slot; + * but use malloc() instead + */ + auto len = slots.length; + auto startlen = len; + if (len == 0) + { + len = 4; + auto p = std.c.stdlib.calloc(slot_t.sizeof, len); + if (!p) + _d_OutOfMemory(); + slots = (cast(slot_t*)p)[0 .. len]; + } + else + { + len += len + 4; + auto p = std.c.stdlib.realloc(slots.ptr, slot_t.sizeof * len); + if (!p) + _d_OutOfMemory(); + slots = (cast(slot_t*)p)[0 .. len]; + slots[startlen .. len] = null; + } + slots[startlen] = slot; + + Object o = _d_toObject(slot.ptr); + o.notifyRegister(&this.unhook); + } + + /*** + * Remove a slot from the list of slots to be called when emit() is called. + */ + void disconnect( slot_t slot) + { + debug (signal) writefln("Signal.disconnect(slot)"); + foreach (inout dg; slots) + { + if (dg == slot) + { dg = null; + + Object o = _d_toObject(slot.ptr); + o.notifyUnRegister(&this.unhook); + } + } + } + + /* ** + * Special function called when o is destroyed. + * It causes any slots dependent on o to be removed from the list + * of slots to be called by emit(). + */ + void unhook(Object o) + { + debug (signal) writefln("Signal.unhook(o = %s)", cast(void*)o); + foreach (inout slot; slots) + { + if (slot.ptr is o) + slot = null; + } + } + + /* ** + * There can be multiple destructors inserted by mixins. + */ + ~this() + { + /* ** + * When this object is destroyed, need to let every slot + * know that this object is destroyed so they are not left + * with dangling references to it. + */ + if (slots) + { + foreach (slot; slots) + { + if (slot) + { Object o = _d_toObject(slot.ptr); + o.notifyUnRegister(&this.unhook); + } + } + free(slots.ptr); + slots = null; + } + } + + private: + slot_t[] slots; // the slots to call from emit() +} + +// A function whose sole purpose is to get this module linked in +// so the unittest will run. +void linkin() { } + +unittest +{ + class Observer + { + void watch(char[] msg, int i) + { + writefln("Observed msg '%s' and value %s", msg, i); + } + } + + class Foo + { + int value() { return _value; } + + int value(int v) + { + if (v != _value) + { _value = v; + emit("setting new value", v); + } + return v; + } + + mixin Signal!(char[], int); + + private: + int _value; + } + + Foo a = new Foo; + Observer o = new Observer; + + a.value = 3; + a.connect(&o.watch); + a.value = 4; + a.disconnect(&o.watch); + a.value = 5; + a.connect(&o.watch); + a.value = 6; + delete o; + a.value = 7; +} diff -uNr dmd-0.172/dmd/src/phobos/std/stream.d dmd-0.173/dmd/src/phobos/std/stream.d --- dmd-0.172/dmd/src/phobos/std/stream.d 2006-10-18 00:18:36.000000000 +0200 +++ dmd-0.173/dmd/src/phobos/std/stream.d 2006-11-01 22:34:00.000000000 +0100 @@ -1625,7 +1625,7 @@ // reusing the memory in buffer if result will fit, otherwise // will reallocate (using concatenation) template TreadLine(T) { - override T[] readLine(T[] inBuffer) + T[] readLine(T[] inBuffer) { size_t lineSize = 0; bool haveCR = false; diff -uNr dmd-0.172/dmd/src/phobos/std/string.d dmd-0.173/dmd/src/phobos/std/string.d --- dmd-0.172/dmd/src/phobos/std/string.d 2006-10-18 00:18:36.000000000 +0200 +++ dmd-0.173/dmd/src/phobos/std/string.d 2006-11-01 22:34:00.000000000 +0100 @@ -1,4 +1,6 @@ +// Written in the D programming language. + /** * String handling functions. * @@ -807,36 +809,40 @@ char[] tolower(char[] s) { - int changed; - int i; - char[] r = s; + bool changed; + auto r = s; - changed = 0; - for (i = 0; i < s.length; i++) + for (size_t i = 0; i < s.length; i++) { auto c = s[i]; if ('A' <= c && c <= 'Z') { if (!changed) - { r = s.dup; - changed = 1; + { + r = s.dup; + changed = true; } r[i] = c + (cast(char)'a' - 'A'); } else if (c >= 0x7F) { - foreach (size_t j, dchar dc; s[i .. length]) + foreach(size_t j, dchar dc; s[i .. length]) { - if (!changed) + if (std.uni.isUniUpper(dc)) { - if (!std.uni.isUniUpper(dc)) - continue; - - r = s[0 .. i + j].dup; - changed = 1; + dc = std.uni.toUniLower(dc); + if (!changed) + { + r = s[0 .. i + j].dup; + changed = true; + } + } + if (changed) + { + if (r.length != i + j) + r = r[0 .. i + j]; + std.utf.encode(r, dc); } - dc = std.uni.toUniLower(dc); - std.utf.encode(r, dc); } break; } @@ -854,6 +860,16 @@ s2 = tolower(s1); assert(cmp(s2, "fol") == 0); assert(s2 != s1); + + s1 = "A\u0100B\u0101d"; + s2 = tolower(s1); + assert(cmp(s2, "a\u0101b\u0101d") == 0); + assert(s2 !is s1); + + s1 = "A\u0460B\u0461d"; + s2 = tolower(s1); + assert(cmp(s2, "a\u0461b\u0461d") == 0); + assert(s2 !is s1); } /************************************ @@ -862,36 +878,40 @@ char[] toupper(char[] s) { - int changed; - int i; - char[] r = s; + bool changed; + auto r = s; - changed = 0; - for (i = 0; i < s.length; i++) + for (size_t i = 0; i < s.length; i++) { auto c = s[i]; if ('a' <= c && c <= 'z') { if (!changed) - { r = s.dup; - changed = 1; + { + r = s.dup; + changed = true; } r[i] = c - (cast(char)'a' - 'A'); } else if (c >= 0x7F) { - foreach (size_t j, dchar dc; s[i .. length]) + foreach(size_t j, dchar dc; s[i .. length]) { - if (!changed) + if (std.uni.isUniLower(dc)) { - if (!std.uni.isUniLower(dc)) - continue; - - r = s[0 .. i + j].dup; - changed = 1; + dc = std.uni.toUniUpper(dc); + if (!changed) + { + r = s[0 .. i + j].dup; + changed = true; + } + } + if (changed) + { + if (r.length != i + j) + r = r[0 .. i + j]; + std.utf.encode(r, dc); } - dc = std.uni.toUniUpper(dc); - std.utf.encode(r, dc); } break; } @@ -909,6 +929,16 @@ s2 = toupper(s1); assert(cmp(s2, "FOL") == 0); assert(s2 !is s1); + + s1 = "a\u0100B\u0101d"; + s2 = toupper(s1); + assert(cmp(s2, "A\u0100B\u0100D") == 0); + assert(s2 !is s1); + + s1 = "a\u0460B\u0461d"; + s2 = toupper(s1); + assert(cmp(s2, "A\u0460B\u0460D") == 0); + assert(s2 !is s1); } diff -uNr dmd-0.172/dmd/src/phobos/std/system.d dmd-0.173/dmd/src/phobos/std/system.d --- dmd-0.172/dmd/src/phobos/std/system.d 2006-10-18 00:18:36.000000000 +0200 +++ dmd-0.173/dmd/src/phobos/std/system.d 2006-11-01 22:34:00.000000000 +0100 @@ -75,4 +75,3 @@ uint os_minor = 0; -// processor: i386 diff -uNr dmd-0.172/dmd/src/phobos/std.ddoc dmd-0.173/dmd/src/phobos/std.ddoc --- dmd-0.172/dmd/src/phobos/std.ddoc 2006-10-18 00:18:36.000000000 +0200 +++ dmd-0.173/dmd/src/phobos/std.ddoc 2006-11-01 22:34:00.000000000 +0100 @@ -60,7 +60,7 @@ @@ -116,6 +116,7 @@ $(LI std.compiler) $(LI std.conv) $(LI std.cover) + $(LI std.cpuid) $(LI std.ctype) $(LI std.date) $(LI std.demangle) @@ -133,6 +134,7 @@ $(LI std.process) $(LI std.random) $(LI std.regexp) + $(LI std.signals) $(LI std.socket) $(LI std.socketstream) $(LI std.stdint) @@ -148,6 +150,7 @@ $(LI std.zip) $(LI std.zlib) $(LI std.c.fenv) + $(LI std.c.locale) $(LI std.c.math) $(LI std.c.process) $(LI std.c.stdarg) @@ -180,3 +183,6 @@ RPAREN = ) LPAREN = ( FOO=$0 + +COPYRIGHT= Copyright © 1999-$(YEAR) by Digital Mars, All Rights Reserved + diff -uNr dmd-0.172/dmd/src/phobos/unittest.d dmd-0.173/dmd/src/phobos/unittest.d --- dmd-0.172/dmd/src/phobos/unittest.d 2006-10-18 00:18:36.000000000 +0200 +++ dmd-0.173/dmd/src/phobos/unittest.d 2006-11-01 22:34:00.000000000 +0100 @@ -1,6 +1,6 @@ /* - * Copyright (C) 1999-2005 by Digital Mars, www.digitalmars.com + * Copyright (C) 1999-2006 by Digital Mars, www.digitalmars.com * Written by Walter Bright * * This software is provided 'as-is', without any express or implied @@ -50,6 +50,8 @@ import std.bitarray; import std.uni; import std.file; +import std.signals; +import std.cpuid; int main(char[][] args) { @@ -117,6 +119,10 @@ foreach_reverse (dchar d; "hello"c) { ; } foreach_reverse (k, dchar d; "hello"c) { ; } + std.signals.linkin(); + + writefln(std.cpuid.toString()); + printf("Success\n!"); return 0; } diff -uNr dmd-0.172/dmd/src/phobos/win32.mak dmd-0.173/dmd/src/phobos/win32.mak --- dmd-0.172/dmd/src/phobos/win32.mak 2006-10-18 00:18:36.000000000 +0200 +++ dmd-0.173/dmd/src/phobos/win32.mak 2006-11-01 22:34:00.000000000 +0100 @@ -74,6 +74,7 @@ perf.obj openrj.obj uni.obj winsock.obj oldsyserror.obj \ errno.obj boxer.obj cstream.obj charset.obj \ gamma.obj demangle.obj cover.obj bitarray.obj aApplyR.obj \ + signals.obj cpuid.obj \ ti_Aa.obj ti_Ag.obj ti_C.obj ti_int.obj ti_char.obj \ ti_wchar.obj ti_uint.obj ti_short.obj ti_ushort.obj \ ti_byte.obj ti_ubyte.obj ti_long.obj ti_ulong.obj ti_ptr.obj \ @@ -98,6 +99,7 @@ $(DOC)\std_conv.html \ $(DOC)\std_boxer.html \ $(DOC)\std_cover.html \ + $(DOC)\std_cpuid.html \ $(DOC)\std_cstream.html \ $(DOC)\std_ctype.html \ $(DOC)\std_demangle.html \ @@ -108,6 +110,7 @@ $(DOC)\std_outofmemory.html \ $(DOC)\std_process.html \ $(DOC)\std_regexp.html \ + $(DOC)\std_signals.html \ $(DOC)\std_socket.html \ $(DOC)\std_socketstream.html \ $(DOC)\std_stdint.html \ @@ -119,6 +122,7 @@ $(DOC)\std_utf.html \ $(DOC)\std_windows_charset.html \ $(DOC)\std_c_fenv.html \ + $(DOC)\std_c_locale.html \ $(DOC)\std_c_math.html \ $(DOC)\std_c_process.html \ $(DOC)\std_c_stdarg.html \ @@ -141,10 +145,12 @@ std\regexp.d std\random.d std\stream.d std\process.d \ std\socket.d std\socketstream.d std\loader.d std\stdarg.d std\format.d \ std\stdio.d std\perf.d std\openrj.d std\uni.d std\boxer.d \ - std\cstream.d std\demangle.d std\cover.d std\bitarray.d + std\cstream.d std\demangle.d std\cover.d std\bitarray.d \ + std\signals.d std\cpuid.d SRC_STD_C= std\c\process.d std\c\stdlib.d std\c\time.d std\c\stdio.d \ - std\c\math.d std\c\stdarg.d std\c\stddef.d std\c\fenv.d std\c\string.d + std\c\math.d std\c\stdarg.d std\c\stddef.d std\c\fenv.d std\c\string.d \ + std\c\locale.d SRC_TI= \ std\typeinfo\ti_wchar.d std\typeinfo\ti_uint.d \ @@ -346,6 +352,9 @@ cover.obj : std\cover.d $(DMD) -c $(DFLAGS) std\cover.d +cpuid.obj : std\cpuid.d + $(DMD) -c $(DFLAGS) std\cpuid.d -ofcpuid.obj + cstream.obj : std\cstream.d $(DMD) -c $(DFLAGS) std\cstream.d @@ -415,6 +424,9 @@ regexp.obj : std\regexp.d $(DMD) -c $(DFLAGS) std\regexp.d +signals.obj : std\signals.d + $(DMD) -c $(DFLAGS) std\signals.d -ofsignals.obj + socket.obj : std\socket.d $(DMD) -c $(DFLAGS) std\socket.d -ofsocket.obj @@ -658,6 +670,9 @@ $(DOC)\std_cover.html : std.ddoc std\cover.d $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_cover.html std.ddoc std\cover.d +$(DOC)\std_cpuid.html : std.ddoc std\cpuid.d + $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_cpuid.html std.ddoc std\cpuid.d + $(DOC)\std_cstream.html : std.ddoc std\cstream.d $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_cstream.html std.ddoc std\cstream.d @@ -712,6 +727,9 @@ $(DOC)\std_regexp.html : std.ddoc std\regexp.d $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_regexp.html std.ddoc std\regexp.d +$(DOC)\std_signals.html : std.ddoc std\signals.d + $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_signals.html std.ddoc std\signals.d + $(DOC)\std_socket.html : std.ddoc std\socket.d $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_socket.html std.ddoc std\socket.d @@ -760,6 +778,9 @@ $(DOC)\std_c_fenv.html : std.ddoc std\c\fenv.d $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_c_fenv.html std.ddoc std\c\fenv.d +$(DOC)\std_c_locale.html : std.ddoc std\c\locale.d + $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_c_locale.html std.ddoc std\c\locale.d + $(DOC)\std_c_math.html : std.ddoc std\c\math.d $(DMD) -c -o- $(DFLAGS) -Df$(DOC)\std_c_math.html std.ddoc std\c\math.d