| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| // Compiler implementation of the D programming language | ||
| // Copyright (c) 1999-2015 by Digital Mars | ||
| // All Rights Reserved | ||
| // written by Walter Bright | ||
| // http://www.digitalmars.com | ||
| // Distributed under the Boost Software License, Version 1.0. | ||
| // http://www.boost.org/LICENSE_1_0.txt | ||
|
|
||
| module ddmd.aliasthis; | ||
|
|
||
| import ddmd.aggregate, ddmd.declaration, ddmd.dscope, ddmd.dsymbol, ddmd.errors, ddmd.expression, ddmd.func, ddmd.globals, ddmd.hdrgen, ddmd.identifier, ddmd.mtype, ddmd.opover, ddmd.root.outbuffer, ddmd.tokens, ddmd.visitor; | ||
|
|
||
| /**************************************************************/ | ||
| extern (C++) final class AliasThis : Dsymbol | ||
| { | ||
| public: | ||
| // alias Identifier this; | ||
| Identifier ident; | ||
|
|
||
| // it's anonymous (no identifier) | ||
| extern (D) this(Loc loc, Identifier ident) | ||
| { | ||
| super(null); | ||
| this.loc = loc; | ||
| this.ident = ident; | ||
| } | ||
|
|
||
| Dsymbol syntaxCopy(Dsymbol s) | ||
| { | ||
| assert(!s); | ||
| /* Since there is no semantic information stored here, | ||
| * we don't need to copy it. | ||
| */ | ||
| return this; | ||
| } | ||
|
|
||
| void semantic(Scope* sc) | ||
| { | ||
| Dsymbol p = sc.parent.pastMixin(); | ||
| AggregateDeclaration ad = p.isAggregateDeclaration(); | ||
| if (!ad) | ||
| { | ||
| .error(loc, "alias this can only be a member of aggregate, not %s %s", p.kind(), p.toChars()); | ||
| return; | ||
| } | ||
| assert(ad.members); | ||
| Dsymbol s = ad.search(loc, ident); | ||
| if (!s) | ||
| { | ||
| s = sc.search(loc, ident, null); | ||
| if (s) | ||
| .error(loc, "%s is not a member of %s", s.toChars(), ad.toChars()); | ||
| else | ||
| .error(loc, "undefined identifier %s", ident.toChars()); | ||
| return; | ||
| } | ||
| else if (ad.aliasthis && s != ad.aliasthis) | ||
| { | ||
| .error(loc, "there can be only one alias this"); | ||
| return; | ||
| } | ||
| if (ad.type.ty == Tstruct && (cast(TypeStruct)ad.type).sym != ad) | ||
| { | ||
| AggregateDeclaration ad2 = (cast(TypeStruct)ad.type).sym; | ||
| assert(ad2.type == Type.terror); | ||
| ad.aliasthis = ad2.aliasthis; | ||
| return; | ||
| } | ||
| /* disable the alias this conversion so the implicit conversion check | ||
| * doesn't use it. | ||
| */ | ||
| ad.aliasthis = null; | ||
| Dsymbol sx = s; | ||
| if (sx.isAliasDeclaration()) | ||
| sx = sx.toAlias(); | ||
| Declaration d = sx.isDeclaration(); | ||
| if (d && !d.isTupleDeclaration()) | ||
| { | ||
| Type t = d.type; | ||
| assert(t); | ||
| if (ad.type.implicitConvTo(t) > MATCHnomatch) | ||
| { | ||
| .error(loc, "alias this is not reachable as %s already converts to %s", ad.toChars(), t.toChars()); | ||
| } | ||
| } | ||
| ad.aliasthis = s; | ||
| } | ||
|
|
||
| const(char)* kind() | ||
| { | ||
| return "alias this"; | ||
| } | ||
|
|
||
| AliasThis isAliasThis() | ||
| { | ||
| return this; | ||
| } | ||
|
|
||
| void accept(Visitor v) | ||
| { | ||
| v.visit(this); | ||
| } | ||
| } | ||
|
|
||
| extern (C++) Expression resolveAliasThis(Scope* sc, Expression e) | ||
| { | ||
| AggregateDeclaration ad = isAggregate(e.type); | ||
| if (ad && ad.aliasthis) | ||
| { | ||
| Loc loc = e.loc; | ||
| Type tthis = (e.op == TOKtype ? e.type : null); | ||
| e = new DotIdExp(loc, e, ad.aliasthis.ident); | ||
| e = e.semantic(sc); | ||
| if (tthis && ad.aliasthis.needThis()) | ||
| { | ||
| if (e.op == TOKvar) | ||
| { | ||
| if (FuncDeclaration f = (cast(VarExp)e).var.isFuncDeclaration()) | ||
| { | ||
| // Bugzilla 13009: Support better match for the overloaded alias this. | ||
| Type t; | ||
| f = f.overloadModMatch(loc, tthis, t); | ||
| if (f && t) | ||
| { | ||
| e = new VarExp(loc, f, 0); // use better match | ||
| e = new CallExp(loc, e); | ||
| goto L1; | ||
| } | ||
| } | ||
| } | ||
| /* non-@property function is not called inside typeof(), | ||
| * so resolve it ahead. | ||
| */ | ||
| { | ||
| int save = sc.intypeof; | ||
| sc.intypeof = 1; // bypass "need this" error check | ||
| e = resolveProperties(sc, e); | ||
| sc.intypeof = save; | ||
| } | ||
| L1: | ||
| e = new TypeExp(loc, new TypeTypeof(loc, e)); | ||
| e = e.semantic(sc); | ||
| } | ||
| e = resolveProperties(sc, e); | ||
| } | ||
| return e; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,143 @@ | ||
| // Compiler implementation of the D programming language | ||
| // Copyright (c) 1999-2015 by Digital Mars | ||
| // All Rights Reserved | ||
| // written by Walter Bright | ||
| // http://www.digitalmars.com | ||
| // Distributed under the Boost Software License, Version 1.0. | ||
| // http://www.boost.org/LICENSE_1_0.txt | ||
|
|
||
| module ddmd.apply; | ||
|
|
||
| import ddmd.arraytypes, ddmd.expression, ddmd.visitor; | ||
|
|
||
| /************************************** | ||
| * An Expression tree walker that will visit each Expression e in the tree, | ||
| * in depth-first evaluation order, and call fp(e,param) on it. | ||
| * fp() signals whether the walking continues with its return value: | ||
| * Returns: | ||
| * 0 continue | ||
| * 1 done | ||
| * It's a bit slower than using virtual functions, but more encapsulated and less brittle. | ||
| * Creating an iterator for this would be much more complex. | ||
| */ | ||
| extern (C++) final class PostorderExpressionVisitor : StoppableVisitor | ||
| { | ||
| alias visit = super.visit; | ||
| public: | ||
| StoppableVisitor v; | ||
|
|
||
| extern (D) this(StoppableVisitor v) | ||
| { | ||
| this.v = v; | ||
| } | ||
|
|
||
| bool doCond(Expression e) | ||
| { | ||
| if (!stop && e) | ||
| e.accept(this); | ||
| return stop; | ||
| } | ||
|
|
||
| bool doCond(Expressions* e) | ||
| { | ||
| if (!e) | ||
| return false; | ||
| for (size_t i = 0; i < e.dim && !stop; i++) | ||
| doCond((*e)[i]); | ||
| return stop; | ||
| } | ||
|
|
||
| bool applyTo(Expression e) | ||
| { | ||
| e.accept(v); | ||
| stop = v.stop; | ||
| return true; | ||
| } | ||
|
|
||
| void visit(Expression e) | ||
| { | ||
| applyTo(e); | ||
| } | ||
|
|
||
| void visit(NewExp e) | ||
| { | ||
| //printf("NewExp::apply(): %s\n", toChars()); | ||
| doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e); | ||
| } | ||
|
|
||
| void visit(NewAnonClassExp e) | ||
| { | ||
| //printf("NewAnonClassExp::apply(): %s\n", toChars()); | ||
| doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e); | ||
| } | ||
|
|
||
| void visit(UnaExp e) | ||
| { | ||
| doCond(e.e1) || applyTo(e); | ||
| } | ||
|
|
||
| void visit(BinExp e) | ||
| { | ||
| doCond(e.e1) || doCond(e.e2) || applyTo(e); | ||
| } | ||
|
|
||
| void visit(AssertExp e) | ||
| { | ||
| //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); | ||
| doCond(e.e1) || doCond(e.msg) || applyTo(e); | ||
| } | ||
|
|
||
| void visit(CallExp e) | ||
| { | ||
| //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); | ||
| doCond(e.e1) || doCond(e.arguments) || applyTo(e); | ||
| } | ||
|
|
||
| void visit(ArrayExp e) | ||
| { | ||
| //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); | ||
| doCond(e.e1) || doCond(e.arguments) || applyTo(e); | ||
| } | ||
|
|
||
| void visit(SliceExp e) | ||
| { | ||
| doCond(e.e1) || doCond(e.lwr) || doCond(e.upr) || applyTo(e); | ||
| } | ||
|
|
||
| void visit(ArrayLiteralExp e) | ||
| { | ||
| doCond(e.elements) || applyTo(e); | ||
| } | ||
|
|
||
| void visit(AssocArrayLiteralExp e) | ||
| { | ||
| doCond(e.keys) || doCond(e.values) || applyTo(e); | ||
| } | ||
|
|
||
| void visit(StructLiteralExp e) | ||
| { | ||
| if (e.stageflags & stageApply) | ||
| return; | ||
| int old = e.stageflags; | ||
| e.stageflags |= stageApply; | ||
| doCond(e.elements) || applyTo(e); | ||
| e.stageflags = old; | ||
| } | ||
|
|
||
| void visit(TupleExp e) | ||
| { | ||
| doCond(e.e0) || doCond(e.exps) || applyTo(e); | ||
| } | ||
|
|
||
| void visit(CondExp e) | ||
| { | ||
| doCond(e.econd) || doCond(e.e1) || doCond(e.e2) || applyTo(e); | ||
| } | ||
| } | ||
|
|
||
| extern (C++) bool walkPostorder(Expression e, StoppableVisitor v) | ||
| { | ||
| scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v); | ||
| e.accept(pv); | ||
| return v.stop; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| // Compiler implementation of the D programming language | ||
| // Copyright (c) 1999-2015 by Digital Mars | ||
| // All Rights Reserved | ||
| // written by Walter Bright | ||
| // http://www.digitalmars.com | ||
| // Distributed under the Boost Software License, Version 1.0. | ||
| // http://www.boost.org/LICENSE_1_0.txt | ||
|
|
||
| module ddmd.arraytypes; | ||
|
|
||
| import ddmd.aggregate, ddmd.backend, ddmd.dclass, ddmd.declaration, ddmd.dmodule, ddmd.dsymbol, ddmd.dtemplate, ddmd.expression, ddmd.func, ddmd.globals, ddmd.identifier, ddmd.init, ddmd.mtype, ddmd.root.array, ddmd.root.file, ddmd.root.rootobject, ddmd.statement; | ||
|
|
||
| alias Strings = Array!(const(char)*); | ||
| alias Identifiers = Array!(Identifier); | ||
| alias TemplateParameters = Array!(TemplateParameter); | ||
| alias Expressions = Array!(Expression); | ||
| alias Statements = Array!(Statement); | ||
| alias BaseClasses = Array!(BaseClass*); | ||
| alias ClassDeclarations = Array!(ClassDeclaration); | ||
| alias Dsymbols = Array!(Dsymbol); | ||
| alias Objects = Array!(RootObject); | ||
| alias FuncDeclarations = Array!(FuncDeclaration); | ||
| alias Parameters = Array!(Parameter); | ||
| alias Initializers = Array!(Initializer); | ||
| alias VarDeclarations = Array!(VarDeclaration); | ||
| alias Types = Array!(Type); | ||
| alias Catches = Array!(Catch); | ||
| alias StaticDtorDeclarations = Array!(StaticDtorDeclaration); | ||
| alias SharedStaticDtorDeclarations = Array!(SharedStaticDtorDeclaration); | ||
| alias AliasDeclarations = Array!(AliasDeclaration); | ||
| alias Modules = Array!(Module); | ||
| alias CaseStatements = Array!(CaseStatement); | ||
| alias ScopeStatements = Array!(ScopeStatement); | ||
| alias GotoCaseStatements = Array!(GotoCaseStatement); | ||
| alias ReturnStatements = Array!(ReturnStatement); | ||
| alias GotoStatements = Array!(GotoStatement); | ||
| alias TemplateInstances = Array!(TemplateInstance); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,221 @@ | ||
| // Compiler implementation of the D programming language | ||
| // Copyright (c) 1999-2015 by Digital Mars | ||
| // All Rights Reserved | ||
| // written by Walter Bright | ||
| // http://www.digitalmars.com | ||
| // Distributed under the Boost Software License, Version 1.0. | ||
| // http://www.boost.org/LICENSE_1_0.txt | ||
|
|
||
| module ddmd.canthrow; | ||
|
|
||
| import ddmd.apply, ddmd.arraytypes, ddmd.attrib, ddmd.declaration, ddmd.dstruct, ddmd.dsymbol, ddmd.dtemplate, ddmd.expression, ddmd.func, ddmd.globals, ddmd.init, ddmd.mtype, ddmd.root.rootobject, ddmd.tokens, ddmd.visitor; | ||
|
|
||
| /******************************************** | ||
| * Returns true if the expression may throw exceptions. | ||
| * If 'mustNotThrow' is true, generate an error if it throws | ||
| */ | ||
| extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow) | ||
| { | ||
| //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars()); | ||
| // stop walking if we determine this expression can throw | ||
| extern (C++) final class CanThrow : StoppableVisitor | ||
| { | ||
| alias visit = super.visit; | ||
| FuncDeclaration func; | ||
| bool mustNotThrow; | ||
|
|
||
| public: | ||
| extern (D) this(FuncDeclaration func, bool mustNotThrow) | ||
| { | ||
| this.func = func; | ||
| this.mustNotThrow = mustNotThrow; | ||
| } | ||
|
|
||
| void visit(Expression) | ||
| { | ||
| } | ||
|
|
||
| void visit(DeclarationExp de) | ||
| { | ||
| stop = Dsymbol_canThrow(de.declaration, func, mustNotThrow); | ||
| } | ||
|
|
||
| void visit(CallExp ce) | ||
| { | ||
| if (global.errors && !ce.e1.type) | ||
| return; // error recovery | ||
| /* If calling a function or delegate that is typed as nothrow, | ||
| * then this expression cannot throw. | ||
| * Note that pure functions can throw. | ||
| */ | ||
| Type t = ce.e1.type.toBasetype(); | ||
| if (ce.f && ce.f == func) | ||
| { | ||
| } | ||
| else if (t.ty == Tfunction && (cast(TypeFunction)t).isnothrow) | ||
| { | ||
| } | ||
| else if (t.ty == Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).isnothrow) | ||
| { | ||
| } | ||
| else | ||
| { | ||
| if (mustNotThrow) | ||
| { | ||
| const(char)* s; | ||
| if (ce.f) | ||
| s = ce.f.toPrettyChars(); | ||
| else if (ce.e1.op == TOKstar) | ||
| { | ||
| // print 'fp' if ce->e1 is (*fp) | ||
| s = (cast(PtrExp)ce.e1).e1.toChars(); | ||
| } | ||
| else | ||
| s = ce.e1.toChars(); | ||
| ce.error("'%s' is not nothrow", s); | ||
| } | ||
| stop = true; | ||
| } | ||
| } | ||
|
|
||
| void visit(NewExp ne) | ||
| { | ||
| if (ne.member) | ||
| { | ||
| // See if constructor call can throw | ||
| Type t = ne.member.type.toBasetype(); | ||
| if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) | ||
| { | ||
| if (mustNotThrow) | ||
| ne.error("constructor %s is not nothrow", ne.member.toChars()); | ||
| stop = true; | ||
| } | ||
| } | ||
| // regard storage allocation failures as not recoverable | ||
| } | ||
|
|
||
| void visit(AssignExp ae) | ||
| { | ||
| // blit-init cannot throw | ||
| if (ae.op == TOKblit) | ||
| return; | ||
| /* Element-wise assignment could invoke postblits. | ||
| */ | ||
| Type t; | ||
| if (ae.type.toBasetype().ty == Tsarray) | ||
| { | ||
| if (!ae.e2.isLvalue()) | ||
| return; | ||
| t = ae.type; | ||
| } | ||
| else if (ae.e1.op == TOKslice) | ||
| t = (cast(SliceExp)ae.e1).e1.type; | ||
| else | ||
| return; | ||
| Type tv = t.baseElemOf(); | ||
| if (tv.ty != Tstruct) | ||
| return; | ||
| StructDeclaration sd = (cast(TypeStruct)tv).sym; | ||
| if (!sd.postblit || sd.postblit.type.ty != Tfunction) | ||
| return; | ||
| if ((cast(TypeFunction)sd.postblit.type).isnothrow) | ||
| { | ||
| } | ||
| else | ||
| { | ||
| if (mustNotThrow) | ||
| ae.error("'%s' is not nothrow", sd.postblit.toPrettyChars()); | ||
| stop = true; | ||
| } | ||
| } | ||
|
|
||
| void visit(NewAnonClassExp) | ||
| { | ||
| assert(0); // should have been lowered by semantic() | ||
| } | ||
| } | ||
|
|
||
| scope CanThrow ct = new CanThrow(func, mustNotThrow); | ||
| return walkPostorder(e, ct); | ||
| } | ||
|
|
||
| /************************************** | ||
| * Does symbol, when initialized, throw? | ||
| * Mirrors logic in Dsymbol_toElem(). | ||
| */ | ||
| extern (C++) bool Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow) | ||
| { | ||
| AttribDeclaration ad; | ||
| VarDeclaration vd; | ||
| TemplateMixin tm; | ||
| TupleDeclaration td; | ||
| //printf("Dsymbol_toElem() %s\n", s->toChars()); | ||
| ad = s.isAttribDeclaration(); | ||
| if (ad) | ||
| { | ||
| Dsymbols* decl = ad.include(null, null); | ||
| if (decl && decl.dim) | ||
| { | ||
| for (size_t i = 0; i < decl.dim; i++) | ||
| { | ||
| s = (*decl)[i]; | ||
| if (Dsymbol_canThrow(s, func, mustNotThrow)) | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
| else if ((vd = s.isVarDeclaration()) !is null) | ||
| { | ||
| s = s.toAlias(); | ||
| if (s != vd) | ||
| return Dsymbol_canThrow(s, func, mustNotThrow); | ||
| if (vd.storage_class & STCmanifest) | ||
| { | ||
| } | ||
| else if (vd.isStatic() || vd.storage_class & (STCextern | STCtls | STCgshared)) | ||
| { | ||
| } | ||
| else | ||
| { | ||
| if (vd._init) | ||
| { | ||
| ExpInitializer ie = vd._init.isExpInitializer(); | ||
| if (ie && canThrow(ie.exp, func, mustNotThrow)) | ||
| return true; | ||
| } | ||
| if (vd.edtor && !vd.noscope) | ||
| return canThrow(vd.edtor, func, mustNotThrow); | ||
| } | ||
| } | ||
| else if ((tm = s.isTemplateMixin()) !is null) | ||
| { | ||
| //printf("%s\n", tm->toChars()); | ||
| if (tm.members) | ||
| { | ||
| for (size_t i = 0; i < tm.members.dim; i++) | ||
| { | ||
| Dsymbol sm = (*tm.members)[i]; | ||
| if (Dsymbol_canThrow(sm, func, mustNotThrow)) | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
| else if ((td = s.isTupleDeclaration()) !is null) | ||
| { | ||
| for (size_t i = 0; i < td.objects.dim; i++) | ||
| { | ||
| RootObject o = (*td.objects)[i]; | ||
| if (o.dyncast() == DYNCAST_EXPRESSION) | ||
| { | ||
| Expression eo = cast(Expression)o; | ||
| if (eo.op == TOKdsymbol) | ||
| { | ||
| DsymbolExp se = cast(DsymbolExp)eo; | ||
| if (Dsymbol_canThrow(se.s, func, mustNotThrow)) | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return false; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| // Compiler implementation of the D programming language | ||
| // Copyright (c) 1999-2015 by Digital Mars | ||
| // All Rights Reserved | ||
| // written by Walter Bright | ||
| // http://www.digitalmars.com | ||
| // Distributed under the Boost Software License, Version 1.0. | ||
| // http://www.boost.org/LICENSE_1_0.txt | ||
|
|
||
| module ddmd.delegatize; | ||
|
|
||
| import ddmd.apply, ddmd.declaration, ddmd.dscope, ddmd.expression, ddmd.func, ddmd.globals, ddmd.mtype, ddmd.statement, ddmd.tokens, ddmd.visitor; | ||
|
|
||
| extern (C++) Expression toDelegate(Expression e, Type t, Scope* sc) | ||
| { | ||
| //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), e->toChars()); | ||
| Loc loc = e.loc; | ||
| auto tf = new TypeFunction(null, t, 0, LINKd); | ||
| if (t.hasWild()) | ||
| tf.mod = MODwild; | ||
| auto fld = new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, null); | ||
| sc = sc.push(); | ||
| sc.parent = fld; // set current function to be the delegate | ||
| lambdaSetParent(e, sc); | ||
| bool r = lambdaCheckForNestedRef(e, sc); | ||
| sc = sc.pop(); | ||
| if (r) | ||
| return new ErrorExp(); | ||
| Statement s; | ||
| if (t.ty == Tvoid) | ||
| s = new ExpStatement(loc, e); | ||
| else | ||
| s = new ReturnStatement(loc, e); | ||
| fld.fbody = s; | ||
| e = new FuncExp(loc, fld); | ||
| e = e.semantic(sc); | ||
| return e; | ||
| } | ||
|
|
||
| /****************************************** | ||
| * Patch the parent of declarations to be the new function literal. | ||
| */ | ||
| extern (C++) void lambdaSetParent(Expression e, Scope* sc) | ||
| { | ||
| extern (C++) final class LambdaSetParent : StoppableVisitor | ||
| { | ||
| alias visit = super.visit; | ||
| Scope* sc; | ||
|
|
||
| public: | ||
| extern (D) this(Scope* sc) | ||
| { | ||
| this.sc = sc; | ||
| } | ||
|
|
||
| void visit(Expression) | ||
| { | ||
| } | ||
|
|
||
| void visit(DeclarationExp e) | ||
| { | ||
| e.declaration.parent = sc.parent; | ||
| } | ||
|
|
||
| void visit(IndexExp e) | ||
| { | ||
| if (e.lengthVar) | ||
| { | ||
| //printf("lengthVar\n"); | ||
| e.lengthVar.parent = sc.parent; | ||
| } | ||
| } | ||
|
|
||
| void visit(SliceExp e) | ||
| { | ||
| if (e.lengthVar) | ||
| { | ||
| //printf("lengthVar\n"); | ||
| e.lengthVar.parent = sc.parent; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| scope LambdaSetParent lsp = new LambdaSetParent(sc); | ||
| walkPostorder(e, lsp); | ||
| } | ||
|
|
||
| /******************************************* | ||
| * Look for references to variables in a scope enclosing the new function literal. | ||
| * Returns true if error occurs. | ||
| */ | ||
| extern (C++) bool lambdaCheckForNestedRef(Expression e, Scope* sc) | ||
| { | ||
| extern (C++) final class LambdaCheckForNestedRef : StoppableVisitor | ||
| { | ||
| alias visit = super.visit; | ||
| public: | ||
| Scope* sc; | ||
| bool result; | ||
|
|
||
| extern (D) this(Scope* sc) | ||
| { | ||
| this.sc = sc; | ||
| this.result = false; | ||
| } | ||
|
|
||
| void visit(Expression) | ||
| { | ||
| } | ||
|
|
||
| void visit(SymOffExp e) | ||
| { | ||
| VarDeclaration v = e.var.isVarDeclaration(); | ||
| if (v) | ||
| result = v.checkNestedReference(sc, Loc()); | ||
| } | ||
|
|
||
| void visit(VarExp e) | ||
| { | ||
| VarDeclaration v = e.var.isVarDeclaration(); | ||
| if (v) | ||
| result = v.checkNestedReference(sc, Loc()); | ||
| } | ||
|
|
||
| void visit(ThisExp e) | ||
| { | ||
| VarDeclaration v = e.var.isVarDeclaration(); | ||
| if (v) | ||
| result = v.checkNestedReference(sc, Loc()); | ||
| } | ||
|
|
||
| void visit(DeclarationExp e) | ||
| { | ||
| VarDeclaration v = e.declaration.isVarDeclaration(); | ||
| if (v) | ||
| { | ||
| result = v.checkNestedReference(sc, Loc()); | ||
| if (result) | ||
| return; | ||
| /* Some expressions cause the frontend to create a temporary. | ||
| * For example, structs with cpctors replace the original | ||
| * expression e with: | ||
| * __cpcttmp = __cpcttmp.cpctor(e); | ||
| * | ||
| * In this instance, we need to ensure that the original | ||
| * expression e does not have any nested references by | ||
| * checking the declaration initializer too. | ||
| */ | ||
| if (v._init && v._init.isExpInitializer()) | ||
| { | ||
| Expression ie = v._init.toExpression(); | ||
| result = lambdaCheckForNestedRef(ie, sc); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| scope LambdaCheckForNestedRef v = new LambdaCheckForNestedRef(sc); | ||
| walkPostorder(e, v); | ||
| return v.result; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,332 @@ | ||
| // Compiler implementation of the D programming language | ||
| // Copyright (c) 1999-2015 by Digital Mars | ||
| // All Rights Reserved | ||
| // written by Walter Bright | ||
| // http://www.digitalmars.com | ||
| // Distributed under the Boost Software License, Version 1.0. | ||
| // http://www.boost.org/LICENSE_1_0.txt | ||
|
|
||
| module ddmd.dinifile; | ||
|
|
||
| import core.stdc.ctype, core.stdc.stdlib, core.stdc.string, core.sys.posix.stdlib, core.sys.windows.windows; | ||
| import ddmd.globals, ddmd.root.file, ddmd.root.filename, ddmd.root.outbuffer, ddmd.root.port, ddmd.root.stringtable; | ||
|
|
||
| version (Windows) extern (C) int putenv(const char*); | ||
| private enum LOG = false; | ||
|
|
||
| /***************************** | ||
| * Find the config file | ||
| * Input: | ||
| * argv0 program name (argv[0]) | ||
| * inifile .ini file name | ||
| * Returns: | ||
| * file path of the config file or NULL | ||
| * Note: this is a memory leak | ||
| */ | ||
| extern (C++) const(char)* findConfFile(const(char)* argv0, const(char)* inifile) | ||
| { | ||
| static if (LOG) | ||
| { | ||
| printf("findinifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile); | ||
| } | ||
| if (FileName.absolute(inifile)) | ||
| return inifile; | ||
| if (FileName.exists(inifile)) | ||
| return inifile; | ||
| /* Look for inifile in the following sequence of places: | ||
| * o current directory | ||
| * o home directory | ||
| * o exe directory (windows) | ||
| * o directory off of argv0 | ||
| * o SYSCONFDIR (default=/etc/) (non-windows) | ||
| */ | ||
| const(char)* filename = FileName.combine(getenv("HOME"), inifile); | ||
| if (FileName.exists(filename)) | ||
| return filename; | ||
| version (Windows) | ||
| { | ||
| // This fix by Tim Matthews | ||
| char[MAX_PATH + 1] resolved_name; | ||
| if (GetModuleFileNameA(null, resolved_name.ptr, MAX_PATH + 1) && FileName.exists(resolved_name.ptr)) | ||
| { | ||
| filename = FileName.replaceName(resolved_name.ptr, inifile); | ||
| if (FileName.exists(filename)) | ||
| return filename; | ||
| } | ||
| } | ||
| filename = FileName.replaceName(argv0, inifile); | ||
| if (FileName.exists(filename)) | ||
| return filename; | ||
| static if (__linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun) | ||
| { | ||
| // Search PATH for argv0 | ||
| const(char)* p = getenv("PATH"); | ||
| static if (LOG) | ||
| { | ||
| printf("\tPATH='%s'\n", p); | ||
| } | ||
| Strings* paths = FileName.splitPath(p); | ||
| const(char)* abspath = FileName.searchPath(paths, argv0, false); | ||
| if (abspath) | ||
| { | ||
| const(char)* absname = FileName.replaceName(abspath, inifile); | ||
| if (FileName.exists(absname)) | ||
| return absname; | ||
| } | ||
| // Resolve symbolic links | ||
| filename = FileName.canonicalName(abspath ? abspath : argv0); | ||
| if (filename) | ||
| { | ||
| filename = FileName.replaceName(filename, inifile); | ||
| if (FileName.exists(filename)) | ||
| return filename; | ||
| } | ||
| // Search /etc/ for inifile | ||
| enum SYSCONFDIR = "/etc/dmd.conf"; | ||
| assert(SYSCONFDIR !is null && strlen(SYSCONFDIR)); | ||
| filename = FileName.combine(SYSCONFDIR, inifile); | ||
| } | ||
| // __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun | ||
| return filename; | ||
| } | ||
|
|
||
| /********************************** | ||
| * Read from environment, looking for cached value first. | ||
| */ | ||
| extern (C++) const(char)* readFromEnv(StringTable* environment, const(char)* name) | ||
| { | ||
| size_t len = strlen(name); | ||
| StringValue* sv = environment.lookup(name, len); | ||
| if (sv) | ||
| return cast(const(char)*)sv.ptrvalue; // get cached value | ||
| return getenv(name); | ||
| } | ||
|
|
||
| /********************************* | ||
| * Write to our copy of the environment, not the real environment | ||
| */ | ||
| extern (C++) static void writeToEnv(StringTable* environment, char* nameEqValue) | ||
| { | ||
| char* p = strchr(nameEqValue, '='); | ||
| assert(p); | ||
| StringValue* sv = environment.update(nameEqValue, p - nameEqValue); | ||
| sv.ptrvalue = cast(void*)(p + 1); | ||
| } | ||
|
|
||
| /************************************ | ||
| * Update real enviroment with our copy. | ||
| */ | ||
| extern (C++) static int envput(StringValue* sv) | ||
| { | ||
| const(char)* name = sv.toDchars(); | ||
| size_t namelen = strlen(name); | ||
| const(char)* value = cast(const(char)*)sv.ptrvalue; | ||
| size_t valuelen = strlen(value); | ||
| char* s = cast(char*)malloc(namelen + 1 + valuelen + 1); | ||
| assert(s); | ||
| memcpy(s, name, namelen); | ||
| s[namelen] = '='; | ||
| memcpy(s + namelen + 1, value, valuelen); | ||
| s[namelen + 1 + valuelen] = 0; | ||
| //printf("envput('%s')\n", s); | ||
| putenv(s); | ||
| return 0; // do all of them | ||
| } | ||
|
|
||
| extern (C++) void updateRealEnvironment(StringTable* environment) | ||
| { | ||
| environment.apply(&envput); | ||
| } | ||
|
|
||
| /***************************** | ||
| * Read and analyze .ini file. | ||
| * Write the entries into environment as | ||
| * well as any entries in one of the specified section(s). | ||
| * | ||
| * Params: | ||
| * environment = our own cache of the program environment | ||
| * path = what @P will expand to | ||
| * buffer[len] = contents of configuration file | ||
| * sections[] = section namesdimension of array of section names | ||
| */ | ||
| extern (C++) void parseConfFile(StringTable* environment, const(char)* path, size_t length, ubyte* buffer, Strings* sections) | ||
| { | ||
| // Parse into lines | ||
| bool envsection = true; // default is to read | ||
| OutBuffer buf; | ||
| bool eof = false; | ||
| for (size_t i = 0; i < length && !eof; i++) | ||
| { | ||
| Lstart: | ||
| size_t linestart = i; | ||
| for (; i < length; i++) | ||
| { | ||
| switch (buffer[i]) | ||
| { | ||
| case '\r': | ||
| break; | ||
| case '\n': | ||
| // Skip if it was preceded by '\r' | ||
| if (i && buffer[i - 1] == '\r') | ||
| { | ||
| i++; | ||
| goto Lstart; | ||
| } | ||
| break; | ||
| case 0: | ||
| case 0x1A: | ||
| eof = true; | ||
| break; | ||
| default: | ||
| continue; | ||
| } | ||
| break; | ||
| } | ||
| buf.reset(); | ||
| // First, expand the macros. | ||
| // Macros are bracketed by % characters. | ||
| for (size_t k = 0; k < i - linestart; k++) | ||
| { | ||
| // The line is buffer[linestart..i] | ||
| char* line = cast(char*)&buffer[linestart]; | ||
| if (line[k] == '%') | ||
| { | ||
| for (size_t j = k + 1; j < i - linestart; j++) | ||
| { | ||
| if (line[j] != '%') | ||
| continue; | ||
| if (j - k == 3 && Port.memicmp(&line[k + 1], "@P", 2) == 0) | ||
| { | ||
| // %@P% is special meaning the path to the .ini file | ||
| const(char)* p = path; | ||
| if (!*p) | ||
| p = "."; | ||
| buf.writestring(p); | ||
| } | ||
| else | ||
| { | ||
| size_t len2 = j - k; | ||
| char* p = cast(char*)malloc(len2); | ||
| len2--; | ||
| memcpy(p, &line[k + 1], len2); | ||
| p[len2] = 0; | ||
| Port.strupr(p); | ||
| const(char)* penv = readFromEnv(environment, p); | ||
| if (penv) | ||
| buf.writestring(penv); | ||
| free(p); | ||
| } | ||
| k = j; | ||
| goto L1; | ||
| } | ||
| } | ||
| buf.writeByte(line[k]); | ||
| L1: | ||
| } | ||
| // Remove trailing spaces | ||
| while (buf.offset && isspace(buf.data[buf.offset - 1])) | ||
| buf.offset--; | ||
| char* p = buf.peekString(); | ||
| // The expanded line is in p. | ||
| // Now parse it for meaning. | ||
| p = skipspace(p); | ||
| switch (*p) | ||
| { | ||
| case ';': | ||
| // comment | ||
| case 0: | ||
| // blank | ||
| break; | ||
| case '[': | ||
| // look for [Environment] | ||
| p = skipspace(p + 1); | ||
| char* pn; | ||
| for (pn = p; isalnum(cast(char)*pn); pn++) | ||
| { | ||
| } | ||
| if (*skipspace(pn) != ']') | ||
| { | ||
| // malformed [sectionname], so just say we're not in a section | ||
| envsection = false; | ||
| break; | ||
| } | ||
| /* Seach sectionnamev[] for p..pn and set envsection to true if it's there | ||
| */ | ||
| for (size_t j = 0; 1; ++j) | ||
| { | ||
| if (j == sections.dim) | ||
| { | ||
| // Didn't find it | ||
| envsection = false; | ||
| break; | ||
| } | ||
| const(char)* sectionname = (*sections)[j]; | ||
| size_t len = strlen(sectionname); | ||
| if (pn - p == len && Port.memicmp(p, sectionname, len) == 0) | ||
| { | ||
| envsection = true; | ||
| break; | ||
| } | ||
| } | ||
| break; | ||
| default: | ||
| if (envsection) | ||
| { | ||
| char* pn = p; | ||
| // Convert name to upper case; | ||
| // remove spaces bracketing = | ||
| for (p = pn; *p; p++) | ||
| { | ||
| if (islower(cast(char)*p)) | ||
| *p &= ~0x20; | ||
| else if (isspace(cast(char)*p)) | ||
| { | ||
| memmove(p, p + 1, strlen(p)); | ||
| p--; | ||
| } | ||
| else if (p[0] == '?' && p[1] == '=') | ||
| { | ||
| *p = '\0'; | ||
| if (readFromEnv(environment, pn)) | ||
| { | ||
| pn = null; | ||
| break; | ||
| } | ||
| // remove the '?' and resume parsing starting from | ||
| // '=' again so the regular variable format is | ||
| // parsed | ||
| memmove(p, p + 1, strlen(p + 1) + 1); | ||
| p--; | ||
| } | ||
| else if (*p == '=') | ||
| { | ||
| p++; | ||
| while (isspace(cast(char)*p)) | ||
| memmove(p, p + 1, strlen(p)); | ||
| break; | ||
| } | ||
| } | ||
| if (pn) | ||
| { | ||
| writeToEnv(environment, strdup(pn)); | ||
| static if (LOG) | ||
| { | ||
| printf("\tputenv('%s')\n", pn); | ||
| //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST")); | ||
| } | ||
| } | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /******************** | ||
| * Skip spaces. | ||
| */ | ||
| extern (C++) char* skipspace(char* p) | ||
| { | ||
| while (isspace(cast(char)*p)) | ||
| p++; | ||
| return p; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| // Compiler implementation of the D programming language | ||
| // Copyright (c) 1999-2015 by Digital Mars | ||
| // All Rights Reserved | ||
| // written by Walter Bright | ||
| // http://www.digitalmars.com | ||
| // Distributed under the Boost Software License, Version 1.0. | ||
| // http://www.boost.org/LICENSE_1_0.txt | ||
|
|
||
| module ddmd.dunittest; | ||
|
|
||
| extern (C++) void unittests() | ||
| { | ||
| version (unittest) | ||
| { | ||
| unittest_speller(); | ||
| unittest_importHint(); | ||
| unittest_aa(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| // Compiler implementation of the D programming language | ||
| // Copyright (c) 1999-2015 by Digital Mars | ||
| // All Rights Reserved | ||
| // written by Walter Bright | ||
| // http://www.digitalmars.com | ||
| // Distributed under the Boost Software License, Version 1.0. | ||
| // http://www.boost.org/LICENSE_1_0.txt | ||
|
|
||
| module ddmd.dversion; | ||
|
|
||
| import ddmd.arraytypes, ddmd.cond, ddmd.dmodule, ddmd.dmodule, ddmd.dscope, ddmd.dsymbol, ddmd.globals, ddmd.hdrgen, ddmd.identifier, ddmd.root.outbuffer, ddmd.visitor; | ||
|
|
||
| extern (C++) final class DebugSymbol : Dsymbol | ||
| { | ||
| public: | ||
| uint level; | ||
|
|
||
| /* ================================================== */ | ||
| /* DebugSymbol's happen for statements like: | ||
| * debug = identifier; | ||
| * debug = integer; | ||
| */ | ||
| extern (D) this(Loc loc, Identifier ident) | ||
| { | ||
| super(ident); | ||
| this.loc = loc; | ||
| } | ||
|
|
||
| extern (D) this(Loc loc, uint level) | ||
| { | ||
| super(); | ||
| this.level = level; | ||
| this.loc = loc; | ||
| } | ||
|
|
||
| Dsymbol syntaxCopy(Dsymbol s) | ||
| { | ||
| assert(!s); | ||
| auto ds = new DebugSymbol(loc, ident); | ||
| ds.level = level; | ||
| return ds; | ||
| } | ||
|
|
||
| char* toChars() | ||
| { | ||
| if (ident) | ||
| return ident.toChars(); | ||
| else | ||
| { | ||
| OutBuffer buf; | ||
| buf.printf("%d", level); | ||
| return buf.extractString(); | ||
| } | ||
| } | ||
|
|
||
| void addMember(Scope* sc, ScopeDsymbol sds) | ||
| { | ||
| //printf("DebugSymbol::addMember('%s') %s\n", sds->toChars(), toChars()); | ||
| Module m = sds.isModule(); | ||
| // Do not add the member to the symbol table, | ||
| // just make sure subsequent debug declarations work. | ||
| if (ident) | ||
| { | ||
| if (!m) | ||
| { | ||
| error("declaration must be at module level"); | ||
| errors = true; | ||
| } | ||
| else | ||
| { | ||
| if (findCondition(m.debugidsNot, ident)) | ||
| { | ||
| error("defined after use"); | ||
| errors = true; | ||
| } | ||
| if (!m.debugids) | ||
| m.debugids = new Strings(); | ||
| m.debugids.push(ident.toChars()); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| if (!m) | ||
| { | ||
| error("level declaration must be at module level"); | ||
| errors = true; | ||
| } | ||
| else | ||
| m.debuglevel = level; | ||
| } | ||
| } | ||
|
|
||
| void semantic(Scope* sc) | ||
| { | ||
| //printf("DebugSymbol::semantic() %s\n", toChars()); | ||
| } | ||
|
|
||
| const(char)* kind() | ||
| { | ||
| return "debug"; | ||
| } | ||
|
|
||
| void accept(Visitor v) | ||
| { | ||
| v.visit(this); | ||
| } | ||
| } | ||
|
|
||
| extern (C++) final class VersionSymbol : Dsymbol | ||
| { | ||
| public: | ||
| uint level; | ||
|
|
||
| /* ================================================== */ | ||
| /* VersionSymbol's happen for statements like: | ||
| * version = identifier; | ||
| * version = integer; | ||
| */ | ||
| extern (D) this(Loc loc, Identifier ident) | ||
| { | ||
| super(ident); | ||
| this.loc = loc; | ||
| } | ||
|
|
||
| extern (D) this(Loc loc, uint level) | ||
| { | ||
| super(); | ||
| this.level = level; | ||
| this.loc = loc; | ||
| } | ||
|
|
||
| Dsymbol syntaxCopy(Dsymbol s) | ||
| { | ||
| assert(!s); | ||
| auto ds = new VersionSymbol(loc, ident); | ||
| ds.level = level; | ||
| return ds; | ||
| } | ||
|
|
||
| char* toChars() | ||
| { | ||
| if (ident) | ||
| return ident.toChars(); | ||
| else | ||
| { | ||
| OutBuffer buf; | ||
| buf.printf("%d", level); | ||
| return buf.extractString(); | ||
| } | ||
| } | ||
|
|
||
| void addMember(Scope* sc, ScopeDsymbol sds) | ||
| { | ||
| //printf("VersionSymbol::addMember('%s') %s\n", sds->toChars(), toChars()); | ||
| Module m = sds.isModule(); | ||
| // Do not add the member to the symbol table, | ||
| // just make sure subsequent debug declarations work. | ||
| if (ident) | ||
| { | ||
| VersionCondition.checkPredefined(loc, ident.toChars()); | ||
| if (!m) | ||
| { | ||
| error("declaration must be at module level"); | ||
| errors = true; | ||
| } | ||
| else | ||
| { | ||
| if (findCondition(m.versionidsNot, ident)) | ||
| { | ||
| error("defined after use"); | ||
| errors = true; | ||
| } | ||
| if (!m.versionids) | ||
| m.versionids = new Strings(); | ||
| m.versionids.push(ident.toChars()); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| if (!m) | ||
| { | ||
| error("level declaration must be at module level"); | ||
| errors = true; | ||
| } | ||
| else | ||
| m.versionlevel = level; | ||
| } | ||
| } | ||
|
|
||
| void semantic(Scope* sc) | ||
| { | ||
| } | ||
|
|
||
| const(char)* kind() | ||
| { | ||
| return "version"; | ||
| } | ||
|
|
||
| void accept(Visitor v) | ||
| { | ||
| v.visit(this); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,287 @@ | ||
| // Compiler implementation of the D programming language | ||
| // Copyright (c) 1999-2015 by Digital Mars | ||
| // All Rights Reserved | ||
| // written by Walter Bright | ||
| // http://www.digitalmars.com | ||
| // Distributed under the Boost Software License, Version 1.0. | ||
| // http://www.boost.org/LICENSE_1_0.txt | ||
|
|
||
| module ddmd.errors; | ||
|
|
||
| import core.stdc.stdarg, core.stdc.stdio, core.stdc.stdlib, core.stdc.string, core.sys.posix.unistd, core.sys.windows.windows; | ||
| import ddmd.globals, ddmd.root.outbuffer, ddmd.root.rmem; | ||
|
|
||
| version (Windows) extern (C) int isatty(int); | ||
| version (Windows) alias _isatty = isatty; | ||
| version (Windows) int _fileno(FILE* f) | ||
| { | ||
| return f._file; | ||
| } | ||
|
|
||
| enum COLOR : int | ||
| { | ||
| COLOR_BLACK = 0, | ||
| COLOR_RED = 1, | ||
| COLOR_GREEN = 2, | ||
| COLOR_BLUE = 4, | ||
| COLOR_YELLOW = COLOR_RED | COLOR_GREEN, | ||
| COLOR_MAGENTA = COLOR_RED | COLOR_BLUE, | ||
| COLOR_CYAN = COLOR_GREEN | COLOR_BLUE, | ||
| COLOR_WHITE = COLOR_RED | COLOR_GREEN | COLOR_BLUE, | ||
| } | ||
|
|
||
| alias COLOR_BLACK = COLOR.COLOR_BLACK; | ||
| alias COLOR_RED = COLOR.COLOR_RED; | ||
| alias COLOR_GREEN = COLOR.COLOR_GREEN; | ||
| alias COLOR_BLUE = COLOR.COLOR_BLUE; | ||
| alias COLOR_YELLOW = COLOR.COLOR_YELLOW; | ||
| alias COLOR_MAGENTA = COLOR.COLOR_MAGENTA; | ||
| alias COLOR_CYAN = COLOR.COLOR_CYAN; | ||
| alias COLOR_WHITE = COLOR.COLOR_WHITE; | ||
|
|
||
| version (Windows) | ||
| { | ||
| extern (C++) static WORD consoleAttributes(HANDLE h) | ||
| { | ||
| static __gshared CONSOLE_SCREEN_BUFFER_INFO sbi; | ||
| static __gshared bool sbi_inited = false; | ||
| if (!sbi_inited) | ||
| sbi_inited = GetConsoleScreenBufferInfo(h, &sbi) != FALSE; | ||
| return sbi.wAttributes; | ||
| } | ||
|
|
||
| enum : int | ||
| { | ||
| FOREGROUND_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, | ||
| } | ||
| } | ||
|
|
||
| extern (C++) bool isConsoleColorSupported() | ||
| { | ||
| version (Windows) | ||
| { | ||
| return _isatty(_fileno(stderr)) != 0; | ||
| } | ||
| else static if (__linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun) | ||
| { | ||
| const(char)* term = getenv("TERM"); | ||
| return isatty(STDERR_FILENO) && term && term[0] && 0 != strcmp(term, "dumb"); | ||
| } | ||
| else | ||
| { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| extern (C++) void setConsoleColorBright(bool bright) | ||
| { | ||
| version (Windows) | ||
| { | ||
| HANDLE h = GetStdHandle(STD_ERROR_HANDLE); | ||
| WORD attr = consoleAttributes(h); | ||
| SetConsoleTextAttribute(h, attr | (bright ? FOREGROUND_INTENSITY : 0)); | ||
| } | ||
| else | ||
| { | ||
| fprintf(stderr, "\033[%dm", bright ? 1 : 0); | ||
| } | ||
| } | ||
|
|
||
| extern (C++) void setConsoleColor(COLOR color, bool bright) | ||
| { | ||
| version (Windows) | ||
| { | ||
| HANDLE h = GetStdHandle(STD_ERROR_HANDLE); | ||
| WORD attr = consoleAttributes(h); | ||
| attr = (attr & ~(FOREGROUND_WHITE | FOREGROUND_INTENSITY)) | ((color & COLOR_RED) ? FOREGROUND_RED : 0) | ((color & COLOR_GREEN) ? FOREGROUND_GREEN : 0) | ((color & COLOR_BLUE) ? FOREGROUND_BLUE : 0) | (bright ? FOREGROUND_INTENSITY : 0); | ||
| SetConsoleTextAttribute(h, attr); | ||
| } | ||
| else | ||
| { | ||
| fprintf(stderr, "\033[%d;%dm", bright ? 1 : 0, 30 + cast(int)color); | ||
| } | ||
| } | ||
|
|
||
| extern (C++) void resetConsoleColor() | ||
| { | ||
| version (Windows) | ||
| { | ||
| HANDLE h = GetStdHandle(STD_ERROR_HANDLE); | ||
| SetConsoleTextAttribute(h, consoleAttributes(h)); | ||
| } | ||
| else | ||
| { | ||
| fprintf(stderr, "\033[m"); | ||
| } | ||
| } | ||
|
|
||
| /************************************** | ||
| * Print error message | ||
| */ | ||
| extern (C++) void error(Loc loc, const(char)* format, ...) | ||
| { | ||
| va_list ap; | ||
| va_start(ap, format); | ||
| verror(loc, format, ap); | ||
| va_end(ap); | ||
| } | ||
|
|
||
| extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...) | ||
| { | ||
| Loc loc; | ||
| loc.filename = cast(char*)filename; | ||
| loc.linnum = linnum; | ||
| loc.charnum = charnum; | ||
| va_list ap; | ||
| va_start(ap, format); | ||
| verror(loc, format, ap); | ||
| va_end(ap); | ||
| } | ||
|
|
||
| extern (C++) void errorSupplemental(Loc loc, const(char)* format, ...) | ||
| { | ||
| va_list ap; | ||
| va_start(ap, format); | ||
| verrorSupplemental(loc, format, ap); | ||
| va_end(ap); | ||
| } | ||
|
|
||
| extern (C++) void warning(Loc loc, const(char)* format, ...) | ||
| { | ||
| va_list ap; | ||
| va_start(ap, format); | ||
| vwarning(loc, format, ap); | ||
| va_end(ap); | ||
| } | ||
|
|
||
| extern (C++) void warningSupplemental(Loc loc, const(char)* format, ...) | ||
| { | ||
| va_list ap; | ||
| va_start(ap, format); | ||
| vwarningSupplemental(loc, format, ap); | ||
| va_end(ap); | ||
| } | ||
|
|
||
| extern (C++) void deprecation(Loc loc, const(char)* format, ...) | ||
| { | ||
| va_list ap; | ||
| va_start(ap, format); | ||
| vdeprecation(loc, format, ap); | ||
| va_end(ap); | ||
| } | ||
|
|
||
| extern (C++) void deprecationSupplemental(Loc loc, const(char)* format, ...) | ||
| { | ||
| va_list ap; | ||
| va_start(ap, format); | ||
| vdeprecation(loc, format, ap); | ||
| va_end(ap); | ||
| } | ||
|
|
||
| // Just print, doesn't care about gagging | ||
| extern (C++) void verrorPrint(Loc loc, COLOR headerColor, const(char)* header, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null) | ||
| { | ||
| char* p = loc.toChars(); | ||
| if (global.params.color) | ||
| setConsoleColorBright(true); | ||
| if (*p) | ||
| fprintf(stderr, "%s: ", p); | ||
| mem.xfree(p); | ||
| if (global.params.color) | ||
| setConsoleColor(headerColor, true); | ||
| fputs(header, stderr); | ||
| if (global.params.color) | ||
| resetConsoleColor(); | ||
| if (p1) | ||
| fprintf(stderr, "%s ", p1); | ||
| if (p2) | ||
| fprintf(stderr, "%s ", p2); | ||
| OutBuffer tmp; | ||
| tmp.vprintf(format, ap); | ||
| fprintf(stderr, "%s\n", tmp.peekString()); | ||
| fflush(stderr); | ||
| } | ||
|
|
||
| // header is "Error: " by default (see errors.h) | ||
| extern (C++) void verror(Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null, const(char)* header = "Error: ") | ||
| { | ||
| global.errors++; | ||
| if (!global.gag) | ||
| { | ||
| verrorPrint(loc, COLOR_RED, header, format, ap, p1, p2); | ||
| if (global.errorLimit && global.errors >= global.errorLimit) | ||
| fatal(); // moderate blizzard of cascading messages | ||
| } | ||
| else | ||
| { | ||
| //fprintf(stderr, "(gag:%d) ", global.gag); | ||
| //verrorPrint(loc, COLOR_RED, header, format, ap, p1, p2); | ||
| global.gaggedErrors++; | ||
| } | ||
| } | ||
|
|
||
| // Doesn't increase error count, doesn't print "Error:". | ||
| extern (C++) void verrorSupplemental(Loc loc, const(char)* format, va_list ap) | ||
| { | ||
| if (!global.gag) | ||
| verrorPrint(loc, COLOR_RED, " ", format, ap); | ||
| } | ||
|
|
||
| extern (C++) void vwarning(Loc loc, const(char)* format, va_list ap) | ||
| { | ||
| if (global.params.warnings && !global.gag) | ||
| { | ||
| verrorPrint(loc, COLOR_YELLOW, "Warning: ", format, ap); | ||
| //halt(); | ||
| if (global.params.warnings == 1) | ||
| global.warnings++; // warnings don't count if gagged | ||
| } | ||
| } | ||
|
|
||
| extern (C++) void vwarningSupplemental(Loc loc, const(char)* format, va_list ap) | ||
| { | ||
| if (global.params.warnings && !global.gag) | ||
| verrorPrint(loc, COLOR_YELLOW, " ", format, ap); | ||
| } | ||
|
|
||
| extern (C++) void vdeprecation(Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null) | ||
| { | ||
| static __gshared const(char)* header = "Deprecation: "; | ||
| if (global.params.useDeprecated == 0) | ||
| verror(loc, format, ap, p1, p2, header); | ||
| else if (global.params.useDeprecated == 2 && !global.gag) | ||
| verrorPrint(loc, COLOR_BLUE, header, format, ap, p1, p2); | ||
| } | ||
|
|
||
| extern (C++) void vdeprecationSupplemental(Loc loc, const(char)* format, va_list ap) | ||
| { | ||
| if (global.params.useDeprecated == 0) | ||
| verrorSupplemental(loc, format, ap); | ||
| else if (global.params.useDeprecated == 2 && !global.gag) | ||
| verrorPrint(loc, COLOR_BLUE, " ", format, ap); | ||
| } | ||
|
|
||
| /*************************************** | ||
| * Call this after printing out fatal error messages to clean up and exit | ||
| * the compiler. | ||
| */ | ||
| extern (C++) void fatal() | ||
| { | ||
| version (none) | ||
| { | ||
| halt(); | ||
| } | ||
| exit(EXIT_FAILURE); | ||
| } | ||
|
|
||
| /************************************** | ||
| * Try to stop forgetting to remove the breakpoints from | ||
| * release builds. | ||
| */ | ||
| extern (C++) void halt() | ||
| { | ||
| debug | ||
| { | ||
| *cast(char*)0 = 0; | ||
| } | ||
| } |