Ejemplo n.º 1
0
  @Override
  public void init(IokeObject obj) throws ControlFlow {
    final Runtime runtime = obj.runtime;

    obj.setKind("Range");
    obj.mimics(
        IokeObject.as(runtime.mixins.getCell(null, null, "Enumerable"), null),
        runtime.nul,
        runtime.nul);

    obj.registerMethod(
        runtime.newJavaMethod(
            "will return a new inclusive Range based on the two arguments",
            new JavaMethod("inclusive") {
              private final DefaultArgumentsDefinition ARGUMENTS =
                  DefaultArgumentsDefinition.builder()
                      .withRequiredPositional("from")
                      .withRequiredPositional("to")
                      .getArguments();

              @Override
              public DefaultArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                List<Object> args = new ArrayList<Object>();
                getArguments()
                    .getEvaluatedArguments(
                        context, message, on, args, new HashMap<String, Object>());

                Object from = args.get(0);
                Object to = args.get(1);

                boolean comparing =
                    IokeObject.isMimic(
                        from,
                        IokeObject.as(context.runtime.mixins.getCells().get("Comparing"), context),
                        context);
                boolean inverted = false;

                if (comparing) {
                  Object result =
                      ((Message) IokeObject.data(context.runtime.spaceShip))
                          .sendTo(context.runtime.spaceShip, context, from, to);
                  if (result != context.runtime.nil
                      && Number.extractInt(result, message, context) == 1) {
                    inverted = true;
                  }
                }

                return runtime.newRange(
                    IokeObject.as(from, context), IokeObject.as(to, context), true, inverted);
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "will return a new exclusive Range based on the two arguments",
            new JavaMethod("exclusive") {
              private final DefaultArgumentsDefinition ARGUMENTS =
                  DefaultArgumentsDefinition.builder()
                      .withRequiredPositional("from")
                      .withRequiredPositional("to")
                      .getArguments();

              @Override
              public DefaultArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                List<Object> args = new ArrayList<Object>();
                getArguments()
                    .getEvaluatedArguments(
                        context, message, on, args, new HashMap<String, Object>());

                Object from = args.get(0);
                Object to = args.get(1);

                boolean comparing =
                    IokeObject.isMimic(
                        from,
                        IokeObject.as(context.runtime.mixins.getCells().get("Comparing"), context),
                        context);
                boolean inverted = false;
                if (comparing) {
                  Object result =
                      ((Message) IokeObject.data(context.runtime.spaceShip))
                          .sendTo(context.runtime.spaceShip, context, from, to);
                  if (result != context.runtime.nil
                      && Number.extractInt(result, message, context) == 1) {
                    inverted = true;
                  }
                }

                return runtime.newRange(
                    IokeObject.as(from, context), IokeObject.as(to, context), false, inverted);
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "returns true if the receiver is an exclusive range, false otherwise",
            new JavaMethod.WithNoArguments("exclusive?") {
              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return ((Range) IokeObject.data(on)).inclusive
                    ? context.runtime._false
                    : context.runtime._true;
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "returns true if the receiver is an inclusive range, false otherwise",
            new JavaMethod.WithNoArguments("inclusive?") {
              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return ((Range) IokeObject.data(on)).inclusive
                    ? context.runtime._true
                    : context.runtime._false;
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "returns the 'from' part of the range",
            new TypeCheckingJavaMethod.WithNoArguments("from", runtime.range) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return ((Range) IokeObject.data(on)).from;
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "returns the 'to' part of the range",
            new JavaMethod.WithNoArguments("to") {
              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return ((Range) IokeObject.data(on)).to;
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "takes either one or two or three arguments. if one argument is given, it should be a message chain that will be sent to each object in the range. the result will be thrown away. if two arguments are given, the first is an unevaluated name that will be set to each of the values in the range in succession, and then the second argument will be evaluated in a scope with that argument in it. if three arguments is given, the first one is an unevaluated name that will be set to the index of each element, and the other two arguments are the name of the argument for the value, and the actual code. the code will evaluate in a lexical context, and if the argument name is available outside the context, it will be shadowed. the method will return the range.",
            new JavaMethod("each") {
              private final DefaultArgumentsDefinition ARGUMENTS =
                  DefaultArgumentsDefinition.builder()
                      .withRequiredPositionalUnevaluated("indexOrArgOrCode")
                      .withOptionalPositionalUnevaluated("argOrCode")
                      .withOptionalPositionalUnevaluated("code")
                      .getArguments();

              @Override
              public DefaultArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments().checkArgumentCount(context, message, on);

                Runtime runtime = context.runtime;

                IokeObject from = IokeObject.as(((Range) IokeObject.data(on)).from, context);
                IokeObject to = IokeObject.as(((Range) IokeObject.data(on)).to, context);
                boolean inclusive = ((Range) IokeObject.data(on)).inclusive;

                IokeObject messageToSend = context.runtime.succ;
                if (((Range) IokeObject.data(on)).inverted) {
                  messageToSend = context.runtime.pred;
                }

                switch (message.getArgumentCount()) {
                  case 1:
                    {
                      IokeObject code = IokeObject.as(message.getArguments().get(0), context);

                      Object current = from;

                      while (!IokeObject.isTrue(
                          ((Message) IokeObject.data(context.runtime.eqMessage))
                              .sendTo(context.runtime.eqMessage, context, current, to))) {
                        ((Message) IokeObject.data(code))
                            .evaluateCompleteWithReceiver(
                                code, context, context.getRealContext(), current);
                        current =
                            ((Message) IokeObject.data(messageToSend))
                                .sendTo(messageToSend, context, current);
                      }
                      if (inclusive) {
                        ((Message) IokeObject.data(code))
                            .evaluateCompleteWithReceiver(
                                code, context, context.getRealContext(), current);
                      }

                      break;
                    }
                  case 2:
                    {
                      LexicalContext c =
                          new LexicalContext(
                              context.runtime,
                              context,
                              "Lexical activation context for Range#each",
                              message,
                              context);
                      String name = IokeObject.as(message.getArguments().get(0), context).getName();
                      IokeObject code = IokeObject.as(message.getArguments().get(1), context);

                      Object current = from;

                      while (!IokeObject.isTrue(
                          ((Message) IokeObject.data(context.runtime.eqMessage))
                              .sendTo(context.runtime.eqMessage, context, current, to))) {
                        c.setCell(name, current);
                        ((Message) IokeObject.data(code))
                            .evaluateCompleteWithoutExplicitReceiver(code, c, c.getRealContext());
                        current =
                            ((Message) IokeObject.data(messageToSend))
                                .sendTo(messageToSend, context, current);
                      }
                      if (inclusive) {
                        c.setCell(name, current);
                        ((Message) IokeObject.data(code))
                            .evaluateCompleteWithoutExplicitReceiver(code, c, c.getRealContext());
                      }

                      break;
                    }
                  case 3:
                    {
                      LexicalContext c =
                          new LexicalContext(
                              context.runtime,
                              context,
                              "Lexical activation context for List#each",
                              message,
                              context);
                      String iname =
                          IokeObject.as(message.getArguments().get(0), context).getName();
                      String name = IokeObject.as(message.getArguments().get(1), context).getName();
                      IokeObject code = IokeObject.as(message.getArguments().get(2), context);

                      int index = 0;

                      Object current = from;

                      while (!IokeObject.isTrue(
                          ((Message) IokeObject.data(context.runtime.eqMessage))
                              .sendTo(context.runtime.eqMessage, context, current, to))) {
                        c.setCell(name, current);
                        c.setCell(iname, runtime.newNumber(index++));
                        ((Message) IokeObject.data(code))
                            .evaluateCompleteWithoutExplicitReceiver(code, c, c.getRealContext());
                        current =
                            ((Message) IokeObject.data(messageToSend))
                                .sendTo(messageToSend, context, current);
                      }
                      if (inclusive) {
                        c.setCell(name, current);
                        c.setCell(iname, runtime.newNumber(index++));
                        ((Message) IokeObject.data(code))
                            .evaluateCompleteWithoutExplicitReceiver(code, c, c.getRealContext());
                      }

                      break;
                    }
                }
                return on;
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "returns true if the argument is within the confines of this range. how this comparison is done depends on if the object mimics Comparing. If it does, < and > will be used. If not, all the available entries in this range will be enumerated using 'succ'/'pred' until either the end or the element we're looking for is found. in that case, comparison is done with '=='",
            new JavaMethod("===") {
              private final DefaultArgumentsDefinition ARGUMENTS =
                  DefaultArgumentsDefinition.builder()
                      .withRequiredPositional("other")
                      .getArguments();

              @Override
              public DefaultArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                List<Object> args = new ArrayList<Object>();
                getArguments()
                    .getEvaluatedArguments(
                        context, message, on, args, new HashMap<String, Object>());
                Object other = args.get(0);

                IokeObject from = IokeObject.as(((Range) IokeObject.data(on)).from, context);
                IokeObject to = IokeObject.as(((Range) IokeObject.data(on)).to, context);
                boolean comparing =
                    IokeObject.isMimic(
                        from,
                        IokeObject.as(context.runtime.mixins.getCells().get("Comparing"), context));
                boolean inclusive = ((Range) IokeObject.data(on)).inclusive;

                if (comparing) {
                  IokeObject firstMessage = context.runtime.lteMessage;
                  IokeObject secondMessageInclusive = context.runtime.gteMessage;
                  IokeObject secondMessageExclusive = context.runtime.gtMessage;

                  if (((Range) IokeObject.data(on)).inverted) {
                    firstMessage = context.runtime.gteMessage;
                    secondMessageInclusive = context.runtime.lteMessage;
                    secondMessageExclusive = context.runtime.ltMessage;
                  }

                  if (IokeObject.isTrue(
                          ((Message) IokeObject.data(firstMessage))
                              .sendTo(firstMessage, context, from, other))
                      && ((inclusive
                              && IokeObject.isTrue(
                                  ((Message) IokeObject.data(secondMessageInclusive))
                                      .sendTo(secondMessageInclusive, context, to, other)))
                          || IokeObject.isTrue(
                              ((Message) IokeObject.data(secondMessageExclusive))
                                  .sendTo(secondMessageExclusive, context, to, other)))) {
                    return context.runtime._true;
                  } else {
                    return context.runtime._false;
                  }
                } else {
                  IokeObject messageToSend = context.runtime.succ;
                  if (((Range) IokeObject.data(on)).inverted) {
                    messageToSend = context.runtime.pred;
                  }

                  Object current = from;

                  while (!IokeObject.isTrue(
                      ((Message) IokeObject.data(context.runtime.eqMessage))
                          .sendTo(context.runtime.eqMessage, context, current, to))) {
                    if (IokeObject.isTrue(
                        ((Message) IokeObject.data(context.runtime.eqMessage))
                            .sendTo(context.runtime.eqMessage, context, current, other))) {
                      return context.runtime._true;
                    }
                    current =
                        ((Message) IokeObject.data(messageToSend))
                            .sendTo(messageToSend, context, current);
                  }

                  if (inclusive
                      && IokeObject.isTrue(
                          ((Message) IokeObject.data(context.runtime.eqMessage))
                              .sendTo(context.runtime.eqMessage, context, to, other))) {
                    return context.runtime._true;
                  }
                  return context.runtime._false;
                }
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "Returns a text inspection of the object",
            new JavaMethod.WithNoArguments("inspect") {
              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return method.runtime.newText(Range.getInspect(on));
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "Returns a brief text inspection of the object",
            new JavaMethod.WithNoArguments("notice") {
              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return method.runtime.newText(Range.getNotice(on));
              }
            }));
  }
Ejemplo n.º 2
0
  @Override
  public void init(IokeObject obj) throws ControlFlow {
    final Runtime runtime = obj.runtime;
    final IokeObject number = obj;

    obj.setKind("Number");
    obj.mimics(
        IokeObject.as(runtime.mixins.getCell(null, null, "Comparing"), obj),
        runtime.nul,
        runtime.nul);

    IokeObject real =
        new IokeObject(
            runtime,
            "A real number can be either a rational number or a decimal number",
            new Number());
    real.mimicsWithoutCheck(number);
    real.setKind("Number Real");
    number.registerCell("Real", real);

    final IokeObject rational =
        new IokeObject(runtime, "A rational number is either an integer or a ratio", new Number());
    rational.mimicsWithoutCheck(real);
    rational.setKind("Number Rational");
    number.registerCell("Rational", rational);

    final IokeObject integer = new IokeObject(runtime, "An integral number", new Number());
    integer.mimicsWithoutCheck(rational);
    integer.setKind("Number Integer");
    number.registerCell("Integer", integer);
    runtime.integer = integer;

    final IokeObject ratio =
        new IokeObject(runtime, "A ratio of two integral numbers", new Number());
    ratio.mimicsWithoutCheck(rational);
    ratio.setKind("Number Ratio");
    number.registerCell("Ratio", ratio);
    runtime.ratio = ratio;

    IokeObject decimal =
        new IokeObject(
            runtime,
            "An exact, unlimited representation of a decimal number",
            new Decimal(BigDecimal.ZERO));
    decimal.mimicsWithoutCheck(real);
    decimal.init();
    number.registerCell("Decimal", decimal);

    final IokeObject infinity =
        new IokeObject(runtime, "A value representing infinity", new Number(RatNum.infinity(1)));
    infinity.mimicsWithoutCheck(ratio);
    infinity.setKind("Number Infinity");
    number.registerCell("Infinity", infinity);
    runtime.infinity = infinity;

    number.registerMethod(
        runtime.newNativeMethod(
            "returns a hash for the number",
            new NativeMethod.WithNoArguments("hash") {
              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return context.runtime.newNumber(((Number) IokeObject.data(on)).value.hashCode());
              }
            }));

    number.registerMethod(
        runtime.newNativeMethod(
            "returns true if the left hand side number is equal to the right hand side number.",
            new TypeCheckingNativeMethod("==") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(runtime.number)
                      .withRequiredPositional("other")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject self,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context, message, on, args, new HashMap<String, Object>());
                Number d = (Number) IokeObject.data(on);
                Object other = args.get(0);
                return ((other instanceof IokeObject)
                        && (IokeObject.data(other) instanceof Number)
                        && (((d.kind || ((Number) IokeObject.data(other)).kind)
                            ? on == other
                            : d.value.equals(((Number) IokeObject.data(other)).value))))
                    ? context.runtime._true
                    : context.runtime._false;
              }
            }));

    rational.registerMethod(
        runtime.newNativeMethod(
            "compares this number against the argument, returning -1, 0 or 1 based on which one is larger. if the argument is a decimal, the receiver will be converted into a form suitable for comparing against a decimal, and then compared - it's not specified whether this will actually call Decimal#<=> or not. if the argument is neither a Rational nor a Decimal, it tries to call asRational, and if that doesn't work it returns nil.",
            new TypeCheckingNativeMethod("<=>") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(rational)
                      .withRequiredPositional("other")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (data instanceof Decimal) {
                  return context.runtime.newNumber(
                      Number.value(on).asBigDecimal().compareTo(Decimal.value(arg)));
                } else {
                  if (!(data instanceof Number)) {
                    arg = IokeObject.convertToRational(arg, message, context, false);
                    if (!(IokeObject.data(arg) instanceof Number)) {
                      // Can't compare, so bail out
                      return context.runtime.nil;
                    }
                  }

                  if (on == rational
                      || arg == rational
                      || on == integer
                      || arg == integer
                      || on == ratio
                      || arg == ratio) {
                    if (arg == on) {
                      return context.runtime.newNumber(0);
                    }
                    return context.runtime.nil;
                  }

                  return context.runtime.newNumber(
                      IntNum.compare(Number.value(on), Number.value(arg)));
                }
              }
            }));

    number.registerMethod(
        runtime.newNativeMethod(
            "compares this against the argument. should be overridden - in this case only used to check for equivalent number kinds",
            new NativeMethod("==") {
              private final DefaultArgumentsDefinition ARGUMENTS =
                  DefaultArgumentsDefinition.builder()
                      .withRequiredPositional("other")
                      .getArguments();

              @Override
              public DefaultArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                List<Object> args = new ArrayList<Object>();
                getArguments()
                    .getEvaluatedArguments(
                        context, message, on, args, new HashMap<String, Object>());

                Object arg = args.get(0);
                if (on == arg) {
                  return context.runtime._true;
                } else {
                  return context.runtime._false;
                }
              }
            }));

    rational.registerMethod(
        runtime.newNativeMethod(
            "compares this number against the argument, true if this number is the same, otherwise false",
            new TypeCheckingNativeMethod("==") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(number)
                      .withRequiredPositional("other")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);
                if (on == rational
                    || arg == rational
                    || on == integer
                    || arg == integer
                    || on == ratio
                    || arg == ratio
                    || on == infinity
                    || arg == infinity) {
                  if (arg == on) {
                    return context.runtime._true;
                  }
                  return context.runtime._false;
                }
                if (IokeObject.data(arg) instanceof Decimal) {
                  return (Number.value(on).asBigDecimal().compareTo(Decimal.value(arg)) == 0)
                      ? context.runtime._true
                      : context.runtime._false;
                } else if (IokeObject.data(arg) instanceof Number) {
                  return IntNum.compare(Number.value(on), Number.value(arg)) == 0
                      ? context.runtime._true
                      : context.runtime._false;
                } else {
                  return context.runtime._false;
                }
              }
            }));

    rational.registerMethod(
        runtime.newNativeMethod(
            "returns the difference between this number and the argument. if the argument is a decimal, the receiver will be converted into a form suitable for subtracting against a decimal, and then subtracted. if the argument is neither a Rational nor a Decimal, it tries to call asRational, and if that fails it signals a condition.",
            new TypeCheckingNativeMethod("-") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(number)
                      .withRequiredPositional("subtrahend")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (data instanceof Decimal) {
                  return ((Message) IokeObject.data(context.runtime.minusMessage))
                      .sendTo(
                          context.runtime.minusMessage,
                          context,
                          context.runtime.newDecimal(((Number) IokeObject.data(on))),
                          arg);
                } else {
                  if (!(data instanceof Number)) {
                    arg = IokeObject.convertToRational(arg, message, context, true);
                  }

                  return context.runtime.newNumber(
                      (RatNum) Number.value(on).sub(Number.value(arg)));
                }
              }
            }));

    rational.registerMethod(
        runtime.newNativeMethod(
            "returns the addition of this number and the argument. if the argument is a decimal, the receiver will be converted into a form suitable for addition against a decimal, and then added. if the argument is neither a Rational nor a Decimal, it tries to call asRational, and if that fails it signals a condition.",
            new TypeCheckingNativeMethod("+") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(number)
                      .withRequiredPositional("addend")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (data instanceof Decimal) {
                  return ((Message) IokeObject.data(context.runtime.plusMessage))
                      .sendTo(
                          context.runtime.plusMessage,
                          context,
                          context.runtime.newDecimal(((Number) IokeObject.data(on))),
                          arg);
                } else {
                  if (!(data instanceof Number)) {
                    arg = IokeObject.convertToRational(arg, message, context, true);
                  }

                  return context.runtime.newNumber(
                      RatNum.add(Number.value(on), Number.value(arg), 1));
                }
              }
            }));

    rational.registerMethod(
        runtime.newNativeMethod(
            "returns the product of this number and the argument. if the argument is a decimal, the receiver will be converted into a form suitable for multiplying against a decimal, and then multiplied. if the argument is neither a Rational nor a Decimal, it tries to call asRational, and if that fails it signals a condition.",
            new TypeCheckingNativeMethod("*") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(number)
                      .withRequiredPositional("multiplier")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (data instanceof Decimal) {
                  return ((Message) IokeObject.data(context.runtime.multMessage))
                      .sendTo(
                          context.runtime.multMessage,
                          context,
                          context.runtime.newDecimal(((Number) IokeObject.data(on))),
                          arg);
                } else {
                  if (!(data instanceof Number)) {
                    arg = IokeObject.convertToRational(arg, message, context, true);
                  }

                  return context.runtime.newNumber(
                      RatNum.times(Number.value(on), Number.value(arg)));
                }
              }
            }));

    rational.registerMethod(
        runtime.newNativeMethod(
            "returns the quotient of this number and the argument. if the division is not exact, it will return a Ratio.",
            new TypeCheckingNativeMethod("/") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(number)
                      .withRequiredPositional("dividend")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  final IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (data instanceof Decimal) {
                  return ((Message) IokeObject.data(context.runtime.divMessage))
                      .sendTo(
                          context.runtime.divMessage,
                          context,
                          context.runtime.newDecimal(((Number) IokeObject.data(on))),
                          arg);
                } else {
                  if (!(data instanceof Number)) {
                    arg = IokeObject.convertToRational(arg, message, context, true);
                  }

                  while (Number.value(arg).isZero()) {
                    final IokeObject condition =
                        IokeObject.as(
                                IokeObject.getCellChain(
                                    context.runtime.condition,
                                    message,
                                    context,
                                    "Error",
                                    "Arithmetic",
                                    "DivisionByZero"),
                                context)
                            .mimic(message, context);
                    condition.setCell("message", message);
                    condition.setCell("context", context);
                    condition.setCell("receiver", on);

                    final Object[] newCell = new Object[] {arg};

                    context.runtime.withRestartReturningArguments(
                        new RunnableWithControlFlow() {
                          public void run() throws ControlFlow {
                            context.runtime.errorCondition(condition);
                          }
                        },
                        context,
                        new Restart.ArgumentGivingRestart("useValue") {
                          public List<String> getArgumentNames() {
                            return new ArrayList<String>(Arrays.asList("newValue"));
                          }

                          public IokeObject invoke(IokeObject c2, List<Object> arguments)
                              throws ControlFlow {
                            newCell[0] = arguments.get(0);
                            return c2.runtime.nil;
                          }
                        });

                    arg = newCell[0];
                  }

                  return context.runtime.newNumber(
                      RatNum.divide(Number.value(on), Number.value(arg)));
                }
              }
            }));

    integer.registerMethod(
        runtime.newNativeMethod(
            "returns the modulo of this number and the argument",
            new TypeCheckingNativeMethod("%") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(integer)
                      .withRequiredPositional("dividend")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (!(data instanceof Number)) {
                  arg = IokeObject.convertToRational(arg, message, context, true);
                }

                return context.runtime.newNumber(
                    IntNum.modulo(Number.intValue(on), Number.intValue(arg)));
              }
            }));

    rational.registerMethod(
        runtime.newNativeMethod(
            "returns this number to the power of the argument",
            new TypeCheckingNativeMethod("**") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(rational)
                      .withRequiredPositional("exponent")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (!(data instanceof Number)) {
                  arg = IokeObject.convertToRational(arg, message, context, true);
                }

                return context.runtime.newNumber(
                    (RatNum) Number.value(on).power(Number.intValue(arg)));
              }
            }));

    integer.registerMethod(
        runtime.newNativeMethod(
            "returns this number bitwise and the argument",
            new TypeCheckingNativeMethod("&") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(integer)
                      .withRequiredPositional("other")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (!(data instanceof Number)) {
                  arg = IokeObject.convertToRational(arg, message, context, true);
                }

                return context.runtime.newNumber(
                    BitOps.and(Number.intValue(on), Number.intValue(arg)));
              }
            }));

    integer.registerMethod(
        runtime.newNativeMethod(
            "returns this number bitwise or the argument",
            new TypeCheckingNativeMethod("|") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(integer)
                      .withRequiredPositional("other")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (!(data instanceof Number)) {
                  arg = IokeObject.convertToRational(arg, message, context, true);
                }

                return context.runtime.newNumber(
                    BitOps.ior(Number.intValue(on), Number.intValue(arg)));
              }
            }));

    integer.registerMethod(
        runtime.newNativeMethod(
            "returns this number bitwise xor the argument",
            new TypeCheckingNativeMethod("^") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(integer)
                      .withRequiredPositional("other")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (!(data instanceof Number)) {
                  arg = IokeObject.convertToRational(arg, message, context, true);
                }

                return context.runtime.newNumber(
                    BitOps.xor(Number.intValue(on), Number.intValue(arg)));
              }
            }));

    integer.registerMethod(
        runtime.newNativeMethod(
            "returns this number left shifted by the argument",
            new TypeCheckingNativeMethod("<<") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(integer)
                      .withRequiredPositional("other")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (!(data instanceof Number)) {
                  arg = IokeObject.convertToRational(arg, message, context, true);
                }

                return context.runtime.newNumber(
                    IntNum.shift(Number.intValue(on), Number.intValue(arg).intValue()));
              }
            }));

    integer.registerMethod(
        runtime.newNativeMethod(
            "returns this number right shifted by the argument",
            new TypeCheckingNativeMethod(">>") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(integer)
                      .withRequiredPositional("other")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Object arg = args.get(0);

                IokeData data = IokeObject.data(arg);

                if (!(data instanceof Number)) {
                  arg = IokeObject.convertToRational(arg, message, context, true);
                }

                return context.runtime.newNumber(
                    IntNum.shift(Number.intValue(on), -Number.intValue(arg).intValue()));
              }
            }));

    rational.registerMethod(
        runtime.newNativeMethod(
            "Returns a text representation of the object",
            new NativeMethod.WithNoArguments("asText") {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return runtime.newText(on.toString());
              }
            }));

    rational.registerMethod(
        obj.runtime.newNativeMethod(
            "Returns a text inspection of the object",
            new TypeCheckingNativeMethod.WithNoArguments("inspect", number) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return method.runtime.newText(Number.getInspect(on));
              }
            }));

    rational.registerMethod(
        obj.runtime.newNativeMethod(
            "Returns a brief text inspection of the object",
            new TypeCheckingNativeMethod.WithNoArguments("notice", number) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return method.runtime.newText(Number.getInspect(on));
              }
            }));

    integer.registerMethod(
        runtime.newNativeMethod(
            "Returns the successor of this number",
            new TypeCheckingNativeMethod.WithNoArguments("succ", integer) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return runtime.newNumber(IntNum.add(Number.intValue(on), IntNum.one()));
              }
            }));

    integer.registerMethod(
        runtime.newNativeMethod(
            "Returns the predecessor of this number",
            new TypeCheckingNativeMethod.WithNoArguments("pred", integer) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return runtime.newNumber(IntNum.sub(Number.intValue(on), IntNum.one()));
              }
            }));

    infinity.registerMethod(
        obj.runtime.newNativeMethod(
            "Returns a text inspection of the object",
            new TypeCheckingNativeMethod.WithNoArguments("inspect", infinity) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return method.runtime.newText("Infinity");
              }
            }));

    infinity.registerMethod(
        obj.runtime.newNativeMethod(
            "Returns a brief text inspection of the object",
            new TypeCheckingNativeMethod.WithNoArguments("notice", infinity) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return method.runtime.newText("Infinity");
              }
            }));

    integer.registerMethod(
        runtime.newNativeMethod(
            "Expects one or two arguments. If one argument is given, executes it as many times as the value of the receiving number. If two arguments are given, the first will be an unevaluated name that will receive the current loop value on each repitition. the iteration length is limited to the positive maximum of a Java int",
            new NativeMethod("times") {
              private final DefaultArgumentsDefinition ARGUMENTS =
                  DefaultArgumentsDefinition.builder()
                      .withRequiredPositionalUnevaluated("argumentNameOrCode")
                      .withOptionalPositionalUnevaluated("code")
                      .getArguments();

              @Override
              public DefaultArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments().checkArgumentCount(context, message, on);

                int num =
                    Number.value(context.runtime.integer.convertToThis(on, message, context))
                        .intValue();
                switch (message.getArgumentCount()) {
                  case 0:
                    return runtime.nil;
                  case 1:
                    {
                      Object result = runtime.nil;
                      while (num > 0) {
                        result =
                            ((Message) IokeObject.data(message))
                                .getEvaluatedArgument(message, 0, context);
                        num--;
                      }
                      return result;
                    }
                  default:
                    int ix = 0;
                    String name = ((IokeObject) Message.getArg1(message)).getName();
                    Object result = runtime.nil;
                    while (ix < num) {
                      context.setCell(name, runtime.newNumber(IntNum.make(ix)));
                      result =
                          ((Message) IokeObject.data(message))
                              .getEvaluatedArgument(message, 1, context);
                      ix++;
                    }
                    return result;
                }
              }
            }));
  }
