diff options
author | Adrian Thurston <thurston@colm.net> | 2020-03-14 15:29:52 +0200 |
---|---|---|
committer | Adrian Thurston <thurston@colm.net> | 2020-03-14 15:29:52 +0200 |
commit | f653735830d537715f2885bd832cf04851d35401 (patch) | |
tree | 95e6551e39407543366d4f49aedf7b78c6e8bbe1 /src/synthesis.cc | |
parent | bcc54d5df10cf425e7134b06f70d7ffe1abee4e4 (diff) | |
download | colm-f653735830d537715f2885bd832cf04851d35401.tar.gz |
moved source files into commit repository
Diffstat (limited to 'src/synthesis.cc')
-rw-r--r-- | src/synthesis.cc | 3370 |
1 files changed, 3370 insertions, 0 deletions
diff --git a/src/synthesis.cc b/src/synthesis.cc new file mode 100644 index 00000000..17c2440a --- /dev/null +++ b/src/synthesis.cc @@ -0,0 +1,3370 @@ +/* + * Copyright 2007-2018 Adrian Thurston <thurston@colm.net> + * + * 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 <assert.h> +#include <stdbool.h> +#include <iostream> +#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 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::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<RhsVal>::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<RhsVal>::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<RhsVal>::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<RhsVal>::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::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::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 ( DefList::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 ( DefList::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(); +} |