LocalVar* push_local_var(const char* name, const QoreProgramLocation& loc, const QoreTypeInfo* typeInfo, bool is_arg, int n_refs, bool top_level) { QoreProgram* pgm = getProgram(); LocalVar* lv = pgm->createLocalVar(name, typeInfo); QoreString ls; loc.toString(ls); //printd(5, "push_local_var() lv: %p name: %s type: %s %s\n", lv, name, typeInfo->getName(), ls.getBuffer()); bool found_block = false; // check stack for duplicate entries bool avs = parse_check_parse_option(PO_ASSUME_LOCAL); if (is_arg) { lv->parseAssigned(); if (pgm->checkWarning(QP_WARN_DUPLICATE_LOCAL_VARS | QP_WARN_DUPLICATE_BLOCK_VARS) || avs) { VNode* vnode = getVStack(); while (vnode) { if (!found_block && vnode->isBlockStart()) found_block = true; if (!strcmp(vnode->getName(), name)) { if (!found_block) { QoreStringNode* desc = new QoreStringNodeMaker("local variable '%s' was already declared in the same block", name); if (avs) { vnode->appendLocation(*desc); parseException(loc, "PARSE-ERRPR", desc); } else { vnode->appendLocation(*desc); qore_program_private::makeParseWarning(getProgram(), loc, QP_WARN_DUPLICATE_BLOCK_VARS, "DUPLICATE-BLOCK-VARIABLE", desc); } } else if (top_level || !vnode->isTopLevel()) { QoreStringNode* desc = new QoreStringNodeMaker("local variable '%s' was already declared in this lexical scope", name); vnode->appendLocation(*desc); qore_program_private::makeParseWarning(getProgram(), loc, QP_WARN_DUPLICATE_LOCAL_VARS, "DUPLICATE-LOCAL-VARIABLE", desc); } break; } vnode = vnode->nextSearch(); } } } //printd(5, "push_local_var(): pushing var %s\n", name); new VNode(lv, &loc, n_refs, top_level); return lv; }
int SwitchStatement::parseInitImpl(LocalVar *oflag, int pflag) { int lvids = 0; // turn off top-level flag for statement vars pflag &= (~PF_TOP_LEVEL); const QoreTypeInfo *argTypeInfo = 0; if (sexp) sexp = sexp->parseInit(oflag, pflag, lvids, argTypeInfo); CaseNode *w = head; ExceptionSink xsink; QoreProgram *pgm = getProgram(); while (w) { if (w->val) { argTypeInfo = 0; w->val = w->val->parseInit(oflag, pflag | PF_CONST_EXPRESSION, lvids, argTypeInfo); if (lvids) { parse_error("illegal local variable declaration in assignment expression for case block"); while (lvids--) pop_local_var(); w = w->next; continue; } // evaluate case expression if necessary and no parse expressions have been raised if (w->val && !w->val->is_value()) { if (pgm->parseExceptionRaised()) { w = w->next; continue; } ReferenceHolder<AbstractQoreNode> v(w->val->eval(&xsink), &xsink); if (!xsink) { w->val->deref(&xsink); w->val = v.release(); if (!w->val) w->val = nothing(); } else qore_program_private::addParseException(pgm, xsink); } //printd(5, "SwitchStatement::parseInit() this=%p case exp: %p %s\n", this, w->val, get_type_name(w->val)); // check for duplicate values CaseNode *cw = head; while (cw != w) { // Check only the simple case blocks (case 1: ...), // not those with relational operators. Could be changed later to provide more checking. // note that no exception can be raised here as the case node values are parse values if (w->isCaseNode() && cw->isCaseNode() && !compareHard(w->val, cw->val, &xsink)) parse_error("duplicate case values in switch"); assert(!xsink); cw = cw->next; } } if (w->code) w->code->parseInitImpl(oflag, pflag); w = w->next; } // save local variables if (lvids) lvars = new LVList(lvids); return 0; }
int ConstantEntry::parseInit(ClassNs ptr) { //printd(5, "ConstantEntry::parseInit() this: %p '%s' pub: %d init: %d in_init: %d node: %p '%s' class context: %p '%s' ns: %p ('%s') pub: %d\n", this, name.c_str(), pub, init, in_init, node, get_type_name(node), ptr.getClass(), ptr.getClass() ? ptr.getClass()->name.c_str() : "<none>", ptr.getNs(), ptr.getNs() ? ptr.getNs()->name.c_str() : "<none>", ptr.getNs() ? ptr.getNs()->pub : 0); if (init) return 0; if (in_init) { parse_error("recursive constant reference found to constant '%s'", name.c_str()); return 0; } ConstantEntryInitHelper ceih(*this); if (!node) return 0; int lvids = 0; { // set parse location in case of errors ParseLocationHelper plh(loc); // push parse class context qore_class_private* p = ptr.getClass(); QoreParseClassHelper qpch(p ? p->cls : 0); // ensure that there is no accessible local variable state VariableBlockHelper vbh; // set parse options and warning mask for this statement ParseWarnHelper pwh(pwo); //printd(5, "ConstantEntry::parseInit() this: %p '%s' about to init node: %p '%s' class: %p '%s'\n", this, name.c_str(), node, get_type_name(node), p, p ? p->name.c_str() : "n/a"); if (typeInfo) typeInfo = 0; node = node->parseInit((LocalVar*)0, PF_CONST_EXPRESSION, lvids, typeInfo); } //printd(5, "ConstantEntry::parseInit() this: %p %s initialized to node: %p (%s) value: %d\n", this, name.c_str(), node, get_type_name(node), node->is_value()); if (node->is_value()) return 0; // do not evaluate expression if any parse exceptions have been thrown QoreProgram* pgm = getProgram(); if (pgm->parseExceptionRaised()) { discard(node, 0); node = 0; typeInfo = nothingTypeInfo; return -1; } // evaluate expression ExceptionSink xsink; { ReferenceHolder<AbstractQoreNode> v(node->eval(&xsink), &xsink); //printd(5, "ConstantEntry::parseInit() this: %p %s evaluated to node: %p (%s)\n", this, name.c_str(), *v, get_type_name(*v)); if (!xsink) { node->deref(&xsink); node = v.release(); if (!node) { node = nothing(); typeInfo = nothingTypeInfo; } else { typeInfo = getTypeInfoForValue(node); check_constant_cycle(pgm, node); // address circular refs: pgm->const->pgm } } else { node->deref(&xsink); node = 0; typeInfo = nothingTypeInfo; } } if (xsink.isEvent()) qore_program_private::addParseException(pgm, xsink, &loc); // scan for call references if (scanValue(node)) { saved_node = node; node = new RuntimeConstantRefNode(refSelf()); } return 0; }