📄 getnamedpart.java
字号:
package gnu.kawa.functions;import gnu.bytecode.*;import gnu.mapping.*;import gnu.kawa.reflect.*;import gnu.expr.*;import java.io.*;import kawa.lang.Translator;/** Procedure to get the value of a named component of an object. */public class GetNamedPart extends Procedure2 implements HasSetter, CanInline{ public static final GetNamedPart getNamedPart = new GetNamedPart(); /** PREFIX:<> is equivalent to the ClassType bound to PREFIX. */ public static final String CLASSTYPE_FOR = "<>"; /** Pseudo-method-name for the cast operation. */ public static final String CAST_METHOD_NAME = "@"; /** Pseudo-method-name for class-membership-test (instanceof) operation. */ public static final String INSTANCEOF_METHOD_NAME = "instance?"; public static String combineName (Expression part1, Expression part2) { String name1; Object name2; if (part2 instanceof QuoteExp && (name2 = ((QuoteExp) part2).getValue()) instanceof String && ((part1 instanceof ReferenceExp && (name1 = ((ReferenceExp) part1).getSimpleName()) != null) || (part1 instanceof GetNamedExp && (name1 = ((GetNamedExp) part1).combinedName) != null))) return (name1+':'+name2).intern(); return null; } public static Expression makeExp (Expression clas, Expression member) { ReferenceExp rexp; String combinedName = combineName(clas, member); Environment env = Environment.getCurrent(); if (combinedName != null) { Translator tr = (Translator) Compilation.getCurrent(); Declaration decl = tr.lexical.lookup(combinedName, false/*FIXME*/); if (! Declaration.isUnknown(decl)) return new ReferenceExp(decl); Symbol symbol = env.defaultNamespace().lookup(combinedName); Object property = null; // FIXME? if (symbol != null && env.isBound(symbol, property)) return new ReferenceExp(combinedName); } if (clas instanceof ReferenceExp && (rexp = (ReferenceExp) clas).isUnknown()) { Object rsym = rexp.getSymbol(); Symbol sym = rsym instanceof Symbol ? (Symbol) rsym : env.getSymbol(rsym.toString()); if (env.get(sym, null) == null) { String name = rexp.getName(); try { Class cl = ClassType.getContextClass(name); clas = QuoteExp.getInstance(Type.make(cl)); } catch (Throwable ex) { } } } Expression[] args = { clas, member }; GetNamedExp exp = new GetNamedExp(args); exp.combinedName = combinedName; return exp; } public static Expression makeExp (Expression clas, String member) { return makeExp(clas, new QuoteExp(member)); } public static Expression makeExp (Type type, String member) { return makeExp(new QuoteExp(type), new QuoteExp(member)); } public Expression inline (ApplyExp exp, ExpWalker walker) { Expression[] args = exp.getArgs(); if (args.length != 2 || ! (args[1] instanceof QuoteExp) || ! (exp instanceof GetNamedExp)) return exp; Expression context = args[0]; Declaration decl = null; if (context instanceof ReferenceExp) { ReferenceExp rexp = (ReferenceExp) context; if ("*".equals(rexp.getName())) return GetNamedInstancePart.makeExp(args[1]); decl = rexp.getBinding(); } String mname = ((QuoteExp) args[1]).getValue().toString(); Type type = context.getType(); boolean isInstanceOperator = context == QuoteExp.nullExp; Compilation comp = walker.getCompilation(); Language language = comp.getLanguage(); Type typeval = language.getTypeFor(context, false); ClassType caller = comp == null ? null : comp.curClass != null ? comp.curClass : comp.mainClass; GetNamedExp nexp = (GetNamedExp) exp; if (typeval instanceof Type) { if (mname.equals(CLASSTYPE_FOR)) return new QuoteExp(typeval); if (typeval instanceof ObjectType) { if (mname.equals("new")) return nexp.setProcedureKind('N'); if (mname.equals(INSTANCEOF_METHOD_NAME)) return nexp.setProcedureKind('I'); if (mname.equals(CAST_METHOD_NAME)) return nexp.setProcedureKind('C'); } } if (typeval instanceof ClassType) { if (mname.length() > 1 && mname.charAt(0) == '.') { // The following would also work: // return nexp.setProcedureKind('D'); // However, it makes optimzing the 'setter' case harder. return new QuoteExp(new NamedPart(typeval, mname, 'D')); } if (Invoke.checkKnownClass(typeval, comp) < 0) return exp; PrimProcedure[] methods = ClassMethods.getMethods((ClassType) typeval, Compilation.mangleName(mname), '\0', caller, language); if (methods != null && methods.length > 0) { nexp.methods = methods; return nexp.setProcedureKind('S'); } ApplyExp aexp = new ApplyExp(SlotGet.staticField, args); aexp.setLine(exp); return ((InlineCalls) walker).walkApplyOnly(aexp); } if (typeval != null) { } /* if (type.isSubtype(Compilation.typeValues)) { // FIXME } */ if (type.isSubtype(Compilation.typeClassType) || type.isSubtype(Type.java_lang_Class_type)) // The container evaluates to a class (so we should look for a static // field or method), but we don't know which class at compile-time. // However, we should still optimize it somewhat, above. FIXME. return exp; if (type instanceof ObjectType) { ObjectType otype = (ObjectType) type; ClassType ctype = type instanceof ClassType ? (ClassType) type : Type.pointer_type; PrimProcedure[] methods = ClassMethods.getMethods(otype, Compilation.mangleName(mname), 'V', caller, language); if (methods != null && methods.length > 0) { nexp.methods = methods; return nexp.setProcedureKind('M'); } Member part = SlotGet.lookupMember(ctype, mname, caller); if (part != null || (mname.equals("length") && type instanceof ArrayType)) { // FIXME: future kludge to avoid re-doing SlotGet.getField. // args = new Expression[] { context, new QuoteExp(part) }); ApplyExp aexp = new ApplyExp(SlotGet.field, args); aexp.setLine(exp); return ((InlineCalls) walker).walkApplyOnly(aexp); } if (type.isSubtype(typeHasNamedParts)) { Object val; if (decl != null && (val = Declaration.followAliases(decl).getConstantValue()) != null) { HasNamedParts value = (HasNamedParts) val; if (value.isConstant(mname)) { val = value.get(mname); return QuoteExp.getInstance(val); } } return new ApplyExp(typeHasNamedParts.getDeclaredMethod("get", 1), args).setLine(exp); } } if (comp.getBooleanOption("warn-invoke-unknown-method", ! comp.immediate)) comp.error('w', "no known slot '"+mname+"' in "+type.getName()); return exp; } static final ClassType typeHasNamedParts = ClassType.make("gnu.mapping.HasNamedParts"); public Object apply2 (Object container, Object part) throws Throwable { if (container instanceof Values) { Object[] values = ((Values) container).getValues(); Values result = new Values(); for (int i = 0; i < values.length; i++) { Values.writeValues(apply2(values[i], part), result); } return result.canonicalize(); } Symbol sym; if (part instanceof Symbol) sym = (Symbol) part; else sym = Namespace.EmptyNamespace.getSymbol(part.toString().intern()); return getNamedPart(container, sym); } public static Object getTypePart (Type type, String name) throws Throwable { if (name.equals(CLASSTYPE_FOR)) return type; if (type instanceof ObjectType) { if (name.equals(INSTANCEOF_METHOD_NAME)) return new NamedPart(type, name, 'I'); if (name.equals(CAST_METHOD_NAME)) return new NamedPart(type, name, 'C'); if (name.equals("new")) return new NamedPart(type, name, 'N'); if (name.equals(".length") || (name.length() > 1 && name.charAt(0) == '.' && type instanceof ClassType)) return new NamedPart(type, name, 'D'); } if (type instanceof ClassType) { try { return gnu.kawa.reflect.SlotGet.staticField(type, name); } catch (Throwable ex) { // FIXME! } return ClassMethods.apply(ClassMethods.classMethods, type, name); } return getMemberPart(type, name); } public static Object getNamedPart (Object container, Symbol part) throws Throwable { String name = part.getName(); if (container instanceof HasNamedParts) return ((HasNamedParts) container).get(name); if (container instanceof Class) container = (ClassType) Type.make((Class) container); if (container instanceof Type) return getTypePart((Type) container, name); return getMemberPart(container, part.toString()); } public static Object getMemberPart(Object container, String name) throws Throwable { try { return gnu.kawa.reflect.SlotGet.field(container, name); } catch (Throwable ex) { // FIXME! } MethodProc methods = ClassMethods.apply((ClassType) ClassType.make(container.getClass()), Compilation.mangleName(name), '\0', Language.getDefaultLanguage()); if (methods != null) return new NamedPart(container, name, 'M', methods); throw new RuntimeException("no part '"+name+"' in "+container); } public Procedure getSetter() { return SetNamedPart.setNamedPart; }}class GetNamedExp extends ApplyExp{ /* * 'N' - new (make) - if methodName is "new". * 'I' - instance of - if methodName is INSTANCEOF_METHOD_NAME. * 'C' - cast - if methodName is CAST_METHOD_NAME. * 'T' - type - if methodName is CLASSTYPE_FOR * 'M' - non-static method * 'S' - static method * 'D' - if methodname starts with '.' */ char kind; PrimProcedure[] methods; public String combinedName; public void apply (CallContext ctx) throws Throwable { if (combinedName != null) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -