Exemplo n.º 1
0
  /**
   * Translate from an array of indices of the burnable inputs to an array of indices of all inputs
   * to the gem
   *
   * @param unboundArgsToBurn An array of indices relative to the burnable (ie unburned, unbound)
   *     inputs of the gem
   * @param sourceGem The gem that these are the inputs of
   * @return An array of indices of inputs relative to ALL inputs of the gem, corresponding to the
   *     contents of unburnedArgsToBurn.
   */
  private static int[] translateBurnCombo(int[] unboundArgsToBurn, Gem sourceGem) {
    int[] argsToBurn = new int[unboundArgsToBurn.length];

    // loop indices:
    // i - index of the current input
    // j - counter to keep track of how many unbound and unburned inputs we have passed
    // k - index of the next element of unboudnArgsToBurn to check
    for (int i = 0, j = 0, k = 0; i < sourceGem.getNInputs() && k < unboundArgsToBurn.length; i++) {
      Gem.PartInput currentInput = sourceGem.getInputPart(i);

      if (currentInput.isConnected() || currentInput.isBurnt()) {
        // Skip over unburnable inputs
        continue;
      }

      // This is the j'th burnable input

      // Check to see if this argument should be burned, and if so, add its index relative to the
      // list of all inputs
      // to the argsToBurn array
      if (unboundArgsToBurn[k] == j) {
        argsToBurn[k] = i;
        k++;
      }
      j++;
    }
    return argsToBurn;
  }
Exemplo n.º 2
0
  /**
   * Determine if the current target Gem only has arguments that we can provide editors for.
   *
   * @return boolean true if we can provide all the arguments, false if we can't
   */
  private boolean targetHasProvidableArgs() {
    // Get the target's arguments first
    List<Gem.PartInput> args = targetDisplayedGem.getTargetArguments();

    // If we have no arguments, then we at least have providable args (we can easily
    // provided none at all!)
    if (args == null) {
      return true;
    }

    // Check all the argument types for being ones that we can provide
    int numArgs = args.size();
    Gem.PartInput sinkPart;
    for (int i = 0; i < numArgs; i++) {
      // Get this part
      sinkPart = args.get(i);

      // Can we deal with this type?
      if (!valueEditorHierarchyManager
          .getValueEditorManager()
          .canInputDefaultValue(sinkPart.getType())) {
        // Oops, can't provide an editor for this type
        return false;
      }
    }

    // If we haven't found any dodgy ones, then we can provide all of them!
    return true;
  }
Exemplo n.º 3
0
    /**
     * Display value entry controls for all unbound arguments. Precondition: the target must be set.
     */
    private void displayArgumentControls() {

      TableTopPanel tableTopPanel = getTableTopPanel();

      // Build the list of value entry panels and place them onto the TableTop

      // Get the list of unbound arguments
      List<Gem.PartInput> argParts = targetDisplayedGem.getTargetArguments();

      // see if it's ok to use the cached argument values
      boolean canUseCachedArgs = canUseCachedArguments();

      // Figure out the types of the argument panels.  Note that we must account for cached values
      int numArgs = argParts.size();

      // make copies of the input types.
      TypeExpr[] inputTypes = new TypeExpr[numArgs];
      for (int i = 0; i < numArgs; i++) {
        // Get this input, and its type
        Gem.PartInput inputPart = argParts.get(i);
        inputTypes[i] = inputPart.getType();
      }

      TypeExpr[] specializedInputTypes;

      if (canUseCachedArgs) {

        // this is the array of types cached for each argument. If there is no cached type, we just
        // use the argument type.
        TypeExpr[] cachedTypes = new TypeExpr[numArgs];
        for (int i = 0; i < numArgs; ++i) {
          // What we do next depends on whether we use cached sink values
          Gem.PartInput inputPart = argParts.get(i);
          ValueNode cachedVN = gemCutter.getTableTop().getCachedValue(inputPart);
          if (cachedVN != null) {
            cachedTypes[i] = cachedVN.getTypeExpr();
          }
        }

        try {
          ModuleTypeInfo contextModuleTypeInfo =
              gemCutter.getPerspective().getWorkingModuleTypeInfo();
          specializedInputTypes =
              TypeExpr.patternMatchPieces(cachedTypes, inputTypes, contextModuleTypeInfo);
        } catch (TypeException te) {
          throw new IllegalStateException("Error reusing cached args.");
        }
      } else {
        specializedInputTypes = TypeExpr.copyTypeExprs(inputTypes);
      }

      ValueEditorManager valueEditorManager = gemCutter.getValueEditorManager();
      ValueEditorDirector valueEditorDirector = valueEditorManager.getValueEditorDirector();

      Map<PartInput, ValueEditor> inputToEditorMap = new LinkedHashMap<PartInput, ValueEditor>();

      // Step through args, create a new value input panel for each, with the correct value type
      for (int i = 0; i < numArgs; i++) {

        // Get the gem and input
        final Gem.PartInput inputPart = argParts.get(i);
        final Gem inputGem = inputPart.getGem();

        int argumentNumber = inputPart.getInputNum();
        QualifiedName scName = null;

        if (inputGem instanceof FunctionalAgentGem) {
          scName = ((FunctionalAgentGem) inputGem).getName();
        }

        // What we do next depends on whether we use cached sink values
        ValueNode cachedVN;
        final ValueEditor editor;
        if (canUseCachedArgs
            && (cachedVN = gemCutter.getTableTop().getCachedValue(inputPart)) != null) {
          // use cached sink value to generate the VEP

          // get a copy of the cached VN but with the new type expr
          ValueNode newVN = cachedVN.copyValueNode();

          // instantiate the VEP with the new VN (which has the old cached value)
          editor =
              valueEditorDirector.getRootValueEditor(
                  valueEditorHierarchyManager,
                  newVN,
                  scName,
                  argumentNumber,
                  new GemCutterMetadataRunner(gemCutter, inputGem));

        } else {
          // don't use cached sink value.  Generate the default VEP for this sink.
          TypeExpr inputType = specializedInputTypes[i];
          editor =
              valueEditorDirector.getRootValueEditor(
                  valueEditorHierarchyManager,
                  inputType,
                  scName,
                  argumentNumber,
                  new GemCutterMetadataRunner(gemCutter, inputGem));
        }

        // If this is a value entry panel then set the name of the input for use in tooltips
        if (editor instanceof ValueEntryPanel) {
          ((ValueEntryPanel) editor)
              .setArgumentName(inputPart.getArgumentName().getCompositeName());
        }

        // Position the editor next to the connection point.
        positionEditor(editor, inputPart);

        // Now add the editor to the table top.
        tableTopPanel.add(editor, 0);

        // Add to the list of active entry panels
        valueEditorHierarchyManager.addTopValueEditor(editor);

        // Update the context and editor map
        editor.setContext(
            new ValueEditorContext() {
              public TypeExpr getLeastConstrainedTypeExpr() {
                return inputPart.getType();
              }
            });
        inputToEditorMap.put(inputPart, editor);

        // If the editor resizes because it's value changes, make sure it stays aligned to the
        // connection
        editor.addComponentListener(
            new ComponentAdapter() {
              @Override
              public void componentResized(ComponentEvent e) {
                positionEditor((ValueEditor) e.getComponent(), inputPart);
              }
            });
      }

      // Must prevent ValueGems from being editable.
      tableTopPanel.setValueGemsEnabled(false);

      // Need to activate the value editor hierarchy to ensure correct highlighting.
      valueEditorHierarchyManager.activateCurrentEditor();

      // Set the context and type switch listener for each new editor.
      ArgumentValueCommitter argumentValueCommitter =
          new ArgumentValueCommitter(valueEditorManager, inputToEditorMap);

      for (final ValueEditor argumentEditor : getArgumentPanels()) {
        argumentEditor.addValueEditorListener(argumentValueCommitter);
      }

      // May need to show argument controls.
      if (numArgs > 0) {
        gemCutter.showArgumentControls(inputToEditorMap);
        gemCutter.getResetAction().setEnabled(true);
      } else {
        gemCutter.getResetAction().setEnabled(false);
      }
    }
