PsyProc.java

  1. package coneforest.psylla.core;

  2. import coneforest.psylla.runtime.*;
  3. import java.util.ArrayList;
  4. import java.util.HashSet;
  5. import java.util.Set;
  6. import java.util.StringJoiner;

  7. /**
  8. *   The representation of {@code proc}, a procedure.
  9. */
  10. @Type("proc")
  11. public class PsyProc
  12.     extends PsyArray
  13.     implements PsyExecutable
  14. {
  15.     /**
  16.     *   Context action of the {@code bind} operator.
  17.     */
  18.     @OperatorType("bind")
  19.     public static final ContextAction PSY_BIND=oContext->
  20.         {
  21.             final var ostack=oContext.operandStackBacked(1);
  22.             final var oProc=ostack.<PsyProc>getBacked(0);
  23.             ostack.push(oProc.psyBind(oContext));
  24.         };
  25.         //=ContextAction.<PsyProc>ofFunction(PsyProc::psyBind);

  26.     /**
  27.     *   Constructs a new empty {@code proc}.
  28.     */
  29.     public PsyProc()
  30.     {
  31.     }

  32.     protected PsyProc(final ArrayList<PsyObject> array)
  33.     {
  34.         super(array);
  35.     }

  36.     @Override
  37.     public void invoke(final PsyContext oContext)
  38.     {
  39.         final var estack=oContext.executionStack();
  40.         try
  41.         {
  42.             for(int i=length()-1; i>=0; i--)
  43.                 estack.push(get(i));
  44.         }
  45.         catch(final PsyRangeCheckException e)
  46.         {
  47.             // NOP
  48.         }
  49.     }

  50.     @SuppressWarnings("unchecked")
  51.     @Override
  52.     public PsyProc psyClone()
  53.     {
  54.         return new PsyProc((ArrayList<PsyObject>)array.clone());
  55.     }

  56.     @Override
  57.     public String toSyntaxString()
  58.     {
  59.         return toSyntaxStringHelper(new HashSet<PsyContainer<? extends PsyObject>>());
  60.     }

  61.     @Override
  62.     public String toSyntaxStringHelper(final Set<PsyContainer<? extends PsyObject>> processed)
  63.     {
  64.         if(!processed.add(this))
  65.             return '%'+typeName()+'%';
  66.         final var sj=new StringJoiner(" ", "{", "}");
  67.         for(final var o: this)
  68.             sj.add(o instanceof PsyContainer<? extends PsyObject> oContainer?
  69.                 oContainer.toSyntaxStringHelper(processed):
  70.                 o.toSyntaxString());
  71.         return sj.toString();
  72.     }

  73.     public PsyProc psyBind(final PsyContext oContext)
  74.     {
  75.         final var dstack=oContext.dictStack();
  76.         final var agenda=new ArrayList<PsyProc>();
  77.         final var bound=new HashSet<PsyProc>();

  78.         agenda.add(this);
  79.         while(!agenda.isEmpty())
  80.         {
  81.             final var oProc=agenda.remove(0);
  82.             if(!bound.add(oProc))
  83.                 break;
  84.             for(int i=0; i<oProc.length(); i++)
  85.             {
  86.                 try
  87.                 {
  88.                     final var o=oProc.get(i);
  89.                     if(o instanceof PsyProc)
  90.                         agenda.add((PsyProc)o);
  91.                     else if(o instanceof PsyName oName)
  92.                     {
  93.                         final var oNew=dstack.load(oName);
  94.                         if(oNew instanceof PsyOperator
  95.                                 || oNew instanceof PsyMark
  96.                                 || oNew instanceof PsyNull)
  97.                             oProc.put(i, oNew);
  98.                     }
  99.                 }
  100.                 catch(final PsyRangeCheckException|PsyUndefinedException e)
  101.                 {
  102.                     // NOP
  103.                 }
  104.             }
  105.         }

  106.         return this;
  107.     }
  108. }