/* * Copyright 2007-2018 Adrian Thurston * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include "compiler.h" using std::cout; using std::cerr; using std::endl; bool isStr( UniqueType *ut ) { return ut->typeId == TYPE_TREE && ut->langEl != 0 && ut->langEl->id == LEL_ID_STR; } bool isTree( UniqueType *ut ) { return ut->typeId == TYPE_TREE; } IterDef::IterDef( Type type ) : type(type), func(0) { } IterDef::IterDef( Type type, Function *func ) : type(type), func(func) {} IterImpl::IterImpl( Type type ) : type(type), func(0), useFuncId(false), useSearchUT(false), useGenericId(false) { switch ( type ) { case Tree: inCreateWV = IN_TRITER_FROM_REF; inCreateWC = IN_TRITER_FROM_REF; inUnwind = IN_TRITER_UNWIND; inDestroy = IN_TRITER_DESTROY; inAdvance = IN_TRITER_ADVANCE; inGetCurR = IN_TRITER_GET_CUR_R; inGetCurWC = IN_TRITER_GET_CUR_WC; inSetCurWC = IN_TRITER_SET_CUR_WC; inRefFromCur = IN_TRITER_REF_FROM_CUR; useSearchUT = true; break; case Child: inCreateWV = IN_TRITER_FROM_REF; inCreateWC = IN_TRITER_FROM_REF; inUnwind = IN_TRITER_UNWIND; inDestroy = IN_TRITER_DESTROY; inAdvance = IN_TRITER_NEXT_CHILD; inGetCurR = IN_TRITER_GET_CUR_R; inGetCurWC = IN_TRITER_GET_CUR_WC; inSetCurWC = IN_TRITER_SET_CUR_WC; inRefFromCur = IN_TRITER_REF_FROM_CUR; useSearchUT = true; break; case RevChild: inCreateWV = IN_REV_TRITER_FROM_REF; inCreateWC = IN_REV_TRITER_FROM_REF; inUnwind = IN_REV_TRITER_UNWIND; inDestroy = IN_REV_TRITER_DESTROY; inAdvance = IN_REV_TRITER_PREV_CHILD; inGetCurR = IN_TRITER_GET_CUR_R; inGetCurWC = IN_TRITER_GET_CUR_WC; inSetCurWC = IN_TRITER_SET_CUR_WC; inRefFromCur = IN_TRITER_REF_FROM_CUR; useSearchUT = true; break; case Repeat: inCreateWV = IN_TRITER_FROM_REF; inCreateWC = IN_TRITER_FROM_REF; inUnwind = IN_TRITER_UNWIND; inDestroy = IN_TRITER_DESTROY; inAdvance = IN_TRITER_NEXT_REPEAT; inGetCurR = IN_TRITER_GET_CUR_R; inGetCurWC = IN_TRITER_GET_CUR_WC; inSetCurWC = IN_TRITER_SET_CUR_WC; inRefFromCur = IN_TRITER_REF_FROM_CUR; useSearchUT = true; break; case RevRepeat: inCreateWV = IN_TRITER_FROM_REF; inCreateWC = IN_TRITER_FROM_REF; inUnwind = IN_TRITER_UNWIND; inDestroy = IN_TRITER_DESTROY; inAdvance = IN_TRITER_PREV_REPEAT; inGetCurR = IN_TRITER_GET_CUR_R; inGetCurWC = IN_TRITER_GET_CUR_WC; inSetCurWC = IN_TRITER_SET_CUR_WC; inRefFromCur = IN_TRITER_REF_FROM_CUR; useSearchUT = true; break; case ListEl: inCreateWV = IN_GEN_ITER_FROM_REF; inCreateWC = IN_GEN_ITER_FROM_REF; inUnwind = IN_GEN_ITER_UNWIND; inDestroy = IN_GEN_ITER_DESTROY; inAdvance = IN_LIST_ITER_ADVANCE; inGetCurR = IN_GEN_ITER_GET_CUR_R; // inGetCurWC = //IN_LIST_ITER_GET_CUR_WC; // inSetCurWC = //IN_HALT; // inRefFromCur = //IN_LIST_ITER_REF_FROM_CUR; useGenericId = true; break; case ListVal: inCreateWV = IN_GEN_ITER_FROM_REF; inCreateWC = IN_GEN_ITER_FROM_REF; inUnwind = IN_GEN_ITER_UNWIND; inDestroy = IN_GEN_ITER_DESTROY; inAdvance = IN_LIST_ITER_ADVANCE; inGetCurR = IN_GEN_VITER_GET_CUR_R; // inGetCurWC = //IN_LIST_ITER_GET_CUR_WC; // inSetCurWC = //IN_HALT; // inRefFromCur = //IN_LIST_ITER_REF_FROM_CUR; useGenericId = true; break; case RevListVal: inCreateWV = IN_GEN_ITER_FROM_REF; inCreateWC = IN_GEN_ITER_FROM_REF; inUnwind = IN_GEN_ITER_UNWIND; inDestroy = IN_GEN_ITER_DESTROY; inAdvance = IN_REV_LIST_ITER_ADVANCE; inGetCurR = IN_GEN_VITER_GET_CUR_R; // inGetCurWC = //IN_LIST_ITER_GET_CUR_WC; // inSetCurWC = //IN_HALT; // inRefFromCur = //IN_LIST_ITER_REF_FROM_CUR; useGenericId = true; break; case MapVal: inCreateWV = IN_GEN_ITER_FROM_REF; inCreateWC = IN_GEN_ITER_FROM_REF; inUnwind = IN_GEN_ITER_UNWIND; inDestroy = IN_GEN_ITER_DESTROY; inAdvance = IN_MAP_ITER_ADVANCE; inGetCurR = IN_GEN_VITER_GET_CUR_R; inGetCurWC = IN_GEN_VITER_GET_CUR_R; //IN_HALT; //IN_LIST_ITER_GET_CUR_WC; // inSetCurWC = IN_HALT;//IN_HALT; // inRefFromCur = IN_HALT;//IN_LIST_ITER_REF_FROM_CUR; useGenericId = true; break; case MapEl: inCreateWV = IN_GEN_ITER_FROM_REF; inCreateWC = IN_GEN_ITER_FROM_REF; inUnwind = IN_GEN_ITER_UNWIND; inDestroy = IN_GEN_ITER_DESTROY; inAdvance = IN_MAP_ITER_ADVANCE; inGetCurR = IN_GEN_ITER_GET_CUR_R; // inGetCurWC = //IN_LIST_ITER_GET_CUR_WC; // inSetCurWC = //IN_HALT; // inRefFromCur = //IN_LIST_ITER_REF_FROM_CUR; useGenericId = true; break; case WithIgnore: inCreateWV = IN_TRITER_FROM_REF; inCreateWC = IN_TRITER_FROM_REF; inUnwind = IN_TRITER_UNWIND; inDestroy = IN_TRITER_DESTROY; inAdvance = IN_TRITER_WIG_ADVANCE; inGetCurR = IN_TRITER_GET_CUR_R; inGetCurWC = IN_TRITER_GET_CUR_WC; inSetCurWC = IN_TRITER_SET_CUR_WC; inRefFromCur = IN_TRITER_REF_FROM_CUR; useSearchUT = true; break; case User: assert(false); } } IterImpl::IterImpl( Type type, Function *func ) : type(type), func(func), useFuncId(true), useSearchUT(true), useGenericId(false), inCreateWV(IN_UITER_CREATE_WV), inCreateWC(IN_UITER_CREATE_WC), inUnwind(IN_UITER_UNWIND), inDestroy(IN_UITER_DESTROY), inAdvance(IN_UITER_ADVANCE), inGetCurR(IN_UITER_GET_CUR_R), inGetCurWC(IN_UITER_GET_CUR_WC), inSetCurWC(IN_UITER_SET_CUR_WC), inRefFromCur(IN_UITER_REF_FROM_CUR) {} IterDef *Compiler::findIterDef( IterDef::Type type, Function *func ) { IterDefSetEl *el = iterDefSet.find( IterDef( type, func ) ); if ( el == 0 ) el = iterDefSet.insert( IterDef( type, func ) ); return &el->key; } IterDef *Compiler::findIterDef( IterDef::Type type ) { IterDefSetEl *el = iterDefSet.find( IterDef( type ) ); if ( el == 0 ) el = iterDefSet.insert( IterDef( type ) ); return &el->key; } UniqueType *Compiler::findUniqueType( enum TYPE typeId ) { UniqueType searchKey( typeId ); UniqueType *uniqueType = uniqeTypeMap.find( &searchKey ); if ( uniqueType == 0 ) { uniqueType = new UniqueType( typeId ); uniqeTypeMap.insert( uniqueType ); } return uniqueType; } UniqueType *Compiler::findUniqueType( enum TYPE typeId, LangEl *langEl ) { UniqueType searchKey( typeId, langEl ); UniqueType *uniqueType = uniqeTypeMap.find( &searchKey ); if ( uniqueType == 0 ) { uniqueType = new UniqueType( typeId, langEl ); uniqeTypeMap.insert( uniqueType ); } return uniqueType; } UniqueType *Compiler::findUniqueType( enum TYPE typeId, IterDef *iterDef ) { UniqueType searchKey( typeId, iterDef ); UniqueType *uniqueType = uniqeTypeMap.find( &searchKey ); if ( uniqueType == 0 ) { uniqueType = new UniqueType( typeId, iterDef ); uniqeTypeMap.insert( uniqueType ); } return uniqueType; } UniqueType *Compiler::findUniqueType( enum TYPE typeId, StructEl *structEl ) { UniqueType searchKey( typeId, structEl ); UniqueType *uniqueType = uniqeTypeMap.find( &searchKey ); if ( uniqueType == 0 ) { uniqueType = new UniqueType( typeId, structEl ); uniqeTypeMap.insert( uniqueType ); } return uniqueType; } UniqueType *Compiler::findUniqueType( enum TYPE typeId, GenericType *generic ) { UniqueType searchKey( typeId, generic ); UniqueType *uniqueType = uniqeTypeMap.find( &searchKey ); if ( uniqueType == 0 ) { uniqueType = new UniqueType( typeId, generic ); uniqeTypeMap.insert( uniqueType ); } return uniqueType; } /* 0-based. */ ObjectField *ObjectDef::findFieldNum( long offset ) { /* Bounds check. */ if ( offset >= fieldList.length() ) return 0; int fn = 0; FieldList::Iter field = fieldList; while ( fn < offset ) { fn++; field++; } return field->value; } /* Finds the first field by type. */ ObjectField *ObjectDef::findFieldType( Compiler *pd, UniqueType *ut ) { for ( FieldList::Iter f = fieldList; f.lte(); f++ ) { UniqueType *fUT = f->value->typeRef->resolveType( pd ); if ( fUT == ut ) return f->value; } return 0; } long sizeOfField( UniqueType *fieldUT ) { long size = 0; switch ( fieldUT->typeId ) { case TYPE_ITER: /* Select on the iterator type. */ switch ( fieldUT->iterDef->type ) { case IterDef::Tree: case IterDef::WithIgnore: case IterDef::Child: case IterDef::Repeat: case IterDef::RevRepeat: size = sizeof(tree_iter_t) / sizeof(word_t); break; case IterDef::RevChild: size = sizeof(rev_tree_iter_t) / sizeof(word_t); break; case IterDef::MapEl: case IterDef::ListEl: case IterDef::RevListVal: size = sizeof(generic_iter_t) / sizeof(word_t); break; case IterDef::User: /* User iterators are just a pointer to the user_iter_t struct. The * struct needs to go right beneath the call to the user iterator * so it can be found by a yield. It is therefore allocated on the * stack right before the call. */ size = 1; break; } break; case TYPE_REF: size = 2; break; case TYPE_GENERIC: size = 1; break; case TYPE_LIST_PTRS: size = COLM_LIST_EL_SIZE; break; case TYPE_MAP_PTRS: size = COLM_MAP_EL_SIZE; break; default: size = 1; break; } return size; } void ObjectDef::referenceField( Compiler *pd, ObjectField *field ) { field->beenReferenced = true; } UniqueType *LangVarRef::loadField( Compiler *pd, CodeVect &code, ObjectDef *inObject, ObjectField *el, bool forWriting, bool revert ) const { /* Ensure that the field is referenced. */ inObject->referenceField( pd, el ); UniqueType *elUT = el->typeRef->uniqueType; if ( elUT->val() ) { if ( forWriting ) { /* The instruction, depends on whether or not we are reverting. */ if ( pd->revertOn && revert ) code.append( el->inGetValWV ); else code.append( el->inGetValWC ); } else { /* Loading for writing */ code.append( el->inGetValR ); } } else { /* If it's a reference then we load it read always. */ if ( forWriting ) { /* The instruction, depends on whether or not we are reverting. */ if ( elUT->typeId == TYPE_ITER ) code.append( el->iterImpl->inGetCurWC ); else if ( pd->revertOn && revert ) code.append( el->inGetWV ); else code.append( el->inGetWC ); } else { /* Loading something for reading */ if ( elUT->typeId == TYPE_ITER ) code.append( el->iterImpl->inGetCurR ); else code.append( el->inGetR ); } } if ( el->useGenericId ) code.appendHalf( el->generic->id ); if ( el->useOffset() ) { /* Gets of locals and fields require offsets. Fake vars like token * data and lhs don't require it. */ code.appendHalf( el->offset ); } else if ( el->isRhsGet() ) { /* Need to place the array computing the val. */ code.append( el->rhsVal.length() ); for ( Vector::Iter rg = el->rhsVal; rg.lte(); rg++ ) { code.append( rg->prodEl->production->prodNum ); code.append( rg->prodEl->pos ); } } if ( el->isConstVal ) { code.appendHalf( el->constValId ); if ( el->constValId == CONST_ARG ) { /* Make sure we have this string. */ StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( el->constValArg, &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; code.appendWord( mapEl->value ); } } /* If we are dealing with an iterator then dereference it. */ if ( elUT->typeId == TYPE_ITER ) elUT = el->typeRef->searchUniqueType; return elUT; } /* The qualification must start at a local frame. There cannot be any pointer. */ long LangVarRef::loadQualificationRefs( Compiler *pd, CodeVect &code, NameScope *rootScope ) const { long count = 0; /* Start the search from the root object. */ NameScope *searchScope = rootScope; for ( QualItemVect::Iter qi = *qual; qi.lte(); qi++ ) { /* Lookup the field in the current qualification. */ ObjectField *el = searchScope->findField( qi->data ); if ( el == 0 ) error(qi->loc) << "cannot resolve qualification " << qi->data << endp; if ( qi.pos() > 0 ) { if ( el->isRhsGet() ) { code.append( IN_RHS_REF_FROM_QUAL_REF ); code.appendHalf( 0 ); code.append( el->rhsVal.length() ); for ( Vector::Iter rg = el->rhsVal; rg.lte(); rg++ ) { code.append( rg->prodEl->production->prodNum ); code.append( rg->prodEl->pos ); } } else { code.append( IN_REF_FROM_QUAL_REF ); code.appendHalf( 0 ); code.appendHalf( el->offset ); } } else if ( el->iterImpl != 0 ) { code.append( el->iterImpl->inRefFromCur ); code.appendHalf( el->offset ); } else if ( el->typeRef->type == TypeRef::Ref ) { code.append( IN_REF_FROM_REF ); code.appendHalf( el->offset ); } else { code.append( IN_REF_FROM_LOCAL ); code.appendHalf( el->offset ); } UniqueType *elUT = el->typeRef->uniqueType; if ( elUT->typeId == TYPE_ITER ) elUT = el->typeRef->searchUniqueType; assert( qi->form == QualItem::Dot ); ObjectDef *searchObjDef = elUT->objectDef(); searchScope = searchObjDef->rootScope; count += 1; } return count; } void LangVarRef::loadQualification( Compiler *pd, CodeVect &code, NameScope *rootScope, int lastPtrInQual, bool forWriting, bool revert ) const { /* Start the search from the root object. */ NameScope *searchScope = rootScope; for ( QualItemVect::Iter qi = *qual; qi.lte(); qi++ ) { /* Lookup the field int the current qualification. */ ObjectField *el = searchScope->findField( qi->data ); if ( el == 0 ) error(qi->loc) << "cannot resolve qualification " << qi->data << endp; if ( forWriting && el->refActive ) error(qi->loc) << "reference active, cannot write to object" << endp; bool lfForWriting = forWriting; bool lfRevert = revert; /* If there is a pointer in the qualification, we need to compute * forWriting and revert. */ if ( lastPtrInQual >= 0 ) { if ( qi.pos() <= lastPtrInQual ) { /* If we are before or at the pointer we are strictly read * only, regardless of the origin. */ lfForWriting = false; lfRevert = false; } else { /* If we are past the pointer then we are always reverting * because the object is global. Forwriting is as passed in. * */ lfRevert = true; } } UniqueType *qualUT = loadField( pd, code, searchScope->owningObj, el, lfForWriting, lfRevert ); if ( qi->form == QualItem::Dot ) { /* Cannot a reference. Iterator yes (access of the iterator not * hte current) */ if ( qualUT->ptr() ) error(loc) << "dot cannot be used to access a pointer" << endp; } else if ( qi->form == QualItem::Arrow ) { if ( qualUT->ptr() ) { /* This deref instruction exists to capture the pointer reverse * execution purposes. */ if ( pd->revertOn && qi.pos() == lastPtrInQual && forWriting ) { /* This is like a global load. */ code.append( IN_PTR_ACCESS_WV ); } } else { error(loc) << "arrow operator cannot be used to " "access this type" << endp; } } ObjectDef *searchObjDef = qualUT->objectDef(); searchScope = searchObjDef->rootScope; } } void LangVarRef::loadContextObj( Compiler *pd, CodeVect &code, int lastPtrInQual, bool forWriting ) const { /* Start the search in the global object. */ ObjectDef *rootObj = structDef->objectDef; if ( forWriting && lastPtrInQual < 0 ) { /* If we are writing an no reference was found in the qualification * then load the gloabl with a revert. */ if ( pd->revertOn ) code.append( IN_LOAD_CONTEXT_WV ); else code.append( IN_LOAD_CONTEXT_WC ); } else { /* Either we are reading or we are loading a pointer that will be * dereferenced. */ code.append( IN_LOAD_CONTEXT_R ); } loadQualification( pd, code, rootObj->rootScope, lastPtrInQual, forWriting, true ); } void LangVarRef::loadGlobalObj( Compiler *pd, CodeVect &code, int lastPtrInQual, bool forWriting ) const { NameScope *scope = nspace != 0 ? nspace->rootScope : pd->rootNamespace->rootScope; if ( forWriting && lastPtrInQual < 0 ) { /* If we are writing an no reference was found in the qualification * then load the gloabl with a revert. */ if ( pd->revertOn ) code.append( IN_LOAD_GLOBAL_WV ); else code.append( IN_LOAD_GLOBAL_WC ); } else { /* Either we are reading or we are loading a pointer that will be * dereferenced. */ code.append( IN_LOAD_GLOBAL_R ); } loadQualification( pd, code, scope, lastPtrInQual, forWriting, true ); } void LangVarRef::loadScopedObj( Compiler *pd, CodeVect &code, NameScope *scope, int lastPtrInQual, bool forWriting ) const { // NameScope *scope = nspace != 0 ? nspace->rootScope : pd->rootNamespace->rootScope; if ( forWriting && lastPtrInQual < 0 ) { /* If we are writing an no reference was found in the qualification * then load the gloabl with a revert. */ if ( pd->revertOn ) code.append( IN_LOAD_GLOBAL_WV ); else code.append( IN_LOAD_GLOBAL_WC ); } else { /* Either we are reading or we are loading a pointer that will be * dereferenced. */ code.append( IN_LOAD_GLOBAL_R ); } loadQualification( pd, code, scope, lastPtrInQual, forWriting, true ); } void LangVarRef::loadInbuiltObject( Compiler *pd, CodeVect &code, int lastPtrInQual, bool forWriting ) const { /* Start the search in the local frame. */ loadQualification( pd, code, scope, lastPtrInQual, forWriting, pd->revertOn ); } void LangVarRef::loadLocalObj( Compiler *pd, CodeVect &code, int lastPtrInQual, bool forWriting ) const { /* Start the search in the local frame. */ loadQualification( pd, code, scope, lastPtrInQual, forWriting, false ); } void LangVarRef::loadObj( Compiler *pd, CodeVect &code, int lastPtrInQual, bool forWriting ) const { if ( nspaceQual != 0 && nspaceQual->qualNames.length() > 0 ) { Namespace *nspace = pd->rootNamespace->findNamespace( nspaceQual->qualNames[0] ); loadScopedObj( pd, code, nspace->rootScope, lastPtrInQual, forWriting ); } else if ( isInbuiltObject() ) loadInbuiltObject( pd, code, lastPtrInQual, forWriting ); else if ( isLocalRef() ) loadLocalObj( pd, code, lastPtrInQual, forWriting ); else if ( isProdRef( pd ) ) { LangVarRef *dup = new LangVarRef( *this ); dup->qual->prepend( QualItem( QualItem::Dot, InputLoc(), scope->caseClauseVarRef->name ) ); dup->loadObj( pd, code, lastPtrInQual, forWriting ); } else if ( isStructRef() ) loadContextObj( pd, code, lastPtrInQual, forWriting ); else loadGlobalObj( pd, code, lastPtrInQual, forWriting ); } bool castAssignment( Compiler *pd, CodeVect &code, UniqueType *destUT, UniqueType *destSearchUT, UniqueType *srcUT ) { if ( destUT == srcUT ) return true; /* Casting trees to any. */ if ( destUT->typeId == TYPE_TREE && destUT->langEl == pd->anyLangEl && srcUT->typeId == TYPE_TREE ) return true; /* Setting a reference from a tree. */ if ( destUT->typeId == TYPE_REF && srcUT->typeId == TYPE_TREE && destUT->langEl == srcUT->langEl ) return true; /* Setting a tree from a reference. */ if ( destUT->typeId == TYPE_TREE && srcUT->typeId == TYPE_REF && destUT->langEl == srcUT->langEl ) return true; /* Setting an iterator from a tree. */ if ( destUT->typeId == TYPE_ITER && srcUT->typeId == TYPE_TREE && destSearchUT->langEl == srcUT->langEl ) return true; /* Assigning nil to a tree. */ if ( destUT->typeId == TYPE_TREE && srcUT->typeId == TYPE_NIL ) return true; if ( destUT->typeId == TYPE_STRUCT && srcUT->typeId == TYPE_NIL ) return true; if ( destUT->typeId == TYPE_GENERIC && srcUT->typeId == TYPE_NIL ) return true; if ( destUT->typeId == TYPE_TREE && srcUT->typeId == TYPE_TREE && srcUT->langEl == pd->anyLangEl ) return true; return false; } void LangVarRef::setFieldIter( Compiler *pd, CodeVect &code, ObjectDef *inObject, ObjectField *el, UniqueType *objUT, UniqueType *exprType, bool revert ) const { code.append( el->iterImpl->inSetCurWC ); code.appendHalf( el->offset ); } void LangVarRef::setField( Compiler *pd, CodeVect &code, ObjectDef *inObject, ObjectField *el, UniqueType *exprUT, bool revert ) const { /* Ensure that the field is referenced. */ inObject->referenceField( pd, el ); if ( exprUT->val() ) { if ( pd->revertOn && revert ) code.append( el->inSetValWV ); else code.append( el->inSetValWC ); } else { if ( pd->revertOn && revert ) code.append( el->inSetWV ); else code.append( el->inSetWC ); } /* Maybe write out an offset. */ if ( el->useOffset() ) code.appendHalf( el->offset ); else if ( el->isRhsGet() ) { /* Need to place the array computing the val. */ code.append( el->rhsVal.length() ); for ( Vector::Iter rg = el->rhsVal; rg.lte(); rg++ ) { code.append( rg->prodEl->production->prodNum ); code.append( rg->prodEl->pos ); } } } UniqueType *LangVarRef::evaluate( Compiler *pd, CodeVect &code, bool forWriting ) const { /* Lookup the loadObj. */ VarRefLookup lookup = lookupField( pd ); /* Load the object, if any. */ loadObj( pd, code, lookup.lastPtrInQual, forWriting ); /* Load the field. */ UniqueType *ut = loadField( pd, code, lookup.inObject, lookup.objField, forWriting, false ); return ut; } bool LangVarRef::canTakeRef( Compiler *pd, VarRefLookup &lookup ) const { bool canTake = false; /* If the var is not a local, it must be an attribute accessed * via a local and attributes. */ if ( lookup.inObject->type == ObjectDef::FrameType ) canTake = true; else if ( isLocalRef() ) { if ( lookup.lastPtrInQual < 0 && ! lookup.uniqueType->ptr() ) canTake = true; } return canTake; } void LangVarRef::verifyRefPossible( Compiler *pd, VarRefLookup &lookup ) const { bool canTake = canTakeRef( pd, lookup ); if ( !canTake ) { error(loc) << "can only take references of locals or " "attributes accessed via a local" << endp; } if ( lookup.objField->refActive ) error(loc) << "reference currently active, cannot take another" << endp; } bool LangExpr::canTakeRef( Compiler *pd ) const { bool canTake = false; if ( type == LangExpr::TermType && term->type == LangTerm::VarRefType ) { VarRefLookup lookup = term->varRef->lookupField( pd ); if ( term->varRef->canTakeRef( pd, lookup ) ) canTake = true; } return canTake; } /* Return the field referenced. */ ObjectField *LangVarRef::preEvaluateRef( Compiler *pd, CodeVect &code ) const { VarRefLookup lookup = lookupField( pd ); verifyRefPossible( pd, lookup ); loadQualificationRefs( pd, code, scope ); return lookup.objField; } /* Return the field referenced. */ ObjectField *LangVarRef::evaluateRef( Compiler *pd, CodeVect &code, long pushCount ) const { VarRefLookup lookup = lookupField( pd ); verifyRefPossible( pd, lookup ); /* Ensure that the field is referenced. */ lookup.inObject->referenceField( pd, lookup.objField ); /* Note that we could have modified children. */ if ( qual->length() == 0 ) lookup.objField->refActive = true; /* Whenever we take a reference we have to assume writing and that the * tree is dirty. */ lookup.objField->dirtyTree = true; if ( qual->length() > 0 ) { if ( lookup.objField->isRhsGet() ) { code.append( IN_RHS_REF_FROM_QUAL_REF ); code.appendHalf( pushCount ); ObjectField *el = lookup.objField; code.append( el->rhsVal.length() ); for ( Vector::Iter rg = el->rhsVal; rg.lte(); rg++ ) { code.append( rg->prodEl->production->prodNum ); code.append( rg->prodEl->pos ); } } else { code.append( IN_REF_FROM_QUAL_REF ); code.appendHalf( pushCount ); code.appendHalf( lookup.objField->offset ); } } else if ( lookup.objField->iterImpl != 0 ) { code.append( lookup.objField->iterImpl->inRefFromCur ); code.appendHalf( lookup.objField->offset ); } else if ( lookup.objField->typeRef->type == TypeRef::Ref ) { code.append( IN_REF_FROM_REF ); code.appendHalf( lookup.objField->offset ); } else { code.append( IN_REF_FROM_LOCAL ); code.appendHalf( lookup.objField->offset ); } return lookup.objField; } IterImpl *LangVarRef::chooseTriterCall( Compiler *pd, UniqueType *searchUT, CallArgVect *args ) { IterImpl *iterImpl = 0; /* Evaluate the triter args and choose the triter call based on it. */ if ( args->length() == 1 ) { /* Evaluate the expression. */ CodeVect unused; CallArgVect::Iter pe = *args; UniqueType *exprUT = (*pe)->expr->evaluate( pd, unused ); if ( exprUT->typeId == TYPE_GENERIC && exprUT->generic->typeId == GEN_LIST ) { if ( searchUT == exprUT->generic->elUt ) iterImpl = new IterImpl( IterImpl::ListEl ); else iterImpl = new IterImpl( IterImpl::ListVal ); } if ( exprUT->typeId == TYPE_GENERIC && exprUT->generic->typeId == GEN_MAP ) { if ( searchUT == exprUT->generic->elUt ) iterImpl = new IterImpl( IterImpl::MapEl ); else iterImpl = new IterImpl( IterImpl::MapVal ); } } if ( iterImpl == 0 ) iterImpl = new IterImpl( IterImpl::Tree ); return iterImpl; } ObjectField **LangVarRef::evaluateArgs( Compiler *pd, CodeVect &code, VarRefLookup &lookup, CallArgVect *args ) { /* Parameter list is given only for user defined methods. Otherwise it * will be null. */ ParameterList *paramList = lookup.objMethod->paramList; /* Match the number of arguments. */ int numArgs = args != 0 ? args->length() : 0; if ( numArgs != lookup.objMethod->numParams ) error(loc) << "wrong number of arguments" << endp; /* This is for storing the object fields used by references. */ ObjectField **paramRefs = new ObjectField*[numArgs]; memset( paramRefs, 0, sizeof(ObjectField*) * numArgs ); /* Done now if there are no args. */ if ( args == 0 ) return paramRefs; /* We use this only if there is a paramter list. */ ParameterList::Iter p; long size = 0; long tempPops = 0; long pos = 0; paramList != 0 && ( p = *paramList ); for ( CallArgVect::Iter pe = *args; pe.lte(); pe++ ) { /* Get the expression and the UT for the arg. */ LangExpr *expression = (*pe)->expr; UniqueType *paramUT = lookup.objMethod->paramUTs[pe.pos()]; if ( paramUT->typeId == TYPE_REF ) { if ( expression->canTakeRef( pd ) ) { /* Push object loads for reference parameters. */ LangVarRef *varRef = expression->term->varRef; ObjectField *refOf = varRef->preEvaluateRef( pd, code ); paramRefs[pe.pos()] = refOf; size += varRef->qual->length() * 2; (*pe)->offQualRef = size; /**/ refOf = varRef->evaluateRef( pd, code, 0 ); //(size - (*pe)->offQualRef) ); paramRefs[pe.pos()] = refOf; //size += 2; } else { /* First pass we need to allocate and evaluate temporaries. */ UniqueType *exprUT = expression->evaluate( pd, code ); (*pe)->exprUT = exprUT; size += 1; (*pe)->offTmp = size; tempPops += 1; /**/ code.append( IN_REF_FROM_BACK ); code.appendHalf( 0 ); //size - (*pe)->offTmp ); //size += 2; } if ( lookup.objMethod->func ) { code.append( IN_STASH_ARG ); code.appendHalf( pos ); code.appendHalf( 2 ); } pos += 2; } else { UniqueType *exprUT = expression->evaluate( pd, code ); // pd->unwindCode.remove( 0, 1 ); if ( !castAssignment( pd, code, paramUT, 0, exprUT ) ) error(loc) << "arg " << pe.pos()+1 << " is of the wrong type" << endp; size += 1; if ( lookup.objMethod->func && !lookup.objMethod->func->inHost ) { code.append( IN_STASH_ARG ); code.appendHalf( pos ); code.appendHalf( 1 ); } pos += 1; } /* Advance the parameter list iterator if we have it. */ paramList != 0 && p.increment(); } argSize = tempPops; return paramRefs; } void LangVarRef::resetActiveRefs( Compiler *pd, VarRefLookup &lookup, ObjectField **paramRefs ) const { /* Parameter list is given only for user defined methods. Otherwise it * will be null. */ for ( long p = 0; p < lookup.objMethod->numParams; p++ ) { if ( paramRefs[p] != 0 ) paramRefs[p]->refActive = false; } } bool LangVarRef::isFinishCall( VarRefLookup &lookup ) const { return lookup.objMethod->type == ObjectMethod::ParseFinish; } void LangVarRef::callOperation( Compiler *pd, CodeVect &code, VarRefLookup &lookup ) const { /* This is for writing if it is a non-const builtin. */ bool forWriting = lookup.objMethod->func == 0 && !lookup.objMethod->isConst; if ( lookup.objMethod->useCallObj ) { /* Load the object, if any. */ loadObj( pd, code, lookup.lastPtrInQual, forWriting ); } /* Check if we need to revert the function. If it operates on a reference * or if it is not local then we need to revert it. */ bool revert = lookup.lastPtrInQual >= 0 || !isLocalRef() || isInbuiltObject(); bool unwind = false; if ( isFinishCall( lookup ) ) { code.append( IN_SEND_EOF_W ); LangTerm::parseFrag( pd, code, 0 ); code.append( IN_GET_PARSER_MEM_R ); code.appendHalf( 0 ); } else { if ( pd->revertOn && revert ) { if ( lookup.objMethod->opcodeWV == IN_CALL_WV || lookup.objMethod->opcodeWC == FN_EXIT ) unwind = true; if ( lookup.objMethod->useFnInstr ) code.append( IN_FN ); code.append( lookup.objMethod->opcodeWV ); } else { if ( lookup.objMethod->opcodeWC == IN_CALL_WC || lookup.objMethod->opcodeWC == FN_EXIT ) unwind = true; if ( lookup.objMethod->useFnInstr ) code.append( IN_FN ); code.append( lookup.objMethod->opcodeWC ); } } if ( lookup.objMethod->useFuncId ) code.appendHalf( lookup.objMethod->funcId ); if ( lookup.objMethod->useGenericId ) code.appendHalf( lookup.objMethod->generic->id ); if ( unwind ) { if ( pd->unwindCode.length() == 0 ) code.appendHalf( 0 ); else { code.appendHalf( pd->unwindCode.length() + 1 ); code.append( pd->unwindCode ); code.append( IN_DONE ); } } } void LangVarRef::popRefQuals( Compiler *pd, CodeVect &code, VarRefLookup &lookup, CallArgVect *args, bool temps ) const { long popCount = 0; /* Evaluate and push the args. */ if ( args != 0 ) { for ( CallArgVect::Iter pe = *args; pe.lte(); pe++ ) { /* Get the expression and the UT for the arg. */ LangExpr *expression = (*pe)->expr; UniqueType *paramUT = lookup.objMethod->paramUTs[pe.pos()]; if ( paramUT->typeId == TYPE_REF ) { if ( expression->canTakeRef( pd ) ) { LangVarRef *varRef = expression->term->varRef; popCount += varRef->qual->length() * 2; } } } if ( popCount > 0 ) { code.append( IN_POP_N_WORDS ); code.appendHalf( (short)popCount ); } if ( temps ) { for ( CallArgVect::Iter pe = *args; pe.lte(); pe++ ) { /* Get the expression and the UT for the arg. */ LangExpr *expression = (*pe)->expr; UniqueType *paramUT = lookup.objMethod->paramUTs[pe.pos()]; if ( paramUT->typeId == TYPE_REF ) { if ( ! expression->canTakeRef( pd ) ) code.append( IN_POP_TREE ); } } } } } UniqueType *LangVarRef::evaluateCall( Compiler *pd, CodeVect &code, CallArgVect *args ) { /* Evaluate the object. */ VarRefLookup lookup = lookupMethod( pd ); Function *func = lookup.objMethod->func; /* Prepare the contiguous call args space. */ int asLoc; if ( func != 0 && !func->inHost ) { code.append( IN_PREP_ARGS ); asLoc = code.length(); code.appendHalf( 0 ); } /* Evaluate and push the arguments. */ ObjectField **paramRefs = evaluateArgs( pd, code, lookup, args ); /* Write the call opcode. */ callOperation( pd, code, lookup ); popRefQuals( pd, code, lookup, args, true ); resetActiveRefs( pd, lookup, paramRefs); delete[] paramRefs; if ( func != 0 && !func->inHost ) { code.append( IN_CLEAR_ARGS ); code.appendHalf( func->paramListSize ); code.setHalf( asLoc, func->paramListSize ); } if ( func != 0 && !func->inHost ) code.append( IN_LOAD_RETVAL ); /* Return the type to the expression. */ return lookup.uniqueType; } /* Can match on a tree or a ref. A tree always comes back. */ UniqueType *LangTerm::evaluateMatch( Compiler *pd, CodeVect &code ) const { /* Add the vars bound by the pattern into the local scope. */ for ( PatternItemList::Iter item = *pattern->list; item.lte(); item++ ) { if ( item->varRef != 0 ) item->bindId = pattern->nextBindId++; } UniqueType *ut = varRef->evaluate( pd, code ); if ( ut->typeId != TYPE_TREE && ut->typeId != TYPE_REF ) { error(varRef->loc) << "expected match against a tree/ref type" << endp; } /* Store the language element type in the pattern. This is needed by * the pattern parser. */ pattern->langEl = ut->langEl; code.append( IN_MATCH ); code.appendHalf( pattern->patRepId ); for ( PatternItemList::Iter item = pattern->list->last(); item.gtb(); item-- ) { if ( item->varRef != 0 ) { /* Compute the unique type. */ UniqueType *exprType = pd->findUniqueType( TYPE_TREE, item->prodEl->langEl ); /* Get the type of the variable being assigned to. */ VarRefLookup lookup = item->varRef->lookupField( pd ); item->varRef->loadObj( pd, code, lookup.lastPtrInQual, false ); item->varRef->setField( pd, code, lookup.inObject, lookup.objField, exprType, false ); } } /* The process of matching turns refs into trees. */ if ( ut->typeId == TYPE_REF ) ut = pd->findUniqueType( TYPE_TREE, ut->langEl ); return ut; } UniqueType *LangTerm::evaluateProdCompare( Compiler *pd, CodeVect &code ) const { UniqueType *ut = varRef->evaluate( pd, code ); if ( ut->typeId != TYPE_TREE && ut->typeId != TYPE_REF ) { error(varRef->loc) << "expected match against a tree/ref type" << endp; } code.append( IN_PROD_NUM ); /* look up the production name. */ Production *prod = pd->findProductionByLabel( ut->langEl, this->prod ); if ( prod == 0 ) { error( this->loc) << "could not find " "production label: " << this->prod << endp; } unsigned int n = prod->prodNum; code.append( IN_LOAD_INT ); code.appendWord( n ); code.append( IN_TST_EQL_VAL ); if ( expr != 0 ) { code.append( IN_DUP_VAL ); /* Test: jump past the match if the production test failed. We don't have * the distance yet. */ long jumpFalse = code.length(); code.append( IN_JMP_FALSE_VAL ); code.appendHalf( 0 ); code.append( IN_POP_VAL ); expr->evaluate( pd, code ); /* Set the jump false distance. */ long falseDist = code.length() - jumpFalse - 3; code.setHalf( jumpFalse+1, falseDist ); return ut; } return pd->uniqueTypeInt; } void LangTerm::evaluateCapture( Compiler *pd, CodeVect &code, UniqueType *valUt ) const { if ( varRef != 0 ) { /* Get the type of the variable being assigned to. */ VarRefLookup lookup = varRef->lookupField( pd ); /* Need a copy of the tree. */ code.append( lookup.uniqueType->tree() ? IN_DUP_TREE : IN_DUP_VAL ); varRef->loadObj( pd, code, lookup.lastPtrInQual, false ); varRef->setField( pd, code, lookup.inObject, lookup.objField, valUt, false ); } } UniqueType *LangTerm::evaluateNew( Compiler *pd, CodeVect &code ) const { /* What is being newstructed. */ UniqueType *newUT = typeRef->uniqueType; if ( newUT->typeId != TYPE_STRUCT && newUT->typeId != TYPE_GENERIC ) error(loc) << "can only new a struct or generic" << endp; bool context = false; if ( newUT->typeId == TYPE_GENERIC && newUT->generic->typeId == GEN_PARSER && newUT->generic->elUt->langEl->contextIn != 0 ) { if ( fieldInitArgs == 0 || fieldInitArgs->length() != 1 ) error(loc) << "parse command requires just context " << endp; context = true; } if ( newUT->typeId == TYPE_GENERIC ) { code.append( IN_CONS_GENERIC ); code.appendHalf( newUT->generic->id ); code.appendHalf( 0 ); // stopId if ( newUT->generic->typeId == GEN_PARSER ) { } } else if ( newUT->typeId == TYPE_STRUCT && newUT->structEl == pd->streamSel ) { code.append( IN_NEW_STREAM ); } else { code.append( IN_NEW_STRUCT ); code.appendHalf( newUT->structEl->id ); } /* * First load the context into the parser. */ if ( context ) { for ( int i = 0; i < fieldInitArgs->length(); i++ ) { /* Eval what we are initializing with. */ UniqueType *argUT = fieldInitArgs->data[i]->expr->evaluate( pd, code ); if ( argUT == pd->uniqueTypeInput ) { code.append( IN_SET_PARSER_INPUT ); } else if ( argUT->typeId == TYPE_STRUCT ) { code.append( IN_SET_PARSER_CONTEXT ); } else { error(loc) << "cannot initialize parser with this type, context or input only" << endp; } } } evaluateCapture( pd, code, newUT ); return newUT; } UniqueType *LangTerm::evaluateCast( Compiler *pd, CodeVect &code ) const { expr->evaluate( pd, code ); code.append( IN_TREE_CAST ); code.appendHalf( typeRef->uniqueType->langEl->id ); return typeRef->uniqueType; } void LangTerm::assignFieldArgs( Compiler *pd, CodeVect &code, UniqueType *replUT ) const { /* Now assign the field initializations. Note that we need to do this in * reverse because the last expression evaluated is at the top of the * stack. */ if ( fieldInitArgs != 0 && fieldInitArgs->length() > 0 ) { ObjectDef *objDef = replUT->objectDef(); /* Note the reverse traversal. */ for ( FieldInitVect::Iter pi = fieldInitArgs->last(); pi.gtb(); pi-- ) { FieldInit *fieldInit = *pi; ObjectField *field = objDef->findFieldNum( pi.pos() ); if ( field == 0 ) { error(fieldInit->loc) << "failed to find init pos " << pi.pos() << " in object" << endp; } /* Lookup the type of the field and compare it to the type of the * expression. */ UniqueType *fieldUT = field->typeRef->uniqueType; if ( !castAssignment( pd, code, fieldUT, 0, fieldInit->exprUT ) ) error(fieldInit->loc) << "type mismatch in initialization" << endp; /* The set field instruction must leave the object on the top of * the stack. */ code.append( IN_SET_FIELD_TREE_LEAVE_WC ); code.appendHalf( field->offset ); } } } UniqueType *LangTerm::evaluateConstruct( Compiler *pd, CodeVect &code ) const { /* Evaluate the initialization expressions. */ if ( fieldInitArgs != 0 && fieldInitArgs->length() > 0 ) { for ( FieldInitVect::Iter pi = *fieldInitArgs; pi.lte(); pi++ ) { FieldInit *fieldInit = *pi; fieldInit->exprUT = fieldInit->expr->evaluate( pd, code ); } } /* Assign bind ids to the variables in the replacement. */ for ( ConsItemList::Iter item = *constructor->list; item.lte(); item++ ) { if ( item->expr != 0 ) item->bindId = constructor->nextBindId++; } /* Evaluate variable references. */ for ( ConsItemList::Iter item = constructor->list->last(); item.gtb(); item-- ) { if ( item->type == ConsItem::ExprType ) { UniqueType *ut = item->expr->evaluate( pd, code ); if ( ut->typeId != TYPE_TREE ) { error(constructor->loc) << "variables used in " "replacements must be trees" << endp; } if ( !isStr( ut ) ) { if ( item->trim == ConsItem::TrimYes ) code.append( IN_TREE_TRIM ); } item->langEl = ut->langEl; } } /* Construct the tree using the tree information stored in the compiled * code. */ code.append( IN_CONSTRUCT ); code.appendHalf( constructor->patRepId ); /* Lookup the type of the replacement and store it in the replacement * object so that replacement parsing has a target. */ UniqueType *replUT = typeRef->uniqueType; if ( replUT->typeId != TYPE_TREE ) error(loc) << "don't know how to construct this type" << endp; constructor->langEl = replUT->langEl; assignFieldArgs( pd, code, replUT ); evaluateCapture( pd, code, replUT ); return replUT; } void LangTerm::parseFrag( Compiler *pd, CodeVect &code, int stopId ) { code.append( IN_PARSE_FRAG_W ); } UniqueType *LangTerm::evaluateReadReduce( Compiler *pd, CodeVect &code ) const { UniqueType *parserUT = typeRef->uniqueType; UniqueType *targetUT = parserUT->generic->elUt; /* Should be one arg and it should be a stream. */ /* Assign bind ids to the variables in the replacement. */ for ( ConsItemList::Iter item = *parserText->list; item.lte(); item++ ) { switch ( item->type ) { case ConsItem::LiteralType: { break; } case ConsItem::InputText: { break; } case ConsItem::ExprType: { item->expr->evaluate( pd, code ); break; }} } code.append( IN_READ_REDUCE ); code.appendHalf( parserUT->generic->id ); code.appendHalf( parserText->reducerId ); return targetUT; } UniqueType *LangTerm::evaluateParse( Compiler *pd, CodeVect &code, bool tree, bool stop ) const { if ( parserText->reduce && parserText->read ) { return evaluateReadReduce( pd, code ); } UniqueType *parserUT = typeRef->uniqueType; UniqueType *targetUT = parserUT->generic->elUt; /* If this is a parse stop then we need to verify that the type is * compatible with parse stop. */ if ( stop ) targetUT->langEl->parseStop = true; int stopId = stop ? targetUT->langEl->id : 0; bool context = false; if ( fieldInitArgs != 0 ) { if ( fieldInitArgs == 0 || ( fieldInitArgs->length() != 1 && fieldInitArgs->length() != 2 ) ) error(loc) << "parse command requires just context and input" << endp; context = true; } /* Evaluate variable references. */ for ( ConsItemList::Iter item = consItemList->last(); item.gtb(); item-- ) { if ( item->type == ConsItem::ExprType ) { UniqueType *ut = item->expr->evaluate( pd, code ); if ( ut->typeId != TYPE_TREE ) error() << "variables used in replacements must be trees" << endp; if ( item->trim == ConsItem::TrimYes ) code.append( IN_TREE_TRIM ); item->langEl = ut->langEl; } } /* Construct the parser. */ if ( parserText->reduce ) { code.append( IN_CONS_REDUCER ); code.appendHalf( parserUT->generic->id ); code.appendHalf( parserText->reducerId ); } else { code.append( IN_CONS_GENERIC ); code.appendHalf( parserUT->generic->id ); code.appendHalf( stopId ); } /* * First load the context into the parser. */ if ( context ) { for ( int i = 0; i < fieldInitArgs->length(); i++ ) { /* Eval what we are initializing with. */ UniqueType *argUT = fieldInitArgs->data[i]->expr->evaluate( pd, code ); if ( argUT == pd->uniqueTypeInput ) { code.append( IN_SET_PARSER_INPUT ); } else if ( argUT->typeId == TYPE_STRUCT && targetUT->langEl->contextIn != 0 ) { code.append( IN_SET_PARSER_CONTEXT ); } else { error(loc) << "cannot initialize parser with this type, context or input only" << endp; } } } /*****************************/ if ( parserText->list->length() == 0 ) { code.append( IN_SEND_NOTHING ); /* Parse instruction, dependent on whether or not we are producing * revert or commit code. */ parseFrag( pd, code, stopId ); } else { for ( ConsItemList::Iter item = *parserText->list; item.lte(); item++ ) { bool isStream = false; uchar trim = TRIM_DEFAULT; switch ( item->type ) { case ConsItem::LiteralType: { String result; bool unusedCI; prepareLitString( result, unusedCI, item->prodEl->typeRef->pdaLiteral->data, item->prodEl->typeRef->pdaLiteral->loc ); /* Make sure we have this string. */ StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( result, &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; code.append( IN_LOAD_STR ); code.appendWord( mapEl->value ); break; } case ConsItem::InputText: { /* Make sure we have this string. */ StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( item->data, &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; code.append( IN_LOAD_STR ); code.appendWord( mapEl->value ); break; } case ConsItem::ExprType: { UniqueType *ut = item->expr->evaluate( pd, code ); if ( ut->typeId == TYPE_VOID ) { /* Clear it away if return type is void. */ code.append( IN_POP_VAL ); continue; } if ( ut->typeId == TYPE_INT || ut->typeId == TYPE_BOOL ) code.append( IN_INT_TO_STR ); if ( ut == pd->uniqueTypeStream ) isStream = true; if ( item->trim == ConsItem::TrimYes ) trim = TRIM_YES; else if ( item->trim == ConsItem::TrimNo ) trim = TRIM_NO; break; }} if ( isStream ) code.append( IN_SEND_STREAM_W ); else if ( tree ) { code.append( IN_SEND_TREE_W ); code.append( trim ); } else { code.append( IN_SEND_TEXT_W ); code.append( trim ); } /* Parse instruction, dependent on whether or not we are producing * revert or commit code. */ parseFrag( pd, code, stopId ); } } /* * Finish operation */ if ( !stop ) { code.append( IN_SEND_EOF_W ); parseFrag( pd, code, stopId ); } if ( parserText->reduce ) { code.append( IN_REDUCE_COMMIT ); } /* Pull out the error and save it off. */ code.append( IN_DUP_VAL ); code.append( IN_GET_PARSER_MEM_R ); code.appendHalf( 1 ); code.append( IN_SET_ERROR ); /* Replace the parser with the parsed tree. */ code.append( IN_GET_PARSER_MEM_R ); code.appendHalf( 0 ); /* Capture to the local var. */ evaluateCapture( pd, code, targetUT ); return targetUT; } void LangTerm::evaluateSendStream( Compiler *pd, CodeVect &code ) const { UniqueType *varUt = varRef->evaluate( pd, code ); if ( varUt->listOf( pd->uniqueTypeStream ) ) { code.append( IN_GET_VLIST_MEM_R ); code.appendHalf( varUt->generic->id ); code.appendHalf( 0 ); } /* Assign bind ids to the variables in the replacement. */ for ( ConsItemList::Iter item = *parserText->list; item.lte(); item++ ) { uchar trim = TRIM_DEFAULT; switch ( item->type ) { case ConsItem::LiteralType: { String result; bool unusedCI; prepareLitString( result, unusedCI, item->prodEl->typeRef->pdaLiteral->data, item->prodEl->typeRef->pdaLiteral->loc ); /* Make sure we have this string. */ StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( result, &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; code.append( IN_LOAD_STR ); code.appendWord( mapEl->value ); break; } case ConsItem::InputText: { /* Make sure we have this string. */ StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( item->data, &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; code.append( IN_LOAD_STR ); code.appendWord( mapEl->value ); break; } case ConsItem::ExprType: { UniqueType *ut = item->expr->evaluate( pd, code ); if ( ut->typeId == TYPE_VOID ) { /* Clear it away if return type is void. */ code.append( IN_POP_VAL ); continue; } if ( ut->typeId == TYPE_INT || ut->typeId == TYPE_BOOL ) code.append( IN_INT_TO_STR ); if ( item->trim == ConsItem::TrimYes ) trim = TRIM_YES; else if ( item->trim == ConsItem::TrimNo ) trim = TRIM_NO; break; }} code.append( IN_PRINT_TREE ); code.append( trim ); } } void LangTerm::evaluateSendParser( Compiler *pd, CodeVect &code, bool strings ) const { UniqueType *varUt = varRef->evaluate( pd, code ); if ( varUt->parser() ) { } else if ( varUt->listOf( pd->uniqueTypeStream ) ) { code.append( IN_GET_VLIST_MEM_R ); code.appendHalf( varUt->generic->id ); code.appendHalf( 0 ); } if ( parserText->list->length() == 0 ) { code.append( IN_SEND_NOTHING ); /* Parse instruction, dependent on whether or not we are producing * revert or commit code. */ parseFrag( pd, code, 0 ); } else { /* Assign bind ids to the variables in the replacement. */ for ( ConsItemList::Iter item = *parserText->list; item.lte(); item++ ) { bool isStream = false; uchar trim = TRIM_DEFAULT; switch ( item->type ) { case ConsItem::LiteralType: { String result; bool unusedCI; prepareLitString( result, unusedCI, item->prodEl->typeRef->pdaLiteral->data, item->prodEl->typeRef->pdaLiteral->loc ); /* Make sure we have this string. */ StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( result, &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; code.append( IN_LOAD_STR ); code.appendWord( mapEl->value ); break; } case ConsItem::InputText: { /* Make sure we have this string. */ StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( item->data, &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; code.append( IN_LOAD_STR ); code.appendWord( mapEl->value ); break; } case ConsItem::ExprType: UniqueType *ut = item->expr->evaluate( pd, code ); if ( ut->typeId == TYPE_VOID ) { /* Clear it away if return type is void. */ code.append( IN_POP_VAL ); continue; } if ( ut == pd->uniqueTypeStream ) isStream = true; if ( item->trim == ConsItem::TrimYes ) trim = TRIM_YES; else if ( item->trim == ConsItem::TrimNo ) trim = TRIM_NO; if ( ut->typeId == TYPE_INT || ut->typeId == TYPE_BOOL ) code.append( IN_INT_TO_STR ); break; } if ( isStream ) code.append( IN_SEND_STREAM_W ); else if ( !strings ) { code.append( IN_SEND_TREE_W ); code.append( trim ); } else { code.append( IN_SEND_TEXT_W ); code.append( trim ); } parseFrag( pd, code, 0 ); } } if ( eof ) { code.append( IN_SEND_EOF_W ); parseFrag( pd, code, 0 ); } } UniqueType *LangTerm::evaluateSend( Compiler *pd, CodeVect &code ) const { UniqueType *varUt = varRef->lookup( pd ); if ( varUt == pd->uniqueTypeStream ) evaluateSendStream( pd, code ); else if ( varUt->listOf( pd->uniqueTypeStream ) ) evaluateSendStream( pd, code ); else if ( varUt->parser() ) evaluateSendParser( pd, code, true ); else error(loc) << "can only send to parsers and streams" << endl; return varUt; } UniqueType *LangTerm::evaluateSendTree( Compiler *pd, CodeVect &code ) const { UniqueType *varUt = varRef->lookup( pd ); if ( varUt->parser() ) evaluateSendParser( pd, code, false ); else error(loc) << "can only send_tree to parsers" << endl; return varUt; } UniqueType *LangTerm::evaluateEmbedString( Compiler *pd, CodeVect &code ) const { /* Assign bind ids to the variables in the replacement. */ for ( ConsItemList::Iter item = *consItemList; item.lte(); item++ ) { switch ( item->type ) { case ConsItem::LiteralType: { String result; bool unusedCI; prepareLitString( result, unusedCI, item->prodEl->typeRef->pdaLiteral->data, item->prodEl->typeRef->pdaLiteral->loc ); /* Make sure we have this string. */ StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( result, &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; code.append( IN_LOAD_STR ); code.appendWord( mapEl->value ); break; } case ConsItem::InputText: { /* Make sure we have this string. */ StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( item->data, &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; code.append( IN_LOAD_STR ); code.appendWord( mapEl->value ); break; } case ConsItem::ExprType: { UniqueType *ut = item->expr->evaluate( pd, code ); if ( ut->typeId == TYPE_INT || ut->typeId == TYPE_BOOL ) code.append( IN_INT_TO_STR ); if ( ut->typeId == TYPE_TREE && ut->langEl != pd->strLangEl && ut != pd->uniqueTypeStream ) { /* Convert it to a string. */ code.append( IN_TREE_TO_STR ); } break; }} } /* If there was nothing loaded, load the empty string. We must produce * something. */ if ( consItemList->length() == 0 ) { String result = ""; /* Make sure we have this string. */ StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( result, &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; code.append( IN_LOAD_STR ); code.appendWord( mapEl->value ); } long items = consItemList->length(); for ( long i = 0; i < items-1; i++ ) code.append( IN_CONCAT_STR ); return pd->uniqueTypeStr; } UniqueType *LangTerm::evaluateSearch( Compiler *pd, CodeVect &code ) const { UniqueType *ut = typeRef->uniqueType; if ( ut->typeId != TYPE_TREE ) error(loc) << "can only search for tree types" << endp; /* Evaluate the expression. */ UniqueType *treeUT = varRef->evaluate( pd, code ); if ( treeUT->typeId != TYPE_TREE && treeUT->typeId != TYPE_REF ) error(loc) << "search can be applied only to tree/ref types" << endp; /* Run the search. */ code.append( IN_TREE_SEARCH ); code.appendWord( ut->langEl->id ); return ut; } UniqueType *LangTerm::evaluate( Compiler *pd, CodeVect &code ) const { UniqueType *retUt = 0; switch ( type ) { case VarRefType: retUt = varRef->evaluate( pd, code ); break; case MethodCallType: retUt = varRef->evaluateCall( pd, code, args ); break; case NilType: code.append( IN_LOAD_NIL ); retUt = pd->uniqueTypeNil; break; case TrueType: code.append( IN_LOAD_TRUE ); retUt = pd->uniqueTypeBool; break; case FalseType: code.append( IN_LOAD_FALSE ); retUt = pd->uniqueTypeBool; break; case MakeTokenType: retUt = evaluateMakeToken( pd, code ); break; case MakeTreeType: retUt = evaluateMakeTree( pd, code ); break; case NumberType: { unsigned int n = atoi( data ); code.append( IN_LOAD_INT ); code.appendWord( n ); retUt = pd->uniqueTypeInt; break; } case StringType: { String interp; bool unused; prepareLitString( interp, unused, data, InputLoc() ); /* Make sure we have this string. */ StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( interp, &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; code.append( IN_LOAD_STR ); code.appendWord( mapEl->value ); retUt = pd->uniqueTypeStr; break; } case MatchType: retUt = evaluateMatch( pd, code ); break; case ProdCompareType: retUt = evaluateProdCompare( pd, code ); break; case ParseType: retUt = evaluateParse( pd, code, false, false ); break; case ParseTreeType: retUt = evaluateParse( pd, code, true, false ); break; case ParseStopType: retUt = evaluateParse( pd, code, false, true ); break; case ConstructType: retUt = evaluateConstruct( pd, code ); break; case SendType: retUt = evaluateSend( pd, code ); break; case SendTreeType: retUt = evaluateSendTree( pd, code ); break; case NewType: retUt = evaluateNew( pd, code ); break; case TypeIdType: { /* Evaluate the expression. */ UniqueType *ut = typeRef->uniqueType; if ( ut->typeId != TYPE_TREE ) error() << "typeid can only be applied to tree types" << endp; code.append( IN_LOAD_INT ); code.appendWord( ut->langEl->id ); retUt = pd->uniqueTypeInt; break; } case SearchType: retUt = evaluateSearch( pd, code ); break; case EmbedStringType: retUt = evaluateEmbedString( pd, code ); break; case CastType: retUt = evaluateCast( pd, code ); break; } // if ( retUt->val() ) // pd->unwindCode.insert( 0, IN_POP_VAL ); // else // pd->unwindCode.insert( 0, IN_POP_TREE ); return retUt; } UniqueType *LangExpr::evaluate( Compiler *pd, CodeVect &code ) const { switch ( type ) { case BinaryType: { switch ( op ) { case '+': { UniqueType *lt = left->evaluate( pd, code ); UniqueType *rt = right->evaluate( pd, code ); // pd->unwindCode.remove( 0, 2 ); // pd->unwindCode.insert( 0, IN_POP_TREE ); if ( lt == pd->uniqueTypeInt && rt == pd->uniqueTypeInt ) { code.append( IN_ADD_INT ); return pd->uniqueTypeInt; } if ( lt == pd->uniqueTypeStr && rt == pd->uniqueTypeStr ) { code.append( IN_CONCAT_STR ); return pd->uniqueTypeStr; } error(loc) << "do not have an addition operator for these types" << endp; break; } case '-': { UniqueType *lt = left->evaluate( pd, code ); UniqueType *rt = right->evaluate( pd, code ); if ( lt == pd->uniqueTypeInt && rt == pd->uniqueTypeInt ) { code.append( IN_SUB_INT ); return pd->uniqueTypeInt; } error(loc) << "do not have an addition operator for these types" << endp; break; } case '*': { UniqueType *lt = left->evaluate( pd, code ); UniqueType *rt = right->evaluate( pd, code ); if ( lt == pd->uniqueTypeInt && rt == pd->uniqueTypeInt ) { code.append( IN_MULT_INT ); return pd->uniqueTypeInt; } error(loc) << "do not have an multiplication " "operator for these types" << endp; break; } case '/': { UniqueType *lt = left->evaluate( pd, code ); UniqueType *rt = right->evaluate( pd, code ); if ( lt == pd->uniqueTypeInt && rt == pd->uniqueTypeInt ) { code.append( IN_DIV_INT ); return pd->uniqueTypeInt; } error(loc) << "do not have an division" "operator for these types" << endp; break; } case OP_DoubleEql: { UniqueType *lt = left->evaluate( pd, code ); UniqueType *rt = right->evaluate( pd, code ); if ( lt != rt ) error(loc) << "comparison of different types" << endp; if ( lt->val() ) code.append( IN_TST_EQL_VAL ); else code.append( IN_TST_EQL_TREE ); return pd->uniqueTypeBool; } case OP_NotEql: { UniqueType *lt = left->evaluate( pd, code ); UniqueType *rt = right->evaluate( pd, code ); if ( lt != rt ) error(loc) << "comparison of different types" << endp; if ( lt->val() ) code.append( IN_TST_NOT_EQL_VAL ); else code.append( IN_TST_NOT_EQL_TREE ); return pd->uniqueTypeBool; } case '<': { UniqueType *lt = left->evaluate( pd, code ); UniqueType *rt = right->evaluate( pd, code ); if ( lt != rt ) error(loc) << "comparison of different types" << endp; if ( lt->val() ) code.append( IN_TST_LESS_VAL ); else code.append( IN_TST_LESS_TREE ); return pd->uniqueTypeBool; } case '>': { UniqueType *lt = left->evaluate( pd, code ); UniqueType *rt = right->evaluate( pd, code ); if ( lt != rt ) error(loc) << "comparison of different types" << endp; if ( lt->val() ) code.append( IN_TST_GRTR_VAL ); else code.append( IN_TST_GRTR_TREE ); return pd->uniqueTypeBool; } case OP_LessEql: { UniqueType *lt = left->evaluate( pd, code ); UniqueType *rt = right->evaluate( pd, code ); if ( lt != rt ) error(loc) << "comparison of different types" << endp; if ( lt->val() ) code.append( IN_TST_LESS_EQL_VAL ); else code.append( IN_TST_LESS_EQL_TREE ); return pd->uniqueTypeBool; } case OP_GrtrEql: { UniqueType *lt = left->evaluate( pd, code ); UniqueType *rt = right->evaluate( pd, code ); if ( lt != rt ) error(loc) << "comparison of different types" << endp; if ( lt->val() ) code.append( IN_TST_GRTR_EQL_VAL ); else code.append( IN_TST_GRTR_EQL_TREE ); return pd->uniqueTypeBool; } case OP_LogicalAnd: { /* Evaluate the left and duplicate it. */ UniqueType *lut = left->evaluate( pd, code ); if ( !lut->val() ) code.append( IN_TST_NZ_TREE ); code.append( IN_DUP_VAL ); /* Jump over the right if false, leaving the original left * result on the top of the stack. We don't know the * distance yet so record the position of the jump. */ long jump = code.length(); code.append( IN_JMP_FALSE_VAL ); code.appendHalf( 0 ); /* Evauluate the right, add the test. Store it separately. */ UniqueType *rut = right->evaluate( pd, code ); if ( !rut->val() ) code.append( IN_TST_NZ_TREE ); code.append( IN_TST_LOGICAL_AND ); /* Set the distance of the jump. */ long distance = code.length() - jump - 3; code.setHalf( jump+1, distance ); return pd->uniqueTypeInt; } case OP_LogicalOr: { /* Evaluate the left and duplicate it. */ UniqueType *lut = left->evaluate( pd, code ); if ( !lut->val() ) code.append( IN_TST_NZ_TREE ); code.append( IN_DUP_VAL ); /* Jump over the right if true, leaving the original left * result on the top of the stack. We don't know the * distance yet so record the position of the jump. */ long jump = code.length(); code.append( IN_JMP_TRUE_VAL ); code.appendHalf( 0 ); /* Evauluate the right, add the test. */ UniqueType *rut = right->evaluate( pd, code ); if ( !rut->val() ) code.append( IN_TST_NZ_TREE ); code.append( IN_TST_LOGICAL_OR ); /* Set the distance of the jump. */ long distance = code.length() - jump - 3; code.setHalf( jump+1, distance ); return pd->uniqueTypeInt; } } assert(false); return 0; } case UnaryType: { switch ( op ) { case '!': { /* Evaluate the left and duplicate it. */ UniqueType *ut = right->evaluate( pd, code ); if ( ut->val() ) code.append( IN_NOT_VAL ); else code.append( IN_NOT_TREE ); return pd->uniqueTypeBool; } case '$': { UniqueType *ut = right->evaluate( pd, code ); if ( ut->typeId == TYPE_INT || ut->typeId == TYPE_BOOL ) code.append( IN_INT_TO_STR ); code.append( IN_TREE_TO_STR_TRIM ); return pd->uniqueTypeStr; } case 'S': { UniqueType *ut = right->evaluate( pd, code ); if ( ut->typeId == TYPE_INT || ut->typeId == TYPE_BOOL ) code.append( IN_INT_TO_STR ); code.append( IN_TREE_TO_STR_TRIM_A ); return pd->uniqueTypeStr; } case '%': { UniqueType *ut = right->evaluate( pd, code ); if ( ut->typeId == TYPE_INT || ut->typeId == TYPE_BOOL ) code.append( IN_INT_TO_STR ); else code.append( IN_TREE_TO_STR ); return pd->uniqueTypeStr; } case '^': { UniqueType *rt = right->evaluate( pd, code ); code.append( IN_TREE_TRIM ); return rt; } case '@': { UniqueType *rt = right->evaluate( pd, code ); //code.append( IN_TREE_TRIM ); return rt; } default: assert(false); } return 0; } case TermType: { return term->evaluate( pd, code ); } } return 0; } void LangVarRef::assignValue( Compiler *pd, CodeVect &code, UniqueType *exprUT ) const { /* Lookup the left hand side of the assignment. */ VarRefLookup lookup = lookupField( pd ); if ( lookup.objField->refActive ) error(loc) << "reference active, cannot write to object" << endp; if ( lookup.firstConstPart >= 0 ) { error(loc) << "left hand side qualification \"" << qual->data[lookup.firstConstPart].data << "\" is const" << endp; } if ( lookup.objField->isConst ) error(loc) << "field \"" << name << "\" is const" << endp; /* Writing guarantees the field is dirty. tree is dirty. */ lookup.objField->dirtyTree = true; /* Check the types of the assignment and possibly cast. */ UniqueType *objUT = lookup.objField->typeRef->uniqueType; assert( lookup.uniqueType == lookup.objField->typeRef->uniqueType ); if ( !castAssignment( pd, code, objUT, lookup.iterSearchUT, exprUT ) ) error(loc) << "type mismatch in assignment" << endp; /* Decide if we need to revert the assignment. */ bool revert = lookup.lastPtrInQual >= 0 || !isLocalRef(); /* Load the object and generate the field setting code. */ loadObj( pd, code, lookup.lastPtrInQual, true ); if ( lookup.uniqueType->typeId == TYPE_ITER ) setFieldIter( pd, code, lookup.inObject, lookup.objField, lookup.uniqueType, exprUT, false ); else setField( pd, code, lookup.inObject, lookup.objField, exprUT, revert ); } UniqueType *LangTerm::evaluateMakeToken( Compiler *pd, CodeVect &code ) const { // if ( pd->compileContext != Compiler::CompileTranslation ) // error(loc) << "make_token can be used only in a translation block" << endp; /* Match the number of arguments. */ int numArgs = args != 0 ? args->length() : 0; if ( numArgs < 2 ) error(loc) << "need at least two arguments" << endp; for ( CallArgVect::Iter pe = *args; pe.lte(); pe++ ) { /* Evaluate. */ UniqueType *exprUT = (*pe)->expr->evaluate( pd, code ); if ( pe.pos() == 0 && exprUT != pd->uniqueTypeInt ) error(loc) << "first arg, id, must be an int" << endp; if ( pe.pos() == 1 && exprUT != pd->uniqueTypeStr ) error(loc) << "second arg, length, must be a string" << endp; } /* The token is now created, send it. */ code.append( IN_MAKE_TOKEN ); code.append( args->length() ); return pd->uniqueTypeAny; } UniqueType *LangTerm::evaluateMakeTree( Compiler *pd, CodeVect &code ) const { // if ( pd->compileContext != Compiler::CompileTranslation ) // error(loc) << "make_tree can be used only in a translation block" << endp; /* Match the number of arguments. */ int numArgs = args != 0 ? args->length() : 0; if ( numArgs < 1 ) error(loc) << "need at least one argument" << endp; for ( CallArgVect::Iter pe = *args; pe.lte(); pe++ ) { /* Evaluate. */ UniqueType *exprUT = (*pe)->expr->evaluate( pd, code ); if ( pe.pos() == 0 && exprUT != pd->uniqueTypeInt ) error(loc) << "first arg, nonterm id, must be an int" << endp; } /* The token is now created, send it. */ code.append( IN_MAKE_TREE ); code.append( args->length() ); return pd->uniqueTypeAny; } void LangStmt::compileForIterBody( Compiler *pd, CodeVect &code, UniqueType *iterUT ) const { /* Remember the top of the loop. */ long top = code.length(); /* Advance */ code.append( objField->iterImpl->inAdvance ); code.appendHalf( objField->offset ); /* Test: jump past the while block if false. Note that we don't have the * distance yet. */ long jumpFalse = code.length(); code.append( IN_JMP_FALSE_VAL ); code.appendHalf( 0 ); /* * Set up the loop cleanup code. */ /* Add the cleanup for the current loop. */ int lcLen = pd->unwindCode.length(); pd->unwindCode.insertHalf( 0, objField->offset ); pd->unwindCode.insert( 0, objField->iterImpl->inUnwind ); /* Compile the contents. */ for ( StmtList::Iter stmt = *stmtList; stmt.lte(); stmt++ ) stmt->compile( pd, code ); pd->unwindCode.remove( 0, pd->unwindCode.length() - lcLen ); /* Jump back to the top to retest. */ long retestDist = code.length() - top + 3; code.append( IN_JMP ); code.appendHalf( -retestDist ); /* Set the jump false distance. */ long falseDist = code.length() - jumpFalse - 3; code.setHalf( jumpFalse+1, falseDist ); /* Compute the jump distance for the break jumps. */ for ( LongVect::Iter brk = pd->breakJumps; brk.lte(); brk++ ) { long distance = code.length() - *brk - 3; code.setHalf( *brk+1, distance ); } pd->breakJumps.empty(); /* Destroy the iterator. */ code.append( objField->iterImpl->inDestroy ); code.appendHalf( objField->offset ); /* Clean up any prepush args. */ } void LangStmt::compileForIter( Compiler *pd, CodeVect &code ) const { /* The type we are searching for. */ UniqueType *searchUT = typeRef->uniqueType; /* Lookup the iterator call. Make sure it is an iterator. */ VarRefLookup lookup = iterCall->langTerm->varRef->lookupIterCall( pd ); if ( lookup.objMethod->iterDef == 0 ) { error(loc) << "attempt to iterate using something " "that is not an iterator" << endp; } /* Prepare the contiguous call args space. */ Function *func = lookup.objMethod->func; int asLoc; if ( func != 0 ) { code.append( IN_PREP_ARGS ); asLoc = code.length(); code.appendHalf( 0 ); } /* * Create the iterator from the local var. */ UniqueType *iterUT = objField->typeRef->uniqueType; IterImpl *iterImpl = 0; switch ( iterUT->iterDef->type ) { case IterDef::Tree: iterImpl = iterCall->langTerm->varRef->chooseTriterCall( pd, searchUT, iterCall->langTerm->args ); break; case IterDef::WithIgnore: iterImpl = new IterImpl( IterImpl::WithIgnore ); break; case IterDef::Child: iterImpl = new IterImpl( IterImpl::Child ); break; case IterDef::RevChild: iterImpl = new IterImpl( IterImpl::RevChild ); break; case IterDef::Repeat: iterImpl = new IterImpl( IterImpl::Repeat ); break; case IterDef::RevRepeat: iterImpl = new IterImpl( IterImpl::RevRepeat ); break; case IterDef::User: iterImpl = new IterImpl( IterImpl::User, iterUT->iterDef->func ); break; case IterDef::ListEl: iterImpl = new IterImpl( IterImpl::ListEl ); break; case IterDef::RevListVal: iterImpl = new IterImpl( IterImpl::RevListVal ); break; case IterDef::MapEl: iterImpl = new IterImpl( IterImpl::MapEl ); break; } objField->iterImpl = iterImpl; /* Evaluate and push the arguments. */ ObjectField **paramRefs = iterCall->langTerm->varRef->evaluateArgs( pd, code, lookup, iterCall->langTerm->args ); if ( pd->revertOn ) code.append( iterImpl->inCreateWV ); else code.append( iterImpl->inCreateWC ); code.appendHalf( objField->offset ); /* Arg size (or func id for user iters). */ if ( lookup.objMethod->func != 0 ) code.appendHalf( lookup.objMethod->func->funcId ); else code.appendHalf( iterCall->langTerm->varRef->argSize ); /* Search type. */ if ( iterImpl->useSearchUT ) code.appendHalf( searchUT->langEl->id ); if ( iterImpl->useGenericId ) { CodeVect unused; UniqueType *ut = iterCall->langTerm->args->data[0]->expr->evaluate( pd, unused ); code.appendHalf( ut->generic->id ); } compileForIterBody( pd, code, iterUT ); iterCall->langTerm->varRef->popRefQuals( pd, code, lookup, iterCall->langTerm->args, false ); iterCall->langTerm->varRef->resetActiveRefs( pd, lookup, paramRefs ); delete[] paramRefs; if ( func != 0 ) { code.append( IN_CLEAR_ARGS ); code.appendHalf( func->paramListSize ); code.setHalf( asLoc, func->paramListSize ); } } void LangStmt::compileWhile( Compiler *pd, CodeVect &code ) const { /* Generate code for the while test. Remember the top. */ long top = code.length(); UniqueType *eut = expr->evaluate( pd, code ); /* Jump past the while block if false. Note that we don't have the * distance yet. */ long jumpFalse = code.length(); half_t jinstr = eut->tree() ? IN_JMP_FALSE_TREE : IN_JMP_FALSE_VAL; code.append( jinstr ); code.appendHalf( 0 ); /* Compute the while block. */ for ( StmtList::Iter stmt = *stmtList; stmt.lte(); stmt++ ) stmt->compile( pd, code ); /* Jump back to the top to retest. */ long retestDist = code.length() - top + 3; code.append( IN_JMP ); code.appendHalf( -retestDist ); /* Set the jump false distance. */ long falseDist = code.length() - jumpFalse - 3; code.setHalf( jumpFalse+1, falseDist ); /* Compute the jump distance for the break jumps. */ for ( LongVect::Iter brk = pd->breakJumps; brk.lte(); brk++ ) { long distance = code.length() - *brk - 3; code.setHalf( *brk+1, distance ); } pd->breakJumps.empty(); } void LangStmt::compile( Compiler *pd, CodeVect &code ) const { CodeVect block; StringMapEl *mapEl = 0; if ( pd->literalStrings.insert( "unwind code\n", &mapEl ) ) mapEl->value = pd->literalStrings.length()-1; block.append( IN_LOAD_STR ); block.appendWord( mapEl->value ); block.append( IN_POP_TREE ); pd->unwindCode.insert( 0, block ); switch ( type ) { case ExprType: { /* Evaluate the exrepssion, then pop it immediately. */ UniqueType *exprUt = expr->evaluate( pd, code ); if ( exprUt->tree() ) code.append( IN_POP_TREE ); else code.append( IN_POP_VAL ); // pd->unwindCode.remove( 0, 1 ); break; } case IfType: { long jumpFalse = 0, jumpPastElse = 0, distance = 0; /* Evaluate the test. */ UniqueType *eut = expr->evaluate( pd, code ); /* Jump past the if block if false. We don't know the distance * yet so store the location of the jump. */ jumpFalse = code.length(); half_t jinstr = eut->tree() ? IN_JMP_FALSE_TREE : IN_JMP_FALSE_VAL; code.append( jinstr ); code.appendHalf( 0 ); /* Compile the if true branch. */ for ( StmtList::Iter stmt = *stmtList; stmt.lte(); stmt++ ) stmt->compile( pd, code ); if ( elsePart != 0 ) { /* Jump past the else code for the if true branch. */ jumpPastElse = code.length(); code.append( IN_JMP ); code.appendHalf( 0 ); } /* Set the distance for the jump false case. */ distance = code.length() - jumpFalse - 3; code.setHalf( jumpFalse+1, distance ); if ( elsePart != 0 ) { /* Compile the else branch. */ elsePart->compile( pd, code ); /* Set the distance for jump over the else part. */ distance = code.length() - jumpPastElse - 3; code.setHalf( jumpPastElse+1, distance ); } break; } case ElseType: { /* Compile the else branch. */ for ( StmtList::Iter stmt = *stmtList; stmt.lte(); stmt++ ) stmt->compile( pd, code ); break; } case RejectType: { code.append( IN_REJECT ); break; } case WhileType: { compileWhile( pd, code ); break; } case AssignType: { /* Evaluate the exrepssion. */ UniqueType *exprUT = expr->evaluate( pd, code ); /* Do the assignment. */ varRef->assignValue( pd, code, exprUT ); break; } case ForIterType: { compileForIter( pd, code ); break; } case ReturnType: { /* Evaluate the exrepssion. */ UniqueType *exprUT = expr->evaluate( pd, code ); if ( pd->curFunction == 0 ) { /* In the main function */ pd->mainReturnUT = exprUT; } else { UniqueType *resUT = pd->curFunction->typeRef->uniqueType; if ( resUT != pd->uniqueTypeVoid && !castAssignment( pd, code, resUT, 0, exprUT ) ) error(loc) << "return value wrong type" << endp; } code.append( IN_SAVE_RET ); /* The loop cleanup code. */ if ( pd->unwindCode.length() > 0 ) code.append( pd->unwindCode ); /* Jump to the return label. The distance will be filled in * later. */ pd->returnJumps.append( code.length() ); code.append( IN_JMP ); code.appendHalf( 0 ); break; } case BreakType: { pd->breakJumps.append( code.length() ); code.append( IN_JMP ); code.appendHalf( 0 ); break; } case YieldType: { /* take a reference and yield it. Immediately reset the referece. */ varRef->preEvaluateRef( pd, code ); ObjectField *objField = varRef->evaluateRef( pd, code, 0 ); code.append( IN_YIELD ); if ( varRef->qual->length() > 0 ) { code.append( IN_POP_N_WORDS ); code.appendHalf( (short)(varRef->qual->length()*2) ); } objField->refActive = false; break; } } pd->unwindCode.remove( 0, block.length() ); } void CodeBlock::compile( Compiler *pd, CodeVect &code ) const { for ( StmtList::Iter stmt = *stmtList; stmt.lte(); stmt++ ) stmt->compile( pd, code ); } void Compiler::findLocals( ObjectDef *localFrame, CodeBlock *block ) { Locals &locals = block->locals; for ( FieldList::Iter ol = localFrame->fieldList; ol.lte(); ol++ ) { ObjectField *el = ol->value; /* FIXME: This test needs to be improved. Match_text was getting * through before useOffset was tested. What will? */ if ( el->useOffset() && !el->isLhsEl() && ( el->beenReferenced || el->isParam() ) ) { UniqueType *ut = el->typeRef->uniqueType; if ( ut->tree() ) { int depth = el->scope->depth(); locals.append( LocalLoc( LT_Tree, depth, el->offset ) ); } } if ( el->useOffset() ) { UniqueType *ut = el->typeRef->uniqueType; if ( ut->typeId == TYPE_ITER ) { int depth = el->scope->depth(); LocalType type = LT_Tree; switch ( ut->iterDef->type ) { case IterDef::Tree: case IterDef::WithIgnore: case IterDef::Child: case IterDef::Repeat: case IterDef::RevRepeat: type = LT_Iter; break; case IterDef::MapEl: case IterDef::ListEl: case IterDef::RevListVal: /* ? */ type = LT_Iter; break; case IterDef::RevChild: type = LT_RevIter; break; case IterDef::User: type = LT_UserIter; break; } locals.append( LocalLoc( type, depth, (int)el->offset ) ); } } } } void Compiler::addProdLHSLoad( Production *prod, CodeVect &code, long &insertPos ) { NameScope *scope = prod->redBlock->localFrame->rootScope; ObjectField *lhsField = scope->findField("lhs"); assert( lhsField != 0 ); CodeVect loads; if ( lhsField->beenReferenced ) { loads.append( IN_INIT_LHS_EL ); loads.appendHalf( lhsField->offset ); } code.insert( insertPos, loads ); insertPos += loads.length(); } void Compiler::addPushBackLHS( Production *prod, CodeVect &code, long &insertPos ) { CodeBlock *block = prod->redBlock; /* If the lhs tree is dirty then we will need to save off the old lhs * before it gets modified. We want to avoid this for attribute * modifications. The computation of dirtyTree should deal with this for * us. */ NameScope *scope = block->localFrame->rootScope; ObjectField *lhsField = scope->findField("lhs"); assert( lhsField != 0 ); if ( lhsField->beenReferenced ) { code.append( IN_STORE_LHS_EL ); code.appendHalf( lhsField->offset ); } } void Compiler::addProdRHSLoads( Production *prod, CodeVect &code, long &insertPos ) { CodeVect loads; long elPos = 0; for ( ProdElList::Iter rhsEl = *prod->prodElList; rhsEl.lte(); rhsEl++, elPos++ ) { if ( rhsEl->type == ProdEl::ReferenceType ) { if ( rhsEl->rhsElField->beenReferenced ) { loads.append ( IN_INIT_RHS_EL ); loads.appendHalf( elPos ); loads.appendHalf( rhsEl->rhsElField->offset ); } } } /* Insert and update the insert position. */ code.insert( insertPos, loads ); insertPos += loads.length(); } void Compiler::makeProdCopies( Production *prod ) { int pos = 0; for ( ProdElList::Iter pel = *prod->prodElList; pel.lte(); pel++, pos++) { if ( pel->captureField != 0 ) { prod->copy.append( pel->captureField->offset ); prod->copy.append( pos ); } } } void Compiler::compileReductionCode( Production *prod ) { CodeBlock *block = prod->redBlock; /* Init the compilation context. */ compileContext = CompileReduction; revertOn = true; block->frameId = nextFrameId++; CodeVect &code = block->codeWV; long afterInit = code.length(); /* Compile the reduce block. */ block->compile( this, code ); /* Might need to load right hand side values. */ addProdRHSLoads( prod, code, afterInit ); addProdLHSLoad( prod, code, afterInit ); addPushBackLHS( prod, code, afterInit ); code.append( IN_PCR_RET ); /* Now that compilation is done variables are referenced. Make the local * trees descriptor. */ findLocals( block->localFrame, block ); } void Compiler::compileTranslateBlock( LangEl *langEl ) { CodeBlock *block = langEl->transBlock; /* Set up compilation context. */ compileContext = CompileTranslation; revertOn = true; block->frameId = nextFrameId++; CodeVect &code = block->codeWV; if ( langEl->tokenDef->reCaptureVect.length() > 0 ) { code.append( IN_INIT_CAPTURES ); code.append( langEl->tokenDef->reCaptureVect.length() ); } /* Set the local frame and compile the reduce block. */ block->compile( this, code ); code.append( IN_PCR_RET ); /* Now that compilation is done variables are referenced. Make the local * trees descriptor. */ findLocals( block->localFrame, block ); } void Compiler::compilePreEof( TokenRegion *region ) { CodeBlock *block = region->preEofBlock; /* Set up compilation context. */ compileContext = CompileTranslation; revertOn = true; block->frameId = nextFrameId++; addInput( block->localFrame ); addThis( block->localFrame ); CodeVect &code = block->codeWV; /* Set the local frame and compile the reduce block. */ block->compile( this, code ); code.append( IN_PCR_RET ); /* Now that compilation is done variables are referenced. Make the local * trees descriptor. */ findLocals( block->localFrame, block ); } int Compiler::arg0Offset() { globalObjectDef->referenceField( this, arg0 ); return arg0->offset; } int Compiler::argvOffset() { globalObjectDef->referenceField( this, argv ); return argv->offset; } int Compiler::stdsOffset() { globalObjectDef->referenceField( this, stds ); return stds->offset; } void Compiler::compileRootBlock( ) { CodeBlock *block = rootCodeBlock; /* The root block never needs to be reverted. */ /* Set up the compile context. No locals are needed for the root code * block, but we need an empty local frame for the compile. */ compileContext = CompileRoot; revertOn = false; /* The block needs a frame id. */ block->frameId = nextFrameId++; /* The root block is not reverted. */ CodeVect &code = block->codeWC; code.append( IN_FN ); code.append( FN_LOAD_ARG0 ); code.appendHalf( arg0Offset() ); code.append( IN_FN ); code.append( FN_LOAD_ARGV ); code.appendHalf( argvOffset() ); code.append( IN_FN ); code.append( FN_INIT_STDS ); code.appendHalf( stdsOffset() ); block->compile( this, code ); code.append( IN_FN ); code.append( FN_STOP ); /* Make the local trees descriptor. */ findLocals( rootLocalFrame, block ); } void ObjectField::initField() { switch ( type ) { case UserLocalType: case LhsElType: case ParamValType: case RedRhsType: inGetR = IN_GET_LOCAL_R; inGetWC = IN_GET_LOCAL_WC; inSetWC = IN_SET_LOCAL_WC; inGetValR = IN_GET_LOCAL_VAL_R; inGetValWC = IN_GET_LOCAL_VAL_R; inGetValWV = IN_GET_LOCAL_VAL_R; inSetValWC = IN_SET_LOCAL_VAL_WC; break; case ParamRefType: inGetR = IN_GET_LOCAL_REF_R; inGetWC = IN_GET_LOCAL_REF_WC; inSetWC = IN_SET_LOCAL_REF_WC; break; case UserFieldType: inGetR = IN_GET_FIELD_TREE_R; inGetWC = IN_GET_FIELD_TREE_WC; inGetWV = IN_GET_FIELD_TREE_WV; inSetWC = IN_SET_FIELD_TREE_WC; inSetWV = IN_SET_FIELD_TREE_WV; //inGetValR; inGetValR = IN_GET_FIELD_VAL_R; //inGetValWC = IN_GET_FIELD_VAL_WC; //inGetValWV; inSetValWC = IN_SET_FIELD_VAL_WC; //inSetValWV; break; case GenericElementType: case GenericDependentType: case StructFieldType: inGetR = IN_GET_STRUCT_R; inGetWC = IN_GET_STRUCT_WC; inGetWV = IN_GET_STRUCT_WV; inSetWC = IN_SET_STRUCT_WC; inSetWV = IN_SET_STRUCT_WV; inGetValR = IN_GET_STRUCT_VAL_R; inGetValWC = IN_GET_STRUCT_VAL_R; inGetValWV = IN_GET_STRUCT_VAL_R; inSetValWC = IN_SET_STRUCT_VAL_WC; inSetValWV = IN_SET_STRUCT_VAL_WV; break; case RhsNameType: inGetR = IN_GET_RHS_VAL_R; inGetWC = IN_GET_RHS_VAL_WC; inGetWV = IN_GET_RHS_VAL_WV; inSetWC = IN_SET_RHS_VAL_WC; inSetWV = IN_SET_RHS_VAL_WC; break; /* Inbuilts have instructions intialized outside the cons, at place of * call. */ case InbuiltFieldType: case InbuiltObjectType: case InbuiltOffType: break; /* Out of date impl. */ case LexSubstrType: break; } } void ObjectDef::placeField( Compiler *pd, ObjectField *field ) { UniqueType *fieldUT = field->typeRef->uniqueType; switch ( field->type ) { case ObjectField::LhsElType: case ObjectField::UserLocalType: case ObjectField::RedRhsType: /* Local frame fields. Move the running offset first since this is * a negative off from the end. */ nextOffset += sizeOfField( fieldUT ); field->offset = -nextOffset; break; case ObjectField::GenericElementType: { /* Tree object frame fields. Record the position, then move the * running offset. */ field->offset = nextOffset; nextOffset += sizeOfField( fieldUT ); if ( fieldUT->typeId == TYPE_MAP_PTRS ) { if ( field->mapKeyField != 0 ) field->mapKeyField->offset = field->offset; } break; } case ObjectField::UserFieldType: /* Tree object frame fields. Record the position, then move the * running offset. */ field->offset = nextOffset; nextOffset += sizeOfField( fieldUT ); break; case ObjectField::StructFieldType: field->offset = nextOffset; nextOffset += sizeOfField( fieldUT ); break; case ObjectField::GenericDependentType: /* There is an object field that this type depends on. When it is * placed, this one will be placed as well. Nothing to do now. */ case ObjectField::InbuiltFieldType: case ObjectField::InbuiltOffType: case ObjectField::InbuiltObjectType: case ObjectField::RhsNameType: case ObjectField::LexSubstrType: case ObjectField::ParamValType: case ObjectField::ParamRefType: break; } } void Compiler::placeAllLanguageObjects() { /* Init all user object fields (need consistent size). */ for ( LelList::Iter lel = langEls; lel.lte(); lel++ ) { ObjectDef *objDef = lel->objectDef; if ( objDef != 0 ) { /* Init all fields of the object. */ for ( FieldList::Iter f = objDef->fieldList; f.lte(); f++ ) objDef->placeField( this, f->value ); } } } void Compiler::placeAllStructObjects() { for ( StructElList::Iter s = structEls; s.lte(); s++ ) { ObjectDef *objectDef = s->structDef->objectDef; for ( FieldList::Iter f = objectDef->fieldList; f.lte(); f++ ) objectDef->placeField( this, f->value ); } } void Compiler::placeFrameFields( ObjectDef *localFrame ) { for ( FieldList::Iter f = localFrame->fieldList; f.lte(); f++ ) localFrame->placeField( this, f->value ); } void Compiler::placeAllFrameObjects() { /* Functions. */ for ( FunctionList::Iter f = functionList; f.lte(); f++ ) placeFrameFields( f->localFrame ); for ( FunctionList::Iter f = inHostList; f.lte(); f++ ) placeFrameFields( f->localFrame ); /* Reduction code. */ for ( ProdList::Iter prod = prodList; prod.lte(); prod++ ) { if ( prod->redBlock != 0 ) placeFrameFields( prod->redBlock->localFrame ); } /* Token translation code. */ for ( LelList::Iter lel = langEls; lel.lte(); lel++ ) { if ( lel->transBlock != 0 ) { ObjectDef *localFrame = lel->transBlock->localFrame; if ( lel->tokenDef->reCaptureVect.length() > 0 ) { FieldList::Iter f = localFrame->fieldList; for ( int i = 0; i < lel->tokenDef->reCaptureVect.length(); i++, f++ ) localFrame->placeField( this, f->value ); } placeFrameFields( localFrame ); } } /* Preeof blocks. */ for ( RegionList::Iter r = regionList; r.lte(); r++ ) { if ( r->preEofBlock != 0 ) placeFrameFields( r->preEofBlock->localFrame ); } /* Root code. */ placeFrameFields( rootLocalFrame ); } void Compiler::placeUserFunction( Function *func, bool isUserIter ) { /* Set up the parameters. */ long paramPos = 0, paramListSize = 0, paramOffset = 0; UniqueType **paramUTs = new UniqueType*[func->paramList->length()]; for ( ParameterList::Iter param = *func->paramList; param.lte(); param++, paramPos++ ) { paramUTs[paramPos] = param->typeRef->uniqueType; paramListSize += sizeOfField( paramUTs[paramPos] ); } /* Param offset is relative to one past the last item in the array of * words containing the args. */ paramOffset = 0; paramPos = 0; for ( ParameterList::Iter param = *func->paramList; param.lte(); param++, paramPos++ ) { /* How much space do we need to make for call overhead. */ long frameAfterArgs = isUserIter ? IFR_AA : FR_AA; param->offset = frameAfterArgs + paramOffset; paramOffset += sizeOfField( paramUTs[paramPos] ); } func->paramListSize = paramListSize; func->paramUTs = paramUTs; func->objMethod->paramUTs = paramUTs; /* Insert the function into the global function map. */ UniqueType *returnUT = func->typeRef != 0 ? func->typeRef->uniqueType : uniqueTypeInt; func->objMethod->returnUT = returnUT; func->objMethod->paramUTs = new UniqueType*[func->paramList->length()]; memcpy( func->objMethod->paramUTs, paramUTs, sizeof(UniqueType*) * func->paramList->length() ); } void Compiler::placeAllFunctions() { for ( FunctionList::Iter f = functionList; f.lte(); f++ ) placeUserFunction( f, f->isUserIter ); for ( FunctionList::Iter f = inHostList; f.lte(); f++ ) placeUserFunction( f, false ); } void Compiler::compileUserIter( Function *func, CodeVect &code ) { CodeBlock *block = func->codeBlock; /* Compile the block. */ block->compile( this, code ); /* Always yeild a nil at the end. This causes iteration to stop. */ code.append( IN_LOAD_NIL ); code.append( IN_YIELD ); } void Compiler::compileUserIter( Function *func ) { CodeBlock *block = func->codeBlock; /* Set up the context. */ compileContext = CompileFunction; curFunction = func; block->frameId = nextFrameId++; /* Compile for revert and commit. */ revertOn = true; compileUserIter( func, block->codeWV ); revertOn = false; compileUserIter( func, block->codeWC ); /* Now that compilation is done variables are referenced. Make the local * trees descriptor. */ findLocals( block->localFrame, block ); /* FIXME: Need to deal with the freeing of local trees. */ } /* Called for each type of function compile: revert and commit. */ void Compiler::compileFunction( Function *func, CodeVect &code ) { CodeBlock *block = func->codeBlock; /* Compile the block. */ block->compile( this, code ); /* Check for a return statement. */ if ( block->stmtList->length() == 0 || block->stmtList->tail->type != LangStmt::ReturnType ) { /* Push the return value. */ code.append( IN_LOAD_NIL ); code.append( IN_SAVE_RET ); } /* Compute the jump distance for the return jumps. */ for ( LongVect::Iter rj = returnJumps; rj.lte(); rj++ ) { long distance = code.length() - *rj - 3; code.setHalf( *rj+1, distance ); } /* Reset the vector of return jumps. */ returnJumps.empty(); /* Return cleans up the stack (including the args) and leaves the return * value on the top. */ code.append( IN_RET ); } void Compiler::compileFunction( Function *func ) { CodeBlock *block = func->codeBlock; /* Set up the compilation context. */ compileContext = CompileFunction; curFunction = func; /* Assign a frame Id. */ block->frameId = nextFrameId++; /* Compile once for revert. */ revertOn = true; compileFunction( func, block->codeWV ); /* Compile once for commit. */ revertOn = false; compileFunction( func, block->codeWC ); /* Now that compilation is done variables are referenced. Make the local * trees descriptor. */ findLocals( block->localFrame, block ); } void Compiler::removeNonUnparsableRepls() { for ( ConsList::Iter repl = replList; repl.lte(); ) { Constructor *maybeDel = repl++; if ( !maybeDel->parse ) replList.detach( maybeDel ); } } void Compiler::compileByteCode() { /* Compile functions. */ for ( FunctionList::Iter f = functionList; f.lte(); f++ ) { if ( f->isUserIter ) compileUserIter( f ); else compileFunction( f ); } /* Compile the reduction code. */ for ( ProdList::Iter prod = prodList; prod.lte(); prod++ ) { makeProdCopies( prod ); if ( prod->redBlock != 0 ) compileReductionCode( prod ); } /* Compile the token translation code. */ for ( LelList::Iter lel = langEls; lel.lte(); lel++ ) { if ( lel->transBlock != 0 ) compileTranslateBlock( lel ); } /* Compile preeof blocks. */ for ( RegionList::Iter r = regionList; r.lte(); r++ ) { if ( r->preEofBlock != 0 ) compilePreEof( r ); } /* Compile the init code */ compileRootBlock( ); removeNonUnparsableRepls(); }