Expression *expandVar(int result, VarDeclaration *v) { //printf("expandVar(result = %d, v = %s)\n", result, v ? v->toChars() : "null"); Expression *e = NULL; if (v && (v->isConst() || v->isInvariant() || v->storage_class & STCmanifest)) { Type *tb = v->type->toBasetype(); if (result & WANTinterpret || v->storage_class & STCmanifest || (tb->ty != Tsarray && tb->ty != Tstruct) ) { if (v->init) { if (v->inuse) goto L1; Expression *ei = v->init->toExpression(); if (!ei) goto L1; if (ei->op == TOKconstruct || ei->op == TOKblit) { AssignExp *ae = (AssignExp *)ei; ei = ae->e2; if (ei->isConst() != 1 && ei->op != TOKstring) goto L1; if (ei->type != v->type) goto L1; } if (v->scope) { v->inuse++; e = ei->syntaxCopy(); e = e->semantic(v->scope); e = e->implicitCastTo(v->scope, v->type); v->scope = NULL; v->inuse--; } else if (!ei->type) { goto L1; } else // Should remove the copy() operation by // making all mods to expressions copy-on-write e = ei->copy(); } else { #if 1 goto L1; #else // BUG: what if const is initialized in constructor? e = v->type->defaultInit(); e->loc = e1->loc; #endif } if (e->type != v->type) { e = e->castTo(NULL, v->type); } e = e->optimize(result); } } L1: //if (e) printf("\te = %s, e->type = %s\n", e->toChars(), e->type->toChars()); return e; }
Expression *semanticTraits(TraitsExp *e, Scope *sc) { #if LOGSEMANTIC printf("TraitsExp::semantic() %s\n", e->toChars()); #endif if (e->ident != Id::compiles && e->ident != Id::isSame && e->ident != Id::identifier && e->ident != Id::getProtection) { if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1)) return new ErrorExp(); } size_t dim = e->args ? e->args->dim : 0; if (e->ident == Id::isArithmetic) { return isTypeX(e, &isTypeArithmetic); } else if (e->ident == Id::isFloating) { return isTypeX(e, &isTypeFloating); } else if (e->ident == Id::isIntegral) { return isTypeX(e, &isTypeIntegral); } else if (e->ident == Id::isScalar) { return isTypeX(e, &isTypeScalar); } else if (e->ident == Id::isUnsigned) { return isTypeX(e, &isTypeUnsigned); } else if (e->ident == Id::isAssociativeArray) { return isTypeX(e, &isTypeAssociativeArray); } else if (e->ident == Id::isStaticArray) { return isTypeX(e, &isTypeStaticArray); } else if (e->ident == Id::isAbstractClass) { return isTypeX(e, &isTypeAbstractClass); } else if (e->ident == Id::isFinalClass) { return isTypeX(e, &isTypeFinalClass); } else if (e->ident == Id::isPOD) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Type *t = isType(o); StructDeclaration *sd; if (!t) { e->error("type expected as second argument of __traits %s instead of %s", e->ident->toChars(), o->toChars()); goto Lfalse; } Type *tb = t->baseElemOf(); if (tb->ty == Tstruct && ((sd = (StructDeclaration *)(((TypeStruct *)tb)->sym)) != NULL)) { if (sd->isPOD()) goto Ltrue; else goto Lfalse; } goto Ltrue; } else if (e->ident == Id::isNested) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); AggregateDeclaration *a; FuncDeclaration *f; if (!s) { } else if ((a = s->isAggregateDeclaration()) != NULL) { if (a->isNested()) goto Ltrue; else goto Lfalse; } else if ((f = s->isFuncDeclaration()) != NULL) { if (f->isNested()) goto Ltrue; else goto Lfalse; } e->error("aggregate or function expected instead of '%s'", o->toChars()); goto Lfalse; } else if (e->ident == Id::isAbstractFunction) { return isFuncX(e, &isFuncAbstractFunction); } else if (e->ident == Id::isVirtualFunction) { return isFuncX(e, &isFuncVirtualFunction); } else if (e->ident == Id::isVirtualMethod) { return isFuncX(e, &isFuncVirtualMethod); } else if (e->ident == Id::isFinalFunction) { return isFuncX(e, &isFuncFinalFunction); } else if (e->ident == Id::isOverrideFunction) { return isFuncX(e, &isFuncOverrideFunction); } else if (e->ident == Id::isStaticFunction) { return isFuncX(e, &isFuncStaticFunction); } else if (e->ident == Id::isRef) { return isDeclX(e, &isDeclRef); } else if (e->ident == Id::isOut) { return isDeclX(e, &isDeclOut); } else if (e->ident == Id::isLazy) { return isDeclX(e, &isDeclLazy); } else if (e->ident == Id::identifier) { // Get identifier for symbol as a string literal /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that * a symbol should not be folded to a constant. * Bit 1 means don't convert Parameter to Type if Parameter has an identifier */ if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 2)) return new ErrorExp(); if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Parameter *po = isParameter(o); Identifier *id; if (po) { id = po->ident; assert(id); } else { Dsymbol *s = getDsymbol(o); if (!s || !s->ident) { e->error("argument %s has no identifier", o->toChars()); goto Lfalse; } id = s->ident; } StringExp *se = new StringExp(e->loc, id->toChars()); return se->semantic(sc); } else if (e->ident == Id::getProtection) { if (dim != 1) goto Ldimerror; Scope *sc2 = sc->push(); sc2->flags = sc->flags | SCOPEnoaccesscheck; bool ok = TemplateInstance::semanticTiargs(e->loc, sc2, e->args, 1); sc2->pop(); if (!ok) return new ErrorExp(); RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { if (!isError(o)) e->error("argument %s has no protection", o->toChars()); goto Lfalse; } if (s->scope) s->semantic(s->scope); const char *protName = protectionToChars(s->prot()); assert(protName); StringExp *se = new StringExp(e->loc, (char *) protName); return se->semantic(sc); } else if (e->ident == Id::parent) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (s) { if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943 s = fd->toAliasFunc(); if (!s->isImport()) // Bugzilla 8922 s = s->toParent(); } if (!s || s->isImport()) { e->error("argument %s has no parent", o->toChars()); goto Lfalse; } if (FuncDeclaration *f = s->isFuncDeclaration()) { if (TemplateDeclaration *td = getFuncTemplateDecl(f)) { if (td->overroot) // if not start of overloaded list of TemplateDeclaration's td = td->overroot; // then get the start Expression *ex = new TemplateExp(e->loc, td, f); ex = ex->semantic(sc); return ex; } if (FuncLiteralDeclaration *fld = f->isFuncLiteralDeclaration()) { // Directly translate to VarExp instead of FuncExp Expression *ex = new VarExp(e->loc, fld, 1); return ex->semantic(sc); } } return (new DsymbolExp(e->loc, s))->semantic(sc); } else if (e->ident == Id::hasMember || e->ident == Id::getMember || e->ident == Id::getOverloads || e->ident == Id::getVirtualMethods || e->ident == Id::getVirtualFunctions) { if (dim != 2) goto Ldimerror; RootObject *o = (*e->args)[0]; Expression *ex = isExpression((*e->args)[1]); if (!ex) { e->error("expression expected as second argument of __traits %s", e->ident->toChars()); goto Lfalse; } ex = ex->ctfeInterpret(); StringExp *se = ex->toStringExp(); if (!se || se->length() == 0) { e->error("string expected as second argument of __traits %s instead of %s", e->ident->toChars(), ex->toChars()); goto Lfalse; } se = se->toUTF8(sc); if (se->sz != 1) { e->error("string must be chars"); goto Lfalse; } Identifier *id = Lexer::idPool((char *)se->string); /* Prefer dsymbol, because it might need some runtime contexts. */ Dsymbol *sym = getDsymbol(o); if (sym) { ex = new DsymbolExp(e->loc, sym); ex = new DotIdExp(e->loc, ex, id); } else if (Type *t = isType(o)) ex = typeDotIdExp(e->loc, t, id); else if (Expression *ex2 = isExpression(o)) ex = new DotIdExp(e->loc, ex2, id); else { e->error("invalid first argument"); goto Lfalse; } if (e->ident == Id::hasMember) { if (sym) { Dsymbol *sm = sym->search(e->loc, id); if (sm) goto Ltrue; } /* Take any errors as meaning it wasn't found */ Scope *sc2 = sc->push(); ex = ex->trySemantic(sc2); sc2->pop(); if (!ex) goto Lfalse; else goto Ltrue; } else if (e->ident == Id::getMember) { ex = ex->semantic(sc); return ex; } else if (e->ident == Id::getVirtualFunctions || e->ident == Id::getVirtualMethods || e->ident == Id::getOverloads) { unsigned errors = global.errors; Expression *eorig = ex; ex = ex->semantic(sc); if (errors < global.errors) e->error("%s cannot be resolved", eorig->toChars()); /* Create tuple of functions of ex */ //ex->print(); Expressions *exps = new Expressions(); FuncDeclaration *f; if (ex->op == TOKvar) { VarExp *ve = (VarExp *)ex; f = ve->var->isFuncDeclaration(); ex = NULL; } else if (ex->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)ex; f = dve->var->isFuncDeclaration(); if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis) ex = NULL; else ex = dve->e1; } else f = NULL; Ptrait p; p.exps = exps; p.e1 = ex; p.ident = e->ident; overloadApply(f, &p, &fptraits); TupleExp *tup = new TupleExp(e->loc, exps); return tup->semantic(sc); } else assert(0); } else if (e->ident == Id::classInstanceSize) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); ClassDeclaration *cd; if (!s || (cd = s->isClassDeclaration()) == NULL) { e->error("first argument is not a class"); goto Lfalse; } if (cd->sizeok == SIZEOKnone) { if (cd->scope) cd->semantic(cd->scope); } if (cd->sizeok != SIZEOKdone) { e->error("%s %s is forward referenced", cd->kind(), cd->toChars()); goto Lfalse; } return new IntegerExp(e->loc, cd->structsize, Type::tsize_t); } else if (e->ident == Id::getAliasThis) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); AggregateDeclaration *ad; if (!s || (ad = s->isAggregateDeclaration()) == NULL) { e->error("argument is not an aggregate type"); goto Lfalse; } Expressions *exps = new Expressions(); if (ad->aliasthis) exps->push(new StringExp(e->loc, ad->aliasthis->ident->toChars())); Expression *ex = new TupleExp(e->loc, exps); ex = ex->semantic(sc); return ex; } else if (e->ident == Id::getAttributes) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { #if 0 Expression *x = isExpression(o); Type *t = isType(o); if (x) printf("e = %s %s\n", Token::toChars(x->op), x->toChars()); if (t) printf("t = %d %s\n", t->ty, t->toChars()); #endif e->error("first argument is not a symbol"); goto Lfalse; } //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->scope); UserAttributeDeclaration *udad = s->userAttribDecl; TupleExp *tup = new TupleExp(e->loc, udad ? udad->getAttributes() : new Expressions()); return tup->semantic(sc); } else if (e->ident == Id::getFunctionAttributes) { /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs. if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); Type *t = isType(o); TypeFunction *tf = NULL; if (s) { if (FuncDeclaration *f = s->isFuncDeclaration()) t = f->type; else if (VarDeclaration *v = s->isVarDeclaration()) t = v->type; } if (t) { if (t->ty == Tfunction) tf = (TypeFunction *)t; else if (t->ty == Tdelegate) tf = (TypeFunction *)t->nextOf(); else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) tf = (TypeFunction *)t->nextOf(); } if (!tf) { e->error("first argument is not a function"); goto Lfalse; } Expressions *mods = new Expressions(); PushAttributes pa; pa.mods = mods; tf->modifiersApply(&pa, &PushAttributes::fp); tf->attributesApply(&pa, &PushAttributes::fp, TRUSTformatSystem); TupleExp *tup = new TupleExp(e->loc, mods); return tup->semantic(sc); } else if (e->ident == Id::allMembers || e->ident == Id::derivedMembers) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); ScopeDsymbol *sds; if (!s) { e->error("argument has no members"); goto Lfalse; } Import *import; if ((import = s->isImport()) != NULL) { // Bugzilla 9692 sds = import->mod; } else if ((sds = s->isScopeDsymbol()) == NULL) { e->error("%s %s has no members", s->kind(), s->toChars()); goto Lfalse; } // use a struct as local function struct PushIdentsDg { static int dg(void *ctx, size_t n, Dsymbol *sm) { if (!sm) return 1; //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); if (sm->ident) { if (sm->ident != Id::ctor && sm->ident != Id::dtor && sm->ident != Id::_postblit && memcmp(sm->ident->string, "__", 2) == 0) { return 0; } //printf("\t%s\n", sm->ident->toChars()); Identifiers *idents = (Identifiers *)ctx; /* Skip if already present in idents[] */ for (size_t j = 0; j < idents->dim; j++) { Identifier *id = (*idents)[j]; if (id == sm->ident) return 0; #ifdef DEBUG // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop. assert(strcmp(id->toChars(), sm->ident->toChars()) != 0); #endif } idents->push(sm->ident); } else { EnumDeclaration *ed = sm->isEnumDeclaration(); if (ed) { ScopeDsymbol::foreach(NULL, ed->members, &PushIdentsDg::dg, (Identifiers *)ctx); } } return 0; } }; Identifiers *idents = new Identifiers; ScopeDsymbol::foreach(sc, sds->members, &PushIdentsDg::dg, idents); ClassDeclaration *cd = sds->isClassDeclaration(); if (cd && e->ident == Id::allMembers) { struct PushBaseMembers { static void dg(ClassDeclaration *cd, Identifiers *idents) { for (size_t i = 0; i < cd->baseclasses->dim; i++) { ClassDeclaration *cb = (*cd->baseclasses)[i]->base; ScopeDsymbol::foreach(NULL, cb->members, &PushIdentsDg::dg, idents); if (cb->baseclasses->dim) dg(cb, idents); } } }; PushBaseMembers::dg(cd, idents); } // Turn Identifiers into StringExps reusing the allocated array assert(sizeof(Expressions) == sizeof(Identifiers)); Expressions *exps = (Expressions *)idents; for (size_t i = 0; i < idents->dim; i++) { Identifier *id = (*idents)[i]; StringExp *se = new StringExp(e->loc, id->toChars()); (*exps)[i] = se; } /* Making this a tuple is more flexible, as it can be statically unrolled. * To make an array literal, enclose __traits in [ ]: * [ __traits(allMembers, ...) ] */ Expression *ex = new TupleExp(e->loc, exps); ex = ex->semantic(sc); return ex; } else if (e->ident == Id::compiles) { /* Determine if all the objects - types, expressions, or symbols - * compile without error */ if (!dim) goto Lfalse; for (size_t i = 0; i < dim; i++) { unsigned errors = global.startGagging(); unsigned oldspec = global.speculativeGag; global.speculativeGag = global.gag; Scope *sc2 = sc->push(); sc2->speculative = true; sc2->flags = sc->flags & ~SCOPEctfe | SCOPEcompile; bool err = false; RootObject *o = (*e->args)[i]; Type *t = isType(o); Expression *ex = t ? t->toExpression() : isExpression(o); if (!ex && t) { Dsymbol *s; t->resolve(e->loc, sc2, &ex, &t, &s); if (t) { t->semantic(e->loc, sc2); if (t->ty == Terror) err = true; } else if (s && s->errors) err = true; } if (ex) { ex = ex->semantic(sc2); ex = resolvePropertiesOnly(sc2, ex); ex = ex->optimize(WANTvalue); if (sc2->func && sc2->func->type->ty == Tfunction) { TypeFunction *tf = (TypeFunction *)sc2->func->type; canThrow(ex, sc2->func, tf->isnothrow); } ex = checkGC(sc2, ex); if (ex->op == TOKerror) err = true; } sc2->pop(); global.speculativeGag = oldspec; if (global.endGagging(errors) || err) { goto Lfalse; } } goto Ltrue; } else if (e->ident == Id::isSame) { /* Determine if two symbols are the same */ if (dim != 2) goto Ldimerror; if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0)) return new ErrorExp(); RootObject *o1 = (*e->args)[0]; RootObject *o2 = (*e->args)[1]; Dsymbol *s1 = getDsymbol(o1); Dsymbol *s2 = getDsymbol(o2); //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars()); #if 0 printf("o1: %p\n", o1); printf("o2: %p\n", o2); if (!s1) { Expression *ea = isExpression(o1); if (ea) printf("%s\n", ea->toChars()); Type *ta = isType(o1); if (ta) printf("%s\n", ta->toChars()); goto Lfalse; } else printf("%s %s\n", s1->kind(), s1->toChars()); #endif if (!s1 && !s2) { Expression *ea1 = isExpression(o1); Expression *ea2 = isExpression(o2); if (ea1 && ea2) { if (ea1->equals(ea2)) goto Ltrue; } } if (!s1 || !s2) goto Lfalse; s1 = s1->toAlias(); s2 = s2->toAlias(); if (s1->isFuncAliasDeclaration()) s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc(); if (s2->isFuncAliasDeclaration()) s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc(); if (s1 == s2) goto Ltrue; else goto Lfalse; } else if (e->ident == Id::getUnitTests) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { e->error("argument %s to __traits(getUnitTests) must be a module or aggregate", o->toChars()); goto Lfalse; } Import *imp = s->isImport(); if (imp) // Bugzilla 10990 s = imp->mod; ScopeDsymbol* scope = s->isScopeDsymbol(); if (!scope) { e->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s", s->toChars(), s->kind()); goto Lfalse; } Expressions* unitTests = new Expressions(); Dsymbols* symbols = scope->members; if (global.params.useUnitTests && symbols) { // Should actually be a set AA* uniqueUnitTests = NULL; collectUnitTests(symbols, uniqueUnitTests, unitTests); } TupleExp *tup = new TupleExp(e->loc, unitTests); return tup->semantic(sc); } else if(e->ident == Id::getVirtualIndex) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); FuncDeclaration *fd; if (!s || (fd = s->isFuncDeclaration()) == NULL) { e->error("first argument to __traits(getVirtualIndex) must be a function"); goto Lfalse; } fd = fd->toAliasFunc(); // Neccessary to support multiple overloads. return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t); } else { if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars)) e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub); else e->error("unrecognized trait '%s'", e->ident->toChars()); goto Lfalse; } return NULL; Ldimerror: e->error("wrong number of arguments %d", (int)dim); goto Lfalse; Lfalse: return new IntegerExp(e->loc, 0, Type::tbool); Ltrue: return new IntegerExp(e->loc, 1, Type::tbool); }
void Output::operator()(Ruleset* r) { Selector* s = r->selector(); Block* b = r->block(); bool decls = false; // Filter out rulesets that aren't printable (process its children though) if (!Util::isPrintable(r, output_style())) { for (size_t i = 0, L = b->length(); i < L; ++i) { Statement* stm = (*b)[i]; if (dynamic_cast<Has_Block*>(stm)) { if (typeid(*stm) != typeid(Declaration)) { stm->perform(this); } } } return; } if (b->has_non_hoistable()) { decls = true; if (output_style() == NESTED) indentation += r->tabs(); if (opt.source_comments) { std::stringstream ss; append_indentation(); ss << "/* line " << r->pstate().line + 1 << ", " << r->pstate().path << " */"; append_string(ss.str()); append_optional_linefeed(); } s->perform(this); append_scope_opener(b); for (size_t i = 0, L = b->length(); i < L; ++i) { Statement* stm = (*b)[i]; bool bPrintExpression = true; // Check print conditions if (typeid(*stm) == typeid(Declaration)) { Declaration* dec = static_cast<Declaration*>(stm); if (dec->value()->concrete_type() == Expression::STRING) { String_Constant* valConst = static_cast<String_Constant*>(dec->value()); std::string val(valConst->value()); if (auto qstr = dynamic_cast<String_Quoted*>(valConst)) { if (!qstr->quote_mark() && val.empty()) { bPrintExpression = false; } } } else if (dec->value()->concrete_type() == Expression::LIST) { List* list = static_cast<List*>(dec->value()); bool all_invisible = true; for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) { Expression* item = (*list)[list_i]; if (!item->is_invisible()) all_invisible = false; } if (all_invisible) bPrintExpression = false; } } // Print if OK if (!stm->is_hoistable() && bPrintExpression) { stm->perform(this); } } if (output_style() == NESTED) indentation -= r->tabs(); append_scope_closer(b); } if (b->has_hoistable()) { if (decls) ++indentation; for (size_t i = 0, L = b->length(); i < L; ++i) { Statement* stm = (*b)[i]; if (stm->is_hoistable()) { stm->perform(this); } } if (decls) --indentation; } }
Expression *EnumDeclaration::getMaxMinValue(Loc loc, Identifier *id) { //printf("EnumDeclaration::getMaxValue()\n"); bool first = true; Expression **pval = (id == Id::max) ? &maxval : &minval; if (inuse) { error(loc, "recursive definition of .%s property", id->toChars()); goto Lerrors; } if (*pval) goto Ldone; if (scope) semantic(scope); if (errors) goto Lerrors; if (semanticRun == PASSinit || !members) { error("is forward referenced looking for .%s", id->toChars()); goto Lerrors; } if (!(memtype && memtype->isintegral())) { error(loc, "has no .%s property because base type %s is not an integral type", id->toChars(), memtype ? memtype->toChars() : ""); goto Lerrors; } for (size_t i = 0; i < members->dim; i++) { EnumMember *em = (*members)[i]->isEnumMember(); if (!em) continue; if (em->errors) goto Lerrors; Expression *e = em->value; if (first) { *pval = e; first = false; } else { /* In order to work successfully with UDTs, * build expressions to do the comparisons, * and let the semantic analyzer and constant * folder give us the result. */ /* Compute: * if (e > maxval) * maxval = e; */ Expression *ec = new CmpExp(id == Id::max ? TOKgt : TOKlt, em->loc, e, *pval); inuse++; ec = ec->semantic(em->scope); inuse--; ec = ec->ctfeInterpret(); if (ec->toInteger()) *pval = e; } } Ldone: { Expression *e = *pval; if (e->op != TOKerror) { e = e->copy(); e->loc = loc; } return e; } Lerrors: *pval = new ErrorExp(); return *pval; }
ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, Expression &expr, bool generate_debug_info) : ExpressionParser (exe_scope, expr, generate_debug_info), m_compiler (), m_code_generator (), m_pp_callbacks(nullptr) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); // We can't compile expressions without a target. So if the exe_scope is null or doesn't have a target, // then we just need to get out of here. I'll lldb_assert and not make any of the compiler objects since // I can't return errors directly from the constructor. Further calls will check if the compiler was made and // bag out if it wasn't. if (!exe_scope) { lldb_assert(exe_scope, "Can't make an expression parser with a null scope.", __FUNCTION__, __FILE__, __LINE__); return; } lldb::TargetSP target_sp; target_sp = exe_scope->CalculateTarget(); if (!target_sp) { lldb_assert(exe_scope, "Can't make an expression parser with a null target.", __FUNCTION__, __FILE__, __LINE__); return; } // 1. Create a new compiler instance. m_compiler.reset(new CompilerInstance()); lldb::LanguageType frame_lang = expr.Language(); // defaults to lldb::eLanguageTypeUnknown bool overridden_target_opts = false; lldb_private::LanguageRuntime *lang_rt = nullptr; std::string abi; ArchSpec target_arch; target_arch = target_sp->GetArchitecture(); const auto target_machine = target_arch.GetMachine(); // If the expression is being evaluated in the context of an existing // stack frame, we introspect to see if the language runtime is available. lldb::StackFrameSP frame_sp = exe_scope->CalculateStackFrame(); lldb::ProcessSP process_sp = exe_scope->CalculateProcess(); // Make sure the user hasn't provided a preferred execution language // with `expression --language X -- ...` if (frame_sp && frame_lang == lldb::eLanguageTypeUnknown) frame_lang = frame_sp->GetLanguage(); if (process_sp && frame_lang != lldb::eLanguageTypeUnknown) { lang_rt = process_sp->GetLanguageRuntime(frame_lang); if (log) log->Printf("Frame has language of type %s", Language::GetNameForLanguageType(frame_lang)); } // 2. Configure the compiler with a set of default options that are appropriate // for most situations. if (target_arch.IsValid()) { std::string triple = target_arch.GetTriple().str(); m_compiler->getTargetOpts().Triple = triple; if (log) log->Printf("Using %s as the target triple", m_compiler->getTargetOpts().Triple.c_str()); } else { // If we get here we don't have a valid target and just have to guess. // Sometimes this will be ok to just use the host target triple (when we evaluate say "2+3", but other // expressions like breakpoint conditions and other things that _are_ target specific really shouldn't just be // using the host triple. In such a case the language runtime should expose an overridden options set (3), // below. m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple(); if (log) log->Printf("Using default target triple of %s", m_compiler->getTargetOpts().Triple.c_str()); } // Now add some special fixes for known architectures: // Any arm32 iOS environment, but not on arm64 if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos && m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos && m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos) { m_compiler->getTargetOpts().ABI = "apcs-gnu"; } // Supported subsets of x86 if (target_machine == llvm::Triple::x86 || target_machine == llvm::Triple::x86_64) { m_compiler->getTargetOpts().Features.push_back("+sse"); m_compiler->getTargetOpts().Features.push_back("+sse2"); } // Set the target CPU to generate code for. // This will be empty for any CPU that doesn't really need to make a special CPU string. m_compiler->getTargetOpts().CPU = target_arch.GetClangTargetCPU(); // Set the target ABI abi = GetClangTargetABI(target_arch); if (!abi.empty()) m_compiler->getTargetOpts().ABI = abi; // 3. Now allow the runtime to provide custom configuration options for the target. // In this case, a specialized language runtime is available and we can query it for extra options. // For 99% of use cases, this will not be needed and should be provided when basic platform detection is not enough. if (lang_rt) overridden_target_opts = lang_rt->GetOverrideExprOptions(m_compiler->getTargetOpts()); if (overridden_target_opts) if (log) { log->Debug("Using overridden target options for the expression evaluation"); auto opts = m_compiler->getTargetOpts(); log->Debug("Triple: '%s'", opts.Triple.c_str()); log->Debug("CPU: '%s'", opts.CPU.c_str()); log->Debug("FPMath: '%s'", opts.FPMath.c_str()); log->Debug("ABI: '%s'", opts.ABI.c_str()); log->Debug("LinkerVersion: '%s'", opts.LinkerVersion.c_str()); StringList::LogDump(log, opts.FeaturesAsWritten, "FeaturesAsWritten"); StringList::LogDump(log, opts.Features, "Features"); StringList::LogDump(log, opts.Reciprocals, "Reciprocals"); } // 4. Create and install the target on the compiler. m_compiler->createDiagnostics(); auto target_info = TargetInfo::CreateTargetInfo(m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts); if (log) { log->Printf("Using SIMD alignment: %d", target_info->getSimdDefaultAlign()); log->Printf("Target datalayout string: '%s'", target_info->getDataLayout().getStringRepresentation().c_str()); log->Printf("Target ABI: '%s'", target_info->getABI().str().c_str()); log->Printf("Target vector alignment: %d", target_info->getMaxVectorAlign()); } m_compiler->setTarget(target_info); assert (m_compiler->hasTarget()); // 5. Set language options. lldb::LanguageType language = expr.Language(); switch (language) { case lldb::eLanguageTypeC: case lldb::eLanguageTypeC89: case lldb::eLanguageTypeC99: case lldb::eLanguageTypeC11: // FIXME: the following language option is a temporary workaround, // to "ask for C, get C++." // For now, the expression parser must use C++ anytime the // language is a C family language, because the expression parser // uses features of C++ to capture values. m_compiler->getLangOpts().CPlusPlus = true; break; case lldb::eLanguageTypeObjC: m_compiler->getLangOpts().ObjC1 = true; m_compiler->getLangOpts().ObjC2 = true; // FIXME: the following language option is a temporary workaround, // to "ask for ObjC, get ObjC++" (see comment above). m_compiler->getLangOpts().CPlusPlus = true; break; case lldb::eLanguageTypeC_plus_plus: case lldb::eLanguageTypeC_plus_plus_11: case lldb::eLanguageTypeC_plus_plus_14: m_compiler->getLangOpts().CPlusPlus11 = true; m_compiler->getHeaderSearchOpts().UseLibcxx = true; LLVM_FALLTHROUGH; case lldb::eLanguageTypeC_plus_plus_03: m_compiler->getLangOpts().CPlusPlus = true; // FIXME: the following language option is a temporary workaround, // to "ask for C++, get ObjC++". Apple hopes to remove this requirement // on non-Apple platforms, but for now it is needed. m_compiler->getLangOpts().ObjC1 = true; break; case lldb::eLanguageTypeObjC_plus_plus: case lldb::eLanguageTypeUnknown: default: m_compiler->getLangOpts().ObjC1 = true; m_compiler->getLangOpts().ObjC2 = true; m_compiler->getLangOpts().CPlusPlus = true; m_compiler->getLangOpts().CPlusPlus11 = true; m_compiler->getHeaderSearchOpts().UseLibcxx = true; break; } m_compiler->getLangOpts().Bool = true; m_compiler->getLangOpts().WChar = true; m_compiler->getLangOpts().Blocks = true; m_compiler->getLangOpts().DebuggerSupport = true; // Features specifically for debugger clients if (expr.DesiredResultType() == Expression::eResultTypeId) m_compiler->getLangOpts().DebuggerCastResultToId = true; m_compiler->getLangOpts().CharIsSigned = ArchSpec(m_compiler->getTargetOpts().Triple.c_str()).CharIsSignedByDefault(); // Spell checking is a nice feature, but it ends up completing a // lot of types that we didn't strictly speaking need to complete. // As a result, we spend a long time parsing and importing debug // information. m_compiler->getLangOpts().SpellChecking = false; if (process_sp && m_compiler->getLangOpts().ObjC1) { if (process_sp->GetObjCLanguageRuntime()) { if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() == ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2) m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::MacOSX, VersionTuple(10, 7)); else m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::FragileMacOSX, VersionTuple(10, 7)); if (process_sp->GetObjCLanguageRuntime()->HasNewLiteralsAndIndexing()) m_compiler->getLangOpts().DebuggerObjCLiteral = true; } } m_compiler->getLangOpts().ThreadsafeStatics = false; m_compiler->getLangOpts().AccessControl = false; // Debuggers get universal access m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name // Set CodeGen options m_compiler->getCodeGenOpts().EmitDeclMetadata = true; m_compiler->getCodeGenOpts().InstrumentFunctions = false; m_compiler->getCodeGenOpts().DisableFPElim = true; m_compiler->getCodeGenOpts().OmitLeafFramePointer = false; if (generate_debug_info) m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo); else m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::NoDebugInfo); // Disable some warnings. m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError, "unused-value", clang::diag::Severity::Ignored, SourceLocation()); m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError, "odr", clang::diag::Severity::Ignored, SourceLocation()); // Inform the target of the language options // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. m_compiler->getTarget().adjust(m_compiler->getLangOpts()); // 6. Set up the diagnostic buffer for reporting errors m_compiler->getDiagnostics().setClient(new ClangDiagnosticManagerAdapter); // 7. Set up the source management objects inside the compiler clang::FileSystemOptions file_system_options; m_file_manager.reset(new clang::FileManager(file_system_options)); if (!m_compiler->hasSourceManager()) m_compiler->createSourceManager(*m_file_manager.get()); m_compiler->createFileManager(); m_compiler->createPreprocessor(TU_Complete); if (ClangModulesDeclVendor *decl_vendor = target_sp->GetClangModulesDeclVendor()) { ClangPersistentVariables *clang_persistent_vars = llvm::cast<ClangPersistentVariables>(target_sp->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); std::unique_ptr<PPCallbacks> pp_callbacks(new LLDBPreprocessorCallbacks(*decl_vendor, *clang_persistent_vars)); m_pp_callbacks = static_cast<LLDBPreprocessorCallbacks*>(pp_callbacks.get()); m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks)); } // 8. Most of this we get from the CompilerInstance, but we // also want to give the context an ExternalASTSource. m_selector_table.reset(new SelectorTable()); m_builtin_context.reset(new Builtin::Context()); std::unique_ptr<clang::ASTContext> ast_context(new ASTContext(m_compiler->getLangOpts(), m_compiler->getSourceManager(), m_compiler->getPreprocessor().getIdentifierTable(), *m_selector_table.get(), *m_builtin_context.get())); ast_context->InitBuiltinTypes(m_compiler->getTarget()); ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); if (decl_map) { llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source(decl_map->CreateProxy()); decl_map->InstallASTContext(ast_context.get()); ast_context->setExternalSource(ast_source); } m_ast_context.reset(new ClangASTContext(m_compiler->getTargetOpts().Triple.c_str())); m_ast_context->setASTContext(ast_context.get()); m_compiler->setASTContext(ast_context.release()); std::string module_name("$__lldb_module"); m_llvm_context.reset(new LLVMContext()); m_code_generator.reset(CreateLLVMCodeGen(m_compiler->getDiagnostics(), module_name, m_compiler->getHeaderSearchOpts(), m_compiler->getPreprocessorOpts(), m_compiler->getCodeGenOpts(), *m_llvm_context)); }
Expression *createTypeInfoArray(Scope *sc, Expression *exps[], size_t dim) { #if 1 /* * Pass a reference to the TypeInfo_Tuple corresponding to the types of the * arguments. Source compatibility is maintained by computing _arguments[] * at the start of the called function by offseting into the TypeInfo_Tuple * reference. */ Parameters *args = Parameters_create(); args->setDim(dim); for (size_t i = 0; i < dim; i++) { Parameter *arg = Parameter::create(STCin, exps[i]->type, NULL, NULL); (*args)[i] = arg; } TypeTuple *tup = TypeTuple::create(args); Expression *e = tup->getTypeInfo(sc); e = e->optimize(WANTvalue); assert(e->op == TOKsymoff); // should be SymOffExp return e; #else /* Improvements: * 1) create an array literal instead, * as it would eliminate the extra dereference of loading the * static variable. */ ArrayInitializer *ai = new ArrayInitializer(0); VarDeclaration *v; Type *t; Expression *e; OutBuffer buf; Identifier *id; char *name; // Generate identifier for _arguments[] buf.writestring("_arguments_"); for (int i = 0; i < dim; i++) { t = exps[i]->type; t->toDecoBuffer(&buf); } buf.writeByte(0); id = Lexer::idPool((char *)buf.data); Module *m = sc->module; Dsymbol *s = m->symtab->lookup(id); if (s && s->parent == m) { // Use existing one v = s->isVarDeclaration(); assert(v); } else { // Generate new one for (int i = 0; i < dim; i++) { t = exps[i]->type; e = t->getTypeInfo(sc); ai->addInit(new IntegerExp(i), new ExpInitializer(Loc(), e)); } t = Type::typeinfo->type->arrayOf(); ai->type = t; v = new VarDeclaration(0, t, id, ai); v->storage_class |= STCtemp; m->members->push(v); m->symtabInsert(v); sc = sc->push(); sc->linkage = LINKc; sc->stc = STCstatic | STCcomdat; ai->semantic(sc, t); v->semantic(sc); v->parent = m; sc = sc->pop(); } e = VarExp::create(Loc(), v); e = e->semantic(sc); return e; #endif }
FunctionInvocation * FunctionInvocation::make_random_binary(CGContext &cg_context, const Type* type) { DEPTH_GUARD_BY_TYPE_RETURN(dtFunctionInvocationRandomBinary, NULL); if (rnd_flipcoin(10) && Type::has_pointer_type()) { ERROR_GUARD(NULL); return make_random_binary_ptr_comparison(cg_context); } eBinaryOps op; do { op = (eBinaryOps)(rnd_upto(MAX_BINARY_OP, BINARY_OPS_PROB_FILTER)); } while (type->is_float() && !BinaryOpWorksForFloat(op)); ERROR_GUARD(NULL); assert(type); SafeOpFlags *flags = SafeOpFlags::make_random_binary(type, NULL, NULL, sOpBinary, op); assert(flags); ERROR_GUARD(NULL); FunctionInvocationBinary *fi = FunctionInvocationBinary::CreateFunctionInvocationBinary(cg_context, op, flags); Effect lhs_eff_accum; CGContext lhs_cg_context(cg_context, cg_context.get_effect_context(), &lhs_eff_accum); // Generate an expression with the correct type required by safe math operands const Type* lhs_type = flags->get_lhs_type(); const Type* rhs_type = flags->get_rhs_type(); assert(lhs_type && rhs_type); if (!BinaryOpWorksForFloat(op)) { assert(!lhs_type->is_float() && "lhs_type is float!"); assert(!rhs_type->is_float() && "rhs_type is float!"); } Expression *lhs = Expression::make_random(lhs_cg_context, lhs_type); ERROR_GUARD_AND_DEL1(NULL, fi); Expression *rhs = 0; cg_context.merge_param_context(lhs_cg_context, true); FactMgr* fm = get_fact_mgr(&cg_context); vector<const Fact*> facts_copy = fm->global_facts; #if 0 if (lhs->term_type == eVariable) { lhs_eff_accum.read_deref_volatile((ExpressionVariable*)lhs); } #endif // If we are guaranteed that the LHS will be evaluated before the RHS, // or if the LHS is pure (not merely side-effect-free), // then we can generate the RHS under the original effect context. if (IsOrderedStandardFunc(op)) { // || lhs_eff_accum.is_pure()) { TODO: need more thoughts on the purity issue. rhs = Expression::make_random(cg_context, rhs_type); } else { // Otherwise, the RHS must be generated under the combined effect // of the original effect and the LHS effect. Effect rhs_eff_context(cg_context.get_effect_context()); rhs_eff_context.add_effect(lhs_eff_accum, true); Effect rhs_eff_accum; CGContext rhs_cg_context(cg_context, rhs_eff_context, &rhs_eff_accum); if (op == eLShift || op == eRShift) { eTermType tt = MAX_TERM_TYPES; bool not_constant = rnd_flipcoin(ShiftByNonConstantProb); // avoid shifting negative or too much if (!not_constant) { rhs = Constant::make_random_upto(lhs_type->SizeInBytes() * 8); } else { rhs = Expression::make_random(rhs_cg_context, rhs_type, NULL, false, true, tt); } } else { rhs = Expression::make_random(rhs_cg_context, rhs_type); // avoid divide by zero or possible zero (reached by pointer comparison) if ((op == eMod || op == eDiv) && (rhs->equals(0) || rhs->is_0_or_1()) && !lhs_type->is_float() && !rhs_type->is_float()) { VectorFilter f; f.add(eMod).add(eDiv).add(eLShift).add(eRShift); op = (eBinaryOps)(rnd_upto(MAX_BINARY_OP, &f)); fi->set_operation(op); } } cg_context.merge_param_context(rhs_cg_context, true); } ERROR_GUARD_AND_DEL2(NULL, fi, lhs); if (!BinaryOpWorksForFloat(op)) { assert(!lhs->get_type().is_float() && "lhs is of float!"); assert(!rhs->get_type().is_float() && "rhs is of float!"); } if (CompatibleChecker::compatible_check(lhs, rhs)) { Error::set_error(COMPATIBLE_CHECK_ERROR); delete lhs; delete rhs; delete fi; return NULL; } // ordered operators such as "||" or "&&" may skip the 2nd parameter if (IsOrderedStandardFunc(op)) { fm->makeup_new_var_facts(facts_copy, fm->global_facts); merge_facts(fm->global_facts, facts_copy); } // TODO: fix `rhs' for eLShift and eRShift and ... // Currently, the "fix" is handled in `FunctionInvocationBinary::Output'. fi->param_value.push_back(lhs); fi->param_value.push_back(rhs); return fi; }
TEST(Expression_Builder, can_build_digit_multiply) { ExpressionBuilder builder("2*3", NULL); Expression* expression = builder.Build(); ASSERT_EQ(2*3, expression->Calculate()); }
TEST(Expression_Builder, can_build_digit_divide) { ExpressionBuilder builder("3/2", NULL); Expression* expression = builder.Build(); ASSERT_EQ(3.0/2.0, expression->Calculate()); }
bool DataReference::gather_info_data_expr_rec(Expression expr, Symbol &base_sym, Source &size, Source &addr, Type &type, bool enclosing_is_array, bool & pointer_member_access, std::stringstream& warnlog) { if (expr.is_id_expression() || expr.is_this_variable() || expr.is_accessed_member()) { Symbol sym(NULL); if (expr.is_this_variable()) { sym = expr.get_this_symbol(); } else { sym = expr.get_id_expression().get_computed_symbol(); } if (!sym.is_valid()) { warnlog << expr.get_ast().get_locus() << ": warning: unknown symbol in data-reference '" << expr.prettyprint() << "'" << std::endl; return false; } if (!sym.is_variable()) { warnlog << expr.get_ast().get_locus() << ": warning: symbol in data-reference '" << expr.prettyprint() << "' " << "is not a variable" << std::endl; return false; } base_sym = sym; Source this_accessor; if(expr.is_id_expression() && sym.is_member() && !sym.is_static()) { this_accessor << "this->"; } type = sym.get_type(); if (type.is_reference()) type = type.references_to(); if (type.is_array() || enclosing_is_array) { addr << this_accessor << sym.get_qualified_name(); } else { addr << "&" << this_accessor << sym.get_qualified_name(); } size = safe_expression_size(type, expr.get_scope()); return true; } else if (expr.is_array_subscript()) { Source arr_size, arr_addr; Type arr_type(NULL); bool b = gather_info_data_expr_rec(expr.get_subscripted_expression(), base_sym, arr_size, arr_addr, arr_type, /* enclosing_is_array */ true, pointer_member_access, warnlog); if (!b) { return false; } if (arr_type.is_array()) { type = arr_type.array_element(); } else if (arr_type.is_pointer()) { type = arr_type.points_to(); } else { warnlog << expr.get_ast().get_locus() << ": warning: array subscript in data-reference '" << expr.prettyprint() << "' is not a variable" << std::endl; return false; } size = safe_expression_size(type, expr.get_scope()); addr = arr_addr << "[" << expr.get_subscript_expression() << "]"; if (!enclosing_is_array) { addr = "&(" + addr.get_source() + ")"; } return true; } else if (expr.is_array_section_range() || expr.is_array_section_size()) { ObjectList<Expression> range_set; Expression current_expr = expr; while (current_expr.is_array_section_range() || current_expr.is_array_section_size()) { range_set.append(current_expr); current_expr = current_expr.array_section_item(); } // Now check that everything makes sense. // - We allow a pointer or an array at the first dimension // - Every other dimension must be an array Type current_type = current_expr.get_type(); for (ObjectList<Expression>::iterator it = range_set.begin(); it != range_set.end(); it++) { if (current_type.is_reference()) current_type = current_type.references_to(); if (!(current_type.is_array() || (current_type.is_pointer() && it == range_set.begin()))) { // Not valid if (!current_type.is_array() && !current_type.is_pointer()) { warnlog << expr.get_ast().get_locus() << ": warning: array section in data-reference '" << expr.prettyprint() << "' is not a pointer or array type" << std::endl; } else if (current_type.is_pointer()) { warnlog << expr.get_ast().get_locus() << ": warning: array section in data-reference '" << expr.prettyprint() << "' is a pointer type but it is not the first section" << std::endl; } return false; } if (current_type.is_array()) { current_type = current_type.array_element(); } else { current_type = current_type.points_to(); } } Source arr_size, arr_addr; Type arr_type(NULL); bool b = gather_info_data_expr_rec(current_expr, base_sym, arr_size, arr_addr, arr_type, /* enclosing_is_array */ true, pointer_member_access, warnlog); if (!b) return false; // Now rebuild the type Type rebuilt_type = current_type; for (ObjectList<Expression>::iterator it = range_set.begin(); it != range_set.end(); it++) { Expression& section(*it); Source upper_bound; if (section.is_array_section_size()) { upper_bound << "((" << section.array_section_lower() << ") + (" << section.array_section_upper() << ") - 1)" ; } else if (section.is_array_section_range()) { upper_bound << section.array_section_upper() ; } AST_t upper_bound_tree = upper_bound.parse_expression(section.get_ast(), section.get_scope_link()); rebuilt_type = rebuilt_type.get_array_to(section.array_section_lower().get_ast(), upper_bound_tree, section.get_scope()); arr_addr << "[" << section.array_section_lower() << "]" ; } addr = arr_addr; type = rebuilt_type; if (!enclosing_is_array) { addr = "&(" + addr.get_source() + ")"; } size = safe_expression_size(type, expr.get_scope()); return true; } else if (expr.is_unary_operation()) { if (expr.get_operation_kind() == Expression::REFERENCE) { Expression ref_expr = expr.get_unary_operand(); if (ref_expr.is_unary_operation() && ref_expr.get_operation_kind() == Expression::DERREFERENCE) { // Case &(*a) return gather_info_data_expr_rec(ref_expr.get_unary_operand(), base_sym, size, addr, type, enclosing_is_array, pointer_member_access, warnlog); } else if (ref_expr.is_array_subscript()) { // Case &(a[0]) return gather_info_data_expr_rec(ref_expr.get_subscripted_expression(), base_sym, size, addr, type, enclosing_is_array, pointer_member_access, warnlog); } else if (ref_expr.is_array_section_range() || ref_expr.is_array_section_size()) { // Case &(a[0:4]) // Case &(a[0;5]) return gather_info_data_expr_rec(ref_expr.array_section_item(), base_sym, size, addr, type, enclosing_is_array, pointer_member_access, warnlog); } } else if (expr.get_operation_kind() == Expression::DERREFERENCE) { Expression ref_expr = expr.get_unary_operand(); if (ref_expr.is_unary_operation() && ref_expr.get_operation_kind() == Expression::REFERENCE) { // Case *(&a) return gather_info_data_expr_rec(ref_expr.get_unary_operand(), base_sym, size, addr, type, enclosing_is_array, pointer_member_access, warnlog); } else { // Case *a Source ptr_size, ptr_addr; bool b = gather_info_data_expr_rec(ref_expr, base_sym, ptr_size, ptr_addr, type, enclosing_is_array, pointer_member_access, warnlog); if (!b) return false; if (type.is_pointer()) { type = type.points_to(); } else if (type.is_array()) { type = type.array_element(); } size = safe_expression_size(type, expr.get_scope()); addr = "(" + ref_expr.prettyprint() + ")"; return true; } } warnlog << expr.get_ast().get_locus() << ": warning: expression '" << expr.prettyprint() << "' is not a valid data-reference" << std::endl; return false; } else if (expr.is_shaping_expression()) { Expression shaped_expr = expr.shaped_expression(); Source arr_size, arr_addr; bool b = gather_info_data_expr_rec(shaped_expr, base_sym, arr_size, arr_addr, type, /* enclosing_is_array */ true, pointer_member_access, warnlog); if (!b) return false; CXX_LANGUAGE() { if (type.is_reference()) { type = type.references_to(); } } // Array to pointer if (type.is_array()) { type = type.array_element().get_pointer_to(); } if (!type.is_pointer()) { warnlog << expr.get_ast().get_locus() << ": warning: in data reference '" << expr.prettyprint() << "' shaped expression does not have pointer type" << std::endl; return false; } type = type.points_to(); ObjectList<Expression> shape_list = expr.shape_list(); for (ObjectList<Expression>::reverse_iterator it = shape_list.rbegin(); it != shape_list.rend(); it++) { type = type.get_array_to(it->get_ast(), it->get_scope()); } size = safe_expression_size(type, expr.get_scope()); Type cast_type = type.array_element().get_pointer_to(); addr << "((" << cast_type.get_declaration(expr.get_scope(), "") << ")" << arr_addr << ")"; return true; }
inline std::string SqlTranslator::BuildQuery() { m_query.clear(); m_expression->Apply(*this); return m_query; }
DataReference::DataReference(Expression expr) : Expression(expr.get_ast(), expr.get_scope_link()), _valid(), _base_symbol(NULL), _type(NULL), _size(), _addr() { _valid = gather_info_data_expr(*this, _base_symbol, _size, _addr, _type, _warnlog); }
void PragmaDeclaration::semantic(Scope *sc) { // Should be merged with PragmaStatement //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); if (ident == Id::msg) { if (args) { for (size_t i = 0; i < args->dim; i++) { Expression *e = args->tdata()[i]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); StringExp *se = e->toString(); if (se) { fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); } else fprintf(stdmsg, "%s", e->toChars()); } fprintf(stdmsg, "\n"); } goto Lnodecl; } else if (ident == Id::lib) { if (!args || args->dim != 1) error("string expected for library name"); else { Expression *e = args->tdata()[0]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); args->tdata()[0] = e; if (e->op == TOKerror) goto Lnodecl; StringExp *se = e->toString(); if (!se) error("string expected for library name, not '%s'", e->toChars()); else if (global.params.verbose) { char *name = (char *)mem.malloc(se->len + 1); memcpy(name, se->string, se->len); name[se->len] = 0; printf("library %s\n", name); mem.free(name); } } goto Lnodecl; } #if IN_GCC else if (ident == Id::GNU_asm) { if (! args || args->dim != 2) error("identifier and string expected for asm name"); else { Expression *e; Declaration *d = NULL; StringExp *s = NULL; e = args->tdata()[0]; e = e->semantic(sc); if (e->op == TOKvar) { d = ((VarExp *)e)->var; if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) d = NULL; } if (!d) error("first argument of GNU_asm must be a function or variable declaration"); e = args->tdata()[1]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); e = e->toString(); if (e && ((StringExp *)e)->sz == 1) s = ((StringExp *)e); else error("second argument of GNU_asm must be a char string"); if (d && s) d->c_ident = Lexer::idPool((char*) s->string); } goto Lnodecl; } #endif #if DMDV2 else if (ident == Id::startaddress) { if (!args || args->dim != 1) error("function name expected for start address"); else { Expression *e = args->tdata()[0]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); args->tdata()[0] = e; Dsymbol *sa = getDsymbol(e); if (!sa || !sa->isFuncDeclaration()) error("function name expected for start address, not '%s'", e->toChars()); } goto Lnodecl; } #endif #if TARGET_NET else if (ident == Lexer::idPool("assembly")) { } #endif // TARGET_NET else if (global.params.ignoreUnsupportedPragmas) { if (global.params.verbose) { /* Print unrecognized pragmas */ printf("pragma %s", ident->toChars()); if (args) { for (size_t i = 0; i < args->dim; i++) { Expression *e = args->tdata()[i]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); if (i == 0) printf(" ("); else printf(","); printf("%s", e->toChars()); } if (args->dim) printf(")"); } printf("\n"); } goto Lnodecl; } else error("unrecognized pragma(%s)", ident->toChars()); if (decl) { for (unsigned i = 0; i < decl->dim; i++) { Dsymbol *s = decl->tdata()[i]; s->semantic(sc); } } return; Lnodecl: if (decl) error("pragma is missing closing ';'"); }
ExpressionResult IncludeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { if (frame.Sandboxed) BOOST_THROW_EXCEPTION(ScriptError("Includes are not allowed in sandbox mode.", m_DebugInfo)); Expression *expr; String name, path, pattern; switch (m_Type) { case IncludeRegular: { ExpressionResult pathres = m_Path->Evaluate(frame, dhint); CHECK_RESULT(pathres); path = pathres.GetValue(); } expr = ConfigCompiler::HandleInclude(m_RelativeBase, path, m_SearchIncludes, m_Zone, m_Package, m_DebugInfo); break; case IncludeRecursive: { ExpressionResult pathres = m_Path->Evaluate(frame, dhint); CHECK_RESULT(pathres); path = pathres.GetValue(); } { ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint); CHECK_RESULT(patternres); pattern = patternres.GetValue(); } expr = ConfigCompiler::HandleIncludeRecursive(m_RelativeBase, path, pattern, m_Zone, m_Package, m_DebugInfo); break; case IncludeZones: { ExpressionResult nameres = m_Name->Evaluate(frame, dhint); CHECK_RESULT(nameres); name = nameres.GetValue(); } { ExpressionResult pathres = m_Path->Evaluate(frame, dhint); CHECK_RESULT(pathres); path = pathres.GetValue(); } { ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint); CHECK_RESULT(patternres); pattern = patternres.GetValue(); } expr = ConfigCompiler::HandleIncludeZones(m_RelativeBase, name, path, pattern, m_Package, m_DebugInfo); break; } ExpressionResult res(Empty); try { res = expr->Evaluate(frame, dhint); } catch (const std::exception&) { delete expr; throw; } delete expr; return res; }
static void dismantle_multi_dim_array_expression( SuifEnv *env, MultiDimArrayExpression *exp, TypeBuilder *type_builder, suif_hash_map<MultiDimArrayType *,Type *> &type_map) { Expression *ref_exp = exp->get_array_address(); Type *typ = ref_exp->get_result_type(); if (is_kind_of<PointerType>(typ)) typ = to<PointerType>(typ)->get_reference_type(); if (is_kind_of<ReferenceType>(typ)) typ = to<ReferenceType>(typ)->get_reference_type(); if (is_kind_of<QualifiedType>(typ)) typ = to<QualifiedType>(typ)->get_base_type(); simple_stack<Expression *> lows; int dims; Type *rep_type; if (is_kind_of<MultiDimArrayType>(typ)) { MultiDimArrayType *mdatyp= to<MultiDimArrayType>(typ); suif_hash_map<MultiDimArrayType *,Type *>::iterator iter = type_map.find(mdatyp); kernel_assert_message(iter != type_map.end(), ("Error - type not converted")); rep_type = (*iter).second; dims = exp->get_index_count(); for (int i = dims - 1;i >=0 ; i--) { lows.push(mdatyp->get_lower_bound(i)); } } else { // this arm should never be taken, so assert kernel_assert_message(false,("This code should not have been accessed")); rep_type = typ; dims = 0; while (is_kind_of<ArrayType>(typ)) { ArrayType *atype = to<ArrayType>(typ); dims ++; lows.push(atype->get_lower_bound()); typ = to<QualifiedType>(atype->get_element_type())->get_base_type(); } } exp->replace(ref_exp,0); ref_exp->set_parent(0); int index_count = exp->get_index_count(); for (int i = 0;i < index_count;i ++) { Type *ref_type = rep_type; for (int j = 0;j <= i;j ++) { ref_type = type_builder->unqualify_type(ref_type); ref_type = to<ArrayType>(ref_type)->get_element_type(); } ref_type = type_builder->unqualify_type(ref_type); ref_type = type_builder->get_pointer_type(ref_type); Expression *index = exp->get_index(index_count - i - 1); // process nested multi dim arra expressions for (Iter<MultiDimArrayExpression> iter = object_iterator<MultiDimArrayExpression>(index); iter.is_valid(); iter.next()) { MultiDimArrayExpression *mexpr = &iter.current(); dismantle_multi_dim_array_expression(env,mexpr,type_builder,type_map); } exp->replace(index,0); index->set_parent(0); ref_exp = create_array_reference_expression( env,to<DataType>(ref_type),ref_exp, index); } exp->get_parent()->replace(exp,ref_exp); }
TEST(Expression_Builder, can_build_digit) { ExpressionBuilder builder("1", NULL); Expression* expression = builder.Build(); ASSERT_EQ(1,expression->Calculate()); }
Expression *createTypeInfoArray(Scope *sc, Expression *exps[], unsigned dim) { #if 1 /* Get the corresponding TypeInfo_Tuple and * point at its elements[]. */ /* Create the TypeTuple corresponding to the types of args[] */ Parameters *args = new Parameters; args->setDim(dim); for (size_t i = 0; i < dim; i++) { Parameter *arg = new Parameter(STCin, exps[i]->type, NULL, NULL); args->tdata()[i] = arg; } TypeTuple *tup = new TypeTuple(args); Expression *e = tup->getTypeInfo(sc); e = e->optimize(WANTvalue); assert(e->op == TOKsymoff); // should be SymOffExp #if BREAKABI /* * Should just pass a reference to TypeInfo_Tuple instead, * but that would require existing code to be recompiled. * Source compatibility can be maintained by computing _arguments[] * at the start of the called function by offseting into the * TypeInfo_Tuple reference. */ #else // Advance to elements[] member of TypeInfo_Tuple SymOffExp *se = (SymOffExp *)e; se->offset += PTRSIZE + PTRSIZE; // Set type to TypeInfo[]* se->type = Type::typeinfo->type->arrayOf()->pointerTo(); // Indirect to get the _arguments[] value e = new PtrExp(0, se); e->type = se->type->next; #endif return e; #else /* Improvements: * 1) create an array literal instead, * as it would eliminate the extra dereference of loading the * static variable. */ ArrayInitializer *ai = new ArrayInitializer(0); VarDeclaration *v; Type *t; Expression *e; OutBuffer buf; Identifier *id; char *name; // Generate identifier for _arguments[] buf.writestring("_arguments_"); for (int i = 0; i < dim; i++) { t = exps[i]->type; t->toDecoBuffer(&buf); } buf.writeByte(0); id = Lexer::idPool((char *)buf.data); Module *m = sc->module; Dsymbol *s = m->symtab->lookup(id); if (s && s->parent == m) { // Use existing one v = s->isVarDeclaration(); assert(v); } else { // Generate new one for (int i = 0; i < dim; i++) { t = exps[i]->type; e = t->getTypeInfo(sc); ai->addInit(new IntegerExp(i), new ExpInitializer(0, e)); } t = Type::typeinfo->type->arrayOf(); ai->type = t; v = new VarDeclaration(0, t, id, ai); m->members->push(v); m->symtabInsert(v); sc = sc->push(); sc->linkage = LINKc; sc->stc = STCstatic | STCcomdat; ai->semantic(sc, t); v->semantic(sc); v->parent = m; sc = sc->pop(); } e = new VarExp(0, v); e = e->semantic(sc); return e; #endif }
TEST(Expression_Builder, can_build_expression_whith_bracket) { ExpressionBuilder builder("(1+2)*3", NULL); Expression* expression = builder.Build(); ASSERT_EQ( (1+2)*3, expression->Calculate()); }
void source_name(Dsymbol *s) { char *name = s->ident->toChars(); TemplateInstance *ti = s->isTemplateInstance(); if (ti) { if (!substitute(ti->tempdecl)) { store(ti->tempdecl); name = ti->name->toChars(); buf.printf("%d%s", strlen(name), name); } buf.writeByte('I'); bool is_var_arg = false; for (size_t i = 0; i < ti->tiargs->dim; i++) { RootObject *o = (RootObject *)(*ti->tiargs)[i]; TemplateParameter *tp = NULL; TemplateValueParameter *tv = NULL; TemplateTupleParameter *tt = NULL; if (!is_var_arg) { TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration(); tp = (*td->parameters)[i]; tv = tp->isTemplateValueParameter(); tt = tp->isTemplateTupleParameter(); } /* * <template-arg> ::= <type> # type or template * ::= <expr-primary> # simple expressions */ if (tt) { buf.writeByte('I'); is_var_arg = true; tp = NULL; } if (tv) { // <expr-primary> ::= L <type> <value number> E # integer literal if (tv->valType->isintegral()) { Expression* e = isExpression(o); assert(e); buf.writeByte('L'); tv->valType->accept(this); if (tv->valType->isunsigned()) { buf.printf("%llu", e->toUInteger()); } else { dinteger_t val = e->toInteger(); if (val < 0) { val = -val; buf.writeByte('n'); } buf.printf("%lld", val); } buf.writeByte('E'); } else { s->error("ICE: C++ %s template value parameter is not supported", tv->valType->toChars()); assert(0); } } else if (!tp || tp->isTemplateTypeParameter()) { Type *t = isType(o); assert(t); t->accept(this); } else if (tp->isTemplateAliasParameter()) { Dsymbol* d = isDsymbol(o); Expression* e = isExpression(o); if (!d && !e) { s->error("ICE: %s is unsupported parameter for C++ template: (%s)", o->toChars()); assert(0); } if (d && d->isFuncDeclaration()) { bool is_nested = d->toParent() && !d->toParent()->isModule() && ((TypeFunction *)d->isFuncDeclaration()->type)->linkage == LINKcpp; if (is_nested) buf.writeByte('X'); buf.writeByte('L'); mangle_function(d->isFuncDeclaration()); buf.writeByte('E'); if (is_nested) buf.writeByte('E'); } else if (e && e->op == TOKvar && ((VarExp*)e)->var->isVarDeclaration()) { VarDeclaration *vd = ((VarExp*)e)->var->isVarDeclaration(); buf.writeByte('L'); mangle_variable(vd, true); buf.writeByte('E'); } else if (d && d->isTemplateDeclaration() && d->isTemplateDeclaration()->onemember) { if (!substitute(d)) { cpp_mangle_name(d); store(d); } } else { s->error("ICE: %s is unsupported parameter for C++ template", o->toChars()); assert(0); } } else { s->error("ICE: C++ templates support only integral value , type parameters, alias templates and alias function parameters"); assert(0); } } if (is_var_arg) { buf.writeByte('E'); } buf.writeByte('E'); return; } else { buf.printf("%d%s", strlen(name), name); } }
TEST(Expression_Builder, can_expression_whith_unary_minus) { ExpressionBuilder builder("-3*2", NULL); Expression* expression = builder.Build(); ASSERT_EQ(-3*2, expression->Calculate()); }
FunctionInvocation * FunctionInvocation::make_random_binary_ptr_comparison(CGContext &cg_context) { eBinaryOps op = rnd_flipcoin(50) ? eCmpEq : eCmpNe; ERROR_GUARD(NULL); SafeOpFlags *flags = SafeOpFlags::make_random_binary(get_int_type(), NULL, NULL, sOpBinary, op); ERROR_GUARD(NULL); FunctionInvocation *fi = FunctionInvocationBinary::CreateFunctionInvocationBinary(cg_context, op, flags); const Type* type = Type::choose_random_pointer_type(); ERROR_GUARD_AND_DEL1(NULL, fi); Effect lhs_eff_accum; CGContext lhs_cg_context(cg_context, cg_context.get_effect_context(), &lhs_eff_accum); lhs_cg_context.flags |= NO_DANGLING_PTR; Expression *lhs = Expression::make_random(lhs_cg_context, type, 0, true); ERROR_GUARD_AND_DEL1(NULL, fi); cg_context.merge_param_context(lhs_cg_context, true); // now focus on RHS ... enum eTermType tt = MAX_TERM_TYPES; // if LHS is const, there is no need for RHS to be const as well if (lhs->term_type == eConstant) { tt = eVariable; } Expression *rhs = 0; // If we are guaranteed that the LHS will be evaluated before the RHS, // or if the LHS is pure (not merely side-effect-free), // then we can generate the RHS under the original effect context. if (IsOrderedStandardFunc(op)) { // lhs_eff_accum.is_pure()) JYTODO: purity needs to be redefined // although we don't need care about other side effect, we do // need to pass in NO_DANGLING_PTR flag unsigned int old_flag = cg_context.flags; cg_context.flags |= NO_DANGLING_PTR; rhs = Expression::make_random(cg_context, type, 0, true, false, tt); cg_context.flags = old_flag; } else { // Otherwise, the RHS must be generated under the combined effect // of the original effect and the LHS effect. Effect rhs_eff_context(cg_context.get_effect_context()); rhs_eff_context.add_effect(lhs_eff_accum); Effect rhs_eff_accum; CGContext rhs_cg_context(cg_context, rhs_eff_context, &rhs_eff_accum); rhs_cg_context.flags |= NO_DANGLING_PTR; rhs = Expression::make_random(rhs_cg_context, type, 0, true, false, tt); cg_context.merge_param_context(rhs_cg_context, true); } ERROR_GUARD_AND_DEL2(NULL, fi, lhs); // typecast, if needed. rhs->check_and_set_cast(&lhs->get_type()); // TODO: fix `rhs' for eLShift and eRShift and ... // Currently, the "fix" is handled in `FunctionInvocationBinary::Output'. fi->param_value.push_back(lhs); fi->param_value.push_back(rhs); fi->ptr_cmp = true; // bookkeeping for pointers Bookkeeper::record_pointer_comparisons(lhs, rhs); return fi; }
TEST(Expression_Builder, can_expression_whith_unary_minus_and_whith_bracket) { ExpressionBuilder builder("4*(-3)", NULL); Expression* expression = builder.Build(); ASSERT_EQ(4*(-3), expression->Calculate()); }
void EnumMember::semantic(Scope *sc) { //printf("EnumMember::semantic() %s\n", toChars()); if (errors || semanticRun >= PASSsemanticdone) return; if (semanticRun == PASSsemantic) { error("circular reference to enum member"); Lerrors: errors = true; semanticRun = PASSsemanticdone; return; } assert(ed); ed->semantic(sc); if (ed->errors) goto Lerrors; if (errors || semanticRun >= PASSsemanticdone) return; semanticRun = PASSsemantic; if (scope) sc = scope; // The first enum member is special bool first = (this == (*ed->members)[0]); if (type) { type = type->semantic(loc, sc); assert(value); // "type id;" is not a valid enum member declaration } if (value) { Expression *e = value; assert(e->dyncast() == DYNCAST_EXPRESSION); e = e->semantic(sc); e = resolveProperties(sc, e); e = e->ctfeInterpret(); if (e->op == TOKerror) goto Lerrors; if (first && !ed->memtype && !ed->isAnonymous()) { ed->memtype = e->type; if (ed->memtype->ty == Terror) { ed->errors = true; goto Lerrors; } } if (ed->memtype && !type) { e = e->implicitCastTo(sc, ed->memtype); e = e->ctfeInterpret(); // save origValue for better json output origValue = e; if (!ed->isAnonymous()) e = e->castTo(sc, ed->type); } else if (type) { e = e->implicitCastTo(sc, type); e = e->ctfeInterpret(); assert(ed->isAnonymous()); // save origValue for better json output origValue = e; } value = e; } else if (first) { Type *t; if (ed->memtype) t = ed->memtype; else { t = Type::tint32; if (!ed->isAnonymous()) ed->memtype = t; } Expression *e = new IntegerExp(loc, 0, Type::tint32); e = e->implicitCastTo(sc, t); e = e->ctfeInterpret(); // save origValue for better json output origValue = e; if (!ed->isAnonymous()) e = e->castTo(sc, ed->type); value = e; } else { /* Find the previous enum member, * and set this to be the previous value + 1 */ EnumMember *emprev = NULL; for (size_t i = 0; i < ed->members->dim; i++) { EnumMember *em = (*ed->members)[i]->isEnumMember(); if (em) { if (em == this) break; emprev = em; } } assert(emprev); if (emprev->semanticRun < PASSsemanticdone) // if forward reference emprev->semantic(emprev->scope); // resolve it if (emprev->errors) goto Lerrors; Expression *eprev = emprev->value; Type *tprev = eprev->type->equals(ed->type) ? ed->memtype : eprev->type; Expression *emax = tprev->getProperty(ed->loc, Id::max, 0); emax = emax->semantic(sc); emax = emax->ctfeInterpret(); // Set value to (eprev + 1). // But first check that (eprev != emax) assert(eprev); Expression *e = new EqualExp(TOKequal, loc, eprev, emax); e = e->semantic(sc); e = e->ctfeInterpret(); if (e->toInteger()) { error("initialization with (%s.%s + 1) causes overflow for type '%s'", emprev->ed->toChars(), emprev->toChars(), ed->type->toBasetype()->toChars()); goto Lerrors; } // Now set e to (eprev + 1) e = new AddExp(loc, eprev, new IntegerExp(loc, 1, Type::tint32)); e = e->semantic(sc); e = e->castTo(sc, eprev->type); e = e->ctfeInterpret(); // save origValue (without cast) for better json output if (e->op != TOKerror) // avoid duplicate diagnostics { assert(emprev->origValue); origValue = new AddExp(loc, emprev->origValue, new IntegerExp(loc, 1, Type::tint32)); origValue = origValue->semantic(sc); origValue = origValue->ctfeInterpret(); } if (e->op == TOKerror) goto Lerrors; if (e->type->isfloating()) { // Check that e != eprev (not always true for floats) Expression *etest = new EqualExp(TOKequal, loc, e, eprev); etest = etest->semantic(sc); etest = etest->ctfeInterpret(); if (etest->toInteger()) { error("has inexact value, due to loss of precision"); goto Lerrors; } } value = e; } assert(origValue); semanticRun = PASSsemanticdone; }
TEST(Expression_Builder, can_expression_whith_variable) { ExpressionBuilder builder("a*(1+2)", new ConsoleStub(2)); // à = 2; Expression* expression = builder.Build(); ASSERT_EQ(2*(1 + 2), expression->Calculate()); }
static BlockScopeRawPtr originalScope(StaticClassName *scn) { Expression *e = dynamic_cast<Expression*>(scn); if (e) return e->getOriginalScope(); return dynamic_cast<Statement*>(scn)->getScope(); }
Walker::ApplyStatus NonConstDimExpressionWalker::operator () (SuifObject *x) { if (_rev_map.find(x) != _rev_map.end()) return Walker::Continue; ArrayExpressionProxy exp(to<Expression>(x)); Expression *ref_exp = exp.get_array_address(); ArrayTypeProxy type(exp.get_array_type()); if (!type.has_non_const_bounds()) return Walker::Continue; DataType *element_type = type.get_element_type(); IInteger bit_size = element_type->get_bit_size(); int dims = exp.get_dimension_count(); int type_dims = type.get_dimension_count(); Expression *index = 0; Expression *offset = 0; int missing_dims = type_dims - dims; // the more nested dims are the missing ones for (int i = type_dims-1;i >=0;i--) { // This code uses an iterative approach which is not good in general // as it serialises everything in the generated code Expression *low = type.get_lower_bound(i); Expression *next_index; if (i < missing_dims) { next_index = low; } else { next_index = exp.get_index(i-missing_dims); } if (!index) { index = next_index; offset = low; } else { Expression *high = type.get_upper_bound(i); Expression *elements = build_dyadic_expression(k_add, build_dyadic_expression(k_subtract, high, low), create_int_constant(get_env(), low->get_result_type(), 1)); index = build_dyadic_expression(k_add, next_index, build_dyadic_expression(k_multiply, elements, index)); offset = build_dyadic_expression(k_add, low, build_dyadic_expression(k_multiply, elements, offset)); } } index = build_dyadic_expression(k_subtract,index,offset); ref_exp = create_array_reference_expression( get_env(), type.get_element_type(), to<Expression>(ref_exp->deep_clone()), index); // next line is done automatically // x->get_parent()->replace(x,ref_exp); _rev_map.enter_value(ref_exp,x); set_address(ref_exp); return Walker::Replaced; }
void ParallelCoordinatesViewerEnginePluginInfo::InitializePlotAtts( AttributeSubject *atts, const avtPlotMetaData &plot) { // If we had scalar names, we can just copy the default atts // and return. if (defaultAtts->GetScalarAxisNames().size() != 0) { // One helpful thing we can do: make sure the user set the // visual axis names. They really should have, but since // we can blindly copy them from the scalar axis names in // this case, no harm doing it for them. if (defaultAtts->GetVisualAxisNames().size() == 0) defaultAtts->SetVisualAxisNames(defaultAtts->GetScalarAxisNames()); *(ParallelCoordinatesAttributes*)atts = *defaultAtts; return; } // Otherwise, we must be an array variable; try to get // some names for its components.... const avtDatabaseMetaData *md = plot.GetMetaData(); const std::string &var = plot.GetVariableName(); const avtArrayMetaData *array = md->GetArray(var); stringVector subNames; if (array) { subNames = array->compNames; } else { Expression *exp = ParsingExprList::GetExpression(plot.GetVariableName()); if (exp == NULL || exp->GetType() != Expression::ArrayMeshVar) { debug3 << "ParallelCoordinatesAttributes::InitializePlotAtts: " << "variable wasn't an array database variable, an " << "array expression, or a list of scalars. This can " << "happen if the user attempts to create this plot " << "without the use off a wizard, e.g. in the case of " << "the cli. Assuming this is the case and continuing " << "without error.\n"; return; } // If we have any problems walking the expression tree, just return; // the worst case scenario if we don't populate the visual axis // name list is that the GUI window is temporarily blank. ExprNode *root = ParsingExprList::GetExpressionTree(exp); if (root->GetTypeName() != "Function") return; FunctionExpr *fn = dynamic_cast<FunctionExpr*>(root); if (fn->GetName() != "array_compose" && fn->GetName() != "array_compose_with_bins") return; ArgsExpr *argsExpr = fn->GetArgsExpr(); std::vector<ArgExpr*> *args = argsExpr ? argsExpr->GetArgs() : NULL; if (!args) return; for (size_t i=0; i<args->size(); i++) { ExprNode *arg = (ExprNode*)((*args)[i]->GetExpr()); if (arg->GetTypeName() == "List") break; subNames.push_back(arg->GetPos().GetText(exp->GetDefinition())); } } doubleVector extMin(subNames.size(), -1e+37); doubleVector extMax(subNames.size(), +1e+37); // Set up the default attributes to contain these values, so // if the user hits reset, the axis names are retained. defaultAtts->SetVisualAxisNames(subNames); defaultAtts->SetExtentMinima(extMin); defaultAtts->SetExtentMaxima(extMax); *(ParallelCoordinatesAttributes*)atts = *defaultAtts; }
/** Convert ArrayReferenceExpression \a top_array to a MultiDimArrayExpression. */ void OneDimArrayConverter:: convert_array_expr2multi_array_expr(ArrayReferenceExpression* top_array){ Expression* expr = top_array; unsigned int i = 0; suif_vector<Expression*> lower_bounds; suif_vector<Expression*> upper_bounds; list<Expression*> indices; IInteger bit_size, bit_alignment; suif_vector<ArrayReferenceExpression *> exprs; do{ ArrayReferenceExpression* are = to<ArrayReferenceExpression>(expr); expr = are->get_base_array_address(); exprs.push_back(are); } while(is_kind_of<ArrayReferenceExpression>(expr)); // collect bounds and indeces for (unsigned int exp_ind = 0; exp_ind < exprs.size();exp_ind++) { ArrayReferenceExpression* are = exprs[exp_ind]; DataType* type = are->get_base_array_address()->get_result_type(); ArrayType* array_type; if(is_kind_of<ArrayType>(type)){ array_type = to<ArrayType>(type); }else{ array_type = to<ArrayType>( unwrap_ptr_ref_type(type)->get_base_type()); } bit_size = array_type->get_element_type()-> get_base_type()->get_bit_size(); bit_alignment = array_type->get_element_type()-> get_base_type()->get_bit_alignment(); // What happens to ArrayType?? Does it become garbage? suif_assert(array_type->get_lower_bound()); suif_assert(array_type->get_upper_bound()); // clone bounds and add to the lists lower_bounds.push_back(array_type->get_lower_bound()); upper_bounds.push_back(array_type->get_upper_bound()); // save the index Expression* index = are->get_index(); remove_suif_object(index); index->set_parent(NULL); indices.push_back(index); suif_assert(upper_bounds[i]); suif_assert(lower_bounds[i]); suif_assert(indices[i]); i++; } // Build the offset for the expression. We have to traverse upwards to do this Expression *top_expr_base = exprs[exprs.size()-1]->get_base_array_address(); DataType* top_expr_base_type = top_expr_base->get_result_type(); ArrayType* top_array_type; if(is_kind_of<ArrayType>(top_expr_base_type)){ top_array_type = to<ArrayType>(top_expr_base_type); }else{ top_array_type = to<ArrayType>(tb->unqualify_data_type(unwrap_ptr_ref_type( top_expr_base_type))); } Expression* inc = create_int_constant(suif_env, 1); Expression* offset = create_int_constant(suif_env, 0); suif_vector<Expression *> elements; for (unsigned int ind = 0;ind < lower_bounds.size(); ind ++) { Expression *lower = lower_bounds[ind]; Expression *upper = upper_bounds[ind]; offset = build_dyadic_expression(k_add, offset, build_dyadic_expression( k_multiply, deep_suif_clone(inc), deep_suif_clone(lower))); Expression *element = build_dyadic_expression(k_add, build_dyadic_expression(k_subtract, deep_suif_clone(upper), deep_suif_clone(lower)), create_int_constant(suif_env,1)); inc = build_dyadic_expression(k_multiply, inc, deep_suif_clone(element)); elements.push_back(element); } // Now, inc and offset are ready // retrieve the multi-type MultiDimArrayType* multi_type; suif_map<ArrayType*, MultiDimArrayType*>::iterator type_iter = type_map->find(top_array_type); #ifdef CONVERT_TYPES suif_assert_message((type_iter != type_map->end()), ("Array type never translated")); #else if(type_iter == type_map->end()){ multi_type = array_type2multi_array_type(top_array_type); }else #endif //CONVERT_TYPES multi_type = (*type_iter).second; remove_suif_object(top_expr_base); // add a convert to the necessary type top_expr_base = create_unary_expression(suif_env, tb->get_pointer_type(multi_type), k_convert, top_expr_base); //top_expr_base->print_to_default(); // construct the expression to be returned MultiDimArrayExpression* mae = create_multi_dim_array_expression(suif_env, top_array->get_result_type(), top_expr_base, offset); // now when we have the expression, set the indices for (list<Expression*>::iterator ind_iter = indices.begin(); ind_iter!=indices.end(); ind_iter++) { Expression* index = *ind_iter; //printf("%p \t", index);index->print_to_default(); mae->append_index(index); } for (suif_vector<Expression *>::iterator eiter = elements.begin(); eiter != elements.end(); eiter ++) { Expression* element = *eiter; mae->append_element(element); } replace_expression(top_array, mae); }
void ParamMapFixup::Do(const Expression& Exp) { ParamMapFixup Fixup; Exp->Accept(&Fixup); return; }
Expression *AddrExp::optimize(int result) { Expression *e; //printf("AddrExp::optimize(result = %d) %s\n", result, toChars()); /* Rewrite &(a,b) as (a,&b) */ if (e1->op == TOKcomma) { CommaExp *ce = (CommaExp *)e1; AddrExp *ae = new AddrExp(loc, ce->e2); ae->type = type; e = new CommaExp(ce->loc, ce->e1, ae); e->type = type; return e->optimize(result); } if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; if (ve->var->storage_class & STCmanifest) e1 = e1->optimize(result); } else e1 = e1->optimize(result); // Convert &*ex to ex if (e1->op == TOKstar) { Expression *ex; ex = ((PtrExp *)e1)->e1; if (type->equals(ex->type)) e = ex; else { e = ex->copy(); e->type = type; } return e; } if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; if (!ve->var->isOut() && !ve->var->isRef() && !ve->var->isImportedSymbol()) { SymOffExp *se = new SymOffExp(loc, ve->var, 0, ve->hasOverloads); se->type = type; return se; } } if (e1->op == TOKindex) { // Convert &array[n] to &array+n IndexExp *ae = (IndexExp *)e1; if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) { integer_t index = ae->e2->toInteger(); VarExp *ve = (VarExp *)ae->e1; if (ve->type->ty == Tsarray && !ve->var->isImportedSymbol()) { TypeSArray *ts = (TypeSArray *)ve->type; integer_t dim = ts->dim->toInteger(); if (index < 0 || index >= dim) error("array index %jd is out of bounds [0..%jd]", index, dim); e = new SymOffExp(loc, ve->var, index * ts->nextOf()->size()); e->type = type; return e; } } } return this; }