Package com.stuffwithstuff.magpie.intrinsic

Source Code of com.stuffwithstuff.magpie.intrinsic.ReflectionMethods$Class_

package com.stuffwithstuff.magpie.intrinsic;

import java.util.Map.Entry;
import java.util.Set;
import java.util.Map;
import java.util.TreeMap;

import com.stuffwithstuff.magpie.Def;
import com.stuffwithstuff.magpie.Doc;
import com.stuffwithstuff.magpie.ast.pattern.Pattern;
import com.stuffwithstuff.magpie.ast.pattern.RecordPattern;
import com.stuffwithstuff.magpie.interpreter.Callable;
import com.stuffwithstuff.magpie.interpreter.ClassObj;
import com.stuffwithstuff.magpie.interpreter.Context;
import com.stuffwithstuff.magpie.interpreter.Multimethod;
import com.stuffwithstuff.magpie.interpreter.DocBuilder;
import com.stuffwithstuff.magpie.interpreter.Name;
import com.stuffwithstuff.magpie.interpreter.Obj;
import com.stuffwithstuff.magpie.interpreter.PatternTester;
import com.stuffwithstuff.magpie.interpreter.Scope;

public class ReflectionMethods {
  @Def("(this) class")
  @Doc("Gets the class of the given object.")
  public static class Class_ implements Intrinsic {
    public Obj invoke(Context context, Obj left, Obj right) {
      return left.getClassObj();
    }
  }

  // TODO(bob): Come up with better name.
  @Def("(this) isa(class is Class)")
  @Doc("Returns true if this is an instance of the given class or one of\n" +
       "its subclasses.")
  public static class Is implements Intrinsic {
    public Obj invoke(Context context, Obj left, Obj right) {
      return context.toObj(left.getClassObj().isSubclassOf(
          right.asClass()));
    }
  }
 
  @Def("(this) sameAs(that)")
  @Doc("Returns true if this and that are the same object.")
  public static class Same implements Intrinsic {
    public Obj invoke(Context context, Obj left, Obj right) {
      return context.toObj(
          left == right);
    }
  }
 
  @Def("showDoc(method is String)")
  @Doc("Displays the documentation for the multimethod with the given name.")
  public static class DocMethod implements Intrinsic {
    public Obj invoke(Context context, Obj left, Obj right) {
      String name = right.asString();
     
      // TODO(bob): Hackish, but works.
      Multimethod multimethod = context.getModule().getScope()
          .lookUpMultimethod(name);
           
      if (multimethod == null) {
        System.out.println(
            "Couldn't find a method named \"" + name + "\".\n");
      } else {
        // showDoc
        // Displays the documentation for the given argument.
        //
        // showDoc(method is String)
        //   Displays the documentation for the multimethod with the given name.
        // showDoc(class is Class)
        //   Displays the documentation for the given class.
        System.out.println(new DocBuilder().append(name, multimethod).toString());
      }
     
      return context.nothing();
    }
  }
 
  @Def("showDoc(class is Class)")
  @Doc("Displays the documentation for the given class.")
  public static class ClassDoc implements Intrinsic {
    public Obj invoke(Context context, Obj left, Obj right) {
      ClassObj classObj = right.asClass();
     
      StringBuilder builder = new StringBuilder();
      builder.append(classObj.getName() + "\n");
      if (classObj.getDoc().length() > 0) {
        builder.append("| " + classObj.getDoc().replace("\n", "\n| ") + "\n");
      } else {
        builder.append("| <no doc>\n");
      }
     
      System.out.println(builder.toString());
     
      return context.nothing();
    }
  }

  private static abstract class Methods implements Intrinsic {
    public Obj invoke(final Context context, Obj left, Obj right) {
    
      final Obj matchingValue = getMatchingValueFromArgs(context, left, right);

      DocBuilder docBuilder = new DocBuilder() {

        @Override
        protected boolean shouldDisplayMethod(Callable callable) {
          return isMatchingMethod(matchingValue, context, callable);
        }
      };

      for(Entry<String, Multimethod> multimethod : findMultimethods(context, matchingValue)) {
        docBuilder.append(multimethod.getKey(), multimethod.getValue());
        docBuilder.append("\n");
      }
      System.out.println(docBuilder.toString());
     
      return context.nothing();
    }

    protected Set<Entry<String, Multimethod>> findMultimethods(Context context, Obj matchingValue) {
      Map<String, Multimethod> matching = new TreeMap<String, Multimethod>();

      Scope scope = context.getModule().getScope();
      while (scope != null) {
        for(Entry<String, Multimethod> multimethod : scope.getMultimethods().entrySet()) {
          for(Callable method : multimethod.getValue().getMethods()) {
            if(isMatchingMethod(matchingValue, context, method)) {
              matching.put(multimethod.getKey(), multimethod.getValue());
              break;
            }
          } 
        }
        scope = scope.getParent();
      }
      return matching.entrySet();
    }
 
    protected abstract Obj getMatchingValueFromArgs(Context context, Obj left, Obj right);
    protected abstract boolean isMatchingMethod(Obj value, Context context, Callable method);
  }

  @Def("(this) showMethods")
  @Doc("Displays the multimethods that can be called with this object on the left.")
  public static class MethodsFromLeft extends Methods {

    @Override
    protected Obj getMatchingValueFromArgs(Context context, Obj left, Obj right) {
      return left;
    }

    @Override
    public boolean isMatchingMethod(Obj value, Context context, Callable method) {
      Pattern leftParam = ((RecordPattern)method.getPattern()).getFields().get(Name.getTupleField(0));
      return PatternTester.test(context, leftParam, value, method.getClosure());
    }
  } 

  @Def("(this) showMethods(_)")
  @Doc("Displays the multimethods that can be called with the given arguments.")
  public static class MethodsFromArgs extends Methods {

    @Override
    protected Obj getMatchingValueFromArgs(Context context, Obj left, Obj right) {
      return context.toObj(left, right);
    }

    @Override
    public boolean isMatchingMethod(Obj value, Context context, Callable method) {
      return PatternTester.test(context, method.getPattern(), value, method.getClosure());
    }
  } 
}
TOP

Related Classes of com.stuffwithstuff.magpie.intrinsic.ReflectionMethods$Class_

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.