示例#1
0
  public static void initRuntime(IokeObject obj) throws ControlFlow {
    obj.setKind("Runtime");

    obj.registerMethod(
        obj.runtime.newNativeMethod(
            "returns the node id for the runtime it's called on",
            new TypeCheckingNativeMethod.WithNoArguments("nodeId", obj) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Runtime r = (Runtime) IokeObject.data(on);
                return method.runtime.newNumber(r.id);
              }
            }));

    obj.registerMethod(
        obj.runtime.newNativeMethod(
            "creates a new runtime and returns that. be careful using this since it will result in some fairly strange behavior if used incorrectly. it will not copy the state of this runtime, but just create a new one from scratch.",
            new TypeCheckingNativeMethod.WithNoArguments("create", obj) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                Runtime r = new Runtime(method.runtime.out, method.runtime.in, method.runtime.err);
                r.init();
                IokeObject o = method.runtime.runtime.allocateCopy(null, null);
                o.mimicsWithoutCheck(method.runtime.runtime);
                o.setData(r);
                return o;
              }
            }));
  }
示例#2
0
文件: Range.java 项目: aneeshpu/ioke
  @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));
              }
            }));
  }
示例#3
0
  @Override
  public void init(IokeObject lexicalBlock) throws ControlFlow {
    lexicalBlock.setKind("LexicalBlock");

    lexicalBlock.registerMethod(
        lexicalBlock.runtime.newNativeMethod(
            "takes two evaluated arguments, where this first one is a list of messages which will be used as the arguments and the code, and the second is the context where this lexical scope should be created in",
            new NativeMethod("createFrom") {
              private final DefaultArgumentsDefinition ARGUMENTS =
                  DefaultArgumentsDefinition.builder()
                      .withRequiredPositional("messageList")
                      .withRequiredPositional("lexicalContext")
                      .getArguments();

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

              @Override
              public Object activate(
                  IokeObject self, IokeObject dynamicContext, IokeObject message, Object on)
                  throws ControlFlow {
                Runtime runtime = dynamicContext.runtime;

                List<Object> positionalArgs = new ArrayList<Object>();
                getArguments()
                    .getEvaluatedArguments(
                        dynamicContext, message, on, positionalArgs, new HashMap<String, Object>());

                List<Object> args = IokeList.getList(positionalArgs.get(0));
                IokeObject ground = IokeObject.as(positionalArgs.get(1), dynamicContext);

                IokeObject code = IokeObject.as(args.get(args.size() - 1), dynamicContext);

                ArgumentsDefinition def =
                    DefaultArgumentsDefinition.createFrom(
                        args, 0, args.size() - 1, message, on, dynamicContext);
                return runtime.newLexicalBlock(
                    null, runtime.lexicalBlock, new LexicalBlock(ground, def, code));
              }
            }));

    lexicalBlock.registerMethod(
        lexicalBlock.runtime.newNativeMethod(
            "invokes the block with the arguments provided, returning the result of the last expression in the block",
            new NativeMethod("call") {
              private final DefaultArgumentsDefinition ARGUMENTS =
                  DefaultArgumentsDefinition.builder()
                      .withRestUnevaluated("arguments")
                      .getArguments();

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

              @Override
              public Object activate(
                  IokeObject self, IokeObject dynamicContext, IokeObject message, Object on)
                  throws ControlFlow {
                return Interpreter.activate(
                    IokeObject.as(on, dynamicContext), dynamicContext, message, on);
              }
            }));

    lexicalBlock.registerMethod(
        lexicalBlock.runtime.newNativeMethod(
            "returns the full code of this lexical block, as a Text",
            new NativeMethod.WithNoArguments("code") {
              @Override
              public Object activate(
                  IokeObject self, IokeObject dynamicContext, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        dynamicContext,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                IokeObject obj = IokeObject.as(on, dynamicContext);
                String x = obj.isActivatable() ? "x" : "";

                String args = ((LexicalBlock) IokeObject.data(on)).arguments.getCode();
                return context.runtime.newText(
                    "fn"
                        + x
                        + "("
                        + args
                        + Message.code(((LexicalBlock) IokeObject.data(on)).message)
                        + ")");
              }
            }));

    lexicalBlock.registerMethod(
        lexicalBlock.runtime.newNativeMethod(
            "returns the code for the argument definition",
            new NativeMethod.WithNoArguments("argumentsCode") {
              @Override
              public Object activate(
                  IokeObject self, IokeObject dynamicContext, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        dynamicContext,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return dynamicContext.runtime.newText(
                    ((AssociatedCode) IokeObject.data(on)).getArgumentsCode());
              }
            }));

    lexicalBlock.registerMethod(
        lexicalBlock.runtime.newNativeMethod(
            "returns a list of the keywords this block takes",
            new NativeMethod.WithNoArguments("keywords") {
              @Override
              public Object activate(
                  IokeObject self, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                List<Object> keywords = new ArrayList<Object>();

                for (String keyword :
                    ((LexicalBlock) IokeObject.data(on)).arguments.getKeywords()) {
                  keywords.add(
                      context.runtime.getSymbol(keyword.substring(0, keyword.length() - 1)));
                }

                return context.runtime.newList(keywords);
              }
            }));

    lexicalBlock.registerMethod(
        lexicalBlock.runtime.newNativeMethod(
            "returns a list of the argument names the positional arguments this block takes",
            new NativeMethod.WithNoArguments("argumentNames") {
              @Override
              public Object activate(
                  IokeObject self, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                List<Object> names = new ArrayList<Object>();

                for (DefaultArgumentsDefinition.Argument arg :
                    ((LexicalBlock) IokeObject.data(on)).arguments.getArguments()) {
                  if (!(arg instanceof DefaultArgumentsDefinition.KeywordArgument)) {
                    names.add(context.runtime.getSymbol(arg.getName()));
                  }
                }

                return context.runtime.newList(names);
              }
            }));

    lexicalBlock.registerMethod(
        lexicalBlock.runtime.newNativeMethod(
            "returns the message chain for this block",
            new NativeMethod.WithNoArguments("message") {
              @Override
              public Object activate(
                  IokeObject self, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return ((AssociatedCode) IokeObject.data(on)).getCode();
              }
            }));
    lexicalBlock.registerMethod(
        lexicalBlock.runtime.newNativeMethod(
            "Returns a text inspection of the object",
            new NativeMethod.WithNoArguments("inspect") {
              @Override
              public Object activate(
                  IokeObject self, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return context.runtime.newText(LexicalBlock.getInspect(on));
              }
            }));
    lexicalBlock.registerMethod(
        lexicalBlock.runtime.newNativeMethod(
            "Returns a brief text inspection of the object",
            new NativeMethod.WithNoArguments("notice") {
              @Override
              public Object activate(
                  IokeObject self, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return context.runtime.newText(LexicalBlock.getNotice(on));
              }
            }));
    lexicalBlock.registerMethod(
        lexicalBlock.runtime.newNativeMethod(
            "returns idiomatically formatted code for this lexical block",
            new NativeMethod.WithNoArguments("formattedCode") {
              @Override
              public Object activate(
                  IokeObject self, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                getArguments()
                    .getEvaluatedArguments(
                        context,
                        message,
                        on,
                        new ArrayList<Object>(),
                        new HashMap<String, Object>());
                return context.runtime.newText(
                    ((AssociatedCode) IokeObject.data(on)).getFormattedCode(self));
              }
            }));
  }
