summaryrefslogtreecommitdiff
path: root/src/synthesis.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/synthesis.cc')
-rw-r--r--src/synthesis.cc2687
1 files changed, 2687 insertions, 0 deletions
diff --git a/src/synthesis.cc b/src/synthesis.cc
new file mode 100644
index 0000000..f6f7b56
--- /dev/null
+++ b/src/synthesis.cc
@@ -0,0 +1,2687 @@
+/*
+ * Copyright 2007-2012 Adrian Thurston <thurston@complang.org>
+ */
+
+/* This file is part of Colm.
+ *
+ * Colm is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Colm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Colm; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "bytecode.h"
+#include "parsedata.h"
+#include "pdarun.h"
+#include "input.h"
+#include <iostream>
+#include <assert.h>
+
+using std::cout;
+using std::cerr;
+using std::endl;
+
+IterDef::IterDef( Type type ) :
+ type(type),
+ func(0),
+ useFuncId(false),
+ useSearchUT(false)
+{
+ switch ( type ) {
+ case Tree:
+ inCreateWV = IN_TRITER_FROM_REF;
+ inCreateWC = IN_TRITER_FROM_REF;
+ 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;
+ 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;
+ 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;
+ 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;
+ 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 User:
+ assert(false);
+ }
+}
+
+IterDef::IterDef( Type type, Function *func ) :
+ type(type),
+ func(func),
+ useFuncId(true),
+ useSearchUT(true),
+ inCreateWV(IN_UITER_CREATE_WV),
+ inCreateWC(IN_UITER_CREATE_WC),
+ 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)
+{}
+
+ObjMethod *initFunction( UniqueType *retType, ObjectDef *obj,
+ const String &name, int methIdWV, int methIdWC, bool isConst )
+{
+ ObjMethod *objMethod = new ObjMethod( retType, name,
+ methIdWV, methIdWC, 0, 0, 0, isConst );
+ obj->objMethodMap->insert( name, objMethod );
+ return objMethod;
+}
+
+ObjMethod *initFunction( UniqueType *retType, ObjectDef *obj,
+ const String &name, int methIdWV, int methIdWC, UniqueType *arg1, bool isConst )
+{
+ UniqueType *args[] = { arg1 };
+ ObjMethod *objMethod = new ObjMethod( retType, name,
+ methIdWV, methIdWC, 1, args, 0, isConst );
+ obj->objMethodMap->insert( name, objMethod );
+ return objMethod;
+}
+
+ObjMethod *initFunction( UniqueType *retType, ObjectDef *obj,
+ const String &name, int methIdWV, int methIdWC,
+ UniqueType *arg1, UniqueType *arg2, bool isConst )
+{
+ UniqueType *args[] = { arg1, arg2 };
+ ObjMethod *objMethod = new ObjMethod( retType, name,
+ methIdWV, methIdWC, 2, args, 0, isConst );
+ obj->objMethodMap->insert( name, objMethod );
+ return objMethod;
+}
+
+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( int typeId )
+{
+ UniqueType searchKey( typeId );
+ UniqueType *uniqueType = uniqeTypeMap.find( &searchKey );
+ if ( uniqueType == 0 ) {
+ uniqueType = new UniqueType( typeId );
+ uniqeTypeMap.insert( uniqueType );
+ }
+ return uniqueType;
+}
+
+UniqueType *Compiler::findUniqueType( int 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( int 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;
+}
+
+
+/* 0-based. */
+ObjectField *ObjectDef::findFieldNum( long offset )
+{
+ int fn = 0;
+ ObjFieldList::Iter field = *objFieldList;
+ while ( fn < offset ) {
+ fn++;
+ field++;
+ }
+ return field->value;
+}
+
+long sizeOfField( UniqueType *fieldUT )
+{
+ long size = 0;
+ if ( fieldUT->typeId == 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(TreeIter) / sizeof(Word);
+ break;
+ case IterDef::RevChild:
+ size = sizeof(RevTreeIter) / sizeof(Word);
+ break;
+
+ case IterDef::User:
+ /* User iterators are just a pointer to the UserIter 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;
+ }
+ }
+ else if ( fieldUT->typeId == TYPE_REF )
+ size = 2;
+ else
+ size = 1;
+
+ return size;
+}
+
+void ObjectDef::referenceField( Compiler *pd, ObjectField *field )
+{
+ field->beenReferenced = true;
+ initField( pd, field );
+}
+
+void ObjectDef::initField( Compiler *pd, ObjectField *field )
+{
+ if ( !field->beenInitialized ) {
+ field->beenInitialized = true;
+ UniqueType *fieldUT = field->typeRef->uniqueType;
+
+ if ( type == FrameType ) {
+ nextOffset += sizeOfField( fieldUT );
+ field->offset = -nextOffset;
+
+ pd->initLocalInstructions( field );
+ }
+ else if ( field->isRhsGet ) {
+ field->useOffset = false;
+ field->inGetR = IN_GET_RHS_VAL_R;
+ field->inGetWC = IN_GET_RHS_VAL_WC;
+ field->inGetWV = IN_GET_RHS_VAL_WV;
+ field->inSetWC = IN_SET_RHS_VAL_WC;
+ field->inSetWV = IN_SET_RHS_VAL_WC;
+ }
+ else {
+ field->offset = nextOffset;
+ nextOffset += sizeOfField( fieldUT );
+
+ /* Initialize the instructions. */
+ pd->initFieldInstructions( field );
+ }
+ }
+}
+
+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 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( elUT->iterDef->inGetCurWC );
+ else if ( pd->revertOn && revert )
+ code.append( el->inGetWV );
+ else
+ code.append( el->inGetWC );
+ }
+ else {
+ /* Loading something for writing */
+ if ( elUT->typeId == TYPE_ITER )
+ code.append( elUT->iterDef->inGetCurR );
+ else
+ code.append( el->inGetR );
+ }
+
+ 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 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, ObjNameScope *rootScope ) const
+{
+ long count = 0;
+
+ /* Start the search from the root object. */
+ ObjNameScope *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 ) {
+ code.append( IN_REF_FROM_QUAL_REF );
+ code.appendHalf( 0 );
+ code.appendHalf( el->offset );
+ }
+ else if ( el->typeRef->iterDef != 0 ) {
+ code.append( el->typeRef->iterDef->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,
+ ObjNameScope *rootScope, int lastPtrInQual, bool forWriting, bool revert ) const
+{
+ /* Start the search from the root object. */
+ ObjNameScope *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->owner,
+ el, lfForWriting, lfRevert );
+
+ if ( qi->form == QualItem::Dot ) {
+ /* Cannot a reference. Iterator yes (access of the iterator not
+ * hte current) */
+ if ( qualUT->typeId == TYPE_PTR )
+ error(loc) << "dot cannot be used to access a pointer" << endp;
+ }
+ else if ( qi->form == QualItem::Arrow ) {
+ if ( qualUT->typeId == TYPE_PTR ) {
+ /* Always dereference references when used for qualification. If
+ * this is the last one then we must start with the reverse
+ * execution business. */
+ if ( pd->revertOn && qi.pos() == lastPtrInQual && forWriting ) {
+ /* This is like a global load. */
+ code.append( IN_PTR_DEREF_WV );
+ }
+ else {
+ /* If reading or not yet the last in ref then we only need a
+ * reading deref. */
+ code.append( IN_PTR_DEREF_R );
+ }
+
+ qualUT = pd->findUniqueType( TYPE_TREE, qualUT->langEl );
+ }
+ 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 = context->contextObjDef;
+
+ 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
+{
+ /* Start the search in the global object. */
+ ObjectDef *rootObj = pd->globalObjectDef;
+
+ 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, rootObj->rootScope, lastPtrInQual, forWriting, true );
+}
+
+void LangVarRef::loadCustom( 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 ( isCustom() )
+ loadCustom( pd, code, lastPtrInQual, forWriting );
+ else if ( isLocalRef() )
+ loadLocalObj( pd, code, lastPtrInQual, forWriting );
+ else if ( isContextRef() )
+ 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;
+
+ /* Assigning nil to a pointer. */
+ if ( destUT->typeId == TYPE_PTR && srcUT->typeId == TYPE_NIL )
+ return true;
+
+ return false;
+}
+
+void LangVarRef::setFieldIter( Compiler *pd, CodeVect &code,
+ ObjectDef *inObject, ObjectField *el, UniqueType *objUT,
+ UniqueType *exprType, bool revert ) const
+{
+ code.append( objUT->iterDef->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 ( pd->revertOn && revert )
+ code.append( el->inSetWV );
+ else
+ code.append( el->inSetWC );
+
+ /* Maybe write out an offset. */
+ if ( el->useOffset )
+ code.appendHalf( el->offset );
+}
+
+
+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::canTakeRefTest( 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() && lookup.lastPtrInQual < 0 && lookup.uniqueType->typeId != TYPE_PTR )
+ canTake = true;
+
+ return canTake;
+}
+
+void LangVarRef::canTakeRef( Compiler *pd, VarRefLookup &lookup ) const
+{
+ bool canTake = canTakeRefTest( 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::canTakeRefTest( Compiler *pd ) const
+{
+ bool canTake = false;
+
+ if ( type == LangExpr::TermType && term->type == LangTerm::VarRefType ) {
+ VarRefLookup lookup = term->varRef->lookupField( pd );
+ if ( term->varRef->canTakeRefTest( pd, lookup ) )
+ canTake = true;
+ }
+ return canTake;
+}
+
+
+/* Return the field referenced. */
+ObjectField *LangVarRef::preEvaluateRef( Compiler *pd, CodeVect &code ) const
+{
+ VarRefLookup lookup = lookupField( pd );
+
+ canTakeRef( 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 );
+
+ canTakeRef( 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 ) {
+ code.append( IN_REF_FROM_QUAL_REF );
+ code.appendHalf( pushCount );
+ code.appendHalf( lookup.objField->offset );
+ }
+ else if ( lookup.objField->typeRef->iterDef != 0 ) {
+ code.append( lookup.objField->typeRef->iterDef->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;
+}
+
+
+ObjectField **LangVarRef::evaluateArgs( Compiler *pd, CodeVect &code,
+ VarRefLookup &lookup, CallArgVect *args ) const
+{
+ /* 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 );
+
+ /* Evaluate and push the args. */
+ if ( args != 0 ) {
+ /* We use this only if there is a paramter list. */
+ ParameterList::Iter p;
+ long size = 0;
+
+ /* First pass we need to allocate and evaluate temporaries. */
+ 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 ) {
+ /* Make sure we are dealing with a variable reference. */
+ if ( ! expression->canTakeRefTest( pd ) ) {
+ /* Evaluate the expression. */
+ UniqueType *exprUT = expression->evaluate( pd, code );
+ (*pe)->exprUT = exprUT;
+
+ size += 1;
+ (*pe)->offTmp = size;
+ }
+ }
+
+ /* Advance the parameter list iterator if we have it. */
+ paramList != 0 && p.increment();
+ }
+
+
+ /* Second pass we need to push object loads for reference parameters. */
+ 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->canTakeRefTest( pd ) ) {
+ /* Lookup the field. */
+ LangVarRef *varRef = expression->term->varRef;
+ ObjectField *refOf = varRef->preEvaluateRef( pd, code );
+ paramRefs[pe.pos()] = refOf;
+
+ size += varRef->qual->length() * 2;
+ (*pe)->offQualRef = size;
+ }
+ }
+
+ /* Advance the parameter list iterator if we have it. */
+ paramList != 0 && p.increment();
+ }
+
+ 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->canTakeRefTest( pd ) ) {
+ /* Lookup the field. */
+ LangVarRef *varRef = expression->term->varRef;
+
+ ObjectField *refOf = varRef->evaluateRef( pd, code, (size - (*pe)->offQualRef) );
+ paramRefs[pe.pos()] = refOf;
+
+ size += 2;
+ }
+ else {
+ code.append( IN_REF_FROM_BACK );
+ code.appendHalf( size - (*pe)->offTmp );
+
+ size += 2;
+ }
+ }
+ else {
+ UniqueType *exprUT = expression->evaluate( pd, code );
+
+ if ( !castAssignment( pd, code, paramUT, 0, exprUT ) )
+ error(loc) << "arg " << pe.pos()+1 << " is of the wrong type" << endp;
+
+ size += 1;
+ }
+
+ /* Advance the parameter list iterator if we have it. */
+ paramList != 0 && p.increment();
+ }
+ }
+
+ 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;
+ }
+}
+
+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() || isCustom();
+
+ /* The call instruction. */
+ if ( pd->revertOn && revert ) {
+ if ( lookup.objMethod->opcodeWV == IN_PARSE_FINISH_WV ) {
+ code.append( IN_PARSE_SAVE_STEPS );
+ code.append( IN_PARSE_FINISH_WV );
+ code.appendHalf( 0 );
+ code.append( IN_PCR_CALL );
+ code.append( IN_PARSE_FINISH_EXIT_WV );
+ }
+ else {
+ code.append( lookup.objMethod->opcodeWV );
+ }
+ }
+ else {
+ if ( lookup.objMethod->opcodeWC == IN_PARSE_FINISH_WC ) {
+ code.append( IN_PARSE_SAVE_STEPS );
+ code.append( IN_PARSE_FINISH_WC );
+ code.appendHalf( 0 );
+ code.append( IN_PCR_CALL );
+ code.append( IN_PARSE_FINISH_EXIT_WC );
+ }
+ else {
+ code.append( lookup.objMethod->opcodeWC );
+ }
+ }
+
+ if ( lookup.objMethod->useFuncId )
+ code.appendHalf( lookup.objMethod->funcId );
+}
+
+void LangVarRef::popRefQuals( Compiler *pd, CodeVect &code,
+ VarRefLookup &lookup, CallArgVect *args ) 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->canTakeRefTest( pd ) ) {
+ LangVarRef *varRef = expression->term->varRef;
+ popCount += varRef->qual->length() * 2;
+ }
+ }
+ }
+
+ if ( popCount > 0 ) {
+ code.append( IN_POP_N_WORDS );
+ code.appendHalf( (short)popCount );
+ }
+
+ 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->canTakeRefTest( pd ) )
+ code.append( IN_POP );
+ }
+ }
+
+ }
+}
+
+bool Compiler::beginContiguous( CodeVect &code, int stretch )
+{
+ bool resetContiguous = false;
+
+ if ( inContiguous )
+ contiguousStretch += stretch;
+ else {
+ /* We add one for the push that always comes with the contiguous
+ * statement. */
+ contiguousStretch = stretch + 1;
+
+ code.append( IN_CONTIGUOUS );
+ contiguousOffset = code.length();
+ code.appendHalf( 0 );
+ inContiguous = true;
+ resetContiguous = true;
+ }
+
+ return resetContiguous;
+}
+
+void Compiler::endContiguous( CodeVect &code, bool resetContiguous )
+{
+ if ( resetContiguous ) {
+ inContiguous = false;
+ code.setHalf( contiguousOffset, contiguousStretch );
+ contiguousOffset = 0;
+ }
+}
+
+void Compiler::clearContiguous( CodeVect &code, bool resetContiguous )
+{
+ if ( resetContiguous ) {
+ code.append( IN_TOP_SWAP );
+ code.append( IN_POP );
+ }
+}
+
+UniqueType *LangVarRef::evaluateCall( Compiler *pd, CodeVect &code, CallArgVect *args )
+{
+ /* Evaluate the object. */
+ VarRefLookup lookup = lookupMethod( pd );
+
+ bool resetContiguous = false;
+ Function *func = lookup.objMethod->func;
+ if ( func != 0 ) {
+ long stretch = func->paramListSize + 5 + func->localFrame->size();
+ resetContiguous = pd->beginContiguous( code, stretch );
+ }
+
+ /* 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 );
+
+ resetActiveRefs( pd, lookup, paramRefs);
+ delete[] paramRefs;
+
+ pd->endContiguous( code, resetContiguous );
+ pd->clearContiguous( code, resetContiguous );
+
+ /* Return the type to the expression. */
+ return lookup.uniqueType;
+}
+
+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 );
+ }
+ }
+
+ return ut;
+}
+
+UniqueType *LangTerm::evaluateNew( Compiler *pd, CodeVect &code ) const
+{
+ /* Evaluate the expression. */
+ UniqueType *ut = expr->evaluate( pd, code );
+ if ( ut->typeId != TYPE_TREE )
+ error() << "new can only be applied to tree types" << endp;
+
+ code.append( IN_TREE_NEW );
+ return pd->findUniqueType( TYPE_PTR, ut->langEl );
+}
+
+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_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() << "variables used in replacements must be trees" << endp;
+
+ 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;
+
+ if ( replUT->langEl->generic != 0 && replUT->langEl->generic->typeId == GEN_PARSER ) {
+ code.append( IN_DUP_TOP );
+ code.append( IN_CONSTRUCT_INPUT );
+ code.append( IN_TOP_SWAP );
+ code.append( IN_SET_INPUT );
+ }
+
+ constructor->langEl = replUT->langEl;
+ assignFieldArgs( pd, code, replUT );
+
+ if ( varRef != 0 ) {
+ code.append( IN_DUP_TOP );
+
+ /* Get the type of the variable being assigned to. */
+ VarRefLookup lookup = varRef->lookupField( pd );
+
+ varRef->loadObj( pd, code, lookup.lastPtrInQual, false );
+ varRef->setField( pd, code, lookup.inObject, lookup.objField, replUT, false );
+ }
+
+ return replUT;
+}
+
+void LangTerm::parseFrag( Compiler *pd, CodeVect &code, int stopId ) const
+{
+ /* Parse instruction, dependent on whether or not we are producing
+ * revert or commit code. */
+ if ( pd->revertOn ) {
+ code.append( IN_PARSE_SAVE_STEPS );
+ code.append( IN_PARSE_FRAG_WV );
+ code.appendHalf( stopId );
+ code.append( IN_PCR_CALL );
+ code.append( IN_PARSE_FRAG_EXIT_WV );
+ }
+ else {
+ code.append( IN_PARSE_SAVE_STEPS );
+ code.append( IN_PARSE_FRAG_WC );
+ code.appendHalf( stopId );
+ code.append( IN_PCR_CALL );
+ code.append( IN_PARSE_FRAG_EXIT_WC );
+ }
+}
+
+UniqueType *LangTerm::evaluateParse( Compiler *pd, CodeVect &code, bool stop ) const
+{
+ UniqueType *targetUT = typeRef->uniqueType->langEl->generic->utArg;
+
+ /* 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 ( targetUT->langEl->contextIn != 0 ) {
+ if ( fieldInitArgs == 0 || fieldInitArgs->length() != 1 )
+ error(loc) << "parse command requires just input" << endp;
+ context = true;
+ }
+
+ /* 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() << "variables used in replacements must be trees" << endp;
+
+ item->langEl = ut->langEl;
+ }
+ }
+
+ /* Construct the tree using the tree information stored in the compiled
+ * code. */
+ code.append( IN_CONSTRUCT );
+ code.appendHalf( constructor->patRepId );
+
+ /* Dup for the finish operation. */
+ code.append( IN_DUP_TOP );
+
+ /*
+ * First load the context into the parser.
+ */
+ if ( context ) {
+ /* Dup the parser. */
+ code.append( IN_DUP_TOP );
+
+ /* Eval the context. */
+ UniqueType *argUT = fieldInitArgs->data[0]->expr->evaluate( pd, code );
+
+ if ( argUT != pd->uniqueTypeStream && argUT->typeId != TYPE_TREE )
+ error(loc) << "context argument must be a stream or a tree" << endp;
+
+ /* Store the context. */
+ code.append( IN_TOP_SWAP );
+ code.append( IN_SET_PARSER_CTX_WC );
+ }
+
+ /* For access to the replacement pattern. */
+ UniqueType *parserUT = typeRef->uniqueType;
+ constructor->langEl = parserUT->langEl;
+
+ /*****************************/
+
+ code.append( IN_DUP_TOP );
+ code.append( IN_CONSTRUCT_INPUT );
+ code.append( IN_TOP_SWAP );
+ code.append( IN_SET_INPUT );
+
+ for ( ConsItemList::Iter item = *parserText->list; item.lte(); item++ )
+ code.append( IN_DUP_TOP );
+
+ /* Assign bind ids to the variables in the replacement. */
+ for ( ConsItemList::Iter item = *parserText->list; 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:
+ item->expr->evaluate( pd, code );
+ break;
+ }
+
+ code.append( IN_TOP_SWAP );
+
+ /* Not a stream. Get the input first. */
+ code.append( IN_GET_INPUT );
+ if ( pd->revertOn )
+ code.append( IN_INPUT_APPEND_WV );
+ else
+ code.append( IN_INPUT_APPEND_WC );
+ code.append( IN_POP );
+
+ code.append( IN_DUP_TOP );
+
+ /* Parse instruction, dependent on whether or not we are producing
+ * revert or commit code. */
+ parseFrag( pd, code, stopId );
+ }
+
+ /*
+ * Finish operation
+ */
+
+ /* Parse instruction, dependent on whether or not we are producing revert
+ * or commit code. */
+ if ( pd->revertOn ) {
+ /* Finish immediately. */
+ code.append( IN_PARSE_SAVE_STEPS );
+ code.append( IN_PARSE_FINISH_WV );
+ code.appendHalf( stopId );
+ code.append( IN_PCR_CALL );
+ code.append( IN_PARSE_FINISH_EXIT_WV );
+ }
+ else {
+ /* Finish immediately. */
+ code.append( IN_PARSE_SAVE_STEPS );
+ code.append( IN_PARSE_FINISH_WC );
+ code.appendHalf( stopId );
+ code.append( IN_PCR_CALL );
+ code.append( IN_PARSE_FINISH_EXIT_WC );
+ }
+
+ code.append( IN_POP );
+
+ /* Parser is on the top of the stack. */
+
+ /* Pull out the error and save it off. */
+ code.append( IN_DUP_TOP );
+ 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.
+ */
+ if ( varRef != 0 ) {
+ code.append( IN_DUP_TOP );
+
+ /* Get the type of the variable being assigned to. */
+ VarRefLookup lookup = varRef->lookupField( pd );
+
+ varRef->loadObj( pd, code, lookup.lastPtrInQual, false );
+ varRef->setField( pd, code, lookup.inObject, lookup.objField, targetUT, false );
+ }
+
+ return targetUT;
+}
+
+void LangTerm::evaluateSendStream( Compiler *pd, CodeVect &code ) const
+{
+ varRef->evaluate( pd, code );
+
+ for ( ConsItemList::Iter item = parserText->list->first(); item.lte(); item++ ) {
+ /* Load a dup of the stream. */
+ code.append( IN_DUP_TOP );
+
+ 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_TREE && ut->langEl == pd->voidLangEl ) {
+ code.append( IN_POP );
+ code.append( IN_POP );
+ continue;
+ }
+
+ break;
+ }
+
+ code.append( IN_PRINT_STREAM );
+ code.append( 1 );
+ }
+
+
+ /* Normally we would have to pop the stream var ref that we evaluated
+ * before all the print arguments (which includes the stream, evaluated
+ * last), however we send is part of an expression, and is supposed to
+ * leave the varref on the stack. */
+}
+
+void LangTerm::evaluateSendParser( Compiler *pd, CodeVect &code ) const
+{
+ varRef->evaluate( pd, code );
+
+ /* Dup for every send. */
+ for ( ConsItemList::Iter item = *parserText->list; item.lte(); item++ )
+ code.append( IN_DUP_TOP );
+
+ /* Assign bind ids to the variables in the replacement. */
+ for ( ConsItemList::Iter item = *parserText->list; 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_TREE && ut->langEl == pd->voidLangEl ) {
+ code.append( IN_POP );
+ code.append( IN_POP );
+ continue;
+ }
+ break;
+ }
+
+ code.append( IN_TOP_SWAP );
+
+ /* Not a stream. Get the input first. */
+ code.append( IN_GET_INPUT );
+ if ( pd->revertOn )
+ code.append( IN_INPUT_APPEND_WV );
+ else
+ code.append( IN_INPUT_APPEND_WC );
+ code.append( IN_POP );
+
+ code.append( IN_DUP_TOP );
+
+ parseFrag( pd, code, 0 );
+ }
+
+ if ( eof ) {
+ code.append( IN_PARSE_SAVE_STEPS );
+ if ( pd->revertOn ) {
+ code.append( IN_PARSE_FINISH_WV );
+ code.appendHalf( 0 );
+ code.append( IN_PCR_CALL );
+ code.append( IN_PARSE_FINISH_EXIT_WV );
+ }
+ else {
+ code.append( IN_PARSE_FINISH_WC );
+ code.appendHalf( 0 );
+ code.append( IN_PCR_CALL );
+ code.append( IN_PARSE_FINISH_EXIT_WC );
+ }
+ }
+}
+
+UniqueType *LangTerm::evaluateSend( Compiler *pd, CodeVect &code ) const
+{
+ UniqueType *varUt = varRef->lookup( pd );
+
+ if ( varUt == pd->uniqueTypeStream ) {
+ evaluateSendStream( pd, code );
+ }
+ else if ( varUt->langEl->generic != 0 &&
+ varUt->langEl->generic->typeId == GEN_PARSER )
+ {
+ evaluateSendParser( pd, code );
+ }
+ else {
+ error(loc) << "can only send to parsers and streams" << 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:
+ item->expr->evaluate( pd, code );
+ 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
+{
+ switch ( type ) {
+ case VarRefType:
+ return varRef->evaluate( pd, code );
+ case MethodCallType:
+ return varRef->evaluateCall( pd, code, args );
+ case NilType:
+ code.append( IN_LOAD_NIL );
+ return pd->uniqueTypeNil;
+ case TrueType:
+ code.append( IN_LOAD_TRUE );
+ return pd->uniqueTypeBool;
+ case FalseType:
+ code.append( IN_LOAD_FALSE );
+ return pd->uniqueTypeBool;
+ case MakeTokenType:
+ return evaluateMakeToken( pd, code );
+ case MakeTreeType:
+ return evaluateMakeTree( pd, code );
+ case NumberType: {
+ unsigned int n = atoi( data );
+ code.append( IN_LOAD_INT );
+ code.appendWord( n );
+ return pd->uniqueTypeInt;
+ }
+ 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 );
+ return pd->uniqueTypeStr;
+ }
+ case MatchType:
+ return evaluateMatch( pd, code );
+ case ParseType:
+ return evaluateParse( pd, code, false );
+ case ParseStopType:
+ return evaluateParse( pd, code, true );
+ case ConstructType:
+ return evaluateConstruct( pd, code );
+ case SendType:
+ return evaluateSend( pd, code );
+ case NewType:
+ return evaluateNew( pd, code );
+ 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 );
+ return pd->uniqueTypeInt;
+ }
+ case SearchType:
+ return evaluateSearch( pd, code );
+ case EmbedStringType:
+ return evaluateEmbedString( pd, code );
+ case CastType:
+ return evaluateCast( pd, code );
+ }
+ return 0;
+}
+
+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 );
+
+ 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;
+
+ code.append( IN_TST_EQL );
+ 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;
+
+ code.append( IN_TST_NOT_EQL );
+ return pd->uniqueTypeBool;
+ }
+ case '<': {
+ left->evaluate( pd, code );
+ right->evaluate( pd, code );
+
+ code.append( IN_TST_LESS );
+ return pd->uniqueTypeBool;
+ }
+ case '>': {
+ left->evaluate( pd, code );
+ right->evaluate( pd, code );
+
+ code.append( IN_TST_GRTR );
+ return pd->uniqueTypeBool;
+ }
+ case OP_LessEql: {
+ left->evaluate( pd, code );
+ right->evaluate( pd, code );
+
+ code.append( IN_TST_LESS_EQL );
+ return pd->uniqueTypeBool;
+ }
+ case OP_GrtrEql: {
+ left->evaluate( pd, code );
+ right->evaluate( pd, code );
+
+ code.append( IN_TST_GRTR_EQL );
+ return pd->uniqueTypeBool;
+ }
+ case OP_LogicalAnd: {
+ /* Evaluate the left and duplicate it. */
+ left->evaluate( pd, code );
+ code.append( IN_DUP_TOP );
+
+ /* 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 );
+ code.appendHalf( 0 );
+
+ /* Evauluate the right, add the test. Store it separately. */
+ right->evaluate( pd, code );
+ 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. */
+ left->evaluate( pd, code );
+ code.append( IN_DUP_TOP );
+
+ /* 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 );
+ code.appendHalf( 0 );
+
+ /* Evauluate the right, add the test. */
+ right->evaluate( pd, code );
+ 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. */
+ right->evaluate( pd, code );
+ code.append( IN_NOT );
+ return pd->uniqueTypeBool;
+ }
+ case '$': {
+ right->evaluate( pd, code );
+ code.append( IN_TREE_TO_STR_TRIM );
+ return pd->uniqueTypeStr;
+
+ }
+ case '%': {
+ right->evaluate( pd, code );
+ code.append( IN_TREE_TO_STR );
+ return pd->uniqueTypeStr;
+ }
+ case '^': {
+ UniqueType *rt = right->evaluate( pd, code );
+ code.append( IN_TREE_TRIM );
+ return rt;
+ }
+ case OP_Deref: {
+ UniqueType *ut = right->evaluate( pd, code );
+ if ( ut->typeId != TYPE_PTR )
+ error(loc) << "can only dereference pointers" << endl;
+
+ code.append( IN_PTR_DEREF_R );
+ ut = pd->findUniqueType( TYPE_TREE, ut->langEl );
+ return ut;
+ }
+ 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( iterUT->iterDef->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 );
+ code.appendHalf( 0 );
+
+ /*
+ * Set up the loop cleanup code.
+ */
+
+ /* Set up the current loop cleanup. */
+ CodeVect loopCleanup;
+ if ( pd->loopCleanup != 0 )
+ loopCleanup.setAs( *pd->loopCleanup );
+
+ /* Add the cleanup for the current loop. */
+ loopCleanup.append( iterUT->iterDef->inDestroy );
+ loopCleanup.appendHalf( objField->offset );
+
+ /* Push the loop cleanup. */
+ CodeVect *oldLoopCleanup = pd->loopCleanup;
+ pd->loopCleanup = &loopCleanup;
+
+ /* Compile the contents. */
+ for ( StmtList::Iter stmt = *stmtList; stmt.lte(); stmt++ )
+ stmt->compile( pd, code );
+
+ pd->loopCleanup = oldLoopCleanup;
+
+ /* 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( iterUT->iterDef->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->lookupMethod( pd );
+ if ( lookup.objMethod->iterDef == 0 ) {
+ error(loc) << "attempt to iterate using something "
+ "that is not an iterator" << endp;
+ }
+
+ bool resetContiguous = false;
+ Function *func = lookup.objMethod->func;
+ if ( func != 0 ) {
+ /* FIXME: what is the right size here (16)? */
+ long stretch = func->paramListSize + 16 + func->localFrame->size();
+ resetContiguous = pd->beginContiguous( code, stretch );
+ }
+
+ /* Also force the field to be initialized. */
+ objField->scope->owner->initField( pd, objField );
+
+ /*
+ * Create the iterator from the local var.
+ */
+
+ UniqueType *iterUT = objField->typeRef->uniqueType;
+
+ /* Evaluate and push the arguments. */
+ ObjectField **paramRefs = iterCall->langTerm->varRef->evaluateArgs(
+ pd, code, lookup, iterCall->langTerm->args );
+
+ pd->endContiguous( code, resetContiguous );
+
+ if ( pd->revertOn )
+ code.append( iterUT->iterDef->inCreateWV );
+ else
+ code.append( iterUT->iterDef->inCreateWC );
+
+ code.appendHalf( objField->offset );
+ if ( lookup.objMethod->func != 0 )
+ code.appendHalf( lookup.objMethod->func->funcId );
+
+ if ( iterUT->iterDef->useSearchUT ) {
+ if ( searchUT->typeId == TYPE_PTR )
+ code.appendHalf( pd->uniqueTypePtr->langEl->id );
+ else
+ code.appendHalf( searchUT->langEl->id );
+ }
+
+ compileForIterBody( pd, code, iterUT );
+
+
+ iterCall->langTerm->varRef->popRefQuals( pd, code, lookup, iterCall->langTerm->args );
+
+ iterCall->langTerm->varRef->resetActiveRefs( pd, lookup, paramRefs );
+ delete[] paramRefs;
+
+ if ( resetContiguous )
+ code.append( IN_POP );
+}
+
+void LangStmt::compileWhile( Compiler *pd, CodeVect &code ) const
+{
+ /* Generate code for the while test. Remember the top. */
+ long top = code.length();
+ expr->evaluate( pd, code );
+
+ /* 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 );
+ 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
+{
+ switch ( type ) {
+ case PrintType:
+ case PrintXMLACType:
+ case PrintXMLType:
+ case PrintStreamType: {
+ UniqueType **types = new UniqueType*[exprPtrVect->length()];
+
+ /* Push the args backwards. */
+ for ( CallArgVect::Iter pex = exprPtrVect->first(); pex.lte(); pex++ )
+ types[pex.pos()] = (*pex)->expr->evaluate( pd, code );
+
+ /* Run the printing forwards. */
+ if ( type == PrintType ) {
+ code.append( IN_PRINT );
+ code.append( exprPtrVect->length() );
+ }
+ else if ( type == PrintXMLACType ) {
+ code.append( IN_PRINT_XML_AC );
+ code.append( exprPtrVect->length() );
+ }
+ else if ( type == PrintXMLType ) {
+ code.append( IN_PRINT_XML );
+ code.append( exprPtrVect->length() );
+ }
+ else if ( type == PrintStreamType ) {
+ /* Minus one because the first arg is the stream. */
+ code.append( IN_PRINT_STREAM );
+ code.append( exprPtrVect->length() - 1 );
+ }
+
+ delete[] types;
+
+ break;
+ }
+ case ExprType: {
+ /* Evaluate the exrepssion, then pop it immediately. */
+ expr->evaluate( pd, code );
+ code.append( IN_POP );
+ break;
+ }
+ case IfType: {
+ long jumpFalse = 0, jumpPastElse = 0, distance = 0;
+
+ /* Evaluate the test. */
+ 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();
+ code.append( IN_JMP_FALSE );
+ 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 ( !castAssignment( pd, code, resUT, 0, exprUT ) )
+ error(loc) << "return value wrong type" << endp;
+ }
+
+ code.append( IN_SAVE_RET );
+
+ /* The loop cleanup code. */
+ if ( pd->loopCleanup != 0 )
+ code.append( *pd->loopCleanup );
+
+ /* Jump to the return label. The distnacnce 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;
+ }
+ }
+}
+
+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 ( ObjFieldList::Iter ol = *localFrame->objFieldList; 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->typeId == TYPE_TREE || ut->typeId == TYPE_PTR ) {
+ 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;
+ switch ( ut->iterDef->type ) {
+ case IterDef::Tree:
+ case IterDef::Child:
+ case IterDef::Repeat:
+ case IterDef::RevRepeat:
+ 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::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;
+
+ /* Add the alloc frame opcode. We don't have the right
+ * frame size yet. We will fill it in later. */
+ code.append( IN_INIT_LOCALS );
+ code.appendHalf( 0 );
+ long afterInit = code.length();
+
+ /* Compile the reduce block. */
+ block->compile( this, code );
+
+ /* We have the frame size now. Set in the alloc frame instruction. */
+ long frameSize = block->localFrame->size();
+ code.setHalf( 1, frameSize );
+
+ /* 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;
+
+ /* Add the alloc frame opcode. We don't have the right
+ * frame size yet. We will fill it in later. */
+ code.append( IN_INIT_LOCALS );
+ code.appendHalf( 0 );
+
+ 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 );
+
+ /* We have the frame size now. Set in the alloc frame instruction. */
+ long frameSize = block->localFrame->size();
+ code.setHalf( 1, frameSize );
+
+ 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 );
+ addCtx( block->localFrame );
+
+ CodeVect &code = block->codeWV;
+
+ /* Add the alloc frame opcode. We don't have the right
+ * frame size yet. We will fill it in later. */
+ code.append( IN_INIT_LOCALS );
+ code.appendHalf( 0 );
+
+ /* Set the local frame and compile the reduce block. */
+ block->compile( this, code );
+
+ /* We have the frame size now. Set in the alloc frame instruction. */
+ long frameSize = block->localFrame->size();
+ code.setHalf( 1, frameSize );
+
+ code.append( IN_PCR_RET );
+
+ /* Now that compilation is done variables are referenced. Make the local
+ * trees descriptor. */
+ findLocals( block->localFrame, block );
+}
+
+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;
+
+ /* Add the alloc frame opcode. We don't have the right
+ * frame size yet. We will fill it in later. */
+ code.append( IN_INIT_LOCALS );
+ code.appendHalf( 0 );
+
+ code.append( IN_LOAD_ARGV );
+ code.appendHalf( argvOffset() );
+
+ block->compile( this, code );
+
+ /* We have the frame size now. Store it in frame init. */
+ long frameSize = rootLocalFrame->size();
+ code.setHalf( 1, frameSize );
+
+ code.append( IN_STOP );
+
+ /* Make the local trees descriptor. */
+ findLocals( rootLocalFrame, block );
+}
+
+void Compiler::initAllLanguageObjects()
+{
+ /* 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 ( ObjFieldList::Iter f = *objDef->objFieldList; f.lte(); f++ )
+ objDef->initField( this, f->value );
+ }
+ }
+
+ /* Init all fields of the global object. */
+ for ( ObjFieldList::Iter f = *globalObjectDef->objFieldList; f.lte(); f++ )
+ globalObjectDef->initField( this, f->value );
+}
+
+void Compiler::initLocalFrame( ObjectDef *localFrame )
+{
+ for ( ObjFieldList::Iter f = *localFrame->objFieldList; f.lte(); f++ )
+ localFrame->initField( this, f->value );
+}
+
+void Compiler::initAllFrameObjects()
+{
+ /* Functions. */
+ for ( FunctionList::Iter f = functionList; f.lte(); f++ )
+ initLocalFrame( f->localFrame );
+
+ /* Reduction code. */
+ for ( DefList::Iter prod = prodList; prod.lte(); prod++ ) {
+ if ( prod->redBlock != 0 )
+ initLocalFrame( 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 ) {
+ ObjFieldList::Iter f = *localFrame->objFieldList;
+ for ( int i = 0; i < lel->tokenDef->reCaptureVect.length(); i++, f++ )
+ localFrame->initField( this, f->value );
+ }
+
+ initLocalFrame( localFrame );
+ }
+ }
+
+ /* Preeof blocks. */
+ for ( RegionList::Iter r = regionList; r.lte(); r++ ) {
+ if ( r->preEofBlock != 0 )
+ initLocalFrame( r->preEofBlock->localFrame );
+ }
+
+ /* Root code. */
+ initLocalFrame( rootLocalFrame );
+}
+
+void Compiler::initUserFunctions( Function *func, bool isUserIter )
+{
+ /* Set up the parameters. */
+ long paramPos = 0, paramListSize = 0;
+ UniqueType **paramUTs = new UniqueType*[func->paramList->length()];
+ for ( ParameterList::Iter param = *func->paramList; param.lte(); param++ ) {
+ paramUTs[paramPos] = param->typeRef->uniqueType;
+
+ /* Initialize the object field as a local variable. We also want trees
+ * downreffed. */
+ if ( paramUTs[paramPos]->typeId == TYPE_REF )
+ initLocalRefInstructions( param );
+ else
+ initLocalInstructions( param );
+
+ paramListSize += sizeOfField( paramUTs[paramPos] );
+ paramPos += 1;
+ }
+
+ /* Param offset is relative to one past the last item in the array of
+ * words containing the args. */
+ long paramOffset = 0;
+ for ( ParameterList::Iter param = *func->paramList; param.lte(); param++ ) {
+ /* Moving downward, and need the offset to point to the lower half of
+ * the argument. */
+ paramOffset -= sizeOfField( paramUTs[param->pos] );
+
+ /* How much space do we need to make for call overhead. */
+ long frameAfterArgs = isUserIter ? IFR_AA : FR_AA;
+
+ /* Going up first we have the frame data, then maybe
+ * the user iterator, then the args from high to low. */
+ param->offset = frameAfterArgs +
+ ( isUserIter ? ( sizeof(UserIter) / sizeof(Word) ) : 0 ) +
+ paramListSize + paramOffset;
+ }
+
+ 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::compileUserIter( Function *func, CodeVect &code )
+{
+ CodeBlock *block = func->codeBlock;
+
+ /* Add the alloc frame opcode. We don't have the right
+ * frame size yet. We will fill it in later. */
+ code.append( IN_INIT_LOCALS );
+ code.appendHalf( 0 );
+
+ /* Compile the block. */
+ block->compile( this, code );
+
+ /* We have the frame size now. Set in the alloc frame instruction. */
+ int frameSize = func->localFrame->size();
+ code.setHalf( 1, frameSize );
+
+ /* Check for a return statement. */
+ if ( block->stmtList->length() == 0 ||
+ block->stmtList->tail->type != LangStmt::YieldType )
+ {
+ /* Push the return value. */
+ 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;
+
+ /* Add the alloc frame opcode. We don't have the right
+ * frame size yet. We will fill it in later. */
+ code.append( IN_INIT_LOCALS );
+ code.appendHalf( 0 );
+
+ /* Compile the block. */
+ block->compile( this, code );
+
+ /* We have the frame size now. Set in the alloc frame instruction. */
+ int frameSize = func->localFrame->size();
+ code.setHalf( 1, frameSize );
+
+ /* 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();
+}