PsyProc.java
package coneforest.psylla.core;
import coneforest.psylla.runtime.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.StringJoiner;
/**
* The representation of {@code proc}, a procedure.
*/
@Type("proc")
public class PsyProc
extends PsyArray
implements PsyExecutable
{
/**
* Context action of the {@code bind} operator.
*/
@OperatorType("bind")
public static final ContextAction PSY_BIND=oContext->
{
final var ostack=oContext.operandStackBacked(1);
final var oProc=ostack.<PsyProc>getBacked(0);
ostack.push(oProc.psyBind(oContext));
};
//=ContextAction.<PsyProc>ofFunction(PsyProc::psyBind);
/**
* Constructs a new empty {@code proc}.
*/
public PsyProc()
{
}
protected PsyProc(final ArrayList<PsyObject> array)
{
super(array);
}
@Override
public void invoke(final PsyContext oContext)
{
final var estack=oContext.executionStack();
try
{
for(int i=length()-1; i>=0; i--)
estack.push(get(i));
}
catch(final PsyRangeCheckException e)
{
// NOP
}
}
@SuppressWarnings("unchecked")
@Override
public PsyProc psyClone()
{
return new PsyProc((ArrayList<PsyObject>)array.clone());
}
@Override
public String toSyntaxString()
{
return toSyntaxStringHelper(new HashSet<PsyContainer<? extends PsyObject>>());
}
@Override
public String toSyntaxStringHelper(final Set<PsyContainer<? extends PsyObject>> processed)
{
if(!processed.add(this))
return '%'+typeName()+'%';
final var sj=new StringJoiner(" ", "{", "}");
for(final var o: this)
sj.add(o instanceof PsyContainer<? extends PsyObject> oContainer?
oContainer.toSyntaxStringHelper(processed):
o.toSyntaxString());
return sj.toString();
}
public PsyProc psyBind(final PsyContext oContext)
{
final var dstack=oContext.dictStack();
final var agenda=new ArrayList<PsyProc>();
final var bound=new HashSet<PsyProc>();
agenda.add(this);
while(!agenda.isEmpty())
{
final var oProc=agenda.remove(0);
if(!bound.add(oProc))
break;
for(int i=0; i<oProc.length(); i++)
{
try
{
final var o=oProc.get(i);
if(o instanceof PsyProc)
agenda.add((PsyProc)o);
else if(o instanceof PsyName oName)
{
final var oNew=dstack.load(oName);
if(oNew instanceof PsyOperator
|| oNew instanceof PsyMark
|| oNew instanceof PsyNull)
oProc.put(i, oNew);
}
}
catch(final PsyRangeCheckException|PsyUndefinedException e)
{
// NOP
}
}
}
return this;
}
}