示例#4
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;
                }
              }
            }));
  }
示例#5
0
  @Override
  public Object activateWithData(
      final IokeObject self,
      IokeObject context,
      IokeObject message,
      Object on,
      Map<String, Object> data)
      throws ControlFlow {
    if (code == null) {
      IokeObject condition =
          IokeObject.as(
                  IokeObject.getCellChain(
                      context.runtime.condition,
                      message,
                      context,
                      "Error",
                      "Invocation",
                      "NotActivatable"),
                  context)
              .mimic(message, context);
      condition.setCell("message", message);
      condition.setCell("context", context);
      condition.setCell("receiver", on);
      condition.setCell("method", self);
      condition.setCell(
          "report",
          context.runtime.newText(
              "You tried to activate a method without any code - did you by any chance activate the DefaultMacro kind by referring to it without wrapping it inside a call to cell?"));
      context.runtime.errorCondition(condition);
      return null;
    }

    IokeObject c = context.runtime.locals.mimic(message, context);
    c.setCell("self", on);
    c.setCell("@", on);
    c.registerMethod(
        c.runtime.newJavaMethod(
            "will return the currently executing macro receiver",
            new JavaMethod.WithNoArguments("@@") {
              @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 self;
              }
            }));
    c.setCell("currentMessage", message);
    c.setCell("surroundingContext", context);
    c.setCell("call", context.runtime.newCallFrom(c, message, context, IokeObject.as(on, context)));
    for (Map.Entry<String, Object> d : data.entrySet()) {
      String s = d.getKey();
      c.setCell(s.substring(0, s.length() - 1), d.getValue());
    }

    try {
      return ((Message) IokeObject.data(code)).evaluateCompleteWith(code, c, on);
    } catch (ControlFlow.Return e) {
      if (e.context == c) {
        return e.getValue();
      } else {
        throw e;
      }
    }
  }
