summaryrefslogtreecommitdiff
path: root/src/synthesis.cc
diff options
context:
space:
mode:
authorAdrian Thurston <thurston@colm.net>2020-03-14 15:29:52 +0200
committerAdrian Thurston <thurston@colm.net>2020-03-14 15:29:52 +0200
commitf653735830d537715f2885bd832cf04851d35401 (patch)
tree95e6551e39407543366d4f49aedf7b78c6e8bbe1 /src/synthesis.cc
parentbcc54d5df10cf425e7134b06f70d7ffe1abee4e4 (diff)
downloadcolm-f653735830d537715f2885bd832cf04851d35401.tar.gz
moved source files into commit repository
Diffstat (limited to 'src/synthesis.cc')
-rw-r--r--src/synthesis.cc3370
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();
+}