Exemplo n.º 4
0
  /**
   * Return whether autoburning will result in a unification. Only inputs on the given gem will be
   * considered for burning.
   *
   * @param destType The destination type to unify with.
   * @param gem The gem on which to attempt "autoburning".
   * @param info the typeCheck info to use.
   * @return AutoburnLogic.AutoburnInfo autoburnable result.
   */
  public static AutoburnInfo getAutoburnInfo(TypeExpr destType, Gem gem, TypeCheckInfo info) {
    // see if we got a real type
    if (destType == null) {
      return AutoburnInfo.makeNoUnificationPossibleAutoburnInfo();
    }

    int[] burnableArgIndices;
    List<TypeExpr> sourceTypeList = new ArrayList<TypeExpr>(); // input types, then output type.

    TypeExpr outType =
        (gem instanceof CollectorGem)
            ? ((CollectorGem) gem).getCollectingPart().getType()
            : gem.getOutputPart().getType();
    TypeExpr[] outTypePieces = outType.getTypePieces();

    // A collector gem's collecting part is not burnable.
    if (gem instanceof CollectorGem && !((CollectorGem) gem).isConnected()) {
      burnableArgIndices = new int[0];

    } else {
      // declare the burnt arg indices array
      burnableArgIndices = new int[gem.getNInputs()];

      if (burnableArgIndices.length != 0) {
        // get the unbound input parts of the gem and keep track of which ones are burnable
        int unburnedCount = 0;
        int burnedCount = 0;
        for (int i = 0, n = gem.getNInputs(); i < n; i++) {
          Gem.PartInput input = gem.getInputPart(i);

          if (!input.isConnected()) {
            if (input.isBurnt()) {
              sourceTypeList.add(outTypePieces[burnedCount]);
              burnedCount++;
            } else {
              sourceTypeList.add(input.getType());
              burnableArgIndices[unburnedCount] = sourceTypeList.size() - 1;
              unburnedCount++;
            }
          }
        }

        // Calculate what the output type would be if none of the arguments were burned.
        TypeExpr newOutType = outTypePieces[outTypePieces.length - 1];
        for (int i = outTypePieces.length - 2; i >= burnedCount; i--) {
          newOutType = TypeExpr.makeFunType(outTypePieces[i], newOutType);
        }
        outType = newOutType;

        // Assign to a new trimmed down array
        int[] newIndices = new int[unburnedCount];
        System.arraycopy(burnableArgIndices, 0, newIndices, 0, unburnedCount);
        burnableArgIndices = newIndices;
      }
    }

    // Add the output type to the source types.
    sourceTypeList.add(outType);

    return getAutoburnInfoWorker(
        destType, sourceTypeList.toArray(new TypeExpr[0]), burnableArgIndices, info, gem);
  }