summaryrefslogtreecommitdiff
path: root/src/iter.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2014-02-01 19:49:33 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2014-02-01 19:49:33 +0000
commit404ae0f284a3b2d41fcdb53826550e4dfec5c65c (patch)
treecc446af26234e4465b8cc168b720ec44816ff5ab /src/iter.c
downloadcolm-tarball-master.tar.gz
Diffstat (limited to 'src/iter.c')
-rw-r--r--src/iter.c490
1 files changed, 490 insertions, 0 deletions
diff --git a/src/iter.c b/src/iter.c
new file mode 100644
index 0000000..9e60a2d
--- /dev/null
+++ b/src/iter.c
@@ -0,0 +1,490 @@
+/*
+ * Copyright 2007-2014 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 <colm/tree.h>
+#include <colm/bytecode.h>
+#include <colm/program.h>
+#include <assert.h>
+
+#define true 1
+#define false 0
+
+void initTreeIter( TreeIter *treeIter, Tree **stackRoot, long rootSize,
+ const Ref *rootRef, int searchId )
+{
+ treeIter->type = IT_Tree;
+ treeIter->rootRef = *rootRef;
+ treeIter->searchId = searchId;
+ treeIter->stackRoot = stackRoot;
+ treeIter->yieldSize = 0;
+ treeIter->rootSize = rootSize;
+ treeIter->ref.kid = 0;
+ treeIter->ref.next = 0;
+}
+
+void initRevTreeIter( RevTreeIter *revTriter, Tree **stackRoot, long rootSize,
+ const Ref *rootRef, int searchId, int children )
+{
+ revTriter->type = IT_RevTree;
+ revTriter->rootRef = *rootRef;
+ revTriter->searchId = searchId;
+ revTriter->stackRoot = stackRoot;
+ revTriter->yieldSize = children;
+ revTriter->rootSize = rootSize;
+ revTriter->kidAtYield = 0;
+ revTriter->children = children;
+ revTriter->ref.kid = 0;
+ revTriter->ref.next = 0;
+}
+
+void initUserIter( UserIter *userIter, Tree **stackRoot, long rootSize,
+ long argSize, long searchId )
+{
+ userIter->type = IT_User;
+ userIter->stackRoot = stackRoot;
+ userIter->argSize = argSize;
+ userIter->yieldSize = 0;
+ userIter->rootSize = rootSize;
+ userIter->resume = 0;
+ userIter->frame = 0;
+ userIter->searchId = searchId;
+
+ userIter->ref.kid = 0;
+ userIter->ref.next = 0;
+}
+
+
+UserIter *uiterCreate( Program *prg, Tree ***psp, FunctionInfo *fi, long searchId )
+{
+ Tree **sp = *psp;
+
+ vm_pushn( sizeof(UserIter) / sizeof(Word) );
+ void *mem = vm_ptop();
+ UserIter *uiter = mem;
+
+ Tree **stackRoot = vm_ptop();
+ long rootSize = vm_ssize();
+
+ initUserIter( uiter, stackRoot, rootSize, fi->argSize, searchId );
+
+ *psp = sp;
+ return uiter;
+}
+
+void uiterInit( Program *prg, Tree **sp, UserIter *uiter,
+ FunctionInfo *fi, int revertOn )
+{
+ /* Set up the first yeild so when we resume it starts at the beginning. */
+ uiter->ref.kid = 0;
+ uiter->yieldSize = vm_ssize() - uiter->rootSize;
+ uiter->frame = &uiter->stackRoot[-IFR_AA];
+
+ if ( revertOn )
+ uiter->resume = prg->rtd->frameInfo[fi->frameId].codeWV;
+ else
+ uiter->resume = prg->rtd->frameInfo[fi->frameId].codeWC;
+}
+
+
+void treeIterDestroy( Program *prg, Tree ***psp, TreeIter *iter )
+{
+ if ( (int)iter->type != 0 ) {
+ Tree **sp = *psp;
+ long curStackSize = vm_ssize() - iter->rootSize;
+ assert( iter->yieldSize == curStackSize );
+ vm_popn( iter->yieldSize );
+ iter->type = 0;
+ *psp = sp;
+ }
+}
+
+void revTreeIterDestroy( struct colm_program *prg, Tree ***psp, RevTreeIter *riter )
+{
+ if ( (int)riter->type != 0 ) {
+ Tree **sp = *psp;
+ long curStackSize = vm_ssize() - riter->rootSize;
+ assert( riter->yieldSize == curStackSize );
+ vm_popn( riter->yieldSize );
+ riter->type = 0;
+ *psp = sp;
+ }
+}
+
+void userIterDestroy( Program *prg, Tree ***psp, UserIter *uiter )
+{
+ if ( uiter != 0 && (int)uiter->type != 0 ) {
+ Tree **sp = *psp;
+
+ /* We should always be coming from a yield. The current stack size will be
+ * nonzero and the stack size in the iterator will be correct. */
+ long curStackSize = vm_ssize() - uiter->rootSize;
+ assert( uiter->yieldSize == curStackSize );
+
+ long argSize = uiter->argSize;
+
+ vm_popn( uiter->yieldSize );
+ vm_popn( sizeof(UserIter) / sizeof(Word) );
+ vm_popn( argSize );
+
+ uiter->type = 0;
+
+ *psp = sp;
+ }
+}
+
+void userIterDestroy2( Program *prg, Tree ***psp, UserIter *uiter )
+{
+ if ( uiter != 0 && (int)uiter->type != 0 ) {
+ Tree **sp = *psp;
+
+ /* We should always be coming from a yield. The current stack size will be
+ * nonzero and the stack size in the iterator will be correct. */
+ long curStackSize = vm_ssize() - uiter->rootSize;
+ assert( uiter->yieldSize == curStackSize );
+
+ long argSize = uiter->argSize;
+
+ vm_popn( uiter->yieldSize );
+ vm_popn( sizeof(UserIter) / sizeof(Word) );
+ vm_popn( argSize );
+ vm_pop();
+
+ uiter->type = 0;
+
+ *psp = sp;
+ }
+}
+
+Tree *treeIterDerefCur( TreeIter *iter )
+{
+ return iter->ref.kid == 0 ? 0 : iter->ref.kid->tree;
+}
+
+void setTriterCur( Program *prg, TreeIter *iter, Tree *tree )
+{
+ iter->ref.kid->tree = tree;
+}
+
+void setUiterCur( Program *prg, UserIter *uiter, Tree *tree )
+{
+ uiter->ref.kid->tree = tree;
+}
+
+void splitIterCur( Program *prg, Tree ***psp, TreeIter *iter )
+{
+ if ( iter->ref.kid == 0 )
+ return;
+
+ splitRef( prg, psp, &iter->ref );
+}
+
+void iterFind( Program *prg, Tree ***psp, TreeIter *iter, int tryFirst )
+{
+ int anyTree = iter->searchId == prg->rtd->anyId;
+ Tree **top = iter->stackRoot;
+ Kid *child;
+ Tree **sp = *psp;
+
+rec_call:
+ if ( tryFirst && ( iter->ref.kid->tree->id == iter->searchId || anyTree ) ) {
+ *psp = sp;
+ return;
+ }
+ else {
+ child = treeChild( prg, iter->ref.kid->tree );
+ if ( child != 0 ) {
+ vm_contiguous( 2 );
+ vm_push( (SW) iter->ref.next );
+ vm_push( (SW) iter->ref.kid );
+ iter->ref.kid = child;
+ iter->ref.next = (Ref*)vm_ptop();
+ while ( iter->ref.kid != 0 ) {
+ tryFirst = true;
+ goto rec_call;
+ rec_return:
+ iter->ref.kid = iter->ref.kid->next;
+ }
+ iter->ref.kid = (Kid*)vm_pop();
+ iter->ref.next = (Ref*)vm_pop();
+ }
+ }
+
+ if ( top != vm_ptop() )
+ goto rec_return;
+
+ iter->ref.kid = 0;
+ *psp = sp;
+}
+
+Tree *treeIterAdvance( Program *prg, Tree ***psp, TreeIter *iter )
+{
+ Tree **sp = *psp;
+ assert( iter->yieldSize == (vm_ssize() - iter->rootSize) );
+
+ if ( iter->ref.kid == 0 ) {
+ /* Kid is zero, start from the root. */
+ iter->ref = iter->rootRef;
+ iterFind( prg, psp, iter, true );
+ }
+ else {
+ /* Have a previous item, continue searching from there. */
+ iterFind( prg, psp, iter, false );
+ }
+
+ sp = *psp;
+ iter->yieldSize = vm_ssize() - iter->rootSize;
+
+ return (iter->ref.kid ? prg->trueVal : prg->falseVal );
+}
+
+Tree *treeIterNextChild( Program *prg, Tree ***psp, TreeIter *iter )
+{
+ Tree **sp = *psp;
+ assert( iter->yieldSize == (vm_ssize() - iter->rootSize) );
+ Kid *kid = 0;
+
+ if ( iter->ref.kid == 0 ) {
+ /* Kid is zero, start from the first child. */
+ Kid *child = treeChild( prg, iter->rootRef.kid->tree );
+
+ if ( child == 0 )
+ iter->ref.next = 0;
+ else {
+ /* Make a reference to the root. */
+ vm_contiguous( 2 );
+ vm_push( (SW) iter->rootRef.next );
+ vm_push( (SW) iter->rootRef.kid );
+ iter->ref.next = (Ref*)vm_ptop();
+
+ kid = child;
+ }
+ }
+ else {
+ /* Start at next. */
+ kid = iter->ref.kid->next;
+ }
+
+ if ( iter->searchId != prg->rtd->anyId ) {
+ /* Have a previous item, go to the next sibling. */
+ while ( kid != 0 && kid->tree->id != iter->searchId )
+ kid = kid->next;
+ }
+
+ iter->ref.kid = kid;
+ iter->yieldSize = vm_ssize() - iter->rootSize;
+ *psp = sp;
+ return ( iter->ref.kid ? prg->trueVal : prg->falseVal );
+}
+
+Tree *treeRevIterPrevChild( Program *prg, Tree ***psp, RevTreeIter *iter )
+{
+ Tree **sp = *psp;
+ assert( iter->yieldSize == ( vm_ssize() - iter->rootSize ) );
+
+ if ( iter->kidAtYield != iter->ref.kid ) {
+ /* Need to reload the kids. */
+ vm_popn( iter->children );
+
+ int c;
+ Kid *kid = treeChild( prg, iter->rootRef.kid->tree );
+ for ( c = 0; c < iter->children; c++ ) {
+ vm_push( (SW)kid );
+ kid = kid->next;
+ }
+ }
+
+ if ( iter->ref.kid != 0 ) {
+ vm_pop_ignore();
+ iter->children -= 1;
+ }
+
+ if ( iter->searchId != prg->rtd->anyId ) {
+ /* Have a previous item, go to the next sibling. */
+ while ( iter->children > 0 && ((Kid*)(vm_top()))->tree->id != iter->searchId ) {
+ iter->children -= 1;
+ vm_pop_ignore();
+ }
+ }
+
+ if ( iter->children == 0 ) {
+ iter->ref.next = 0;
+ iter->ref.kid = 0;
+ }
+ else {
+ iter->ref.next = &iter->rootRef;
+ iter->ref.kid = (Kid*)vm_top();
+ }
+
+ /* We will use this to detect a split above the iterated tree. */
+ iter->kidAtYield = iter->ref.kid;
+
+ iter->yieldSize = vm_ssize() - iter->rootSize;
+
+ *psp = sp;
+
+ return (iter->ref.kid ? prg->trueVal : prg->falseVal );
+}
+
+void iterFindRepeat( Program *prg, Tree ***psp, TreeIter *iter, int tryFirst )
+{
+ Tree **sp = *psp;
+ int anyTree = iter->searchId == prg->rtd->anyId;
+ Tree **top = iter->stackRoot;
+ Kid *child;
+
+rec_call:
+ if ( tryFirst && ( iter->ref.kid->tree->id == iter->searchId || anyTree ) ) {
+ *psp = sp;
+ return;
+ }
+ else {
+ /* The repeat iterator is just like the normal top-down-left-right,
+ * execept it only goes into the children of a node if the node is the
+ * root of the iteration, or if does not have any neighbours to the
+ * right. */
+ if ( top == vm_ptop() || iter->ref.kid->next == 0 ) {
+ child = treeChild( prg, iter->ref.kid->tree );
+ if ( child != 0 ) {
+ vm_contiguous( 2 );
+ vm_push( (SW) iter->ref.next );
+ vm_push( (SW) iter->ref.kid );
+ iter->ref.kid = child;
+ iter->ref.next = (Ref*)vm_ptop();
+ while ( iter->ref.kid != 0 ) {
+ tryFirst = true;
+ goto rec_call;
+ rec_return:
+ iter->ref.kid = iter->ref.kid->next;
+ }
+ iter->ref.kid = (Kid*)vm_pop();
+ iter->ref.next = (Ref*)vm_pop();
+ }
+ }
+ }
+
+ if ( top != vm_ptop() )
+ goto rec_return;
+
+ iter->ref.kid = 0;
+ *psp = sp;
+}
+
+Tree *treeIterNextRepeat( Program *prg, Tree ***psp, TreeIter *iter )
+{
+ Tree **sp = *psp;
+ assert( iter->yieldSize == ( vm_ssize() - iter->rootSize ) );
+
+ if ( iter->ref.kid == 0 ) {
+ /* Kid is zero, start from the root. */
+ iter->ref = iter->rootRef;
+ iterFindRepeat( prg, psp, iter, true );
+ }
+ else {
+ /* Have a previous item, continue searching from there. */
+ iterFindRepeat( prg, psp, iter, false );
+ }
+
+ sp = *psp;
+ iter->yieldSize = vm_ssize() - iter->rootSize;
+
+ return (iter->ref.kid ? prg->trueVal : prg->falseVal );
+}
+
+void iterFindRevRepeat( Program *prg, Tree ***psp, TreeIter *iter, int tryFirst )
+{
+ Tree **sp = *psp;
+ int anyTree = iter->searchId == prg->rtd->anyId;
+ Tree **top = iter->stackRoot;
+ Kid *child;
+
+ if ( tryFirst ) {
+ while ( true ) {
+ if ( top == vm_ptop() || iter->ref.kid->next == 0 ) {
+ child = treeChild( prg, iter->ref.kid->tree );
+
+ if ( child == 0 )
+ break;
+ vm_contiguous( 2 );
+ vm_push( (SW) iter->ref.next );
+ vm_push( (SW) iter->ref.kid );
+ iter->ref.kid = child;
+ iter->ref.next = (Ref*)vm_ptop();
+ }
+ else {
+ /* Not the top and not there is a next, go over to it. */
+ iter->ref.kid = iter->ref.kid->next;
+ }
+ }
+
+ goto first;
+ }
+
+ while ( true ) {
+ if ( top == vm_ptop() ) {
+ iter->ref.kid = 0;
+ return;
+ }
+
+ if ( iter->ref.kid->next == 0 ) {
+ /* Go up one and then down. Remember we can't use iter->ref.next
+ * because the chain may have been split, setting it null (to
+ * prevent repeated walks up). */
+ Ref *ref = (Ref*)vm_ptop();
+ iter->ref.kid = treeChild( prg, ref->kid->tree );
+ }
+ else {
+ iter->ref.kid = (Kid*)vm_pop();
+ iter->ref.next = (Ref*)vm_pop();
+ }
+first:
+ if ( iter->ref.kid->tree->id == iter->searchId || anyTree ) {
+ *psp = sp;
+ return;
+ }
+ }
+ *psp = sp;
+ return;
+}
+
+
+Tree *treeIterPrevRepeat( Program *prg, Tree ***psp, TreeIter *iter )
+{
+ Tree **sp = *psp;
+ assert( iter->yieldSize == (vm_ssize() - iter->rootSize) );
+
+ if ( iter->ref.kid == 0 ) {
+ /* Kid is zero, start from the root. */
+ iter->ref = iter->rootRef;
+ iterFindRevRepeat( prg, psp, iter, true );
+ }
+ else {
+ /* Have a previous item, continue searching from there. */
+ iterFindRevRepeat( prg, psp, iter, false );
+ }
+
+ sp = *psp;
+ iter->yieldSize = vm_ssize() - iter->rootSize;
+
+ return (iter->ref.kid ? prg->trueVal : prg->falseVal );
+}
+
+
+