Ejemplo n.º 3
0
  public void init() throws ControlFlow {
    Base.init(base);
    DefaultBehavior.init(defaultBehavior);
    Mixins.init(mixins);
    system.init();
    Runtime.initRuntime(runtime);
    message.init();
    Ground.init(iokeGround, ground);
    Origin.init(origin);
    nil.init();
    _true.init();
    _false.init();
    text.init();
    symbol.init();
    number.init();
    range.init();
    pair.init();
    tuple.init();
    dateTime.init();
    lexicalContext.init();
    list.init();
    dict.init();
    set.init();
    call.init();
    Locals.init(locals);
    Condition.init(condition);
    Rescue.init(rescue);
    Handler.init(handler);
    io.init();
    FileSystem.init(fileSystem);
    regexp.init();
    JavaGround.init(javaGround);
    JavaArray.init(javaArray);
    javaWrapper.init();

    iokeGround.mimicsWithoutCheck(defaultBehavior);
    iokeGround.mimicsWithoutCheck(base);
    ground.mimicsWithoutCheck(iokeGround);
    ground.mimicsWithoutCheck(javaGround);
    origin.mimicsWithoutCheck(ground);

    mixins.mimicsWithoutCheck(defaultBehavior);

    system.mimicsWithoutCheck(ground);
    system.mimicsWithoutCheck(defaultBehavior);
    runtime.mimicsWithoutCheck(ground);
    runtime.mimicsWithoutCheck(defaultBehavior);

    nil.mimicsWithoutCheck(origin);
    _true.mimicsWithoutCheck(origin);
    _false.mimicsWithoutCheck(origin);
    text.mimicsWithoutCheck(origin);
    symbol.mimicsWithoutCheck(origin);
    number.mimicsWithoutCheck(origin);
    range.mimicsWithoutCheck(origin);
    pair.mimicsWithoutCheck(origin);
    dateTime.mimicsWithoutCheck(origin);

    message.mimicsWithoutCheck(origin);
    method.mimicsWithoutCheck(origin);

    list.mimicsWithoutCheck(origin);
    dict.mimicsWithoutCheck(origin);
    set.mimicsWithoutCheck(origin);

    condition.mimicsWithoutCheck(origin);
    rescue.mimicsWithoutCheck(origin);
    handler.mimicsWithoutCheck(origin);

    io.mimicsWithoutCheck(origin);

    fileSystem.mimicsWithoutCheck(origin);

    regexp.mimicsWithoutCheck(origin);

    method.init();
    defaultMethod.init();
    nativeMethod.init();
    lexicalBlock.init();
    defaultMacro.init();
    lexicalMacro.init();
    defaultSyntax.init();
    arity.init();
    call.mimicsWithoutCheck(origin);

    method.mimicsWithoutCheck(origin);
    defaultMethod.mimicsWithoutCheck(method);
    nativeMethod.mimicsWithoutCheck(method);
    defaultMacro.mimicsWithoutCheck(origin);
    lexicalMacro.mimicsWithoutCheck(origin);
    defaultSyntax.mimicsWithoutCheck(origin);
    arity.mimicsWithoutCheck(origin);
    lexicalBlock.mimicsWithoutCheck(origin);

    Restart.init(restart);
    restart.mimicsWithoutCheck(origin);

    javaWrapper.mimicsWithoutCheck(origin);

    Reflector.init(this);
    Hook.init(this);

    Sequence.init(sequence);
    iteratorSequence.init();
    keyValueIteratorSequence.init();

    addBuiltinScript(
        "benchmark",
        new Builtin() {
          public IokeObject load(Runtime runtime, IokeObject context, IokeObject message)
              throws ControlFlow {
            return ioke.lang.extensions.benchmark.Benchmark.create(runtime);
          }
        });

    addBuiltinScript(
        "readline",
        new Builtin() {
          public IokeObject load(Runtime runtime, IokeObject context, IokeObject message)
              throws ControlFlow {
            return ioke.lang.extensions.readline.Readline.create(runtime);
          }
        });

    try {
      evaluateString("use(\"builtin/A05_conditions\")", message, ground);
      evaluateString("use(\"builtin/A10_defaultBehavior\")", message, ground);
      evaluateString("use(\"builtin/A15_dmacro\")", message, ground);
      evaluateString("use(\"builtin/A20_comparing\")", message, ground);
      evaluateString("use(\"builtin/A25_defaultBehavior_inspection\")", message, ground);
      evaluateString("use(\"builtin/A30_system\")", message, ground);

      evaluateString("use(\"builtin/D05_number\")", message, ground);
      evaluateString("use(\"builtin/D10_call\")", message, ground);
      evaluateString("use(\"builtin/D15_range\")", message, ground);
      evaluateString("use(\"builtin/D20_booleans\")", message, ground);
      evaluateString("use(\"builtin/D25_list\")", message, ground);
      evaluateString("use(\"builtin/D30_dict\")", message, ground);
      evaluateString("use(\"builtin/D35_pair\")", message, ground);
      evaluateString("use(\"builtin/D37_tuple\")", message, ground);
      evaluateString("use(\"builtin/D40_text\")", message, ground);
      evaluateString("use(\"builtin/D43_regexp\")", message, ground);
      evaluateString("use(\"builtin/D45_fileSystem\")", message, ground);
      evaluateString("use(\"builtin/D50_runtime\")", message, ground);

      evaluateString("use(\"builtin/F05_case\")", message, ground);
      evaluateString("use(\"builtin/F10_comprehensions\")", message, ground);
      evaluateString("use(\"builtin/F15_message\")", message, ground);
      evaluateString("use(\"builtin/F20_set\")", message, ground);
      evaluateString("use(\"builtin/F25_cond\")", message, ground);
      evaluateString("use(\"builtin/F30_enumerable\")", message, ground);
      evaluateString("use(\"builtin/F32_sequence\")", message, ground);

      evaluateString("use(\"builtin/G05_aspects\")", message, ground);
      evaluateString("use(\"builtin/G10_origin\")", message, ground);
      evaluateString("use(\"builtin/G10_arity\")", message, ground);

      evaluateString("use(\"builtin/G50_hook\")", message, ground);

      evaluateString("use(\"builtin/H10_lexicalBlock\")", message, ground);

      evaluateString("use(\"builtin/J05_javaGround\")", message, ground);
    } catch (ControlFlow cf) {
    }
  }
