From 870acf3fddd73080f566d1b529a6682ebc0731fe Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Sun, 28 Sep 2008 10:31:39 +0100 Subject: [PATCH] Merged Delight changes to D1 into D2 --- Make-lang.in | 2 +- dmd2/cast.c | 12 +- dmd2/class.c | 49 +++- dmd2/declaration.c | 18 ++ dmd2/declaration.h | 14 ++ dmd2/doc.c | 2 +- dmd2/expression.c | 52 +++- dmd2/expression.h | 8 + dmd2/func.c | 40 ++- dmd2/idgen.c | 14 ++ dmd2/lexer.c | 133 ++++++++-- dmd2/lexer.h | 19 +- dmd2/mangle.c | 12 +- dmd2/mars.c | 7 +- dmd2/mars.h | 1 + dmd2/module.c | 121 ++++++++-- dmd2/module.h | 3 +- dmd2/mtype.c | 213 +++++++++++++++- dmd2/mtype.h | 26 ++ dmd2/parse.c | 699 +++++++++++++++++++++++++++++++++++++++++------------ dmd2/parse.h | 29 ++- dmd2/scope.c | 2 + dmd2/scope.h | 1 + dmd2/statement.c | 176 +++++++++++++- dmd2/statement.h | 28 +++ dmd2/template.c | 13 +- dmd2/template.h | 4 +- dmd2/typinf.c | 19 ++ 28 files changed, 1484 insertions(+), 233 deletions(-) diff --git a/Make-lang.in b/Make-lang.in index 670f8f2..10ed140 100644 --- a/Make-lang.in +++ b/Make-lang.in @@ -21,7 +21,7 @@ # Manual configuration since patching gcc/configure.ac is troublesome... # Which version of the language to build? '1' or '2'. -D_LANGUAGE_VERSION=1 +D_LANGUAGE_VERSION=2 # The file d-make-include is created by setup-gcc.sh -include $(srcdir)/d/d-make-include diff --git a/dmd2/cast.c b/dmd2/cast.c index 95d88fe..8569419 100644 --- a/dmd2/cast.c +++ b/dmd2/cast.c @@ -369,6 +369,7 @@ MATCH NullExp::implicitConvTo(Type *t) printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif + if (this->type->equals(t)) return MATCHexact; @@ -384,11 +385,18 @@ MATCH NullExp::implicitConvTo(Type *t) { if (t->ty == Ttypedef) t = ((TypeTypedef *)t)->sym->basetype; - if (t->ty == Tpointer || t->ty == Tarray || - t->ty == Taarray || t->ty == Tclass || + if (t->ty == Tarray || + t->ty == Taarray || t->ty == Tmaybe || t->ty == Tdelegate) return committed ? MATCHconvert : MATCHexact; } + + /* Null can only be implicitly converted to a maybe type */ + if (t->ty != Tmaybe) + return MATCHnomatch; + + t = t->nextOf(); + return Expression::implicitConvTo(t); } diff --git a/dmd2/class.c b/dmd2/class.c index 57c15d8..d82be46 100644 --- a/dmd2/class.c +++ b/dmd2/class.c @@ -111,6 +111,12 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla Type::typeinfopointer = this; } + if (id == Id::TypeInfo_Maybe) + { if (Type::typeinfomaybe) + Type::typeinfomaybe->error("%s", msg); + Type::typeinfomaybe = this; + } + if (id == Id::TypeInfo_Array) { if (Type::typeinfoarray) Type::typeinfoarray->error("%s", msg); @@ -615,18 +621,41 @@ void ClassDeclaration::semantic(Scope *sc) // If this class has no constructor, but base class does, create // a constructor: + // // this() { } - if (!ctor && baseClass && baseClass->ctor) + // + // Also do this if we have some "in" fields on the class, or + // if there are non-null fields + if (!ctor) { - //printf("Creating default this(){} for class %s\n", toChars()); - ctor = new CtorDeclaration(0, 0, NULL, 0); - ctor->fbody = new CompoundStatement(0, new Statements()); - members->push(ctor); - ctor->addMember(sc, this, 1); - *sc = scsave; // why? What about sc->nofree? - sc->offset = structsize; - ctor->semantic(sc); - defaultCtor = ctor; + bool hasInArgs = false; + bool hasNonNull = false; + for (int i = 0; i < fields.dim; i++) + { + VarDeclaration *var = (VarDeclaration *) fields.data[i]; + + if (var->isIn()) { + hasInArgs = true; + break; + } + + if (var->type->ty == Tclass) { + hasNonNull = true; + break; + } + } + if (hasInArgs || hasNonNull || (baseClass && baseClass->ctor)) + { + //printf("Creating default this(){} for class %s\n", toChars()); + ctor = new CtorDeclaration(0, 0, NULL, 0); + ctor->fbody = new CompoundStatement(0, new Statements()); + members->push(ctor); + ctor->addMember(sc, this, 1); + *sc = scsave; // why? What about sc->nofree? + sc->offset = structsize; + ctor->semantic(sc); + defaultCtor = ctor; + } } #if 0 diff --git a/dmd2/declaration.c b/dmd2/declaration.c index d9d541d..5da4074 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.c @@ -616,6 +616,8 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer this->loc = loc; offset = 0; noauto = 0; + skipnullcheck = 0; + dltNormalMode = 0; inuse = 0; ctorinit = 0; aliassym = NULL; @@ -645,6 +647,7 @@ Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); sv->storage_class = storage_class; } + sv->skipnullcheck = skipnullcheck; #ifdef _DH // Syntax copy for header file if (!htype) // Don't overwrite original @@ -680,6 +683,9 @@ void VarDeclaration::semantic(Scope *sc) if (storage_class & STCextern && init) error("extern symbols cannot have initializers"); + if (dltNormalMode && (storage_class & STCstatic)) + error("no static variables in Delight"); + /* If auto type inference, do the inference */ int inferred = 0; @@ -1224,6 +1230,9 @@ ExpInitializer *VarDeclaration::getExpInitializer() ei = init->isExpInitializer(); else { + if ((type->ty == Tclass || type->ty == Tpointer) && !skipnullcheck) + error("non-null, but missing initialiser"); + Expression *e = type->defaultInit(); if (e) ei = new ExpInitializer(loc, e); @@ -1233,6 +1242,7 @@ ExpInitializer *VarDeclaration::getExpInitializer() return ei; } + /******************************************* * If variable has a constant expression initializer, get it. * Otherwise, return NULL. @@ -1535,6 +1545,13 @@ TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) { } +/***************************** TypeInfoMaybeDeclaration *********************/ + +TypeInfoMaybeDeclaration::TypeInfoMaybeDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + /***************************** TypeInfoArrayDeclaration ***********************/ TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo) @@ -1592,6 +1609,7 @@ ThisDeclaration::ThisDeclaration(Type *t) : VarDeclaration(0, t, Id::This, NULL) { noauto = 1; + skipnullcheck = true; } Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) diff --git a/dmd2/declaration.h b/dmd2/declaration.h index 02aebd3..76eb690 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -240,6 +240,13 @@ struct VarDeclaration : Declaration // (NULL if value not determinable) Scope *scope; // !=NULL means context to use + // We'll make sure this gets initialised, so don't worry about it. + // Used for the fensure argument. + bool skipnullcheck; + + // Reject static variables (during semantic pass) + bool dltNormalMode; + VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); @@ -365,6 +372,13 @@ struct TypeInfoPointerDeclaration : TypeInfoDeclaration void toDt(dt_t **pdt); }; +struct TypeInfoMaybeDeclaration : TypeInfoDeclaration +{ + TypeInfoMaybeDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); +}; + struct TypeInfoArrayDeclaration : TypeInfoDeclaration { TypeInfoArrayDeclaration(Type *tinfo); diff --git a/dmd2/doc.c b/dmd2/doc.c index 5f130b9..a0fc04a 100644 --- a/dmd2/doc.c +++ b/dmd2/doc.c @@ -1914,7 +1914,7 @@ void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) char *sid = s->ident->toChars(); FuncDeclaration *f = s->isFuncDeclaration(); unsigned errorsave = global.errors; - Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); + Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1, false); Token tok; OutBuffer res; unsigned char *lastp = buf->data; diff --git a/dmd2/expression.c b/dmd2/expression.c index 1adbbd2..5cd0d2b 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -2108,6 +2108,24 @@ Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e) return this; } +/******************************** GetLoggerExp **************************/ + +GetLoggerExp::GetLoggerExp(Loc loc) + : Expression(loc, TOKlogger, sizeof(GetLoggerExp)) +{ +} + +Expression *GetLoggerExp::semantic(Scope *sc) +{ + Expression *log = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), Id::__log); + return log->semantic(sc); +} + +void GetLoggerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("log"); +} + /******************************** ThisExp **************************/ ThisExp::ThisExp(Loc loc) @@ -5349,6 +5367,13 @@ Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) printf("var->type = %s\n", var->type->toChars()); #endif + // Also need this for non-null fields. + VarDeclaration *v = var->isVarDeclaration(); + if (v) // When is it not a VarDeclaration? + v->ctorinit = 1; + else + error("Just curious"); + if (var->isCtorinit()) { // It's only modifiable if inside the right constructor Dsymbol *s = sc->func; @@ -6720,7 +6745,7 @@ Expression *CastExp::semantic(Scope *sc) { error("cannot cast tuple"); to = Type::terror; } - e = e1->castTo(sc, to); + e = e1->castTo(sc, to->maybe(true)); return e; } @@ -7652,6 +7677,21 @@ Expression *AssignExp::checkToBoolean() /************************************************************/ +/* Allow pointer arithmetic on e1? */ +static bool allowPtrArith(Scope *sc, Expression *e1) +{ + if (e1->type->ty == Tpointer) + return true; + else if (e1->type->ty == Tmaybe && e1->type->nextOf()->ty == Tpointer) + { + if (!sc->inDtemplate) + e1->error("Can't do pointer arithmetic on pointer ('%s') that could be null", + e1->toChars()); + return true; + } + return false; +} + AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2) : BinExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2) { @@ -7687,7 +7727,7 @@ Expression *AddAssignExp::semantic(Scope *sc) { e1->checkScalar(); e1->checkNoBool(); - if (tb1->ty == Tpointer && tb2->isintegral()) + if (allowPtrArith(sc, e1) && tb2->isintegral()) e = scaleFactor(sc); else if (tb1->ty == Tbit || tb1->ty == Tbool) { @@ -7769,7 +7809,8 @@ Expression *MinAssignExp::semantic(Scope *sc) e1 = e1->modifiableLvalue(sc, e1); e1->checkScalar(); e1->checkNoBool(); - if (e1->type->ty == Tpointer && e2->type->isintegral()) + + if (allowPtrArith(sc, e1) && e2->type->isintegral()) e = scaleFactor(sc); else { @@ -8311,6 +8352,9 @@ Expression *CatExp::semantic(Scope *sc) } typeCombine(sc); + if (type->ty == Tmaybe) + error("Cannot join arrays that may be null (%s)", toChars()); + type = type->toHeadMutable(); Type *tb = type->toBasetype(); @@ -8844,7 +8888,7 @@ Expression *InExp::semantic(Scope *sc) e1 = e1->implicitCastTo(sc, ta->index); // Return type is pointer to value - type = ta->nextOf()->pointerTo(); + type = ta->nextOf()->pointerTo()->maybe(true); } return this; } diff --git a/dmd2/expression.h b/dmd2/expression.h index 769240e..6f0143c 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -260,6 +260,14 @@ struct DsymbolExp : Expression Expression *toLvalue(Scope *sc, Expression *e); }; +struct GetLoggerExp : Expression +{ + GetLoggerExp(Loc loc); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + //void scanForNestedRef(Scope *sc); +}; + struct ThisExp : Expression { Declaration *var; diff --git a/dmd2/func.c b/dmd2/func.c index f913def..c12b8a9 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -363,7 +363,7 @@ void FuncDeclaration::semantic(Scope *sc) if (fdv->isFinal()) error("cannot override final function %s", fdv->toPrettyChars()); - if (!isOverride() && global.params.warnings) + if (!isOverride() && (global.params.warnings || sc->module->isDltFile)) error("overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); if (fdv->toParent() == parent) @@ -724,6 +724,7 @@ void FuncDeclaration::semantic3(Scope *sc) //t = Type::typeinfo->type->constOf()->arrayOf(); t = Type::typeinfo->type->arrayOf(); _arguments = new VarDeclaration(0, t, Id::_arguments, NULL); + _arguments->skipnullcheck = TRUE; _arguments->semantic(sc2); sc2->insert(_arguments); _arguments->parent = this; @@ -744,6 +745,7 @@ void FuncDeclaration::semantic3(Scope *sc) t = Type::tvoid->pointerTo(); #endif argptr = new VarDeclaration(0, t, Id::_argptr, NULL); + argptr->skipnullcheck = TRUE; argptr->semantic(sc2); sc2->insert(argptr); argptr->parent = this; @@ -887,6 +889,7 @@ void FuncDeclaration::semantic3(Scope *sc) v = new VarDeclaration(loc, type->nextOf(), outId, NULL); v->noauto = 1; + v->skipnullcheck = 1; sc2->incontract--; v->semantic(sc2); sc2->incontract++; @@ -1017,13 +1020,20 @@ void FuncDeclaration::semantic3(Scope *sc) //printf("callSuper = x%x\n", sc2->callSuper); // Verify that all the ctorinit fields got initialized + // Also check that non-null members got set if (!(sc2->callSuper & CSXthis_ctor)) { for (int i = 0; i < cd->fields.dim; i++) { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - if (v->ctorinit == 0 && v->isCtorinit()) - error("missing initializer for final field %s", v->toChars()); + if (v->ctorinit == 0) + { + if (v->isCtorinit()) + error("missing initializer for final field %s", v->toChars()); + else if (!v->skipnullcheck && + (v->type->ty == Tclass || v->type->ty == Tpointer)) + error("missing initializer for non-null field %s", v->toChars()); + } } } @@ -2307,7 +2317,31 @@ void CtorDeclaration::semantic(Scope *sc) tret = Type::tvoid; } else + { tret = cd->type; //->referenceTo(); + + for (int i = 0; i < cd->fields.dim; i++) + { + VarDeclaration *vd = (VarDeclaration *) cd->fields.data[i]; + if (vd->isIn()) + { + if (!arguments) + arguments = new Arguments(); + Argument *a = new Argument(vd->storage_class, vd->type, vd->ident, 0); + // BUG: We don't really want these arguments in scope... + arguments->push(a); + + Statement *assign = new ExpStatement(loc, new AssignExp(loc, + new DotIdExp(loc, new ThisExp(loc), a->ident), + new IdentifierExp(loc, a->ident))); + if (fbody) + fbody = new CompoundStatement(loc, assign, fbody); + else + fbody = assign; + } + } + } + type = new TypeFunction(arguments, tret, varargs, LINKd); sc->flags |= SCOPEctor; diff --git a/dmd2/idgen.c b/dmd2/idgen.c index 98e168f..0265df4 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.c @@ -82,6 +82,7 @@ struct Msgtable msgtable[] = { "TypeInfo_Enum" }, { "TypeInfo_Typedef" }, { "TypeInfo_Pointer" }, + { "TypeInfo_Maybe" }, { "TypeInfo_Array" }, { "TypeInfo_StaticArray" }, { "TypeInfo_AssociativeArray" }, @@ -220,6 +221,16 @@ struct Msgtable msgtable[] = { "aaValues", "_aaValues" }, { "aaRehash", "_aaRehash" }, + // Delight + { "dlt" }, + { "core" }, + { "_externals" }, + { "Externals" }, + { "externals" }, + { "args" }, + { "__log" }, // dlt.core.__log + { "SystemExit" }, + // For pragma's { "GNU_asm" }, { "GNU_attribute" }, @@ -269,6 +280,9 @@ struct Msgtable msgtable[] = { "derivedMembers" }, { "isSame" }, { "compiles" }, + + // Special classes + { "Main" }, }; diff --git a/dmd2/lexer.c b/dmd2/lexer.c index 12155b1..8acb708 100644 --- a/dmd2/lexer.c +++ b/dmd2/lexer.c @@ -264,8 +264,8 @@ OutBuffer Lexer::stringbuffer; Lexer::Lexer(Module *mod, unsigned char *base, unsigned begoffset, unsigned endoffset, - int doDocComment, int commentToken) - : loc(mod, 1) + int doDocComment, int commentToken, bool dltSyntax) + : loc(mod, 1), dltSyntax(dltSyntax) { //printf("Lexer::Lexer(%p,%d)\n",base,length); //printf("lexer.mod = %p, %p\n", mod, this->loc.mod); @@ -277,6 +277,10 @@ Lexer::Lexer(Module *mod, this->doDocComment = doDocComment; this->anyToken = 0; this->commentToken = commentToken; + this->nesting = 0; + this->indent = 0; + this->atStartOfLine = 1; + this->incLineno = 0; //initKeywords(); /* If first line starts with '#!', ignore the line @@ -494,11 +498,46 @@ void Lexer::scan(Token *t) unsigned lastLine = loc.linnum; unsigned linnum; + // Delayed line-number updating + if (incLineno) + { + assert(incLineno == 1); + incLineno = 0; + loc.linnum++; + } + t->blockComment = NULL; t->lineComment = NULL; while (1) { t->ptr = p; + + if (dltSyntax && atStartOfLine) { + // Check indent + int i; + for (i = 0; p[i] == '\t'; i++) { + } + if (p[i] == ' ') { + error("Whitespace error: use tabs to indent!"); + } + if (p[i] == '#') { + p += i; + atStartOfLine = 0; + } else if (p[i] != '\n' && p[i] != '\r') { + if (p[i] == '\0') + i = 0; // End-of-file always has no indent + if (i > indent) { + error("unexpected indentation (expected %d tabs, not %d)", + indent, i); + } else if (i < indent) { + indent -= 1; + t->value = TOKrcurly; + return; + } + atStartOfLine = 0; + } /* else ignore blank line */ + } + //printf("p = %p, *p = '%c'\n",p,*p); switch (*p) { @@ -515,16 +554,30 @@ void Lexer::scan(Token *t) continue; // skip white space case '\r': - p++; - if (*p != '\n') // if CR stands by itself - loc.linnum++; - continue; // skip white space - + if (p[1] == '\n') { // if CRLF + p++; + continue; + } + // fall-through case '\n': p++; - loc.linnum++; - continue; // skip white space + if (dltSyntax) + { + // Delay incrementing the line number until after sending + // the TOKendline, for better error messages + assert(!incLineno); + incLineno++; + if (!nesting) + { + atStartOfLine = 1; + t->value = TOKendline; + return; + } + } + else + loc.linnum++; + continue; // Ignore newlines inside brackets case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': t->value = number(t); @@ -980,6 +1033,8 @@ void Lexer::scan(Token *t) else if (*p == '&') { p++; t->value = TOKandand; + if (dltSyntax) + error("Use 'and' instead of '&&'"); } else t->value = TOKand; @@ -994,6 +1049,8 @@ void Lexer::scan(Token *t) else if (*p == '|') { p++; t->value = TOKoror; + if (dltSyntax) + error("Use 'or' instead of '||'"); } else t->value = TOKor; @@ -1156,22 +1213,31 @@ void Lexer::scan(Token *t) t->value = TOKtilde; // ~ return; -#define SINGLE(c,tok) case c: p++; t->value = tok; return; +#define NESTED(cin,tokin,cout,tokout) \ + case cin: nesting++; p++; t->value = tokin; return;\ + case cout: if (nesting == 0) {error("Unexpected '%c'", cout);} else {nesting--;} p++; t->value = tokout; return; - SINGLE('(', TOKlparen) - SINGLE(')', TOKrparen) - SINGLE('[', TOKlbracket) - SINGLE(']', TOKrbracket) - SINGLE('{', TOKlcurly) - SINGLE('}', TOKrcurly) + NESTED('(', TOKlparen, ')', TOKrparen) + NESTED('[', TOKlbracket, ']', TOKrbracket) + NESTED('{', TOKlcurly, '}', TOKrcurly) +#undef NESTED + +#define SINGLE(c,tok) case c: p++; t->value = tok; return; SINGLE('?', TOKquestion) SINGLE(',', TOKcomma) SINGLE(';', TOKsemicolon) - SINGLE(':', TOKcolon) SINGLE('$', TOKdollar) + SINGLE('@', TOKat) #undef SINGLE + case ':': + p++; + if (!nesting) + indent += 1; + t->value = TOKcolon; + return; + #define DOUBLE(c1,tok1,c2,tok2) \ case c1: \ p++; \ @@ -1189,9 +1255,16 @@ void Lexer::scan(Token *t) #undef DOUBLE - case '#': - p++; - pragma(); + case '#': // do # style comments and pragmas + if (dltSyntax) + { + do { p++; } while (*p != '\n'); + } + else + { + p++; + pragma(); + } continue; default: @@ -2501,6 +2574,10 @@ void Lexer::pragma() char *filespec = NULL; Loc loc = this->loc; + while (isblank(*p)) p++; + if (*p == '\n') + goto Lerr; + scan(&tok); if (tok.value != TOKidentifier || tok.ident != Id::line) goto Lerr; @@ -2887,6 +2964,7 @@ static Keyword keywords[] = { "asm", TOKasm }, { "foreach", TOKforeach }, { "foreach_reverse", TOKforeach_reverse }, + { "reversed", TOKreversed }, { "scope", TOKscope }, { "struct", TOKstruct }, @@ -2929,6 +3007,18 @@ static Keyword keywords[] = // Added after 1.0 { "ref", TOKref }, { "macro", TOKmacro }, + + + // TAL + { "and", TOKandand }, + { "or", TOKoror }, + { "not", TOKnot }, + { "extends", TOKextends }, + { "implements", TOKimplements }, + { "log_error", TOKlog_error }, + { "log_warning", TOKlog_warning }, + { "log_info", TOKlog_info }, + { "log_trace", TOKlog_trace }, #if V2 { "pure", TOKpure }, { "nothrow", TOKnothrow }, @@ -3000,6 +3090,7 @@ void Lexer::initKeywords() Token::tochars[TOKnotequal] = "!="; Token::tochars[TOKnotidentity] = "!is"; Token::tochars[TOKtobool] = "!!"; + Token::tochars[TOKat] = "@"; Token::tochars[TOKunord] = "!<>="; Token::tochars[TOKue] = "!<>"; @@ -3055,6 +3146,7 @@ void Lexer::initKeywords() Token::tochars[TOKcall] = "call"; Token::tochars[TOKidentity] = "is"; Token::tochars[TOKnotidentity] = "!is"; + Token::tochars[TOKendline] = "\\n"; Token::tochars[TOKorass] = "|="; Token::tochars[TOKidentifier] = "identifier"; @@ -3075,5 +3167,6 @@ void Lexer::initKeywords() Token::tochars[TOKtuple] = "tuple"; Token::tochars[TOKdeclaration] = "declaration"; Token::tochars[TOKdottd] = "dottd"; + Token::tochars[TOKlogger] = "logger"; Token::tochars[TOKon_scope_exit] = "scope(exit)"; } diff --git a/dmd2/lexer.h b/dmd2/lexer.h index a9d6bf6..8e350c1 100644 --- a/dmd2/lexer.h +++ b/dmd2/lexer.h @@ -35,6 +35,7 @@ struct Module; ++ -- . -> : , ? && || + @ */ enum TOK @@ -137,9 +138,10 @@ enum TOK TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith, TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally, - TOKasm, TOKforeach, TOKforeach_reverse, + TOKasm, TOKforeach, TOKforeach_reverse, TOKreversed, TOKscope, TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success, + TOKlog_error, TOKlog_warning, TOKlog_info, TOKlog_trace, // Contracts TOKbody, TOKinvariant, @@ -160,6 +162,13 @@ enum TOK TOKfile, #endif + // TAL + TOKextends, + TOKimplements, + TOKendline, + TOKat, + TOKlogger, // Not a real symbol + TOKMAX }; @@ -261,9 +270,15 @@ struct Lexer int anyToken; // !=0 means seen at least one token int commentToken; // !=0 means comments are TOKcomment's + bool dltSyntax; + unsigned int indent; // Current indent level + int atStartOfLine; + int nesting; // Counts { [ (; we ignore indents inside these + int incLineno; // Increate line number at next opportunity + Lexer(Module *mod, unsigned char *base, unsigned begoffset, unsigned endoffset, - int doDocComment, int commentToken); + int doDocComment, int commentToken, bool dltSyntax); static void initKeywords(); static Identifier *idPool(const char *s); diff --git a/dmd2/mangle.c b/dmd2/mangle.c index e853e97..312b83f 100644 --- a/dmd2/mangle.c +++ b/dmd2/mangle.c @@ -77,7 +77,17 @@ L1: if (fd && (fd->needThis() || fd->isNested())) buf.writeByte(Type::needThisPrefix()); if (sthis->type->deco) - buf.writestring(sthis->type->deco); + { + /* It's too hard to figure out when a symbol came from D and when from Dlt, + * so strip the maybe IDs. + */ + char *p = sthis->type->deco; + while (*p) { + if (*p != '?') + buf.writebyte(*p); + p++; + } + } else { assert(fd->inferRetType); } diff --git a/dmd2/mars.c b/dmd2/mars.c index 69bf9be..9b7d76a 100644 --- a/dmd2/mars.c +++ b/dmd2/mars.c @@ -56,6 +56,7 @@ Global::Global() hdr_ext = "di"; doc_ext = "html"; ddoc_ext = "ddoc"; + dlt_ext = "dlt"; #ifndef IN_GCC #if _WIN32 @@ -737,6 +738,7 @@ int main(int argc, char *argv[]) { char *ext; char *name; + bool isDltFile = 0; p = (char *) files.data[i]; @@ -804,12 +806,15 @@ int main(int argc, char *argv[]) /* Examine extension to see if it is a valid * D source file extension */ + isDltFile = (stricmp(ext, global.dlt_ext) == 0); if (stricmp(ext, global.mars_ext) == 0 || + stricmp(ext, global.dlt_ext) == 0 || stricmp(ext, "dd") == 0 || stricmp(ext, "htm") == 0 || stricmp(ext, "html") == 0 || stricmp(ext, "xhtml") == 0) { + ext--; // skip onto '.' assert(*ext == '.'); name = (char *)mem.malloc((ext - p) + 1); @@ -841,7 +846,7 @@ int main(int argc, char *argv[]) */ Identifier *id = new Identifier(name, 0); - m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration); + m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration, isDltFile); modules.push(m); if (firstmodule) diff --git a/dmd2/mars.h b/dmd2/mars.h index 723d359..1da820e 100644 --- a/dmd2/mars.h +++ b/dmd2/mars.h @@ -135,6 +135,7 @@ struct Param struct Global { char *mars_ext; + char *dlt_ext; char *sym_ext; char *obj_ext; char *lib_ext; diff --git a/dmd2/module.c b/dmd2/module.c index 32b3b6f..4d070b1 100644 --- a/dmd2/module.c +++ b/dmd2/module.c @@ -32,6 +32,7 @@ #include "dsymbol.h" #include "hdrgen.h" #include "lexer.h" +#include "init.h" #define MARS 1 #include "html.h" @@ -54,8 +55,8 @@ void Module::init() modules = new DsymbolTable(); } -Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen) - : Package(ident) +Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen, int isDltFile) + : Package(ident), isDltFile(isDltFile) { FileName *srcfilename; FileName *cfilename; @@ -108,8 +109,9 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen cov = NULL; covb = NULL; - srcfilename = FileName::defaultExt(filename, global.mars_ext); + srcfilename = FileName::defaultExt(filename, global.dlt_ext); if (!srcfilename->equalsExt(global.mars_ext) && + !srcfilename->equalsExt(global.dlt_ext) && !srcfilename->equalsExt("dd")) { if (srcfilename->equalsExt("html") || @@ -120,7 +122,7 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen isHtml = 1; } else - { error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); + { error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.dlt_ext); fatal(); } } @@ -236,6 +238,7 @@ char *Module::kind() Module *Module::load(Loc loc, Array *packages, Identifier *ident) { Module *m; char *filename; + bool dltSyntax = false; //printf("Module::load(ident = '%s')\n", ident->toChars()); @@ -264,18 +267,22 @@ Module *Module::load(Loc loc, Array *packages, Identifier *ident) filename = (char *)buf.extractData(); } - m = new Module(filename, ident, 0, 0); - m->loc = loc; - - /* Search along global.path for .di file, then .d file. + /* Search along global.path for a .dlt file, then a .di file, then a .d file. */ char *result = NULL; + FileName *fdlt = FileName::forceExt(filename, global.dlt_ext); FileName *fdi = FileName::forceExt(filename, global.hdr_ext); FileName *fd = FileName::forceExt(filename, global.mars_ext); + char *sdlt = fdlt->toChars(); char *sdi = fdi->toChars(); char *sd = fd->toChars(); - if (FileName::exists(sdi)) + if (FileName::exists(sdlt)) + { + result = sdlt; + dltSyntax = true; + } + else if (FileName::exists(sdi)) result = sdi; else if (FileName::exists(sd)) result = sd; @@ -288,12 +295,23 @@ Module *Module::load(Loc loc, Array *packages, Identifier *ident) for (size_t i = 0; i < global.path->dim; i++) { char *p = (char *)global.path->data[i]; - char *n = FileName::combine(p, sdi); + char *n; + + n = FileName::combine(p, sdlt); + if (FileName::exists(n)) + { result = n; + dltSyntax = true; + break; + } + mem.free(n); + + n = FileName::combine(p, sdi); if (FileName::exists(n)) { result = n; break; } mem.free(n); + n = FileName::combine(p, sd); if (FileName::exists(n)) { result = n; @@ -302,6 +320,10 @@ Module *Module::load(Loc loc, Array *packages, Identifier *ident) mem.free(n); } } + + m = new Module(filename, ident, 0, 0, dltSyntax); + m->loc = loc; + if (result) m->srcfile = new File(result); @@ -582,11 +604,23 @@ void Module::parse() d_gcc_dump_source(srcname, "d.utf-8", buf, buflen); #endif } - Parser p(this, buf, buflen, docfile != NULL); - p.nextToken(); - members = p.parseModule(); - md = p.md; - numlines = p.loc.linnum; + + if (isDltFile) + { + DltParser p(this, buf, buflen, docfile != NULL); + p.nextToken(); + members = p.parseModule(); + md = p.md; + numlines = p.loc.linnum; + } + else + { + Parser p(this, buf, buflen, docfile != NULL); + p.nextToken(); + members = p.parseModule(); + md = p.md; + numlines = p.loc.linnum; + } DsymbolTable *dst; @@ -618,12 +652,42 @@ void Module::parse() } } +static FuncDeclaration *addMainFunction(Dsymbol *mainClass) { + ClassDeclaration *klass = mainClass->isClassDeclaration(); + if (klass == NULL) { + // Just ignore it then? + error("'Main' is not a class!"); + return NULL; + } + + Loc loc = mainClass->loc; + + // Create a main(string[] args) function + Arguments *arguments = new Arguments(); + + Type *tstr = new TypeDArray(Type::tchar); + Type *targv = new TypeDArray(tstr); + + Argument *a = new Argument(STCin, targv, Id::args, NULL); + arguments->push(a); + + TypeFunction *ta = new TypeFunction(arguments, new Type(Tvoid), 0, LINKc); + FuncDeclaration *f = new FuncDeclaration(loc, 0, Id::main, STCundefined, ta); + + f->fbody = new InjectorMainBody(loc, klass); + + return f; +} + void Module::semantic() { int i; if (semanticstarted) return; + Array *dlt_package = new Array(); + dlt_package->push(Id::dlt); + //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); semanticstarted = 1; @@ -634,11 +698,36 @@ void Module::semantic() //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage); + // Find Main class + for (i = 0; i < members->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)members->data[i]; + + if (s->ident && s->ident == Id::Main) { + Dsymbol *mainFn = addMainFunction(s); + if (!mainFn) + return; + members->push(mainFn); + + Import *im = new Import(0, dlt_package, Id::_externals, NULL, true); + members->shift(im); + + break; + } + } + // Add import of "object" if this module isn't "object" - if (ident != Id::object) + if (ident != Id::object || parent) { Import *im = new Import(0, NULL, Id::object, NULL, 0); members->shift(im); + + /* If this is not dlt.core ... */ + if (ident != Id::core || parent == NULL || parent->parent || parent->ident != Id::dlt) { + Import *im = new Import(0, dlt_package, Id::core, NULL, 0); + members->shift(im); + } } #ifdef IN_GCC else diff --git a/dmd2/module.h b/dmd2/module.h index 6f58b00..45e7060 100644 --- a/dmd2/module.h +++ b/dmd2/module.h @@ -68,6 +68,7 @@ struct Module : Package unsigned numlines; // number of lines in source file int isHtml; // if it is an HTML file int isDocFile; // if it is a documentation input file, not D source + int isDltFile; // if it is a Delight source file int needmoduleinfo; #ifdef IN_GCC int strictlyneedmoduleinfo; @@ -104,7 +105,7 @@ struct Module : Package Macro *macrotable; // document comment macros Escape *escapetable; // document comment escapes - Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen); + Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen, int isDltFile); ~Module(); static Module *load(Loc loc, Array *packages, Identifier *ident); diff --git a/dmd2/mtype.c b/dmd2/mtype.c index 60bfeff..42136c3 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "gdc_alloca.h" @@ -119,6 +120,7 @@ ClassDeclaration *Type::typeinfointerface; ClassDeclaration *Type::typeinfostruct; ClassDeclaration *Type::typeinfotypedef; ClassDeclaration *Type::typeinfopointer; +ClassDeclaration *Type::typeinfomaybe; ClassDeclaration *Type::typeinfoarray; ClassDeclaration *Type::typeinfostaticarray; ClassDeclaration *Type::typeinfoassociativearray; @@ -146,6 +148,7 @@ Type::Type(TY ty) this->ito = NULL; #endif this->pto = NULL; + this->mbe = NULL; this->rto = NULL; this->arrayof = NULL; this->vtinfo = NULL; @@ -211,6 +214,11 @@ void Type::init() mangleChar[Tsarray] = 'G'; mangleChar[Taarray] = 'H'; mangleChar[Tpointer] = 'P'; + + // For compat with D libraries, the maybe qualifier gets stripped from + // symbol names. In TypeInfo names, it is replaced by 'Q'. + mangleChar[Tmaybe] = '?'; + mangleChar[Treference] = 'R'; mangleChar[Tfunction] = 'F'; mangleChar[Tident] = 'I'; @@ -483,6 +491,39 @@ Type *Type::toHeadMutable() return mutableOf(); } + +// If this type can be null, wrap it in TypeMaybe. +// Otherwise just, returns itself. This is so that +// we can try wrapping everything in D source easily. +// merge should be false if we haven't yet run semantic +// on the type. +Type *Type::maybe(bool merge) +{ + if (ty == Tmaybe) + { + return this; + } + + // For some reason, "void*?" causes problems. + // Since it's not type safe anyway, don't worry about it. + if (ty == Tpointer && nextOf()->ty == Tvoid) + return this; + + if (ty != Tpointer && ty != Tclass && ty != Tident) + return this; // Can't be null + + if (!mbe) + { Type *t; + + t = new TypeMaybe(this); + if (!merge || t->reliesOnTident()) + mbe = t; + else + mbe = t->merge(); + } + return mbe; +} + Type *Type::pointerTo() { if (!pto) @@ -613,7 +654,6 @@ void Type::toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod) Type *Type::merge() { Type *t; - //printf("merge(%s)\n", toChars()); t = this; assert(t); @@ -629,7 +669,7 @@ Type *Type::merge() if (sv->ptrvalue) { t = (Type *) sv->ptrvalue; if (! t->deco) { - fprintf(stderr, "nooooooooooooooooooooooo!\n"); + fprintf(stderr, "nooooooooooooooooooooooo! %s %s\n", toChars(), t->toChars()); } assert(t->deco); //printf("old value, deco = '%s' %p\n", t->deco, t->deco); @@ -928,9 +968,21 @@ Identifier *Type::getTypeInfoIdent(int internal) } else toDecoBuffer(&buf); + len = buf.offset; name = (char *)alloca(19 + sizeof(len) * 3 + len + 1); + + /* Maybe types contain invalid char ?, because they don't appear in + * mangled names. Use unused char Q for TypeInfo instead. + */ + for (int i = 0; i < buf.offset; i++) + { + if (buf.data[i] == '?') + buf.data[i] = 'Q'; + } + buf.writeByte(0); + sprintf(name, "_D%dTypeInfo_%s6__initZ", 9 + len, buf.data); if (global.params.isWindows) name++; // C mangling will add it back in @@ -2233,6 +2285,9 @@ MATCH TypeSArray::implicitConvTo(Type *to) { //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars()); + if (to->ty == Tmaybe && to->nextOf()) + to = to->nextOf(); + // Allow implicit conversion of static array to pointer or dynamic array if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer) { @@ -2411,7 +2466,7 @@ Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident) } else if (ident == Id::ptr) { - e = e->castTo(sc, next->pointerTo()); + e = e->castTo(sc, next->pointerTo()->maybe(true)); return e; } else @@ -2433,6 +2488,9 @@ MATCH TypeDArray::implicitConvTo(Type *to) if (equals(to)) return MATCHexact; + if (to->ty == Tmaybe) + to = to->nextOf(); + // Allow implicit conversion of array to pointer if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer) { @@ -2751,7 +2809,6 @@ MATCH TypeAArray::implicitConvTo(Type *to) //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars()); if (equals(to)) return MATCHexact; - if (to->ty == Taarray) { TypeAArray *ta = (TypeAArray *)to; @@ -2789,6 +2846,130 @@ MATCH TypeAArray::constConv(Type *to) return Type::constConv(to); } +/***************************** TypeMaybe *****************************/ + +TypeMaybe::TypeMaybe(Type *t) + : TypeNext(Tmaybe, t) +{ +} + +Type *TypeMaybe::syntaxCopy() +{ + Type *t = next->syntaxCopy(); + if (t == next) + t = this; + else + t = new TypeMaybe(t); + return t; +} + +Type *TypeMaybe::toBasetype() +{ + return next->toBasetype(); +} + +Expression *TypeMaybe::dotExp(Scope *sc, Expression *e, Identifier *ident) +{ + if (sc->module->isDltFile) + e->error("attempt to access property '%s' for '%s' of type '%s', which may be null.", + ident->string, e->toChars(), toChars()); + // else it came from D - ignore any problems since we can't check + return next->dotExp(sc, e, ident); +} + +Type *TypeMaybe::semantic(Loc loc, Scope *sc) +{ + //printf("TypeMaybe::semantic()\n"); + Type *n = next->semantic(loc, sc); + + switch (n->ty) + { + case Tpointer: + if (n->nextOf()->ty == Tvoid) + return n; + break; + case Tclass: + break; + default: + error(loc, "can't have maybe for %s of type %d", n->toChars(), n->toBasetype()->ty); + return n; + } + if (n != next) + deco = NULL; + next = n; + return merge(); +} + +d_uns64 TypeMaybe::size(Loc loc) +{ + return next->size(); +} + +void TypeMaybe::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +{ + //printf("TypeMaybe::toCBuffer2() next = %d\n", next->ty); + if (mod != this->mod) + { toCBuffer3(buf, hgs, mod); + return; + } + next->toCBuffer2(buf, hgs, this->mod); + buf->writeByte('?'); +} + +MATCH TypeMaybe::implicitConvTo(Type *to) +{ + //printf("TypeMaybe::implicitConvTo(%s)\n", to->toChars()); + + if (this == to) + return MATCHexact; + + if (to->ty == Tmaybe) + { + // Allow (Subclass?) -> (ParentClass?) + return next->implicitConvTo(to->nextOf()); + } + + // Deny (Subclass?) -> (ParentClass) + // (Subclass) -> (ParentClass?) handled in TypeClass + + // Can always convert Foo*? to void* + if (to->ty == Tpointer && to->nextOf()) + { + if (to->nextOf()->ty == Tvoid) + return MATCHconvert; + } + + return MATCHnomatch; +} + +int TypeMaybe::isscalar() +{ + return next->isscalar(); +} + +Expression *TypeMaybe::defaultInit(Loc loc) +{ +#if LOGDEFAULTINIT + printf("TypeMaybe::defaultInit() '%s'\n", toChars()); +#endif + return next->defaultInit(); +} + +int TypeMaybe::isZeroInit() +{ + return next->isZeroInit(); +} + +int TypeMaybe::hasPointers() +{ + return next->hasPointers(); +} + +int TypeMaybe::checkBoolean() +{ + return TRUE; +} + /***************************** TypePointer *****************************/ TypePointer::TypePointer(Type *t) @@ -2853,6 +3034,11 @@ MATCH TypePointer::implicitConvTo(Type *to) if (equals(to)) return MATCHexact; + + // Can always convert a "Foo*" to a "Foo*?" + if (to->ty == Tmaybe) + to = to->nextOf(); + if (to->ty == Tpointer) { TypePointer *tp = (TypePointer *)to; assert(tp->next); @@ -3084,6 +3270,14 @@ int Type::covariant(Type *t) if (t1n->equals(t2n)) goto Lcovariant; + + if (t2n->ty == Tmaybe) + { + t2n = t2n->nextOf(); // Foo -> Foo? is OK + if (t1n->ty == Tmaybe) + t1n = t1n->nextOf(); // Foo? -> Foo? is OK + } + if (t1n->ty == Tclass && t2n->ty == Tclass) { /* If same class type, but t2n is const, then it's @@ -3890,6 +4084,7 @@ TypeIdentifier::TypeIdentifier(Loc loc, Identifier *ident) : TypeQualified(Tident, loc) { this->ident = ident; + this->maybe = 0; } @@ -3898,6 +4093,7 @@ Type *TypeIdentifier::syntaxCopy() TypeIdentifier *t; t = new TypeIdentifier(loc, ident); + t->maybe = maybe; t->syntaxCopyHelper(this); t->mod = mod; return t; @@ -3998,6 +4194,11 @@ Type *TypeIdentifier::semantic(Loc loc, Scope *sc) t = t->constOf(); else if (isInvariant()) t = t->invariantOf(); + + // Do the delayed wrapping now we're sure it's a type + if (maybe) { + return t->maybe(false)->semantic(loc, sc); + } } else { @@ -5562,6 +5763,10 @@ MATCH TypeClass::implicitConvTo(Type *to) if (m != MATCHnomatch) return m; + // Can always convert a "Foo" to a "Foo?" + if (to->ty == Tmaybe) + to = to->nextOf(); + ClassDeclaration *cdto = to->isClassHandle(); if (cdto && cdto->isBaseOf(sym, NULL)) { //printf("'to' is base\n"); diff --git a/dmd2/mtype.h b/dmd2/mtype.h index f68b714..9f08ba1 100644 --- a/dmd2/mtype.h +++ b/dmd2/mtype.h @@ -106,6 +106,7 @@ enum ENUMTY Ttuple, Tslice, Treturn, + Tmaybe, TMAX }; typedef unsigned char TY; // ENUMTY @@ -129,6 +130,7 @@ struct Type : Object Type *cto; // MODconst ? mutable version of this type : const version Type *ito; // MODinvariant ? mutable version of this type : invariant version Type *pto; // merged pointer to this type + Type *mbe; // maybe null of this pointer or reference Type *rto; // reference to this type Type *arrayof; // array of this type TypeInfoDeclaration *vtinfo; // TypeInfo object for this Type @@ -180,6 +182,7 @@ struct Type : Object static ClassDeclaration *typeinfostruct; static ClassDeclaration *typeinfotypedef; static ClassDeclaration *typeinfopointer; + static ClassDeclaration *typeinfomaybe; static ClassDeclaration *typeinfoarray; static ClassDeclaration *typeinfostaticarray; static ClassDeclaration *typeinfoassociativearray; @@ -243,6 +246,7 @@ struct Type : Object Type *invariantOf(); Type *mutableOf(); Type *pointerTo(); + Type *maybe(bool merge); Type *referenceTo(); Type *arrayOf(); virtual Type *makeConst(); @@ -446,6 +450,27 @@ struct TypePointer : TypeNext type *toCtype(); }; +struct TypeMaybe : TypeNext +{ + TypeMaybe(Type *t); + Type *syntaxCopy(); + + Type *toBasetype(); + Type *semantic(Loc loc, Scope *sc); + d_uns64 size(Loc loc); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + MATCH implicitConvTo(Type *to); + int isscalar(); + Expression *defaultInit(Loc loc); + int isZeroInit(); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + int checkBoolean(); + + type *toCtype(); +}; + struct TypeReference : TypeNext { TypeReference(Type *t); @@ -539,6 +564,7 @@ struct TypeQualified : Type struct TypeIdentifier : TypeQualified { Identifier *ident; + bool maybe; // If this turns out to be a type, wrap with TypeMaybe TypeIdentifier(Loc loc, Identifier *ident); Type *syntaxCopy(); diff --git a/dmd2/parse.c b/dmd2/parse.c index 17fc25c..f041319 100644 --- a/dmd2/parse.c +++ b/dmd2/parse.c @@ -59,21 +59,32 @@ Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment) - : Lexer(module, base, 0, length, doDocComment, 0) + : Lexer(module, base, 0, length, doDocComment, 0, module->isDltFile) { //printf("Parser::Parser()\n"); md = NULL; linkage = LINKd; + dltNormalMode = FALSE; endloc = 0; inBrackets = 0; + startBlockTok = TOKlcurly; //nextToken(); // start up the scanner } +DltParser::DltParser(Module *module, unsigned char *base, unsigned length, int doDocComment) + : Parser(module, base, length, doDocComment) +{ + //printf("DltParser::DltParser(%s)\n", module->ident->string); + startBlockTok = TOKcolon; + dltNormalMode = TRUE; // becomes false if we find a "module dlt.*" +} + Array *Parser::parseModule() { Array *decldefs; // ModuleDeclation leads off + optionalEndline(); if (token.value == TOKmodule) { unsigned char *comment = token.blockComment; @@ -89,6 +100,10 @@ Array *Parser::parseModule() Identifier *id; id = token.ident; + + if (dltSyntax && id == Id::dlt) + dltNormalMode = FALSE; + while (nextToken() == TOKdot) { if (!a) @@ -104,8 +119,10 @@ Array *Parser::parseModule() md = new ModuleDeclaration(a, id); - if (token.value != TOKsemicolon) - error("';' expected following module declaration instead of %s", token.toChars()); + TOK end = dltSyntax ? TOKendline : TOKsemicolon; + if (token.value != end) + error("%s expected following module declaration instead of %s", Token::toChars(end), token.toChars()); + nextToken(); addComment(mod, comment); } @@ -113,9 +130,23 @@ Array *Parser::parseModule() decldefs = parseDeclDefs(0); if (token.value != TOKeof) - { error("unrecognized declaration"); + { error("unrecognized declaration '%s'", token.toChars()); goto Lerr; } + + if (dltNormalMode) + { + // Check for global variables + for (int i = 0; i < decldefs->dim; i++) + { + Dsymbol *d = (Dsymbol *) decldefs->data[i]; + if (d->isVarDeclaration()) { + error("no global variables (%s) allowed in Delight; " + "try const, or put it in a class", d->toChars()); + } + } + } + return decldefs; Lerr: @@ -144,6 +175,9 @@ Array *Parser::parseDeclDefs(int once) storageClass = 0; switch (token.value) { + case TOKendline: + nextToken(); + continue; case TOKenum: { /* Determine if this is a manifest constant declaration, * or a conventional enum. @@ -258,9 +292,17 @@ Array *Parser::parseDeclDefs(int once) case TOKstatic: nextToken(); if (token.value == TOKthis) + { s = parseStaticCtor(); + if (dltNormalMode) + error("no static constructors in Delight"); + } else if (token.value == TOKtilde) + { s = parseStaticDtor(); + if (dltNormalMode) + error("no static destructors in Delight"); + } else if (token.value == TOKassert) s = parseStaticAssert(); else if (token.value == TOKif) @@ -284,6 +326,11 @@ Array *Parser::parseDeclDefs(int once) } break; + case TOKin: + nextToken(); + stc = STCin; + goto Lstc2; + case TOKconst: if (peek(&token)->value == TOKlparen) goto Ldeclaration; @@ -355,8 +402,9 @@ Array *Parser::parseDeclDefs(int once) Initializer *init = parseInitializer(); VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); v->storage_class = storageClass; + v->dltNormalMode = dltNormalMode; s = v; - if (token.value == TOKsemicolon) + if (token.value == TOKsemicolon || token.value == TOKendline) { nextToken(); } @@ -374,7 +422,7 @@ Array *Parser::parseDeclDefs(int once) error("Identifier expected following comma"); } else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); + error("%s expected following declaration, not '%s'", endToken(), token.toChars()); break; } } @@ -395,6 +443,9 @@ Array *Parser::parseDeclDefs(int once) a = parseBlock(); s = new LinkDeclaration(linkage, a); linkage = linksave; + + if (dltNormalMode) + error("access to external symbols can be done only by dlt.* modules"); break; } case TOKprivate: prot = PROTprivate; goto Lprot; @@ -461,8 +512,14 @@ Array *Parser::parseDeclDefs(int once) else check(TOKrparen); // pragma(identifier) - if (token.value == TOKsemicolon) + if (token.value == TOKsemicolon || token.value == TOKendline) a = NULL; + else if (dltSyntax) + { + check(TOKcolon); + a = parseDeclDefs(0); + check(TOKrcurly); + } else a = parseBlock(); s = new PragmaDeclaration(loc, ident, args, a); @@ -506,8 +563,8 @@ Array *Parser::parseDeclDefs(int once) s = NULL; } nextToken(); - if (token.value != TOKsemicolon) - error("semicolon expected"); + if (token.value != TOKsemicolon && token.value != TOKendline) + error("%s expected after version assignment", endToken()); nextToken(); break; } @@ -531,7 +588,7 @@ Array *Parser::parseDeclDefs(int once) default: error("Declaration expected, not '%s'",token.toChars()); Lerror: - while (token.value != TOKsemicolon && token.value != TOKeof) + while (token.value != TOKsemicolon && token.value != TOKendline && token.value != TOKeof) nextToken(); nextToken(); s = NULL; @@ -555,7 +612,7 @@ Array *Parser::parseBlock() Array *a = NULL; Dsymbol *s; - //printf("parseBlock()\n"); + //printf("Parser::parseBlock()\n"); switch (token.value) { case TOKsemicolon: @@ -590,6 +647,38 @@ Array *Parser::parseBlock() return a; } +Array *DltParser::parseBlock() +{ + Array *a = NULL; + Dsymbol *s; + + optionalEndline(); + switch (token.value) + { + case TOKendline: + case TOKsemicolon: + error("declaration expected following attribute, not %s", token.toChars()); + nextToken(); + break; + + case TOKcolon: + nextToken(); + a = parseDeclDefs(0); + if (token.value != TOKrcurly) + { + error("matching end-of-block expected, not %s", token.toChars()); + } + else + nextToken(); + break; + + default: + a = parseDeclDefs(1); + break; + } + return a; +} + /********************************** * Parse a static assertion. */ @@ -602,15 +691,18 @@ StaticAssert *Parser::parseStaticAssert() //printf("parseStaticAssert()\n"); nextToken(); - check(TOKlparen); + checkLParen(); exp = parseAssignExp(); if (token.value == TOKcomma) { nextToken(); msg = parseAssignExp(); } - check(TOKrparen); - check(TOKsemicolon); - return new StaticAssert(loc, exp, msg); + checkRParen(); + if (token.value == TOKsemicolon || token.value == TOKendline) { + nextToken(); + return new StaticAssert(loc, exp, msg); + } + error("expected %s after static assert", endToken()); } /*********************************** @@ -715,9 +807,13 @@ Condition *Parser::parseDebugCondition() nextToken(); check(TOKrparen); c = new DebugCondition(mod, level, id); - } - else + if (dltSyntax && token.value != TOKcolon) + error("expected colon after debug(), not '%s'", token.toChars()); + } else { + if (dltSyntax && token.value != TOKcolon) + error("expected ':' or '(' after 'debug', not '%s'", token.toChars()); c = new DebugCondition(mod, 1, NULL); + } return c; } @@ -775,16 +871,10 @@ Condition *Parser::parseStaticIfCondition() Loc loc = this->loc; nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - exp = parseAssignExp(); - check(TOKrparen); - } - else - { error("(expression) expected following static if"); - exp = NULL; - } + checkLParen(); + exp = parseAssignExp(); + checkRParen(); + condition = new StaticIfCondition(loc, exp); return condition; } @@ -1131,7 +1221,7 @@ EnumDeclaration *Parser::parseEnum() else id = NULL; - if (token.value == TOKcolon) + if (token.value == (dltSyntax ? TOKextends : TOKcolon)) { nextToken(); memtype = parseBasicType(); @@ -1143,12 +1233,13 @@ EnumDeclaration *Parser::parseEnum() e = new EnumDeclaration(loc, id, memtype); if (token.value == TOKsemicolon && id) nextToken(); - else if (token.value == TOKlcurly) + else if (token.value == startBlockTok) { //printf("enum definition\n"); e->members = new Array(); nextToken(); unsigned char *comment = token.blockComment; + optionalEndline(); while (token.value != TOKrcurly) { /* Can take the following forms: @@ -1243,14 +1334,9 @@ Dsymbol *Parser::parseAggregate() error("anonymous classes not allowed"); // Collect base class(es) - BaseClasses *baseclasses = NULL; - if (token.value == TOKcolon) - { - nextToken(); - baseclasses = parseBaseClasses(); - - if (token.value != TOKlcurly) - error("members expected"); + BaseClasses *baseclasses = parseBaseClasses(); + if (baseclasses && token.value != startBlockTok) { + error("members expected"); } if (tok == TOKclass) @@ -1278,16 +1364,17 @@ Dsymbol *Parser::parseAggregate() assert(0); break; } - if (a && token.value == TOKsemicolon) + if (a && token.value == (dltSyntax ? TOKendline : TOKsemicolon)) { nextToken(); } - else if (token.value == TOKlcurly) + else if (token.value == startBlockTok) { //printf("aggregate definition\n"); nextToken(); + optionalEndline(); Array *decl = parseDeclDefs(0); if (token.value != TOKrcurly) - error("} expected following member declarations in aggregate"); + error("end-of-block expected following member declarations in aggregate"); nextToken(); if (anon) { @@ -1300,7 +1387,7 @@ Dsymbol *Parser::parseAggregate() } else { - error("{ } expected following aggregate declaration"); + error("%s expected following aggregate declaration", Token::toChars(startBlockTok)); a = new StructDeclaration(loc, NULL); } @@ -1311,7 +1398,7 @@ Dsymbol *Parser::parseAggregate() // Wrap a template around the aggregate declaration decldefs = new Array(); decldefs->push(a); - tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs); + tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs, dltSyntax); return tempdecl; } @@ -1321,8 +1408,30 @@ Dsymbol *Parser::parseAggregate() /******************************************* */ +/* If current token is TOKcolon, TOKextends or TOKimplements, return + * the bases. Otherwise, return null. + */ BaseClasses *Parser::parseBaseClasses() { + enum PROT protection = PROTpublic; + int type; // 1 = extends, 2 = implements, 3 = unknown + + if (dltSyntax) { + if (token.value == TOKextends) + type = 1; + else if (token.value == TOKimplements) + type = 2; + else + return NULL; + } else { + if (token.value == TOKcolon) + type = 3; + else + return NULL; + } + + nextToken(); + BaseClasses *baseclasses = new BaseClasses(); for (; 1; nextToken()) @@ -1351,8 +1460,24 @@ BaseClasses *Parser::parseBaseClasses() { BaseClass *b = new BaseClass(parseBasicType(), protection); baseclasses->push(b); - if (token.value != TOKcomma) - break; + + switch (token.value) { + case TOKcomma: + continue; + case TOKextends: + if (type == 2) + error("extends part must come before implements"); + else + error("only one extends is permitted"); + continue; + case TOKimplements: + if (type == 1) + type = 2; + else + error("separate implemented interfaces with commas"); + continue; + } + break; } else { @@ -1386,7 +1511,7 @@ TemplateDeclaration *Parser::parseTemplateDeclaration() if (!tpl) goto Lerr; - if (token.value != TOKlcurly) + if (token.value != startBlockTok) { error("members of template declaration expected"); goto Lerr; } @@ -1401,7 +1526,7 @@ TemplateDeclaration *Parser::parseTemplateDeclaration() nextToken(); } - tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs); + tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs, dltSyntax); return tempdecl; Lerr: @@ -1739,11 +1864,15 @@ Import *Parser::parseImport(Array *decldefs, int isstatic) */ if (token.value == TOKcolon) { - do + nextToken(); + while (1) { Identifier *name; Identifier *alias; - nextToken(); + optionalEndline(); + + if (dltSyntax && token.value == TOKrcurly) + break; if (token.value != TOKidentifier) { error("Identifier expected following :"); break; @@ -1765,18 +1894,27 @@ Import *Parser::parseImport(Array *decldefs, int isstatic) alias = NULL; } s->addAlias(name, alias); - } while (token.value == TOKcomma); - break; // no comma-separated imports of this form + if (token.value != TOKcomma && token.value != TOKendline) + break; + nextToken(); + } + if (dltSyntax) + { + check(TOKrcurly); + return NULL; + } + else + break; } aliasid = NULL; } while (token.value == TOKcomma); - if (token.value == TOKsemicolon) + if (token.value == TOKsemicolon || token.value == TOKendline) nextToken(); else { - error("';' expected"); + error("%s expected", endToken()); nextToken(); } @@ -1980,12 +2118,38 @@ Type *Parser::parseBasicType2(Type *t) continue; } + case TOKquestion: + if (dltSyntax) + { + Type *old = t; + t = t->maybe(false); + if (t == old) + error("Type %s cannot be null; ? is pointless", old->toChars()); + nextToken(); + continue; + } + // fall-through to default + default: ts = t; break; } break; } + + if (!dltSyntax) + { + switch (ts->ty) { + case Tident: + // Don't wrap it yet, because that confuses resolve() + ((TypeIdentifier *) ts)->maybe = 1; + break; + case Tpointer: + ts = ts->maybe(false); + break; + } + } + return ts; } @@ -2036,6 +2200,10 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters * case TOKlbracket: { // This is the old C-style post [] syntax. TypeNext *ta; + + if (dltSyntax) + error("use 'type[] var', not 'type var[]'"); + nextToken(); if (token.value == TOKrbracket) { // It's a dynamic array @@ -2240,8 +2408,9 @@ Array *Parser::parseDeclarations() Initializer *init = parseInitializer(); VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); v->storage_class = storage_class; + v->dltNormalMode = dltNormalMode; a->push(v); - if (token.value == TOKsemicolon) + if (token.value == TOKsemicolon || token.value == TOKendline) { nextToken(); addComment(v, comment); @@ -2257,7 +2426,7 @@ Array *Parser::parseDeclarations() continue; } else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); + error("%s expected following auto declaration, not '%s'", endToken(), token.toChars()); return a; } @@ -2320,6 +2489,7 @@ Array *Parser::parseDeclarations() } switch (token.value) { case TOKsemicolon: + case TOKendline: nextToken(); addComment(v, comment); break; @@ -2330,7 +2500,7 @@ Array *Parser::parseDeclarations() continue; default: - error("semicolon expected to close %s declaration", Token::toChars(tok)); + error("%s expected to close %s declaration", endToken(), Token::toChars(tok)); break; } } @@ -2359,7 +2529,7 @@ Array *Parser::parseDeclarations() // Wrap a template around the aggregate declaration decldefs = new Array(); decldefs->push(s); - tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs); + tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs, dltSyntax); s = tempdecl; } addComment(s, comment); @@ -2377,6 +2547,7 @@ Array *Parser::parseDeclarations() } v = new VarDeclaration(loc, t, ident, init); v->storage_class = storage_class; + v->dltNormalMode = dltNormalMode; if (link == linkage) a->push(v); else @@ -2387,18 +2558,23 @@ Array *Parser::parseDeclarations() a->push(s); } switch (token.value) - { case TOKsemicolon: + { + case TOKendline: nextToken(); addComment(v, comment); break; - + case TOKsemicolon: + if (!dltSyntax) + nextToken(); + addComment(v, comment); + break; case TOKcomma: nextToken(); addComment(v, comment); continue; default: - error("semicolon expected, not '%s'", token.toChars()); + error("%s expected, not '%s'", endToken(), token.toChars()); break; } } @@ -2423,9 +2599,12 @@ L1: switch (token.value) { case TOKlcurly: + case TOKcolon: + if (token.value != startBlockTok) + error("use %s to start a new block", Token::toChars(startBlockTok)); if (f->frequire || f->fensure) error("missing body { ... } after in or out"); - f->fbody = parseStatement(PSsemi); + f->fbody = parseStatement(PSsemi | PScolon); f->endloc = endloc; break; @@ -2436,6 +2615,10 @@ L1: break; case TOKsemicolon: + if (dltSyntax) + error("unexpected semi-colon after function declaration"); + // fall-through + case TOKendline: if (f->frequire || f->fensure) error("missing body { ... } after in or out"); nextToken(); @@ -2478,7 +2661,7 @@ L1: case TOKout: // parse: out (identifier) { statement } nextToken(); - if (token.value != TOKlcurly) + if (token.value != startBlockTok) { check(TOKlparen); if (token.value != TOKidentifier) @@ -2493,7 +2676,7 @@ L1: goto L1; default: - error("semicolon expected following function declaration"); + error("%s expected following function declaration", endToken()); break; } linkage = linksave; @@ -2658,7 +2841,7 @@ Initializer *Parser::parseInitializer() case TOKvoid: t = peek(&token); - if (t->value == TOKsemicolon || t->value == TOKcomma) + if (t->value == TOKsemicolon || t->value == TOKcomma || t->value == TOKendline) { nextToken(); return new VoidInitializer(loc); @@ -2700,11 +2883,26 @@ Expression *Parser::parseDefaultInitExp() return e; } +Statement *Parser::logStatement(int level) { + nextToken(); + if (token.value != TOKlparen) + error(loc, "found '%s' when expecting '('", token.toChars()); + return new LogStatement(loc, level, parseArguments()); +} + /***************************************** * Input: * flags PSxxxx */ +Statement *DltParser::parseStatement(int flags) +{ + optionalEndline(); + if (flags & (PScolon | PSscope)) + flags |= PScurly; + return Parser::parseStatement(flags); +} + Statement *Parser::parseStatement(int flags) { Statement *s; Token *t; @@ -2715,26 +2913,31 @@ Statement *Parser::parseStatement(int flags) //printf("parseStatement()\n"); - if (flags & PScurly && token.value != TOKlcurly) - error("statement expected to be { }, not %s", token.toChars()); + if ((flags & PScurly) && token.value != startBlockTok) + error("statement expected to start with %s, not %s", Token::toChars(startBlockTok), token.toChars()); + + int tok = token.value; switch (token.value) { case TOKidentifier: - // Need to look ahead to see if it is a declaration, label, or expression - t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - Identifier *ident; + if (!dltSyntax) + { + // Need to look ahead to see if it is a declaration, label, or expression + t = peek(&token); + if (t->value == TOKcolon) + { // It's a label + Identifier *ident; - ident = token.ident; - nextToken(); - nextToken(); - s = parseStatement(PSsemi); - s = new LabelStatement(loc, ident, s); - break; + ident = token.ident; + nextToken(); + nextToken(); + s = parseStatement(PSsemi); + s = new LabelStatement(loc, ident, s); + break; + } } - // fallthrough to TOKdot + // fallthrough to TOKdot case TOKdot: case TOKtypeof: if (isDeclaration(&token, 2, TOKreserved, NULL)) @@ -2784,7 +2987,8 @@ Statement *Parser::parseStatement(int flags) { Expression *exp; exp = parseExpression(); - check(TOKsemicolon, "statement"); + if (!dltSyntax) + check(TOKsemicolon, "statement"); s = new ExpStatement(loc, exp); break; } @@ -2806,6 +3010,8 @@ Statement *Parser::parseStatement(int flags) condition = parseStaticIfCondition(); goto Lcondition; } + if (dltNormalMode) + error("no static variables in Delight"); goto Ldeclaration; } @@ -2888,7 +3094,13 @@ Statement *Parser::parseStatement(int flags) check(TOKlparen, "mixin"); Expression *e = parseAssignExp(); check(TOKrparen); - check(TOKsemicolon); + if (dltSyntax) { + if (token.value != TOKsemicolon && token.value != TOKendline) { + error("expected newline after mixin(), not '%s'", token.toChars()); + } + } else { + check(TOKsemicolon); + } s = new CompileStatement(loc, e); break; } @@ -2897,14 +3109,20 @@ Statement *Parser::parseStatement(int flags) break; } + case TOKcolon: case TOKlcurly: { Statements *statements; + if (token.value != startBlockTok) + error("statement expected to start with %s, not %s", Token::toChars(startBlockTok), token.toChars()); + nextToken(); + optionalEndline(); statements = new Statements(); while (token.value != TOKrcurly) { statements->push(parseStatement(PSsemi | PScurlyscope)); + optionalEndline(); } endloc = this->loc; s = new CompoundStatement(loc, statements); @@ -2914,14 +3132,19 @@ Statement *Parser::parseStatement(int flags) break; } + case TOKlog_error: s = logStatement(LogStatement::Error); break; + case TOKlog_warning: s = logStatement(LogStatement::Warn); break; + case TOKlog_info: s = logStatement(LogStatement::Info); break; + case TOKlog_trace: s = logStatement(LogStatement::Trace); break; + case TOKwhile: { Expression *condition; Statement *body; nextToken(); - check(TOKlparen); + checkLParen(); condition = parseExpression(); - check(TOKrparen); + checkRParen(); body = parseStatement(PSscope); s = new WhileStatement(loc, condition, body); break; @@ -2941,9 +3164,9 @@ Statement *Parser::parseStatement(int flags) nextToken(); body = parseStatement(PSscope); check(TOKwhile); - check(TOKlparen); + checkLParen(); condition = parseExpression(); - check(TOKrparen); + checkRParen(); s = new DoStatement(loc, body, condition); break; } @@ -2956,51 +3179,67 @@ Statement *Parser::parseStatement(int flags) Statement *body; nextToken(); - check(TOKlparen); - if (token.value == TOKsemicolon) - { init = NULL; - nextToken(); - } - else - { init = parseStatement(0); - } - if (token.value == TOKsemicolon) - { - condition = NULL; - nextToken(); - } - else - { - condition = parseExpression(); - check(TOKsemicolon, "for condition"); - } - if (token.value == TOKrparen) - { increment = NULL; + + if (token.value == TOKlparen) { + /* for (init; cond; incr): ... */ nextToken(); - } - else - { increment = parseExpression(); - check(TOKrparen); - } - body = parseStatement(PSscope); - s = new ForStatement(loc, init, condition, increment, body); - if (init) - s = new ScopeStatement(loc, s); + if (token.value == TOKsemicolon) + { init = NULL; + nextToken(); + } + else + { init = parseStatement(0); + if (dltSyntax) + check(TOKsemicolon); + } + if (token.value == TOKsemicolon) + { + condition = NULL; + nextToken(); + } + else + { + condition = parseExpression(); + check(TOKsemicolon, "for condition"); + } + if (token.value == TOKrparen) + { increment = NULL; + nextToken(); + } + else + { increment = parseExpression(); + check(TOKrparen); + } + body = parseStatement(PSscope); + s = new ForStatement(loc, init, condition, increment, body); + if (init) + s = new ScopeStatement(loc, s); + } else if (dltSyntax) + goto caseForeach; break; } + caseForeach: case TOKforeach: case TOKforeach_reverse: { - enum TOK op = token.value; + /* for var in seq: ... */ + /* for index, var in seq: ... */ Arguments *arguments; Statement *d; Statement *body; Expression *aggr; + enum TOK op = (TOK) tok; - nextToken(); - check(TOKlparen); + if (tok == TOKfor) + op = TOKforeach; // Delight foreach syntax + else + nextToken(); + + checkLParen(); + + TOK inTok = dltSyntax ? TOKin : TOKsemicolon; arguments = new Arguments(); @@ -3020,7 +3259,7 @@ Statement *Parser::parseStatement(int flags) if (token.value == TOKidentifier) { Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) + if (t->value == TOKcomma || t->value == inTok) { ai = token.ident; at = NULL; // infer argument type nextToken(); @@ -3039,7 +3278,8 @@ Statement *Parser::parseStatement(int flags) } break; } - check(TOKsemicolon); + + check(inTok); aggr = parseExpression(); if (token.value == TOKslice && arguments->dim == 1) @@ -3048,13 +3288,23 @@ Statement *Parser::parseStatement(int flags) delete arguments; nextToken(); Expression *upr = parseExpression(); - check(TOKrparen); + checkRParen(); + if (token.value == TOKreserved) + { + op = TOKforeach_reverse; + nextToken(); + } body = parseStatement(0); s = new ForeachRangeStatement(loc, op, a, aggr, upr, body); } else { - check(TOKrparen); + checkRParen(); + if (token.value == TOKreserved) + { + op = TOKforeach_reverse; + nextToken(); + } body = parseStatement(0); s = new ForeachStatement(loc, op, arguments, aggr, body); } @@ -3068,7 +3318,7 @@ Statement *Parser::parseStatement(int flags) Statement *elsebody; nextToken(); - check(TOKlparen); + checkLParen(); if (token.value == TOKauto) { @@ -3103,7 +3353,7 @@ Statement *Parser::parseStatement(int flags) } // Check for " ident;" - else if (token.value == TOKidentifier) + else if (token.value == TOKidentifier && !dltSyntax) { Token *t = peek(&token); if (t->value == TOKcomma || t->value == TOKsemicolon) @@ -3117,12 +3367,24 @@ Statement *Parser::parseStatement(int flags) } condition = parseExpression(); - check(TOKrparen); + checkRParen(); ifbody = parseStatement(PSscope); if (token.value == TOKelse) { nextToken(); - elsebody = parseStatement(PSscope); + if (dltSyntax) + { + if (token.value == TOKcolon) { + elsebody = parseStatement(PSscope); + } else if (token.value == TOKif) { + elsebody = parseStatement(0); + } else { + error("Expected 'else:' or 'else if', not 'else %s'", token.toChars()); + elsebody = NULL; + } + } + else + elsebody = parseStatement(PSscope); } else elsebody = NULL; @@ -3153,7 +3415,7 @@ Statement *Parser::parseStatement(int flags) error("valid scope identifiers are exit, failure, or success, not %s", id->toChars()); nextToken(); check(TOKrparen); - Statement *st = parseStatement(PScurlyscope); + Statement *st = parseStatement(PScolon | PScurlyscope); s = new OnScopeStatement(loc, t, st); break; } @@ -3169,12 +3431,14 @@ Statement *Parser::parseStatement(int flags) goto Lcondition; Lcondition: - ifbody = parseStatement(0 /*PSsemi*/); + if (dltSyntax && token.value != TOKcolon) + error("expected colon after condition, not '%s'", token.toChars()); + ifbody = parseStatement(PScolon /*PSsemi*/); elsebody = NULL; if (token.value == TOKelse) { nextToken(); - elsebody = parseStatement(0 /*PSsemi*/); + elsebody = parseStatement(PScolon /*PSsemi*/); } s = new ConditionalStatement(loc, condition, ifbody, elsebody); break; @@ -3201,7 +3465,7 @@ Statement *Parser::parseStatement(int flags) body = NULL; } else - body = parseStatement(PSsemi); + body = parseStatement(PSsemi | PScolon); s = new PragmaStatement(loc, ident, args, body); break; } @@ -3211,10 +3475,10 @@ Statement *Parser::parseStatement(int flags) Statement *body; nextToken(); - check(TOKlparen); + checkLParen(); condition = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); + checkRParen(); + body = parseStatement(PSscope | PScolon); s = new SwitchStatement(loc, condition, body); break; } @@ -3232,16 +3496,25 @@ Statement *Parser::parseStatement(int flags) if (token.value != TOKcomma) break; } - check(TOKcolon); - statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKrcurly) + if (dltSyntax) { - statements->push(parseStatement(PSsemi | PScurlyscope)); + s = parseStatement(PSsemi | PScurlyscope | PScolon); } - s = new CompoundStatement(loc, statements); + else + { + check(TOKcolon); + + statements = new Statements(); + while (token.value != TOKcase && + token.value != TOKdefault && + token.value != TOKrcurly) + { + statements->push(parseStatement(PSsemi | PScurlyscope)); + } + s = new CompoundStatement(loc, statements); + } + s = new ScopeStatement(loc, s); // Keep cases in order by building the case statements backwards @@ -3258,16 +3531,25 @@ Statement *Parser::parseStatement(int flags) Statements *statements; nextToken(); - check(TOKcolon); - statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKrcurly) + if (dltSyntax) { - statements->push(parseStatement(PSsemi | PScurlyscope)); + s = parseStatement(PSsemi | PScurlyscope | PScolon); } - s = new CompoundStatement(loc, statements); + else + { + check(TOKcolon); + + statements = new Statements(); + while (token.value != TOKcase && + token.value != TOKdefault && + token.value != TOKrcurly) + { + statements->push(parseStatement(PSsemi | PScurlyscope)); + } + s = new CompoundStatement(loc, statements); + } + s = new ScopeStatement(loc, s); s = new DefaultStatement(loc, s); break; @@ -3277,11 +3559,17 @@ Statement *Parser::parseStatement(int flags) { Expression *exp; nextToken(); - if (token.value == TOKsemicolon) + if (token.value == TOKsemicolon || token.value == TOKendline) exp = NULL; else exp = parseExpression(); - check(TOKsemicolon, "return statement"); + + if (!dltSyntax) + check(TOKsemicolon, "return statement"); + else if (token.value != TOKendline) { + error("Expected end-of-line after return statement, but found '%s'", token.toChars()); + } + s = new ReturnStatement(loc, exp); break; } @@ -3296,7 +3584,11 @@ Statement *Parser::parseStatement(int flags) } else ident = NULL; - check(TOKsemicolon, "break statement"); + if (token.value != TOKsemicolon && token.value != TOKendline) { + error("expected %s after break, not '%s'", endToken(), token.toChars()); + } + if (!dltSyntax) + nextToken(); s = new BreakStatement(loc, ident); break; } @@ -3346,7 +3638,9 @@ Statement *Parser::parseStatement(int flags) } s = new GotoStatement(loc, ident); } - check(TOKsemicolon, "goto statement"); + if (token.value != TOKsemicolon && token.value != TOKendline) { + error("expected %s after goto statement, not '%s'", endToken(), token.toChars()); + } break; } @@ -3397,7 +3691,7 @@ Statement *Parser::parseStatement(int flags) Loc loc = this->loc; nextToken(); - if (token.value == TOKlcurly) + if (token.value == startBlockTok) { t = NULL; id = NULL; @@ -3409,7 +3703,7 @@ Statement *Parser::parseStatement(int flags) t = parseType(&id); check(TOKrparen); } - handler = parseStatement(0); + handler = parseStatement(PScolon); c = new Catch(loc, t, id, handler); if (!catches) catches = new Array(); @@ -3418,7 +3712,7 @@ Statement *Parser::parseStatement(int flags) if (token.value == TOKfinally) { nextToken(); - finalbody = parseStatement(0); + finalbody = parseStatement(PScolon); } s = body; @@ -3438,7 +3732,11 @@ Statement *Parser::parseStatement(int flags) nextToken(); exp = parseExpression(); - check(TOKsemicolon, "throw statement"); + if (token.value != TOKsemicolon && token.value != TOKendline) { + error("%s expected after throw statement, not '%s'", endToken(), token.toChars()); + } + if (!dltSyntax) + nextToken(); s = new ThrowStatement(loc, exp); break; } @@ -3472,7 +3770,7 @@ Statement *Parser::parseStatement(int flags) break; } #endif - check(TOKlcurly); + check(startBlockTok); toklist = NULL; ptoklist = &toklist; label = NULL; @@ -3504,6 +3802,7 @@ Statement *Parser::parseStatement(int flags) } break; + case TOKendline: case TOKsemicolon: s = NULL; if (toklist || label) @@ -3679,6 +3978,12 @@ Statement *Parser::parseExtAsm(int expect_rparen) argConstraints, nOutputArgs, clobbers); } +void Parser::optionalEndline() { + while (token.value == TOKendline) { + nextToken(); + } +} + void Parser::check(enum TOK value) { check(loc, value); @@ -3699,6 +4004,22 @@ void Parser::check(enum TOK value, char *string) nextToken(); } +char *Parser::endToken() +{ + return "semicolon"; +} + +char *DltParser::endToken() +{ + return "newline"; +} + +void Parser::checkLParen() { check(TOKlparen); } +void Parser::checkRParen() { check(TOKrparen); } + +void DltParser::checkLParen() { } +void DltParser::checkRParen() { } + /************************************ * Determine if the scanner is sitting on the start of a declaration. * Input: @@ -3831,6 +4152,7 @@ int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok) parens = FALSE; switch (t->value) { + case TOKquestion: case TOKmul: case TOKand: t = peek(t); @@ -3946,6 +4268,7 @@ int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok) case TOKrbracket: case TOKassign: case TOKcomma: + case TOKendline: case TOKsemicolon: case TOKlcurly: case TOKin: @@ -4516,13 +4839,16 @@ Expression *Parser::parsePrimaryExp() { Expression *msg = NULL; nextToken(); - check(TOKlparen, "assert"); + + checkLParen(); e = parseAssignExp(); - if (token.value == TOKcomma) + if (token.value == (dltSyntax ? TOKelse : TOKcomma)) { nextToken(); msg = parseAssignExp(); - } - check(TOKrparen); + } else if (token.value == TOKcomma) + error("Suspicious comma after assert; try 'else' instead"); + checkRParen(); + e = new AssertExp(loc, e, msg); break; } @@ -4623,7 +4949,7 @@ Expression *Parser::parsePrimaryExp() bool isnothrow = false; bool ispure = false; - if (token.value == TOKlcurly) + if (token.value == startBlockTok) { t = NULL; varargs = 0; @@ -4654,7 +4980,18 @@ Expression *Parser::parsePrimaryExp() tf->ispure = ispure; tf->isnothrow = isnothrow; fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL); + if (dltSyntax) + { + check(TOKcolon); + if (!nesting) + indent--; // This colon doesn't start a new indent level + fd->fbody = new ReturnStatement(loc, parseAssignExp()); + fd->endloc = loc; + } + else + { parseContracts(fd); + } e = new FuncExp(loc, fd); break; } @@ -5094,6 +5431,18 @@ Expression *Parser::parseEqualExp() case TOKis: value = TOKidentity; + error("TOKis"); + if (dltSyntax) + { + t = peek(&token); + error("next: %s", t->toChars()); + if (t->value == TOKnot) + { + // X is not Y + value = TOKnotidentity; + nextToken(); + } + } goto L1; case TOKnot: @@ -5139,6 +5488,16 @@ Expression *Parser::parseCmpExp() case TOKis: op = TOKidentity; + if (dltSyntax) + { + t = peek(&token); + if (t->value == TOKnot) + { + // X is not Y + op = TOKnotidentity; + nextToken(); + } + } goto L1; case TOKnot: @@ -5293,6 +5652,24 @@ Expression *Parser::parseCondExp() return e; } +Expression *DltParser::parseCondExp() +{ Expression *e; + Expression *e1; + Expression *e2; + Loc loc = this->loc; + + e = parseOrOrExp(); + if (token.value == TOKif) + { + nextToken(); + e1 = parseExpression(); + check(TOKelse); + e2 = parseCondExp(); + e = new CondExp(loc, e1, e, e2); + } + return e; +} + Expression *Parser::parseAssignExp() { Expression *e; Expression *e2; @@ -5404,6 +5781,10 @@ Expression *Parser::parseNewExp(Expression *thisexp) if (token.value == TOKclass) { nextToken(); + + if (dltSyntax) + error("no anonymous classes in Delight"); + if (token.value == TOKlparen) arguments = parseArguments(); @@ -5414,7 +5795,7 @@ Expression *Parser::parseNewExp(Expression *thisexp) Identifier *id = NULL; ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses); - if (token.value != TOKlcurly) + if (token.value != startBlockTok) { error("{ members } expected for anonymous class"); cd->members = NULL; } diff --git a/dmd2/parse.h b/dmd2/parse.h index e79f5da..d1d9c85 100644 --- a/dmd2/parse.h +++ b/dmd2/parse.h @@ -54,6 +54,7 @@ enum ParseStatementFlags PSscope = 2, // start a new scope PScurly = 4, // { } statement is required PScurlyscope = 8, // { } starts a new scope + PScolon = 16, // in Delight, : is required }; @@ -63,12 +64,14 @@ struct Parser : Lexer enum LINK linkage; Loc endloc; // set to location of last right curly int inBrackets; // inside [] of array index or slice + TOK startBlockTok; + bool dltNormalMode; // disallow various dangerous features Parser(Module *module, unsigned char *base, unsigned length, int doDocComment); Array *parseModule(); Array *parseDeclDefs(int once); - Array *parseBlock(); + virtual Array *parseBlock(); TemplateDeclaration *parseTemplateDeclaration(); TemplateParameters *parseTemplateParameterList(int flag = 0); Dsymbol *parseMixin(); @@ -100,13 +103,17 @@ struct Parser : Lexer Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL); Array *parseDeclarations(); void parseContracts(FuncDeclaration *f); - Statement *parseStatement(int flags); + virtual Statement *parseStatement(int flags); Statement *parseExtAsm(int expect_rparen); Initializer *parseInitializer(); Expression *parseDefaultInitExp(); + void optionalEndline(); void check(Loc loc, enum TOK value); void check(enum TOK value); void check(enum TOK value, char *string); + virtual void checkLParen(); + virtual void checkRParen(); + virtual char *endToken(); // for error messages int isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt); int isBasicType(Token **pt); int isDeclarator(Token **pt, int *haveId, enum TOK endtok); @@ -130,14 +137,30 @@ struct Parser : Lexer Expression *parseOrExp(); Expression *parseAndAndExp(); Expression *parseOrOrExp(); - Expression *parseCondExp(); + virtual Expression *parseCondExp(); Expression *parseAssignExp(); Expressions *parseArguments(); Expression *parseNewExp(Expression *thisexp); + Statement *logStatement(int level); void addComment(Dsymbol *s, unsigned char *blockComment); }; +/************************************ + * Delight + */ + +struct DltParser : Parser { + DltParser(Module *module, unsigned char *base, unsigned length, int doDocComment); + + Statement *parseStatement(int flags); + Array *parseBlock(); + Expression *parseCondExp(); + char *endToken(); + void checkLParen(); + void checkRParen(); +}; + #endif /* DMD_PARSE_H */ diff --git a/dmd2/scope.c b/dmd2/scope.c index 3de7470..577dfc2 100644 --- a/dmd2/scope.c +++ b/dmd2/scope.c @@ -73,6 +73,7 @@ Scope::Scope() this->offset = 0; this->inunion = 0; this->incontract = 0; + this->inDtemplate = 0; this->nofree = 0; this->noctor = 0; this->noaccesscheck = 0; @@ -93,6 +94,7 @@ Scope::Scope(Scope *enclosing) this->module = enclosing->module; this->func = enclosing->func; this->parent = enclosing->parent; + this->inDtemplate = enclosing->inDtemplate; this->scopesym = NULL; this->sd = NULL; this->sw = enclosing->sw; diff --git a/dmd2/scope.h b/dmd2/scope.h index 975be26..e54781f 100644 --- a/dmd2/scope.h +++ b/dmd2/scope.h @@ -62,6 +62,7 @@ struct Scope int intypeof; // in typeof(exp) int parameterSpecialization; // if in template parameter specialization int noaccesscheck; // don't do access checks + bool inDtemplate; // use D type rules, not Dlt ones, in this template unsigned callSuper; // primitive flow analysis for constructors #define CSXthis_ctor 1 // called this() diff --git a/dmd2/statement.c b/dmd2/statement.c index 3d04673..de06a83 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -354,6 +354,104 @@ void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) } +/******************************** InjectorMainBody ***************************/ + +static Expressions *getAutoArgs(Loc loc, Arguments *arguments) { + Expressions *args = new Expressions(); + + Expression *externals = new IdentifierExp(loc, Id::externals); + // Collect all the objects we need for the constructor's arguments + for (int i = 0; i < arguments->dim; i++) { + Argument *arg = (Argument *) arguments->data[i]; + if (arg->ident == Id::args) { + // For 'args', just pass through the string[] passed to main() + args->push(new IdentifierExp(loc, arg->ident)); + } else { + // For everything else, call a getter in the _externals module + Expression *getter = new DotIdExp(loc, externals, arg->ident); + args->push(getter); + } + } + + return args; +} + +InjectorMainBody::InjectorMainBody(Loc loc, ClassDeclaration *mainClass) + : Statement(loc), mainClass(mainClass) +{ +} + +Statement *InjectorMainBody::semantic(Scope *sc) +{ + // Find the constructor and the main method + CtorDeclaration *ctor = NULL; + FuncDeclaration *mainDecl = NULL; + for (int i = 0; i < mainClass->members->dim; i++) { + Dsymbol *s; + + s = (Dsymbol *)mainClass->members->data[i]; + + CtorDeclaration *thisCtor = s->isCtorDeclaration(); + if (thisCtor) { + if (ctor) { + error("Multiple constructors for Main class!"); + return NULL; + } else { + ctor = thisCtor; + } + } + + FuncDeclaration *thisMethod = s->isFuncDeclaration(); + if (thisMethod && thisMethod->ident == Id::main) { + if (mainDecl) { + error("Multiple main methods for Main class!"); + return NULL; + } else { + mainDecl = thisMethod; + } + } + } + + if (mainDecl == NULL) { + error("No main method in Main class!"); + return NULL; + } + + // Externals externals = new _externals.Externals() + TypeIdentifier *extType = new TypeIdentifier(loc, Id::dlt); + extType->addIdent(Id::_externals); + extType->addIdent(Id::Externals); + + Expression *newExt = new NewExp(loc, NULL, NULL, extType, NULL); + VarDeclaration *v = new VarDeclaration(loc, extType, Id::externals, + new ExpInitializer(loc, newExt)); + Statement *assignExt = new DeclarationStatement(loc, v); + Expression *newMain = new NewExp(loc, NULL, NULL, mainClass->getType(), + ctor ? getAutoArgs(ctor->loc, ctor->arguments) : NULL); + + // Then invoke the main() method inside it + // mainObject.main(...) + Expression *mainMethod = new DotIdExp(mainDecl->loc, newMain, Id::main); + Expression *mainCall = new CallExp(mainMethod->loc, mainMethod, + getAutoArgs(mainDecl->loc, + ((TypeFunction *) mainDecl->type)->parameters)); + + Statement *s = new ExpStatement(loc, mainCall); + Statement *runMain = new CompoundStatement(loc, assignExt, s); + + // catch (SystemExit) + Array *catches = new Array(); + Statement *handler = new ExpStatement(loc, new CallExp(loc, + new DotIdExp(loc, + new IdentifierExp(loc, Id::externals), + Id::SystemExit), + new IdentifierExp(loc, Id::result))); + Catch *c = new Catch(loc, new TypeIdentifier(loc, Id::SystemExit), Id::result, handler); + catches->push(c); + Statement *body = new TryCatchStatement(loc, runMain, catches); + return body->semantic(sc); +} + /******************************** CompoundStatement ***************************/ CompoundStatement::CompoundStatement(Loc loc, Statements *s) @@ -1975,7 +2073,8 @@ Statement *IfStatement::semantic(Scope *sc) scd = sc->push(sym); Type *t = arg->type ? arg->type : condition->type; - match = new VarDeclaration(loc, t, arg->ident, NULL); + match = new VarDeclaration(loc, t->maybe(true), arg->ident, NULL); + match->skipnullcheck = true; match->noauto = 1; match->semantic(scd); if (!scd->insert(match)) @@ -1988,6 +2087,13 @@ Statement *IfStatement::semantic(Scope *sc) VarExp *v = new VarExp(0, match); condition = new AssignExp(loc, v, condition); condition = condition->semantic(scd); + + if (match && match->type->ty == Tmaybe) + { + // Matched object cannot be null in the then block + // (and isn't in scope in the else) + match->type = match->type->nextOf(); + } } else scd = sc->push(); @@ -2285,6 +2391,74 @@ void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) } +/******************************** LogStatement ***************************/ + +LogStatement::LogStatement(Loc loc, int level, Expressions *args) + : Statement(loc) +{ + this->level = level; + this->args = args; +} + +Statement *LogStatement::syntaxCopy() +{ + Expressions *copied_args = Expression::arraySyntaxCopy(args); + LogStatement *s = new LogStatement(loc, level, copied_args); + return s; +} + +Statement *LogStatement::semantic(Scope *sc) +{ + Expression *logger = new GetLoggerExp(loc); + Type *type = NULL; + + for (Dsymbol *s = sc->parent; s; s = s->parent) + { + ClassDeclaration *cd; + StructDeclaration *sd; + + cd = s->isClassDeclaration(); + if (cd) + { + type = cd->type; + break; + } + } + + if (type == NULL) { + // We're a top-level function. Generate log messages from the module + args->shift(new StringExp(loc, strdup(sc->module->ident->string))); + } else { + args->shift(new StringExp(loc, type->toChars())); + } + + args->shift(new IntegerExp(loc, level, Type::tint32)); + Expression *callLogger = new CallExp(loc, logger, args); + + Statement *s = new ExpStatement(loc, callLogger); + + return s->semantic(sc); +} + +void LogStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + char *l; + switch (level) { + case 10: l = "log_debug"; break; + case 20: l = "log_info"; break; + case 30: l = "log_warning"; break; + case 40: l = "log_error"; break; + default: + error("Unknown log level %d", level); + l = "log_UNKNOWN"; + } + buf->writestring(l); + buf->writeByte('('); + argsToCBuffer(buf, args, hgs); + buf->writeByte(')'); + buf->writenl(); +} + /******************************** StaticAssertStatement ***************************/ StaticAssertStatement::StaticAssertStatement(StaticAssert *sa) diff --git a/dmd2/statement.h b/dmd2/statement.h index 3daee8f..9f248e7 100644 --- a/dmd2/statement.h +++ b/dmd2/statement.h @@ -164,6 +164,13 @@ struct DeclarationStatement : ExpStatement DeclarationStatement *isDeclarationStatement() { return this; } }; +struct InjectorMainBody : Statement { + ClassDeclaration *mainClass; + + InjectorMainBody(Loc loc, ClassDeclaration *mainClass); + Statement *semantic(Scope *sc); +}; + struct CompoundStatement : Statement { Statements *statements; @@ -426,6 +433,27 @@ struct PragmaStatement : Statement void toIR(IRState *irs); }; +struct LogStatement : Statement +{ + enum Level { + Trace = 0, + Info, + Warn, + Error, + Fatal, + None, + }; + + int level; + Expressions *args; + + LogStatement(Loc loc, int level, Expressions *args); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + struct StaticAssertStatement : Statement { StaticAssert *sa; diff --git a/dmd2/template.c b/dmd2/template.c index 475e5ff..d39af8f 100644 --- a/dmd2/template.c +++ b/dmd2/template.c @@ -261,8 +261,8 @@ void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) /* ======================== TemplateDeclaration ============================= */ -TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs) - : ScopeDsymbol(id) +TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs, bool dltSource) + : ScopeDsymbol(id), dltSource(dltSource) { #if LOG printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars()); @@ -308,7 +308,7 @@ Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) } } d = Dsymbol::arraySyntaxCopy(members); - td = new TemplateDeclaration(loc, ident, p, d); + td = new TemplateDeclaration(loc, ident, p, d, dltSource); return td; } @@ -1324,6 +1324,11 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, if (!tparam) goto Lnomatch; + if (tparam->ty == Tmaybe) + tparam = tparam->nextOf(); + if (this->ty == Tmaybe) + return nextOf()->deduceType(sc, tparam, parameters, dedtypes); + if (this == tparam) goto Lexact; @@ -3158,6 +3163,7 @@ void TemplateInstance::semantic(Scope *sc) sc2 = scope->push(this); //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars()); sc2->parent = /*isnested ? sc->parent :*/ this; + sc2->inDtemplate = !tempdecl->dltSource; #ifndef IN_GCC #if _WIN32 @@ -3824,6 +3830,7 @@ void TemplateInstance::semantic3(Scope *sc) sc = tempdecl->scope; sc = sc->push(argsym); sc = sc->push(this); + sc->inDtemplate = !tempdecl->dltSource; for (int i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; diff --git a/dmd2/template.h b/dmd2/template.h index e518e26..e618149 100644 --- a/dmd2/template.h +++ b/dmd2/template.h @@ -60,7 +60,9 @@ struct TemplateDeclaration : ScopeDsymbol Scope *scope; Dsymbol *onemember; // if !=NULL then one member of this template - TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs); + bool dltSource; // for Delight code, we can do not-null type checks + + TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs, bool dltSource); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); int overloadInsert(Dsymbol *s); diff --git a/dmd2/typinf.c b/dmd2/typinf.c index ab3baf1..726a7b5 100644 --- a/dmd2/typinf.c +++ b/dmd2/typinf.c @@ -170,6 +170,11 @@ TypeInfoDeclaration *TypePointer::getTypeInfoDeclaration() return new TypeInfoPointerDeclaration(this); } +TypeInfoDeclaration *TypeMaybe::getTypeInfoDeclaration() +{ + return new TypeInfoMaybeDeclaration(this); +} + TypeInfoDeclaration *TypeDArray::getTypeInfoDeclaration() { return new TypeInfoArrayDeclaration(this); @@ -351,6 +356,20 @@ void TypeInfoPointerDeclaration::toDt(dt_t **pdt) dtxoff(pdt, tc->next->vtinfo->toSymbol(), 0, TYnptr); // TypeInfo for type being pointed to } +void TypeInfoMaybeDeclaration::toDt(dt_t **pdt) +{ + //printf("TypeInfoMaybeDeclaration::toDt()\n"); + dtxoff(pdt, Type::typeinfomaybe->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Maybe + dtdword(pdt, 0); // monitor + + assert(tinfo->ty == Tmaybe); + + TypeMaybe *tc = (TypeMaybe *)tinfo; + + tc->next->getTypeInfo(NULL); + dtxoff(pdt, tc->next->vtinfo->toSymbol(), 0, TYnptr); // TypeInfo for pointer type +} + void TypeInfoArrayDeclaration::toDt(dt_t **pdt) { //printf("TypeInfoArrayDeclaration::toDt()\n"); -- 2.11.4.GIT