mohayonao/SCScript

View on GitHub
src/sc/classlib/Core/AbstractFunction.js

Summary

Maintainability
F
3 days
Test Coverage
SCScript.install(function(sc) {
  "use strict";

  require("./Object");

  var $ = sc.lang.$;
  var $int0 = $.int0;

  sc.lang.klass.refine("AbstractFunction", function(builder) {
    builder.addMethod("composeUnaryOp", function($aSelector) {
      return $("UnaryOpFunction").new($aSelector, this);
    });

    builder.addMethod("composeBinaryOp", function($aSelector, $something, $adverb) {
      return $("BinaryOpFunction").new($aSelector, this, $something, $adverb);
    });

    builder.addMethod("reverseComposeBinaryOp", function($aSelector, $something, $adverb) {
      return $("BinaryOpFunction").new($aSelector, $something, this, $adverb);
    });

    builder.addMethod("composeNAryOp", function($aSelector, $anArgList) {
      return $("NAryOpFunction").new($aSelector, this, $anArgList);
    });

    builder.addMethod("performBinaryOpOnSimpleNumber", function($aSelector, $aNumber, $adverb) {
      return this.reverseComposeBinaryOp($aSelector, $aNumber, $adverb);
    });

    builder.addMethod("performBinaryOpOnSignal", function($aSelector, $aSignal, $adverb) {
      return this.reverseComposeBinaryOp($aSelector, $aSignal, $adverb);
    });

    builder.addMethod("performBinaryOpOnComplex", function($aSelector, $aComplex, $adverb) {
      return this.reverseComposeBinaryOp($aSelector, $aComplex, $adverb);
    });

    builder.addMethod("performBinaryOpOnSeqColl", function($aSelector, $aSeqColl, $adverb) {
      return this.reverseComposeBinaryOp($aSelector, $aSeqColl, $adverb);
    });

    builder.addMethod("neg", function() {
      return this.composeUnaryOp($.Symbol("neg"));
    });

    builder.addMethod("reciprocal", function() {
      return this.composeUnaryOp($.Symbol("reciprocal"));
    });

    builder.addMethod("bitNot", function() {
      return this.composeUnaryOp($.Symbol("bitNot"));
    });

    builder.addMethod("abs", function() {
      return this.composeUnaryOp($.Symbol("abs"));
    });

    builder.addMethod("asFloat", function() {
      return this.composeUnaryOp($.Symbol("asFloat"));
    });

    builder.addMethod("asInteger", function() {
      return this.composeUnaryOp($.Symbol("asInteger"));
    });

    builder.addMethod("ceil", function() {
      return this.composeUnaryOp($.Symbol("ceil"));
    });

    builder.addMethod("floor", function() {
      return this.composeUnaryOp($.Symbol("floor"));
    });

    builder.addMethod("frac", function() {
      return this.composeUnaryOp($.Symbol("frac"));
    });

    builder.addMethod("sign", function() {
      return this.composeUnaryOp($.Symbol("sign"));
    });

    builder.addMethod("squared", function() {
      return this.composeUnaryOp($.Symbol("squared"));
    });

    builder.addMethod("cubed", function() {
      return this.composeUnaryOp($.Symbol("cubed"));
    });

    builder.addMethod("sqrt", function() {
      return this.composeUnaryOp($.Symbol("sqrt"));
    });

    builder.addMethod("exp", function() {
      return this.composeUnaryOp($.Symbol("exp"));
    });

    builder.addMethod("midicps", function() {
      return this.composeUnaryOp($.Symbol("midicps"));
    });

    builder.addMethod("cpsmidi", function() {
      return this.composeUnaryOp($.Symbol("cpsmidi"));
    });

    builder.addMethod("midiratio", function() {
      return this.composeUnaryOp($.Symbol("midiratio"));
    });

    builder.addMethod("ratiomidi", function() {
      return this.composeUnaryOp($.Symbol("ratiomidi"));
    });

    builder.addMethod("ampdb", function() {
      return this.composeUnaryOp($.Symbol("ampdb"));
    });

    builder.addMethod("dbamp", function() {
      return this.composeUnaryOp($.Symbol("dbamp"));
    });

    builder.addMethod("octcps", function() {
      return this.composeUnaryOp($.Symbol("octcps"));
    });

    builder.addMethod("cpsoct", function() {
      return this.composeUnaryOp($.Symbol("cpsoct"));
    });

    builder.addMethod("log", function() {
      return this.composeUnaryOp($.Symbol("log"));
    });

    builder.addMethod("log2", function() {
      return this.composeUnaryOp($.Symbol("log2"));
    });

    builder.addMethod("log10", function() {
      return this.composeUnaryOp($.Symbol("log10"));
    });

    builder.addMethod("sin", function() {
      return this.composeUnaryOp($.Symbol("sin"));
    });

    builder.addMethod("cos", function() {
      return this.composeUnaryOp($.Symbol("cos"));
    });

    builder.addMethod("tan", function() {
      return this.composeUnaryOp($.Symbol("tan"));
    });

    builder.addMethod("asin", function() {
      return this.composeUnaryOp($.Symbol("asin"));
    });

    builder.addMethod("acos", function() {
      return this.composeUnaryOp($.Symbol("acos"));
    });

    builder.addMethod("atan", function() {
      return this.composeUnaryOp($.Symbol("atan"));
    });

    builder.addMethod("sinh", function() {
      return this.composeUnaryOp($.Symbol("sinh"));
    });

    builder.addMethod("cosh", function() {
      return this.composeUnaryOp($.Symbol("cosh"));
    });

    builder.addMethod("tanh", function() {
      return this.composeUnaryOp($.Symbol("tanh"));
    });

    builder.addMethod("rand", function() {
      return this.composeUnaryOp($.Symbol("rand"));
    });

    builder.addMethod("rand2", function() {
      return this.composeUnaryOp($.Symbol("rand2"));
    });

    builder.addMethod("linrand", function() {
      return this.composeUnaryOp($.Symbol("linrand"));
    });

    builder.addMethod("bilinrand", function() {
      return this.composeUnaryOp($.Symbol("bilinrand"));
    });

    builder.addMethod("sum3rand", function() {
      return this.composeUnaryOp($.Symbol("sum3rand"));
    });

    builder.addMethod("distort", function() {
      return this.composeUnaryOp($.Symbol("distort"));
    });

    builder.addMethod("softclip", function() {
      return this.composeUnaryOp($.Symbol("softclip"));
    });

    builder.addMethod("coin", function() {
      return this.composeUnaryOp($.Symbol("coin"));
    });

    builder.addMethod("even", function() {
      return this.composeUnaryOp($.Symbol("even"));
    });

    builder.addMethod("odd", function() {
      return this.composeUnaryOp($.Symbol("odd"));
    });

    builder.addMethod("rectWindow", function() {
      return this.composeUnaryOp($.Symbol("rectWindow"));
    });

    builder.addMethod("hanWindow", function() {
      return this.composeUnaryOp($.Symbol("hanWindow"));
    });

    builder.addMethod("welWindow", function() {
      return this.composeUnaryOp($.Symbol("welWindow"));
    });

    builder.addMethod("triWindow", function() {
      return this.composeUnaryOp($.Symbol("triWindow"));
    });

    builder.addMethod("scurve", function() {
      return this.composeUnaryOp($.Symbol("scurve"));
    });

    builder.addMethod("ramp", function() {
      return this.composeUnaryOp($.Symbol("ramp"));
    });

    builder.addMethod("isPositive", function() {
      return this.composeUnaryOp($.Symbol("isPositive"));
    });

    builder.addMethod("isNegative", function() {
      return this.composeUnaryOp($.Symbol("isNegative"));
    });

    builder.addMethod("isStrictlyPositive", function() {
      return this.composeUnaryOp($.Symbol("isStrictlyPositive"));
    });

    builder.addMethod("rho", function() {
      return this.composeUnaryOp($.Symbol("rho"));
    });

    builder.addMethod("theta", function() {
      return this.composeUnaryOp($.Symbol("theta"));
    });

    builder.addMethod("rotate", function($function) {
      return this.composeBinaryOp($.Symbol("rotate"), $function);
    });

    builder.addMethod("dist", function($function) {
      return this.composeBinaryOp($.Symbol("dist"), $function);
    });

    builder.addMethod("+", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("+"), $function, $adverb);
    });

    builder.addMethod("-", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("-"), $function, $adverb);
    });

    builder.addMethod("*", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("*"), $function, $adverb);
    });

    builder.addMethod("/", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("/"), $function, $adverb);
    });

    builder.addMethod("div", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("div"), $function, $adverb);
    });

    builder.addMethod("mod", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("mod"), $function, $adverb);
    });

    builder.addMethod("pow", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("pow"), $function, $adverb);
    });

    builder.addMethod("min", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("min"), $function, $adverb);
    });

    builder.addMethod("max", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("max"), $function, $adverb);
    });

    builder.addMethod("<", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("<"), $function, $adverb);
    });

    builder.addMethod("<=", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("<="), $function, $adverb);
    });

    builder.addMethod(">", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol(">"), $function, $adverb);
    });

    builder.addMethod(">=", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol(">="), $function, $adverb);
    });

    builder.addMethod("bitAnd", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("bitAnd"), $function, $adverb);
    });

    builder.addMethod("bitOr", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("bitOr"), $function, $adverb);
    });

    builder.addMethod("bitXor", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("bitXor"), $function, $adverb);
    });

    builder.addMethod("bitHammingDistance", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("bitHammingDistance"), $function, $adverb);
    });

    builder.addMethod("lcm", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("lcm"), $function, $adverb);
    });

    builder.addMethod("gcd", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("gcd"), $function, $adverb);
    });

    builder.addMethod("round", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("round"), $function, $adverb);
    });

    builder.addMethod("roundUp", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("roundUp"), $function, $adverb);
    });

    builder.addMethod("trunc", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("trunc"), $function, $adverb);
    });

    builder.addMethod("atan2", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("atan2"), $function, $adverb);
    });

    builder.addMethod("hypot", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("hypot"), $function, $adverb);
    });

    builder.addMethod("hypotApx", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("hypotApx"), $function, $adverb);
    });

    builder.addMethod("leftShift", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("leftShift"), $function, $adverb);
    });

    builder.addMethod("rightShift", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("rightShift"), $function, $adverb);
    });

    builder.addMethod("unsignedRightShift", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("unsignedRightShift"), $function, $adverb);
    });

    builder.addMethod("ring1", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("ring1"), $function, $adverb);
    });

    builder.addMethod("ring2", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("ring2"), $function, $adverb);
    });

    builder.addMethod("ring3", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("ring3"), $function, $adverb);
    });

    builder.addMethod("ring4", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("ring4"), $function, $adverb);
    });

    builder.addMethod("difsqr", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("difsqr"), $function, $adverb);
    });

    builder.addMethod("sumsqr", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("sumsqr"), $function, $adverb);
    });

    builder.addMethod("sqrsum", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("sqrsum"), $function, $adverb);
    });

    builder.addMethod("sqrdif", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("sqrdif"), $function, $adverb);
    });

    builder.addMethod("absdif", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("absdif"), $function, $adverb);
    });

    builder.addMethod("thresh", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("thresh"), $function, $adverb);
    });

    builder.addMethod("amclip", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("amclip"), $function, $adverb);
    });

    builder.addMethod("scaleneg", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("scaleneg"), $function, $adverb);
    });

    builder.addMethod("clip2", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("clip2"), $function, $adverb);
    });

    builder.addMethod("fold2", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("fold2"), $function, $adverb);
    });

    builder.addMethod("wrap2", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("wrap2"), $function, $adverb);
    });

    builder.addMethod("excess", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("excess"), $function, $adverb);
    });

    builder.addMethod("firstArg", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("firstArg"), $function, $adverb);
    });

    builder.addMethod("rrand", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("rrand"), $function, $adverb);
    });

    builder.addMethod("exprand", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("exprand"), $function, $adverb);
    });

    builder.addMethod("@", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("@"), $function, $adverb);
    });

    builder.addMethod("real");

    builder.addMethod("imag", function() {
      return $.Float(0.0);
    });

    builder.addMethod("||", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("||"), $function, $adverb);
    });

    builder.addMethod("&&", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("&&"), $function, $adverb);
    });

    builder.addMethod("xor", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("xor"), $function, $adverb);
    });

    builder.addMethod("nand", function($function, $adverb) {
      return this.composeBinaryOp($.Symbol("nand"), $function, $adverb);
    });

    builder.addMethod("not", function() {
      return this.composeUnaryOp($.Symbol("not"));
    });

    builder.addMethod("ref", function() {
      return this.composeUnaryOp($.Symbol("asRef"));
    });

    builder.addMethod("clip", function($lo, $hi) {
      return this.composeNAryOp($.Symbol("clip"), $.Array([ $lo, $hi ]));
    });

    builder.addMethod("wrap", function($lo, $hi) {
      return this.composeNAryOp($.Symbol("wrap"), $.Array([ $lo, $hi ]));
    });

    builder.addMethod("fold", function($lo, $hi) {
      return this.composeNAryOp($.Symbol("fold"), $.Array([ $lo, $hi ]));
    });

    builder.addMethod("blend", {
      args: "that; blendFrac=0.5"
    }, function($that, $blendFrac) {
      return this.composeNAryOp(
        $.Symbol("blend"), $.Array([ $that, $blendFrac ])
      );
    });

    builder.addMethod("linlin", {
      args: "inMin; inMax; outMin; outMax; clip=\\minmax"
    }, function($inMin, $inMax, $outMin, $outMax, $clip) {
      return this.composeNAryOp(
        $.Symbol("linlin"), $.Array([ $inMin, $inMax, $outMin, $outMax, $clip ])
      );
    });

    builder.addMethod("linexp", {
      args: "inMin; inMax; outMin; outMax; clip=\\minmax"
    }, function($inMin, $inMax, $outMin, $outMax, $clip) {
      return this.composeNAryOp(
        $.Symbol("linexp"), $.Array([ $inMin, $inMax, $outMin, $outMax, $clip ])
      );
    });

    builder.addMethod("explin", {
      args: "inMin; inMax; outMin; outMax; clip=\\minmax"
    }, function($inMin, $inMax, $outMin, $outMax, $clip) {
      return this.composeNAryOp(
        $.Symbol("explin"), $.Array([ $inMin, $inMax, $outMin, $outMax, $clip ])
      );
    });

    builder.addMethod("expexp", {
      args: "inMin; inMax; outMin; outMax; clip=\\minmax"
    }, function($inMin, $inMax, $outMin, $outMax, $clip) {
      return this.composeNAryOp(
        $.Symbol("expexp"), $.Array([ $inMin, $inMax, $outMin, $outMax, $clip ])
      );
    });

    builder.addMethod("lincurve", {
      args: "inMin=0; inMax=1; outMin=1; outMax=1; curve=-4; clip=\\minmax"
    }, function($inMin, $inMax, $outMin, $outMax, $curve, $clip) {
      return this.composeNAryOp(
        $.Symbol("lincurve"), $.Array([ $inMin, $inMax, $outMin, $outMax, $curve, $clip ])
      );
    });

    builder.addMethod("curvelin", {
      args: "inMin=0; inMax=1; outMin=1; outMax=1; curve=-4; clip=\\minmax"
    }, function($inMin, $inMax, $outMin, $outMax, $curve, $clip) {
      return this.composeNAryOp(
        $.Symbol("curvelin"), $.Array([ $inMin, $inMax, $outMin, $outMax, $curve, $clip ])
      );
    });

    builder.addMethod("bilin", {
      args: "inCenter; inMin; inMax; outCenter; outMin; outMax; clip=\\minmax"
    }, function($inCenter, $inMin, $inMax, $outCenter, $outMin, $outMax, $clip) {
      return this.composeNAryOp(
        $.Symbol("bilin"), $.Array([
          $inCenter, $inMin, $inMax, $outCenter, $outMin, $outMax, $clip
        ])
      );
    });

    builder.addMethod("biexp", {
      args: "inCenter; inMin; inMax; outCenter; outMin; outMax; clip=\\minmax"
    }, function($inCenter, $inMin, $inMax, $outCenter, $outMin, $outMax, $clip) {
      return this.composeNAryOp(
        $.Symbol("biexp"), $.Array([
          $inCenter, $inMin, $inMax, $outCenter, $outMin, $outMax, $clip
        ])
      );
    });

    builder.addMethod("moddif", {
      args: "function; mod"
    }, function($function, $mod) {
      return this.composeNAryOp(
        $.Symbol("moddif"), $.Array([ $function, $mod ])
      );
    });

    builder.addMethod("degreeToKey", {
      args: "scale; stepsPerOctave=12"
    }, function($scale, $stepsPerOctave) {
      return this.composeNAryOp(
        $.Symbol("degreeToKey"), $.Array([ $scale, $stepsPerOctave ])
      );
    });

    builder.addMethod("degrad", function() {
      return this.composeUnaryOp($.Symbol("degrad"));
    });

    builder.addMethod("raddeg", function() {
      return this.composeUnaryOp($.Symbol("raddeg"));
    });

    builder.addMethod("applyTo", function() {
      return this.value.apply(this, arguments);
    });

    // TODO: implements <>
    // TODO: implements sampled

    builder.addMethod("asUGenInput", function($for) {
      return this.value($for);
    });

    builder.addMethod("asAudioRateInput", function($for) {
      var $result;

      $result = this.value($for);

      if ($result.rate().__sym__() !== "audio") {
        return $("K2A").ar($result);
      }

      return $result;
    });

    builder.addMethod("asControlInput", function() {
      return this.value();
    });

    builder.addMethod("isValidUGenInput", sc.TRUE);
  });

  sc.lang.klass.define("UnaryOpFunction : AbstractFunction", function(builder, _) {
    builder.addClassMethod("new", function($selector, $a) {
      return _.newCopyArgs(this, {
        selector: $selector,
        a: $a
      });
    });

    builder.addMethod("value", function() {
      var $a = this._$a;
      return $a.value.apply($a, arguments).perform(this._$selector);
    });

    builder.addMethod("valueArray", function($args) {
      return this._$a.valueArray($args).perform(this._$selector);
    });

    builder.addMethod("valueEnvir", function() {
      var $a = this._$a;
      return $a.valueEnvir.apply($a, arguments).perform(this._$selector);
    });

    builder.addMethod("valueArrayEnvir", function($args) {
      return this._$a.valueArrayEnvir($args).perform(this._$selector);
    });

    builder.addMethod("functionPerformList", function($selector, $arglist) {
      return this.performList($selector, $arglist);
    });
    // TODO: implements storeOn
  });

  sc.lang.klass.define("BinaryOpFunction : AbstractFunction", function(builder, _) {
    builder.addClassMethod("new", function($selector, $a, $b, $adverb) {
      return _.newCopyArgs(this, {
        selector: $selector,
        a: $a,
        b: $b,
        adverb: $adverb
      });
    });

    builder.addMethod("value", function() {
      return this._$a.value.apply(this._$a, arguments)
        .perform(this._$selector, this._$b.value.apply(this._$b, arguments), this._$adverb);
    });

    builder.addMethod("valueArray", function($args) {
      return this._$a.valueArray($args)
        .perform(this._$selector, this._$b.valueArray($args, arguments), this._$adverb);
    });

    // TODO: implements valueEnvir
    // TODO: implements valueArrayEnvir

    builder.addMethod("functionPerformList", function($selector, $arglist) {
      return this.performList($selector, $arglist);
    });
    // TODO: implements storeOn
  });

  sc.lang.klass.define("NAryOpFunction : AbstractFunction", function(builder, _) {
    builder.addClassMethod("new", function($selector, $a, $arglist) {
      return _.newCopyArgs(this, {
        selector: $selector,
        a: $a,
        arglist: $arglist
      });
    });

    builder.addMethod("value", function() {
      var args = arguments;
      return this._$a.value.apply(this._$a, args)
        .performList(this._$selector, this._$arglist.collect($.Func(function($_) {
          return $_.value.apply($_, args);
        })));
    });

    builder.addMethod("valueArray", function($args) {
      return this._$a.valueArray($args)
        .performList(this._$selector, this._$arglist.collect($.Func(function($_) {
          return $_.valueArray($args);
        })));
    });

    // TODO: implements valueEnvir
    // TODO: implements valueArrayEnvir

    builder.addMethod("functionPerformList", function($selector, _$arglist) {
      return this.performList($selector, _$arglist);
    });
    // TODO: implements storeOn
  });

  sc.lang.klass.define("FunctionList : AbstractFunction", function(builder, _) {
    builder.addProperty("<>", "array");

    builder.addMethod("__init__", function() {
      this.__super__("__init__");
      this._flopped = false;
    });

    builder.addClassMethod("new", function($functions) {
      return _.newCopyArgs(this, {
        array: $functions
      });
    });

    builder.addMethod("flopped", function() {
      return $.Boolean(this._flopped);
    });

    builder.addMethod("addFunc", {
      args: "*functions"
    }, function($$functions) {
      if (this._flopped) {
        throw new Error("cannot add a function to a flopped FunctionList");
      }

      this._$array = this._$array.addAll($$functions);

      return this;
    });

    builder.addMethod("removeFunc", function($function) {
      this._$array.remove($function);

      if (this._$array.size() < 2) {
        return this._$array.at($int0);
      }

      return this;
    });

    builder.addMethod("replaceFunc", function($find, $replace) {
      this._$array = this._$array.replace($find, $replace);
      return this;
    });

    builder.addMethod("value", function() {
      var $res, args = arguments;

      $res = this._$array.collect($.Func(function($_) {
        return $_.value.apply($_, args);
      }));

      return this._flopped ? $res.flop() : $res;
    });

    builder.addMethod("valueArray", function($args) {
      var $res;

      $res = this._$array.collect($.Func(function($_) {
        return $_.valueArray($args);
      }));

      return this._flopped ? $res.flop() : $res;
    });

    // TODO: implements valueEnvir
    // TODO: implements valueArrayEnvir

    builder.addMethod("do", function($function) {
      this._$array.do($function);
      return this;
    });

    builder.addMethod("flop", function() {
      if (!this._flopped) {
        this._$array = this._$array.collect($.Func(function($_) {
          return $_.$("flop");
        }));
      }
      this._flopped = true;

      return this;
    });

    // TODO: implements envirFlop

    builder.addMethod("storeArgs", function() {
      return $.Array([ this._$array ]);
    });
  });
});