Ejemplo n.º 4
0
  @Override
  public void init(IokeObject obj) throws ControlFlow {
    final Runtime runtime = obj.runtime;

    obj.setKind("Call");

    obj.registerMethod(
        runtime.newJavaMethod(
            "returns a list of all the unevaluated arguments",
            new TypeCheckingJavaMethod.WithNoArguments("arguments", runtime.call) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return context.runtime.newList(((Call) IokeObject.data(on)).message.getArguments());
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "returns the ground of the place this call originated",
            new TypeCheckingJavaMethod.WithNoArguments("ground", runtime.call) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());

                return ((Call) IokeObject.data(on)).surroundingContext;
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "returns the receiver of the call",
            new TypeCheckingJavaMethod.WithNoArguments("receiver", runtime.call) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());

                return ((Call) IokeObject.data(on)).on;
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "returns the currently executing context",
            new TypeCheckingJavaMethod.WithNoArguments("currentContext", runtime.call) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());

                return ((Call) IokeObject.data(on)).ctx;
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "returns the message that started this call",
            new TypeCheckingJavaMethod.WithNoArguments("message", runtime.call) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());

                return ((Call) IokeObject.data(on)).message;
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "returns a list of the result of evaluating all the arguments to this call",
            new TypeCheckingJavaMethod.WithNoArguments("evaluatedArguments", runtime.call) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());

                return context.runtime.newList(
                    ((Call) IokeObject.data(on))
                        .message.getEvaluatedArguments(
                            ((Call) IokeObject.data(on)).surroundingContext));
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "takes one evaluated text or symbol argument and resends the current message to that method/macro on the current receiver.",
            new TypeCheckingJavaMethod("resendToMethod") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(runtime.call)
                      .withRequiredPositional("cellName")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Call c = (Call) IokeObject.data(on);
                String name = Text.getText(runtime.asText.sendTo(context, args.get(0)));
                IokeObject m = Message.copy(c.message);
                Message.setName(m, name);
                return m.sendTo(c.surroundingContext, c.on);
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "uhm. this is a strange one. really.",
            new TypeCheckingJavaMethod("resendToValue") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(runtime.call)
                      .withRequiredPositional("value")
                      .withOptionalPositional("newSelf", "nil")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Call c = (Call) IokeObject.data(on);
                Object self = c.on;
                if (args.size() > 1) {
                  self = args.get(1);
                }

                return IokeObject.getOrActivate(args.get(0), c.surroundingContext, c.message, self);
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "uhm. this one isn't too bad.",
            new TypeCheckingJavaMethod("activateValue") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(runtime.call)
                      .withRequiredPositional("value")
                      .withOptionalPositional("newSelf", "nil")
                      .withKeywordRest("valuesToAdd")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keys,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Call c = (Call) IokeObject.data(on);
                Object self = c.on;
                if (args.size() > 1) {
                  self = args.get(1);
                }

                return IokeObject.as(args.get(0), context)
                    .activateWithData(c.surroundingContext, c.message, self, keys);
              }
            }));

    obj.registerMethod(
        runtime.newJavaMethod(
            "I really ought to write documentation for these methods, but I don't know how to describe what they do.",
            new TypeCheckingJavaMethod("activateValueWithCachedArguments") {
              private final TypeCheckingArgumentsDefinition ARGUMENTS =
                  TypeCheckingArgumentsDefinition.builder()
                      .receiverMustMimic(runtime.call)
                      .withRequiredPositional("value")
                      .withOptionalPositional("newSelf", "nil")
                      .withKeywordRest("valuesToAdd")
                      .getArguments();

              @Override
              public TypeCheckingArgumentsDefinition getArguments() {
                return ARGUMENTS;
              }

              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keys,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Call c = (Call) IokeObject.data(on);
                Object self = c.on;
                if (args.size() > 1) {
                  self = args.get(1);
                }

                return IokeObject.as(args.get(0), context)
                    .activateWithCallAndData(c.surroundingContext, c.message, self, on, keys);
              }
            }));
  }
Ejemplo n.º 5
0
 public static Runtime getRuntime(PrintWriter out, Reader in, PrintWriter err) throws ControlFlow {
   Runtime r = new Runtime(out, in, err);
   r.init();
   return r;
 }