示例#6
0
  @Override
  public void init(IokeObject macro) throws ControlFlow {
    macro.setKind("DefaultMacro");
    macro.registerCell("activatable", macro.runtime._true);

    macro.registerMethod(
        macro.runtime.newJavaMethod(
            "returns the name of the macro",
            new TypeCheckingJavaMethod.WithNoArguments("name", macro) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return context.runtime.newText(((DefaultMacro) IokeObject.data(on)).name);
              }
            }));

    macro.registerMethod(
        macro.runtime.newJavaMethod(
            "activates this macro with the arguments given to call",
            new JavaMethod("call") {
              private final DefaultArgumentsDefinition ARGUMENTS =
                  DefaultArgumentsDefinition.builder()
                      .withRestUnevaluated("arguments")
                      .getArguments();

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

              @Override
              public Object activate(
                  IokeObject self, IokeObject context, IokeObject message, Object on)
                  throws ControlFlow {
                return IokeObject.as(on, context)
                    .activate(context, message, context.getRealContext());
              }
            }));

    macro.registerMethod(
        macro.runtime.newJavaMethod(
            "returns the message chain for this macro",
            new TypeCheckingJavaMethod.WithNoArguments("message", macro) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return ((AssociatedCode) IokeObject.data(on)).getCode();
              }
            }));

    macro.registerMethod(
        macro.runtime.newJavaMethod(
            "returns the code for the argument definition",
            new TypeCheckingJavaMethod.WithNoArguments("argumentsCode", macro) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return context.runtime.newText(
                    ((AssociatedCode) IokeObject.data(on)).getArgumentsCode());
              }
            }));

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

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

    macro.registerMethod(
        macro.runtime.newJavaMethod(
            "returns the full code of this macro, as a Text",
            new TypeCheckingJavaMethod.WithNoArguments("code", macro) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                IokeData data = IokeObject.data(on);

                if (data instanceof DefaultMacro) {
                  return context.runtime.newText(((DefaultMacro) data).getCodeString());
                } else {
                  return context.runtime.newText(((AliasMethod) data).getCodeString());
                }
              }
            }));

    macro.registerMethod(
        macro.runtime.newJavaMethod(
            "returns idiomatically formatted code for this macro",
            new TypeCheckingJavaMethod.WithNoArguments("formattedCode", macro) {
              @Override
              public Object activate(
                  IokeObject method,
                  Object on,
                  List<Object> args,
                  Map<String, Object> keywords,
                  IokeObject context,
                  IokeObject message)
                  throws ControlFlow {
                return context.runtime.newText(
                    ((AssociatedCode) IokeObject.data(on)).getFormattedCode(method));
              }
            }));
  }
示例#7
0
文件: Call.java 项目: Narnach/ioke
  @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);
              }
            }));
  }