/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* NGlobal.java
* Created: Sep 23, 2002 at 2:51:22 PM
* By: Raymond Cypher
*/
package org.openquark.cal.internal.machine.g;
import org.openquark.cal.compiler.QualifiedName;
import org.openquark.cal.runtime.CALExecutorException;
import org.openquark.cal.runtime.CalValue;
/**
* This is the NGlobal class
*
* Represents a global supercombinator node in the
* program graph.
* Creation: Sep 23, 2002 at 2:51:22 PM
* @author Raymond Cypher
*/
public class NGlobal extends NInd {
private final QualifiedName name;
private final int arity;
private Code code;
NGlobal (int arity, Code code, QualifiedName name) {
super ();
this.arity = arity;
this.code = code;
this.name = name;
}
NGlobal (NGlobal ng) {
super ();
this.arity = ng.arity;
this.code = ng.code;
this.name = ng.name;
}
protected int getArity() {
return arity;
}
protected QualifiedName getName() {
return name;
}
protected void setCode (Code code) {
this.code = code;
}
@Override
public String toString (int indent) {
if (getIndirectionNode() != null) {
StringBuilder sp = new StringBuilder ();
for (int i = 0; i < indent; ++i) {
sp.append (" ");
}
return sp.toString() + idString(0) + " <" + name + " / " + arity + ">" + indString(0);
} else {
StringBuilder sp = new StringBuilder ();
for (int i = 0; i < indent; ++i) {
sp.append (" ");
}
return sp.toString() + idString(0) + " <" + name + " / " + arity + ">";
}
}
/**
* {@inheritDoc}
*/
@Override
public final int debug_getNChildren() {
if (hasIndirection()) {
return super.debug_getNChildren();
}
return 0;
}
/**
* {@inheritDoc}
*/
@Override
public final CalValue debug_getChild(int childN) {
if (hasIndirection()) {
return super.debug_getChild(childN);
}
throw new IndexOutOfBoundsException();
}
/**
* {@inheritDoc}
*/
@Override
public final String debug_getNodeStartText() {
if (hasIndirection()) {
return super.debug_getNodeStartText();
}
return name.getQualifiedName();
}
/**
* {@inheritDoc}
*/
@Override
public final String debug_getNodeEndText() {
if (hasIndirection()) {
return super.debug_getNodeEndText();
}
return "";
}
/**
* {@inheritDoc}
*/
@Override
public final String debug_getChildPrefixText(int childN) {
if (hasIndirection()) {
return super.debug_getChildPrefixText(childN);
}
throw new IndexOutOfBoundsException();
}
@Override
protected void setIndirectionNode (Node n) {
super.setIndirectionNode(n);
code = null;
if (arity != 0) {
System.out.println ("indirection node in non-CAF global");
}
}
/*
* Functions to perform state transitions
*/
/**
* Do the Eval state transition.
*/
@Override
protected void i_eval (Executor e) throws CALExecutorException {
if (getLeafNode() != this) {
e.stack.pop ();
e.stack.push (getLeafNode());
getLeafNode().i_eval(e);
return;
}
e.pushDumpItem();
i_unwind (e);
}
@Override
protected void i_dispatch (Executor e, int k) throws CALExecutorException {
if (arity == 0) {
super.i_dispatch (e, k);
} else
if (arity == k) {
// Tail call case.
// <f:S, G[f = FUN k C], Dispatch k:[], D>
// =>
// <S, G, C, D>
// Pop this global node off of the stack.
e.stack.pop ();
// Set the instruction pointer.
//e.setIP (new CodeOffset (code));
e.setIP (code);
} else
if (arity < k) {
// <f:n1:n2:...:nk:r:S, G[f=FUN a C], Dispatch k:[], D>
// a < k
// <n1:...:na:va:...:v(k-1):r:S, G[va = HOLE ], C, D>
// [vi = AP v(i-1) ni (a<i<k)]
// [r = AP v(k-1) nk ]
e.stack.pop ();
int si = e.stack.size() - (arity + 1);
Node n = e.stack.get (si);
e.stack.set (si, new NInd ());
for (int i = arity + 1; i < k; ++i) {
Node na = new NAp (e.stack.get (si--), n);
n = e.stack.get (si);
e.stack.set (si,na);
}
Node na = new NAp (e.stack.get (si--), n);
e.stack.get (si).setIndirectionNode (na);
e.stack.set (si, na);
// Set the instruction pointer.
//e.setIP (new CodeOffset (code));
e.setIP (code);
} else
if (arity > k) {
// Two different transitions at this point:
//
// Not enough arguments on stack for f:
// <f:n1:n2:...:nk:r:v(k+1):...:vd:[], G[f = FUN a C], Dispatch k:[], (S, C1):D>
// (k < d < a) =>
// <vd:S, G[v1 = AP f n1 ], C1, D>
// [vi = AP v(i-1) ni (1 < i < k)]
// [r = AP v(k-1) nk ]
//
// Enough arguments on stack for f:
// <f:n1:n2:...:nk:r:v(k+1):...:vd:S, G[f = FUN a C ], Dispatch k:[], D>
// [v(k+1) = AP r n(k+1) ]
// [vi = AP v(i-1) ni ((k+1) < i <=a)]
//
// (k < a) =>
// <n1:n2:...:nk:n(k+1):...:na:va:S, G[v1 = AP f n1 ], C, D>
// [vi = AP v(i-1) ni (1<i<k)]
// [r = AP v(k-1) nk ]
if (e.stack.size() < (arity + 2)) {
super.i_dispatch (e, k);
} else {
// System.out.println ("---------------");
// System.out.println (e.showStack (0));
// System.out.println ("---------------");
NAp vi = new NAp (e.stack.pop (), e.stack.peek());
for (int i = 2; i < k; ++i) {
vi = new NAp (vi, e.stack.get (e.stack.size() - i));
}
// root index
int ir = e.stack.size() - (k + 1);
if (k == 1) {
((NInd)e.stack.get(ir)).setIndirectionNode(vi);
} else {
NAp nr = new NAp (vi, e.stack.get (e.stack.size() - k));
((NInd)e.stack.get(ir)).setIndirectionNode(nr);
}
for (int i = k; i < arity; ++i) {
e.stack.set (ir, ((NAp)e.stack.get(--ir)).getN2());
}
// System.out.println ("---------------");
// System.out.println (e.showStack (0));
// System.out.println ("---------------");
// Set the instruction pointer.
e.setIP (code);
}
} else {
// default case
super.i_dispatch (e, k);
}
}
/**
* Do Unwind state transition.
*/
@Override
protected void i_unwind (Executor e) throws CALExecutorException {
Executor.GStack stack = e.stack;
if (getLeafNode() != this) {
stack.pop ();
stack.push (getLeafNode());
//ip.setIP (ip.getIP() - 1);
getLeafNode().i_unwind (e);
return;
}
// Determine the number of necessary args.
int nArgs = arity;
int stackSize = stack.size ();
if (stackSize - 1 < nArgs) {
e.popDumpItemBottom ();
} else {
// Re-arrange the stack to expose the arguments.
if (nArgs > 0) {
// Pop off the NGlobal
stack.pop ();
//System.out.println ("\n" + showStack(0) + "\n");
// insert a second instance of the nth node
stackSize--;
Node argN = stack.get (stackSize - nArgs);
stack.add(stackSize - nArgs, argN);
//System.out.println ("\n" + showStack(0) + "\n");
int stackSizeMinusOne = stackSize;
//stackSize increases by one, but it is not neccessary to do this computation
//stackSize++;
for (int i = 0; i < nArgs; ++i) {
int rearrangePosition = stackSizeMinusOne - i;
NAp ap = (NAp)stack.get (rearrangePosition);
stack.set(rearrangePosition, ap.getN2());
//System.out.println ("\n" + showStack(0) + "\n");
}
((NAp)argN).clear();
}
// Set the instruction pointer.
//e.setIP (new CodeOffset (code));
e.setIP (code);
}
}
}