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 + -
显示快捷键?