001: // Copyright (c) 2001 Per M.A. Bothner and Brainfood Inc.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.kawa.reflect;
005:
006: import gnu.expr.*;
007: import gnu.bytecode.*;
008: import gnu.mapping.*;
009:
010: /** Implement 'typeswitch' (as in XQuery) or 'typecase'.
011: * Usage: (typeswitch SELECTOR CASE-LAMBDA ... DEFAULT-LAMBDA)
012: * Each CASE-LAMBDA is a 1-argument MethodProc, while DEFAULT-LAMBDA
013: * is a 0-argument Procedure. Calls the first CASE-LAMBDA such that
014: * SELECTOR is a valid argument; if there is none, calls DEFAULT-LAMBDA.
015: * In the current implementation, all of CASE-LAMBDA and DEFAULT-LAMBDA
016: * must be LambdaExps, and the call must be inlined.
017: */
018:
019: public class TypeSwitch extends MethodProc implements CanInline,
020: Inlineable {
021: public static final TypeSwitch typeSwitch = new TypeSwitch(
022: "typeswitch");
023:
024: public TypeSwitch(String name) {
025: setName(name);
026: }
027:
028: public int numArgs() {
029: return 0xfffff002;
030: }
031:
032: public void apply(CallContext ctx) throws Throwable {
033: Object[] args = ctx.getArgs();
034: Object selector = args[0];
035: int n = args.length - 1;
036: for (int i = 1; i < n; i++) {
037: MethodProc caseProc = (MethodProc) args[i];
038: int m = caseProc.match1(selector, ctx);
039: if (m >= 0)
040: return;
041: }
042: Procedure defaultProc = (Procedure) args[n];
043: defaultProc.check1(selector, ctx);
044: }
045:
046: public Expression inline(ApplyExp exp, ExpWalker walker) {
047: Expression[] args = exp.getArgs();
048: for (int i = 1; i < args.length; i++) {
049: if (args[i] instanceof LambdaExp) {
050: LambdaExp lexp = (LambdaExp) args[i];
051: lexp.setInlineOnly(true);
052: lexp.returnContinuation = exp;
053: }
054: }
055: return exp;
056: }
057:
058: public void compile(ApplyExp exp, Compilation comp, Target target) {
059: Expression[] args = exp.getArgs();
060:
061: CodeAttr code = comp.getCode();
062: code.pushScope();
063: Variable selector = code.addLocal(Type.pointer_type);
064: args[0].compile(comp, Target.pushObject);
065: code.emitStore(selector);
066:
067: for (int i = 1; i < args.length;) {
068: if (i > 1)
069: code.emitElse();
070:
071: Expression arg = args[i++];
072:
073: if (arg instanceof LambdaExp) {
074: LambdaExp lambda = (LambdaExp) arg;
075: Declaration param = lambda.firstDecl();
076: Type type = param.getType();
077: if (!param.getCanRead())
078: param = null;
079: else
080: param.allocateVariable(code);
081:
082: if (type instanceof TypeValue)
083: ((TypeValue) type)
084: .emitTestIf(selector, param, comp);
085: else {
086: if (i < args.length) {
087: code.emitLoad(selector);
088: type.emitIsInstance(code);
089: code.emitIfIntNotZero();
090: }
091: if (param != null) {
092: code.emitLoad(selector);
093: param.compileStore(comp);
094: }
095: }
096: lambda.allocChildClasses(comp);
097: lambda.body.compileWithPosition(comp, target);
098: } else {
099: throw new Error(
100: "not implemented: typeswitch arg not LambdaExp");
101: }
102: }
103: for (int i = args.length - 2; --i >= 0;)
104: code.emitFi();
105:
106: code.popScope();
107: }
108:
109: public Type getReturnType(Expression[] args) {
110: return Type.pointer_type;
111: }
112: }
|