bool SymbolWithValue::getArrayValueAsString(std::string& vstr) { BV8K dval; bool oktoprint = getValueReadyToPrint(dval); if(!oktoprint) return false; UTI tuti = getUlamTypeIdx(); UlamType * tut = m_state.getUlamTypeByIndex(tuti); if(tut->getTotalBitSize() == 0) { vstr = "10"; //empty array return true; } //get the number of bits for this type into u64 // convert to a lex-number as a string, applying type specifics // return the completed string of all the array values in arg vstr. std::ostringstream tovstr; s32 bs = tut->getBitSize(); s32 arraysize = tut->getArraySize(); for(s32 i=0; i < arraysize; i++) { u64 thisval = dval.ReadLong(i * bs, bs); //pos and len std::string str; convertValueToALexString(thisval, tuti, str, m_state); tovstr << str; } vstr = tovstr.str(); return true; } //getArrayValueAsString
void NodeVarRef::printTypeAndName(File * fp) { UTI vuti = m_varSymbol->getUlamTypeIdx(); UlamKeyTypeSignature vkey = m_state.getUlamKeyTypeSignatureByIndex(vuti); UlamType * vut = m_state.getUlamTypeByIndex(vuti); if(m_state.isConstantRefType(vuti)) fp->write(" constant"); //t41242,3 fp->write(" "); if(vut->getUlamTypeEnum() != Class) { fp->write(vkey.getUlamKeyTypeSignatureNameAndBitSize(&m_state).c_str()); fp->write("&"); //<--the only difference!!! } else fp->write(vut->getUlamTypeClassNameBrief(vuti).c_str()); //includes any & fp->write(" "); fp->write(getName()); s32 arraysize = m_state.getArraySize(vuti); if(arraysize > NONARRAYSIZE) { fp->write("["); fp->write_decimal(arraysize); fp->write("]"); } else if(arraysize == UNKNOWNSIZE) { fp->write("[UNKNOWN]"); } } //printTypeAndName
// replaced by NodeVarDecl:genCode to leverage the declaration order preserved by the parse tree. void SymbolVariableDataMember::generateCodedVariableDeclarations(File * fp, ULAMCLASSTYPE classtype) { assert(classtype == UC_ELEMENT); //really? UTI vuti = getUlamTypeIdx(); UlamType * vut = m_state.getUlamTypeByIndex(vuti); ULAMCLASSTYPE vclasstype = vut->getUlamClassType(); m_state.indentUlamCode(fp); fp->write(vut->getUlamTypeMangledName().c_str()); //for C++ if(vclasstype == UC_QUARK) //called on classtype elements only { fp->write("<"); fp->write_decimal(getPosOffset()); fp->write(">"); } fp->write(" "); fp->write(getMangledName().c_str()); #if 0 s32 arraysize = vut->getArraySize(); if(arraysize > NONARRAYSIZE) { fp->write("["); fp->write_decimal(arraysize); fp->write("]"); } else if(arraysize == UNKNOWNSIZE) { fp->write("[UNKNOWN]"); } #endif fp->write(";"); GCNL; } //generateCodedVariableDeclarations
FORECAST UlamTypePrimitive::explicitlyCastable(UTI typidx) { FORECAST scr = UlamType::safeCast(typidx); //default if(scr == CAST_CLEAR) { // primitives must be the same sizes when casting to a reference type if(isReference() && !UlamType::checkReferenceCast(typidx)) scr = CAST_BAD; // strings cannot be cast explicitly to other primitive types, except Void (t3961) UlamType * vut = m_state.getUlamTypeByIndex(typidx); ULAMTYPE valtypEnum = vut->getUlamTypeEnum(); if((getUlamTypeEnum() != Void) && ((valtypEnum == String) ^ (getUlamTypeEnum() == String))) scr = CAST_BAD; //only quarks may be cast to Ints, explicitly or not; requires toInt method (t3996) if(valtypEnum == Class) { ULAMCLASSTYPE vclasstype = vut->getUlamClassType(); if(vclasstype != UC_QUARK) scr = CAST_BAD; } } return scr; } //explicitlyCastable
//atomic parameter type, not model parameter. const std::string Symbol::getMangledNameForParameterType() { assert(!isModelParameter()); UlamType * sut = m_state.getUlamTypeByIndex(getUlamTypeIdx()); ULAMCLASSTYPE classtype = sut->getUlamClass(); //another way, like this? if(isModelParameter()) { std::ostringstream epmangled; epmangled << sut->getImmediateModelParameterStorageTypeAsString(); //if(classtype == UC_QUARK) // epmangled << "::Us"; assert(classtype == UC_NOTACLASS); return epmangled.str(); } // to distinguish btn an atomic parameter typedef and quark typedef; // use atomic parameter with array of classes bool isaclass = (( classtype == UC_QUARK || classtype == UC_ELEMENT || classtype == UC_UNSEEN) && sut->isScalar()); std::ostringstream pmangled; pmangled << Symbol::getParameterTypePrefix(isaclass).c_str() << getMangledName(); return pmangled.str(); } //getMangledNameForParameterType
UlamValue NodeInstanceof::makeUlamValuePtr() { // (from NodeVarDecl's makeUlamValuePtr) UlamValue ptr; UlamValue atomuv; UTI auti = getOfType(); UlamType * aut = m_state.getUlamTypeByIndex(auti); ULAMCLASSTYPE aclasstype = aut->getUlamClassType(); u32 atop = 1; atop = m_state.m_funcCallStack.getAbsoluteStackIndexOfSlot(atop); if(m_state.isAtom(auti)) atomuv = UlamValue::makeAtom(auti); else if(aclasstype == UC_ELEMENT) atomuv = UlamValue::makeDefaultAtom(auti, m_state); else if(aclasstype == UC_QUARK) { u32 dq = 0; AssertBool isDefinedQuark = m_state.getDefaultQuark(auti, dq); //returns scalar dq assert(isDefinedQuark); atomuv = UlamValue::makeImmediateClass(auti, dq, aut->getTotalBitSize()); } else if(aclasstype == UC_TRANSIENT) atomuv = UlamValue::makeDefaultAtom(auti, m_state); //size limited to atom for eval else m_state.abortUndefinedUlamClassType(); m_state.m_funcCallStack.storeUlamValueAtStackIndex(atomuv, atop); //stackframeslotindex ? ptr = UlamValue::makePtr(atop, STACK, auti, m_state.determinePackable(auti), m_state, 0); ptr.setUlamValueTypeIdx(PtrAbs); return ptr; } //makeUlamValuePtr
void NodeVarRefAs::genCodeRefAsSelf(File * fp, UVPass& uvpass) { //no tmpref needed since 'self' (i.e. ur) is already a C++ reference //t3821, t3815 (transient), t3828 (quark) Symbol * stgcos = m_state.m_currentObjSymbolsForCodeGen[0]; UTI vuti = m_varSymbol->getUlamTypeIdx(); UlamType * vut = m_state.getUlamTypeByIndex(vuti); m_state.indentUlamCode(fp); fp->write(vut->getLocalStorageTypeAsString().c_str()); //for C++ local vars, ie non-data members fp->write(" "); fp->write(m_varSymbol->getMangledName().c_str()); fp->write("("); fp->write(stgcos->getMangledName().c_str()); //stg fp->write(", 0u, "); fp->write(stgcos->getMangledName().c_str()); //stg fp->write(".GetEffectiveSelf()"); fp->write("); //shadows lhs of 'as'"); GCNL; m_state.indentUlamCode(fp); fp->write("UlamRef<EC>& ur = "); fp->write(m_varSymbol->getMangledName().c_str()); fp->write("; //shadows self"); GCNL; m_varSymbol->setIsSelf(); //nope m_state.clearCurrentObjSymbolsForCodeGen(); //clear remnant of lhs } //genCodeRefAsSelf
EvalStatus NodeVarRefAs::eval() { assert(m_varSymbol); UTI nuti = getNodeType(); if(nuti == Nav) return ERROR; if(nuti == Hzy) return NOTREADY; assert(m_varSymbol->getUlamTypeIdx() == nuti); assert(!m_state.isAtom(nuti)); //rhs type of conditional as/has can't be an atom UlamValue pluv = m_state.m_currentAutoObjPtr; ((SymbolVariableStack *) m_varSymbol)->setAutoPtrForEval(pluv); //for future ident eval uses UTI luti = pluv.getPtrTargetType(); assert(m_state.okUTItoContinue(luti)); UlamType * lut = m_state.getUlamTypeByIndex(luti); ULAMCLASSTYPE lclasstype = lut->getUlamClassType(); UTI autostgtype = m_state.m_currentAutoStorageType; if((UlamType::compare(autostgtype, UAtom, m_state) == UTIC_SAME) && (lclasstype == UC_ELEMENT)) autostgtype = luti; //e.g. funccall expects a class, not an atom (t3636) ((SymbolVariableStack *) m_varSymbol)->setAutoStorageTypeForEval(autostgtype); //for future virtual function call eval uses //m_state.m_funcCallStack.storeUlamValueInSlot(pluv, ((SymbolVariableStack *) m_varSymbol)->getStackFrameSlotIndex()); //doesn't seem to matter.. return NORMAL; } //eval
const std::string NodeBinaryOpEqualShift::methodNameForCodeGen() { std::ostringstream methodname; //methodname << "_Shift"; determined by each op UlamType * nut = m_state.getUlamTypeByIndex(getNodeType()); // common part of name ULAMTYPE etyp = nut->getUlamTypeEnum(); switch(etyp) { case Int: case Unsigned: case Bool: case Unary: case Bits: methodname << UlamType::getUlamTypeEnumAsString(etyp); break; default: m_state.abortUndefinedUlamPrimitiveType(); break; }; methodname << nut->getTotalWordSize(); return methodname.str(); } //methodNameForCodeGen
const std::string UlamType::castMethodForCodeGen(UTI nodetype) { std::ostringstream rtnMethod; UlamType * nut = m_state.getUlamTypeByIndex(nodetype); //base types e.g. Int, Bool, Unary, Foo, Bar.. u32 sizeByIntBitsToBe = getTotalWordSize(); u32 sizeByIntBits = nut->getTotalWordSize(); if(sizeByIntBitsToBe != sizeByIntBits) { std::ostringstream msg; msg << "Casting different word sizes; " << sizeByIntBits; msg << ", Value Type and size was: " << nut->getUlamTypeName().c_str(); msg << ", to be: " << sizeByIntBitsToBe << " for type: "; msg << getUlamTypeName().c_str(); MSG(m_state.getFullLocationAsString(m_state.m_locOfNextLineText).c_str(), msg.str().c_str(), DEBUG); //use the larger word size if(sizeByIntBitsToBe < sizeByIntBits) //downcast using larger sizeByIntBitsToBe = sizeByIntBits; else sizeByIntBits = sizeByIntBitsToBe; } rtnMethod << "_" << nut->getUlamTypeNameOnly().c_str() << sizeByIntBits << "To"; rtnMethod << getUlamTypeNameOnly().c_str() << sizeByIntBitsToBe; return rtnMethod.str(); } //castMethodForCodeGen
// replaces NodeTypedef:printPostfix to learn the values of Class' storage in center site void SymbolTypedef::printPostfixValuesOfVariableDeclarations(File * fp, s32 slot, u32 startpos, ULAMCLASSTYPE classtype) { UTI tuti = getUlamTypeIdx(); UlamKeyTypeSignature tkey = m_state.getUlamKeyTypeSignatureByIndex(tuti); UlamType * tut = m_state.getUlamTypeByIndex(tuti); fp->write(" typedef"); fp->write(" "); if(tut->getUlamTypeEnum() != Class) fp->write(tkey.getUlamKeyTypeSignatureNameAndBitSize(&m_state).c_str()); else fp->write(tut->getUlamTypeNameBrief().c_str()); fp->write(" "); fp->write(m_state.m_pool.getDataAsString(getId()).c_str()); s32 arraysize = m_state.getArraySize(tuti); if(arraysize > NONARRAYSIZE) { fp->write("["); fp->write_decimal(arraysize); fp->write("]"); } else if(arraysize == UNKNOWNSIZE) { fp->write("[UNKNOWN]"); } fp->write("; "); } //printPostfixValuesOfVariableDeclarations
const std::string NodeBinaryOpEqualArith::methodNameForCodeGen() { std::ostringstream methodname; //methodname << "_BitwiseOr"; determined by each op UlamType * nut = m_state.getUlamTypeByIndex(getNodeType()); // common part of name ULAMTYPE etyp = nut->getUlamTypeEnum(); switch(etyp) { case Int: case Unsigned: case Bool: case Unary: methodname << UlamType::getUlamTypeEnumAsString(etyp); break; case Bits: default: assert(0); methodname << "NAV"; break; }; methodname << nut->getTotalWordSize(); return methodname.str(); } //methodNameForCodeGen
UTI NodeBinaryOpEqualArith::checkAndLabelType() { UTI nodeType = NodeBinaryOpEqual::checkAndLabelType(); UlamType * nut = m_state.getUlamTypeByIndex(nodeType); // common part of name ULAMTYPE enodetyp = nut->getUlamTypeEnum(); if(enodetyp == Bits) { // can happen with op-equal operations when both sides are the same type MSG(getNodeLocationAsString().c_str(), "Arithmetic Operations are invalid on 'Bits' type", ERR); nodeType = Nav; } if(enodetyp == Bool) { // can happen with op-equal operations when both sides are the same type MSG(getNodeLocationAsString().c_str(), "Arithmetic Operations are invalid on 'Bool' type", ERR); nodeType = Nav; } if((nodeType != Nav) && !nut->isScalar()) { std::ostringstream msg; msg << "Non-scalars require a loop for operator" << getName(); MSG(getNodeLocationAsString().c_str(), msg.str().c_str(), ERR); nodeType = Nav; } setNodeType(nodeType); return nodeType; } //checkAndLabelType
void NodeUnaryOp::genCode(File * fp, UVPass& uvpass) { assert(m_node); m_node->genCode(fp, uvpass); UTI nuti = getNodeType(); UlamType * nut = m_state.getUlamTypeByIndex(nuti); s32 tmpVarNum = m_state.getNextTmpVarNumber(); m_state.indentUlamCode(fp); fp->write("const "); fp->write(nut->getTmpStorageTypeAsString().c_str()); //e.g. u32, s32, u64.. fp->write(" "); fp->write(m_state.getTmpVarAsString(nuti, tmpVarNum, TMPREGISTER).c_str()); fp->write(" = "); fp->write(methodNameForCodeGen().c_str()); fp->write("("); fp->write(uvpass.getTmpVarAsString(m_state).c_str()); fp->write(", "); fp->write_decimal(nut->getBitSize()); fp->write(");"); GCNL; uvpass = UVPass::makePass(tmpVarNum, TMPREGISTER, nuti, m_state.determinePackable(nuti), m_state, 0, 0); //POS 0 rightjustified. } //genCode
const std::string NodeBinaryOpCompare::methodNameForCodeGen() { std::ostringstream methodname; //methodname << "_BitwiseOr"; determined by each op UlamType * lut = m_state.getUlamTypeByIndex(m_nodeLeft->getNodeType()); // common part of name ULAMTYPE etyp = lut->getUlamTypeEnum(); switch(etyp) { case Int: methodname << "Int"; break; case Unsigned: methodname << "Unsigned"; break; case Bits: methodname << "Bits"; break; case Bool: methodname << "Bool"; break; case String: methodname << "String"; break; default: m_state.abortUndefinedUlamPrimitiveType(); methodname << "NAV"; break; }; methodname << lut->getTotalWordSize(); return methodname.str(); } // methodNameForCodeGen
FORECAST NodeConstantArray::safeToCastTo(UTI newType) { if(isReadyConstant()) { UlamType * newut = m_state.getUlamTypeByIndex(newType); return newut->safeCast(getNodeType()); } return CAST_HAZY; } //safeToCastTo
void NodeConstantArray::makeUVPassForCodeGen(UVPass& uvpass) { assert(m_constSymbol); s32 tmpnum = m_state.getNextTmpVarNumber(); UTI nuti = getNodeType(); UlamType * nut = m_state.getUlamTypeByIndex(nuti); uvpass = UVPass::makePass(tmpnum, nut->getTmpStorageTypeForTmpVar(), nuti, m_state.determinePackable(nuti), m_state, 0, m_constSymbol->getId()); }
bool SymbolWithValue::convertValueToANonPrettyString(u64 varg, UTI tuti, std::string& vstr, CompilerState & state) { std::ostringstream ostr; UlamType * tut = state.getUlamTypeByIndex(tuti); s32 bs = tut->getBitSize(); ULAMTYPE etyp = tut->getUlamTypeEnum(); switch(etyp) { case Int: { if(bs <= MAXBITSPERINT) { s32 sval = _Int32ToInt32((u32) varg, bs, MAXBITSPERINT); ostr << sval; } else if(bs <= MAXBITSPERLONG) { s64 sval = _Int64ToInt64(varg, bs, MAXBITSPERLONG); ostr << sval; } else state.abortGreaterThanMaxBitsPerLong(); } break; case Unsigned: { if( bs <= MAXBITSPERINT) ostr << (u32) varg << "u"; else if( bs <= MAXBITSPERLONG) ostr << varg << "u"; else state.abortGreaterThanMaxBitsPerLong(); } break; case Unary: case Bool: case Bits: case Class: { ostr << "0x" << std::hex << varg; } break; case String: { std::string fstr = state.getDataAsUnFormattedUserString((u32) varg); u32 flen = fstr.length() - 1; //exclude null terminator for(u32 i = 0; i < flen; i++) ostr << std::hex << std::setfill('0') << std::setw(2) << (u32) fstr[i]; } break; default: state.abortUndefinedUlamType(); }; vstr = ostr.str(); return true; } //convertValueToANonPrettyString (static helper)
UTI NodeBinaryOpCompare::checkAndLabelType() { assert(m_nodeLeft && m_nodeRight); UTI leftType = m_nodeLeft->checkAndLabelType(); UTI rightType = m_nodeRight->checkAndLabelType(); UlamType * lut = m_state.getUlamTypeByIndex(leftType); if((lut->getUlamTypeEnum() == Class)) { Node * newnode = buildOperatorOverloadFuncCallNode(); if(newnode) { AssertBool swapOk = Node::exchangeNodeWithParent(newnode); assert(swapOk); m_nodeLeft = NULL; //recycle as memberselect m_nodeRight = NULL; //recycle as func call arg delete this; //suicide is painless.. return newnode->checkAndLabelType(); //t41109 } //else should fail again as non-primitive; } //done UTI newType = calcNodeType(leftType, rightType); //for casting if(m_state.isComplete(newType)) { u32 errCnt = 0; if(UlamType::compareForMakingCastingNode(rightType, newType, m_state) != UTIC_SAME) { if(!Node::makeCastingNode(m_nodeRight, newType, m_nodeRight)) errCnt++; } if(UlamType::compareForMakingCastingNode(leftType, newType, m_state) != UTIC_SAME) { if(!Node::makeCastingNode(m_nodeLeft, newType, m_nodeLeft)) errCnt++; } if(errCnt) newType = Nav; else newType = Bool; //always Bool (default size) for node; after castings! } setNodeType(newType); if(newType == Hzy) m_state.setGoAgain(); //nolonger needed in calcnodetypes Node::setStoreIntoAble(TBOOL_FALSE); //still may need casting (e.g. unary compared to an int) before constantfolding if((newType != Nav) && isAConstant() && m_nodeLeft->isReadyConstant() && m_nodeRight->isReadyConstant()) return NodeBinaryOp::constantFold(); return newType; } //checkAndLabelType
void NodeBinaryOpEqualShift::genCode(File * fp, UVPass& uvpass) { assert(m_nodeLeft && m_nodeRight); assert(m_state.m_currentObjSymbolsForCodeGen.empty()); // generate rhs first; may update current object globals (e.g. function call) UVPass ruvpass; m_nodeRight->genCode(fp, ruvpass); // restore current object globals assert(m_state.m_currentObjSymbolsForCodeGen.empty()); // lhs should be the new current object: node member select updates them, // but a plain NodeIdent does not!!! because genCodeToStoreInto has been repurposed // to mean "don't read into a TmpVar" (e.g. by NodeCast). UVPass luvpass; m_nodeLeft->genCodeToStoreInto(fp, luvpass); //may update m_currentObjSymbol //wiped out by left read; need to write back into left std::vector<Symbol *> saveCOSVector = m_state.m_currentObjSymbolsForCodeGen; uvpass = luvpass; //keep luvpass slot untouched Node::genCodeReadIntoATmpVar(fp, uvpass); m_state.m_currentObjSymbolsForCodeGen = saveCOSVector; //restore vector after lhs read************* UTI nuti = getNodeType(); UlamType * nut = m_state.getUlamTypeByIndex(nuti); s32 tmpVarNum = m_state.getNextTmpVarNumber(); m_state.indentUlamCode(fp); fp->write("const "); fp->write(nut->getTmpStorageTypeAsString().c_str()); //e.g. u32, s32, u64.. fp->write(" "); fp->write(m_state.getTmpVarAsString(nuti, tmpVarNum, TMPREGISTER).c_str()); fp->write(" = "); fp->write(methodNameForCodeGen().c_str()); fp->write("("); fp->write(uvpass.getTmpVarAsString(m_state).c_str()); fp->write(", "); fp->write(ruvpass.getTmpVarAsString(m_state).c_str()); fp->write(", "); fp->write_decimal(nut->getBitSize()); fp->write(");"); GCNL; uvpass = UVPass::makePass(tmpVarNum, TMPREGISTER, nuti, m_state.determinePackable(nuti), m_state, uvpass.getPassPos(), uvpass.getPassNameId()); //P // current object globals should pertain to lhs for the write genCodeWriteFromATmpVar(fp, luvpass, uvpass); //uses rhs' tmpvar; orig lhs assert(m_state.m_currentObjSymbolsForCodeGen.empty()); } //genCode
bool NodeMemberSelect::passalongUVPass() { bool rtnb = false; //don't pass along if(!m_state.m_currentObjSymbolsForCodeGen.empty()) { Symbol * cossym = m_state.m_currentObjSymbolsForCodeGen.back(); UTI cosuti = cossym->getUlamTypeIdx(); UlamType * cosut = m_state.getUlamTypeByIndex(cosuti); //t3913, t3915 tmpref may not be a ref, but may need adjusting (i.e. anonymous element returned) rtnb = (!cosut->isReference() && (!cossym->isTmpVarSymbol() || Node::needAdjustToStateBits(cosuti))); } return rtnb; }
UTI NodeControl::checkAndLabelType() { assert(m_nodeCondition && m_nodeBody); UTI newType = Bool; ULAMTYPE newEnumTyp = Bool; // condition should be a bool, safely cast UTI cuti = m_nodeCondition->checkAndLabelType(); if(m_state.okUTItoContinue(cuti) && m_state.isComplete(cuti)) { assert(m_state.isScalar(cuti)); UlamType * cut = m_state.getUlamTypeByIndex(cuti); ULAMTYPE ctypEnum = cut->getUlamTypeEnum(); if(ctypEnum != newEnumTyp) { if(checkSafeToCastTo(cuti, newType)) { if(!Node::makeCastingNode(m_nodeCondition, newType, m_nodeCondition)) newType = Nav; } //else not safe, newType changed } else { //caution: c&l called multiple times //always cast: Bools are maintained as unsigned in gen code, //until c-bool is needed if(cuti != newType) { if(checkSafeToCastTo(cuti, newType)) { if(!Node::makeCastingNode(m_nodeCondition, cuti, m_nodeCondition)) newType = Nav; else newType = cuti; } } } } else { newType = Hzy; //was = cuti; m_state.setGoAgain(); } m_nodeBody->checkAndLabelType(); //side-effect setNodeType(newType); //stays the same Node::setStoreIntoAble(TBOOL_FALSE); return getNodeType(); } //checkAndLabelType
void NodeAtomof::genCodeToStoreInto(File * fp, UVPass& uvpass) { //lhs, no longer allowed with packed elements assert(getStoreIntoAble() == TBOOL_TRUE); UTI nuti = getNodeType(); //UAtomRef if(m_nodeOf->hasASymbolReference() && (m_state.getUlamTypeByIndex(getOfType())->getUlamClassType() == UC_QUARK)) { Symbol * stgcos = NULL; AssertBool gotstg = m_nodeOf->getStorageSymbolPtr(stgcos); assert(gotstg); m_state.indentUlamCode(fp); fp->write("if("); fp->write(stgcos->getMangledName().c_str()); fp->write(".GetType() == T::ATOM_UNDEFINED_TYPE)"); GCNL; m_state.m_currentIndentLevel++; m_state.indentUlamCode(fp); fp->write("FAIL(NOT_AN_ELEMENT);"); GCNL; m_state.m_currentIndentLevel--; UlamType * nut = m_state.getUlamTypeByIndex(nuti); s32 tmpVarNum = m_state.getNextTmpVarNumber(); //tmp for atomref m_state.indentUlamCode(fp); //non-const fp->write(nut->getLocalStorageTypeAsString().c_str()); //for C++ local vars fp->write(" "); fp->write(m_state.getTmpVarAsString(nuti, tmpVarNum, TMPBITVAL).c_str()); fp->write("("); fp->write(stgcos->getMangledName().c_str()); //ur for self fp->write(", "); //is storage! can't be const (error/t3659) fp->write(" - T::ATOM_FIRST_STATE_BIT"); //must be an effective element ref (e.g.t3684, t3663) fp->write("); //atomof"); GCNL; uvpass = UVPass::makePass(tmpVarNum, TMPBITVAL, nuti, UNPACKED, m_state, uvpass.getPassPos(), uvpass.getPassNameId()); } else { //lhs assert(getStoreIntoAble() == TBOOL_TRUE); assert(m_nodeOf); m_nodeOf->genCodeToStoreInto(fp, uvpass); //does it handle array item members selected? assert(!m_state.m_currentObjSymbolsForCodeGen.empty()); uvpass = UVPass::makePass(uvpass.getPassVarNum(), TMPTATOM, getNodeType(), UNPACKED, m_state, uvpass.getPassPos(), uvpass.getPassNameId()); } } //genCodeToStoreInto
FORECAST UlamTypeInt::safeCast(UTI typidx) { FORECAST scr = UlamType::safeCast(typidx); if(scr != CAST_CLEAR) return scr; bool brtn = true; UlamType * vut = m_state.getUlamTypeByIndex(typidx); s32 valbitsize = m_state.getBitSize(typidx); s32 bitsize = getBitSize(); ULAMTYPE valtypEnum = vut->getUlamTypeEnum(); switch(valtypEnum) { case Int: brtn = (bitsize >= valbitsize); break; case Unsigned: brtn = (bitsize > valbitsize); break; case Unary: brtn = (bitsize > (s32) _getLogBase2(valbitsize) + 1); break; case Bool: case Bits: case Void: case UAtom: brtn = false; break; case Class: { //must be Quark! treat as Int if it has a toInt method if(vut->isNumericType()) brtn = (bitsize >= MAXBITSPERINT); else { std::ostringstream msg; msg << "Class: "; msg << m_state.getUlamTypeNameBriefByIndex(typidx).c_str(); msg << " is not a numeric type and cannot be safely cast to an Int"; MSG(m_state.getFullLocationAsString(m_state.m_locOfNextLineText).c_str(),msg.str().c_str(), ERR); brtn = false; } } break; default: assert(0); //std::cerr << "UlamTypeInt (cast) error! Value Type was: " << valtypidx << std::endl; brtn = false; }; return brtn ? CAST_CLEAR : CAST_BAD; } //safeCast
UTI NodeBinaryOpArithRemainder::castThyselfToResultType(UTI rt, UTI lt, UTI newType) { UTI nuti = newType; //because the result bitsize for mod should be the right bitsize // create a cast! combining newType's base type and right resultbitsize. // could be the same, or "unsafe". if(m_state.okUTItoContinue(newType) && m_state.isComplete(newType)) { UlamType * newut = m_state.getUlamTypeByIndex(newType); ULAMTYPE typEnum = newut->getUlamTypeEnum(); u32 convertSize = m_state.getUlamTypeByIndex(rt)->bitsizeToConvertTypeTo(typEnum); u32 enumStrIdx = m_state.m_pool.getIndexForDataString(UlamType::getUlamTypeEnumAsString(typEnum)); UlamKeyTypeSignature tokey(enumStrIdx, convertSize, NONARRAYSIZE); ULAMCLASSTYPE newclasstype = newut->getUlamClassType(); nuti = m_state.makeUlamType(tokey, typEnum, newclasstype); if(UlamType::compareForMakingCastingNode(nuti, newType, m_state) != UTIC_SAME) //not same, or dontknow { NNO pno = Node::getYourParentNo(); //save assert(pno); //not using use makeCastingNode since don't want recursive c&l call Node * castNode = Node::newCastingNode(this, nuti); Node * parentNode = m_state.findNodeNoInThisClass(pno); if(!parentNode) { std::ostringstream msg; msg << "Remainder cast cannot be exchanged at this time while compiling class: "; msg << m_state.getUlamTypeNameBriefByIndex(m_state.getCompileThisIdx()).c_str(); msg << " Parent required"; MSG(getNodeLocationAsString().c_str(), msg.str().c_str(), DEBUG); assert(0); //parent required } AssertBool swapOk = parentNode->exchangeKids(this, castNode); assert(swapOk); std::ostringstream msg; msg << "Exchanged kids! of parent of binary operator" << getName(); msg << ", with a cast to type: "; msg << m_state.getUlamTypeNameBriefByIndex(nuti).c_str(); msg << " while compiling class: "; msg << m_state.getUlamTypeNameBriefByIndex(m_state.getCompileThisIdx()).c_str(); MSG(getNodeLocationAsString().c_str(), msg.str().c_str(), DEBUG); castNode->setYourParentNo(pno); //inverts normal update lineage setYourParentNo(castNode->getNodeNo()); } } return nuti; } //castThyselfToResultType
bool SymbolWithValue::getArrayItemValue(u32 item, u64& rtnitem) { if(isReady()) { UTI suti = getUlamTypeIdx(); UlamType * sut = m_state.getUlamTypeByIndex(suti); u32 bs = sut->getBitSize(); s32 arrsize = sut->getArraySize(); assert(bs <= MAXBITSPERLONG); assert((arrsize >= 0) && (item < (u32) arrsize)); //no casting! rtnitem = m_constantValue.ReadLong(item * bs, bs); return true; } return false; }
// eval() no longer performed before check and label // returns false if error; UNKNOWNSIZE is not an error! bool NodeSquareBracket::getArraysizeInBracket(s32 & rtnArraySize) { bool noerr = true; // since square brackets determine the constant size for this type, else error s32 newarraysize = NONARRAYSIZE; UTI sizetype = m_nodeRight->checkAndLabelType(); if(sizetype == Nav) { rtnArraySize = UNKNOWNSIZE; return true; } UlamType * sizeut = m_state.getUlamTypeByIndex(sizetype); // expects a constant, numeric type within [] if(sizeut->isNumericType() && m_nodeRight->isAConstant()) { evalNodeProlog(0); //new current frame pointer makeRoomForNodeType(sizetype); //offset a constant expression if(m_nodeRight->eval() == NORMAL) { UlamValue arrayUV = m_state.m_nodeEvalStack.popArg(); u32 arraysizedata = arrayUV.getImmediateData(m_state); newarraysize = sizeut->getDataAsCs32(arraysizedata); if(newarraysize < 0 && newarraysize != UNKNOWNSIZE) //NONARRAY or UNKNOWN { MSG(getNodeLocationAsString().c_str(), "Array size specifier in [] is not a positive number", ERR); noerr = false; } //else unknown is not an error } else //newarraysize = UNKNOWNSIZE; //still true noerr = false; evalNodeEpilog(); } else { MSG(getNodeLocationAsString().c_str(), "Array size specifier in [] is not a constant number", ERR); noerr = false; } rtnArraySize = newarraysize; return noerr; } //getArraysizeInBracket
bool SymbolWithValue::getArrayItemInitValue(u32 item, u32& rtnitem) { assert(hasInitValue()); if(isInitValueReady()) { UTI suti = getUlamTypeIdx(); UlamType * sut = m_state.getUlamTypeByIndex(suti); u32 bs = sut->getBitSize(); s32 arrsize = sut->getArraySize(); assert(bs <= MAXBITSPERINT); assert((arrsize >= 0) && (item < (u32) arrsize)); //no casting! rtnitem = m_initialValue.Read(item * bs, bs); return true; } return false; }
void NodeBinaryOpCompare::genCode(File * fp, UVPass& uvpass) { assert(m_nodeLeft && m_nodeRight); assert(m_state.m_currentObjSymbolsForCodeGen.empty()); //************* // generate rhs first; may update current object globals (e.g. function call) UVPass ruvpass; m_nodeRight->genCode(fp, ruvpass); // restore current object globals assert(m_state.m_currentObjSymbolsForCodeGen.empty()); //************* UVPass luvpass; m_nodeLeft->genCode(fp, luvpass); //updates m_currentObjSymbol UTI nuti = getNodeType(); UlamType * nut = m_state.getUlamTypeByIndex(nuti); s32 tmpVarNum = m_state.getNextTmpVarNumber(); m_state.indentUlamCode(fp); fp->write("const "); fp->write(nut->getTmpStorageTypeAsString().c_str()); //e.g. u32, s32, u64.. fp->write(" "); fp->write(m_state.getTmpVarAsString(nuti, tmpVarNum, TMPREGISTER).c_str()); fp->write(" = "); fp->write(methodNameForCodeGen().c_str()); fp->write("("); UTI luti = luvpass.getPassTargetType(); //reset fp->write(luvpass.getTmpVarAsString(m_state).c_str()); fp->write(", "); fp->write(ruvpass.getTmpVarAsString(m_state).c_str()); fp->write(", "); //compare needs size of left/right nodes (only difference!) fp->write_decimal(m_state.getUlamTypeByIndex(luti)->getTotalBitSize()); fp->write(");"); GCNL; uvpass = UVPass::makePass(tmpVarNum, TMPREGISTER, nuti, m_state.determinePackable(nuti), m_state, 0, 0); //P assert(m_state.m_currentObjSymbolsForCodeGen.empty()); //************* } //genCode
FORECAST UlamTypePrimitiveInt::safeCast(UTI typidx) { FORECAST scr = UlamType::safeCast(typidx); if(scr != CAST_CLEAR) return scr; bool brtn = true; UlamType * vut = m_state.getUlamTypeByIndex(typidx); s32 valbitsize = m_state.getBitSize(typidx); s32 bitsize = getBitSize(); ULAMTYPE valtypEnum = vut->getUlamTypeEnum(); switch(valtypEnum) { case Int: brtn = (bitsize >= valbitsize); break; case Unsigned: brtn = (bitsize > valbitsize); break; case Unary: brtn = (bitsize > (s32) _getLogBase2(valbitsize) + 1); break; case Bool: case Bits: case Void: case UAtom: brtn = false; break; case Class: { //must be Quark! treat as Int if it has a toInt method if(vut->isNumericType()) brtn = (bitsize >= MAXBITSPERINT); else brtn = false; //t41131 called by matching args (no error msg please) } break; default: m_state.abortUndefinedUlamType(); //std::cerr << "UlamTypePrimitiveInt (cast) error! Value Type was: " << valtypidx << std::endl; brtn = false; }; return brtn ? CAST_CLEAR : CAST_BAD; } //safeCast