checkers.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 601 行 · 第 1/2 页

SCALA
601
字号
           stack.push(toTypeKind(field.tpe))         case LOAD_MODULE(module) =>           checkBool((module.isModule || module.isModuleClass),                     "Expected module: " + module + " flags: " + Flags.flagsToString(module.flags));           stack.push(toTypeKind(module.tpe));         case STORE_ARRAY_ITEM(kind) =>           checkStack(3);           (stack.pop3: @unchecked) match {             case (k, INT, ARRAY(elem)) =>                if (!(k <:< kind))                  typeError(kind, k);                if (!(k <:< elem))                  typeError(elem, k);             case (a, b, c) =>                error(" expected and array reference, and int and " + kind +                       " but " + a + ", " + b + ", " + c + " found");           }         case STORE_LOCAL(local) =>           checkLocal(local)           checkStack(1)           val actualType = stack.pop;           if (!(actualType <:< local.kind) &&                //actualType != CASE_CLASS &&               local.kind != SCALA_ALL_REF)             typeError(local.kind, actualType);         case STORE_FIELD(field, isStatic) =>           if (isStatic) {             checkStack(1);             val fieldType = toTypeKind(field.tpe);             val actualType = stack.pop;             if (!(actualType <:< fieldType))                   // && actualType != CASE_CLASS)               typeError(fieldType, actualType);           } else {             checkStack(2);             stack.pop2 match {               case (value, obj) =>                 checkField(obj, field);                 val fieldType = toTypeKind(field.tpe);                 if (fieldType != SCALA_ALL_REF && !(value <:< fieldType))                     //&& value != CASE_CLASS)                 typeError(fieldType, value);             }           }         case CALL_PRIMITIVE(primitive) =>           checkStack(instr.consumed);           primitive match {             case Negation(kind) =>               checkType(kind, BOOL, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE);               checkType(stack.pop, kind);               stack push kind;             case Test(op, kind, zero) =>               if (zero) {                 val actualType = stack.pop;                 checkType(actualType, kind);               } else                 checkBinop(kind);               stack push BOOL             case Comparison(op, kind) =>               checkType(kind, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE)               checkBinop(kind)               stack push INT             case Arithmetic(op, kind) =>               checkType(kind, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE)               if (op == NOT)                 checkType(stack.pop, kind)               else                 checkBinop(kind)               stack push kind             case Logical(op, kind) =>               checkType(kind,  BOOL, BYTE, CHAR, SHORT, INT, LONG)               checkBinop(kind)               stack push kind             case Shift(op, kind) =>               checkType(kind, BYTE, CHAR, SHORT, INT, LONG)               val (a, b) = stack.pop2               checkType(a, INT)               checkType(b, kind)               stack push kind             case Conversion(src, dst) =>               checkType(src, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE)               checkType(dst, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE)               checkType(stack.pop, src)               stack push dst             case ArrayLength(kind) =>               val arr = stack.pop               arr match {                 case ARRAY(elem) =>                   checkType(elem, kind);                 case _ =>                   error(" array reference expected, but " + arr + " found");               }               stack push INT             case StartConcat =>               stack.push(ConcatClass)             case EndConcat =>               checkType(stack.pop, ConcatClass)               stack.push(STRING)             case StringConcat(el) =>               checkType(stack.pop, el)               checkType(stack.pop, ConcatClass)               stack push ConcatClass           }         case CALL_METHOD(method, style) =>           style match {             case Dynamic =>               checkStack(1 + method.info.paramTypes.length)               checkMethodArgs(method)               checkMethod(stack.pop, method)               stack.push(toTypeKind(method.info.resultType))             case Static(onInstance) =>               if (onInstance) {                 checkStack(1 + method.info.paramTypes.length)                 checkBool(method.hasFlag(Flags.PRIVATE) || method.isConstructor,                           "Static call to non-private method.")                 checkMethodArgs(method)                 checkMethod(stack.pop, method)                 if (!method.isConstructor)                   stack.push(toTypeKind(method.info.resultType));               } else {                 checkStack(method.info.paramTypes.length);                 checkMethodArgs(method);                 stack.push(toTypeKind(method.info.resultType));               }             case SuperCall(mix) =>               checkStack(1 + method.info.paramTypes.length)               checkMethodArgs(method)               checkMethod(stack.pop, method)               stack.push(toTypeKind(method.info.resultType))           }          case NEW(kind) =>            kind match {              case REFERENCE(cls) =>                stack.push(kind)              //bq: had to change from _ to null, because otherwise would be unreachable code              case null =>                error("NEW call to non-reference type: " + kind)            }          case CREATE_ARRAY(elem, dims) =>            checkStack(dims)            stack.pop(dims) foreach (checkType(_, INT))            stack.push(ARRAY(elem))          case IS_INSTANCE(tpe) =>            val ref = stack.pop            checkBool(ref.isReferenceType || ref.isArrayType,                      "IS_INSTANCE on primitive type: " + ref)            checkBool(tpe.isReferenceType || tpe.isArrayType,                      "IS_INSTANCE to primitive type: " + tpe)            stack.push(BOOL);          case CHECK_CAST(tpe) =>            val ref = stack.pop            checkBool(ref.isReferenceType || ref.isArrayType,                      "CHECK_CAST on primitive type: " + ref)            checkBool(tpe.isReferenceType || tpe.isArrayType,                      "CHECK_CAST to primitive type: " + tpe)            stack.push(tpe);          case SWITCH(tags, labels) =>            checkType(stack.pop, INT)            checkBool(tags.length == labels.length - 1,                      "The number of tags and labels does not coincide.")            checkBool(labels forall (b => code.blocks contains b),                      "Switch target cannot be found in code.")          case JUMP(whereto) =>            checkBool(code.blocks contains whereto,                      "Jump to non-existant block " + whereto)          case CJUMP(success, failure, cond, kind) =>            checkBool(code.blocks contains success,                      "Jump to non-existant block " + success)            checkBool(code.blocks contains failure,                      "Jump to non-existant block " + failure)            checkBinop(kind)          case CZJUMP(success, failure, cond, kind) =>            checkBool(code.blocks contains success,                      "Jump to non-existant block " + success)            checkBool(code.blocks contains failure,                      "Jump to non-existant block " + failure)            checkType(stack.pop, kind)          case RETURN(kind) =>            kind match {              case UNIT => ()              case REFERENCE(_) | ARRAY(_) =>                checkStack(1)                val top = stack.pop                checkBool(top.isReferenceType || top.isArrayType,                            "" + kind + " is a reference type, but " + top + " is not");              case _ =>                checkStack(1)                val top = stack.pop                checkType(top, kind)            }          case THROW() =>            val thrown = stack.pop            checkBool(thrown.toType <:< definitions.ThrowableClass.tpe,                      "Element on top of stack should implement 'Throwable': " + thrown);            stack.push(SCALA_ALL)          case DROP(kind) =>            checkType(stack.pop, kind)          case DUP(kind) =>            val top = stack.pop            checkType(top, kind)            stack.push(top)            stack.push(top)          case MONITOR_ENTER() =>            checkStack(1)            checkBool(stack.pop.isReferenceType,                      "MONITOR_ENTER on non-reference type")          case MONITOR_EXIT() =>            checkStack(1)            checkBool(stack.pop.isReferenceType,                      "MONITOR_EXIT on non-reference type")          case BOX(kind) =>            checkStack(1)            checkType(stack.pop, kind)            stack.push(icodes.AnyRefReference)                      case UNBOX(kind) =>            checkStack(1)            stack.pop            stack.push(kind)                      case _ =>            abort("Unknown instruction: " + instr)        }      });      stack    }    //////////////// Error reporting /////////////////////////    def error(msg: String) {      Console.println(method.toString() + " in block: " + basicBlock.label)      printLastIntructions      Checkers.this.global.error("ICode checker: " + method + ": " + msg)    }    /** Prints the last 4 instructions. */    def printLastIntructions {      var printed = 0      var buf: List[Instruction] = Nil      basicBlock.traverseBackwards( (i) =>        if (i == instruction || (printed > 0 && printed < 3)) {          buf = i :: buf          printed += 1        });      buf foreach Console.println      Console.println("at: " + (buf.head.pos))    }    def error(msg: String, stack: TypeStack) {      error(msg + "\n type stack: " + stack)    }    //////////////////// Checking /////////////////////////////    /** Return true if <code>k1</code> is a subtype of any of the following     *  types.     */    def isOneOf(k1: TypeKind, kinds: TypeKind*) =      kinds.exists( k => k1 <:< k)  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?