Beispiel #1
0
		AST::Value CallValue(Context& context, AST::Value rawValue, HeapArray<AST::Value> args, const Debug::SourceLocation& location) {
			auto value = derefValue(std::move(rawValue));
			
			if (getDerefType(value.type())->isTypename()) {
				return CallValue(context, GetStaticMethod(context, std::move(value), context.getCString("create"), location), std::move(args), location);
			}
			
			if (!value.type()->isCallable()) {
				// Try to use 'call' method.
				if (TypeCapabilities(context).hasCallMethod(getDerefType(value.type()))) {
					return CallValue(context, GetMethod(context, std::move(value),
					                                    context.getCString("call"), location),
					                 std::move(args), location);
				} else {
					context.issueDiag(TypeNotCallableDiag(getDerefType(value.type())),
					                  location);
					return AST::Value::Constant(Constant::Integer(0), context.typeBuilder().getIntType());
				}
			}
			
			const auto functionType = value.type()->asFunctionType();
			const auto& typeList = functionType.parameterTypes();
			
			if (functionType.attributes().isVarArg()) {
				if (args.size() < typeList.size()) {
					context.issueDiag(VarArgTooFewArgsDiag(value.toDiagString(),
					                                       args.size(), typeList.size()),
					                  location);
				}
			} else {
				if (args.size() != typeList.size()) {
					context.issueDiag(CallIncorrectArgCountDiag(value.toDiagString(),
					                                            args.size(), typeList.size()),
					                  location);
				}
			}
			
			if (!TypeCapabilities(context).isSized(functionType.returnType())) {
				// TODO: also check that the type is not abstract.
				context.issueDiag(CallReturnTypeIsUnsizedDiag(functionType.returnType()),
				                  location);
			}
			
			if (functionType.returnType()->hasConst()) {
				context.issueDiag(CallReturnTypeIsConstDiag(functionType.returnType()),
						  location);
			}
			
			return addDebugInfo(AST::Value::Call(std::move(value), CastFunctionArguments(context, std::move(args), typeList, location),
							     functionType.returnType()->stripConst()), location);
		}
Beispiel #2
0
bool ScriptInterpreter::execOpcode(byte opcode) {

	debugCN(kDebugScript, "opcode = %d (%s)\n", opcode, opcodeNames[opcode]);

	ScriptValue value1, value2, value3;
	uint32 temp;

	/* TODO: Put all opcodes into separate functions and into an array
			 (but only after all needed opcodes are known and frozen)
	*/

	switch (opcode) {

	case opRet:
		return false;

	case opPush:
		loadValue(value1);
		derefValue(value1);
		push(value1);
		return true;

	case opPush0:
		push(ScriptValue(0));
		return true;

	case opPush1:
		push(ScriptValue(1));
		return true;

	case opPushNeg1:
		push(ScriptValue(-1));
		return true;

	case opPop:
		loadValue(value1);
		pop(value2);
		copyValue(value1, value2);
		return true;

	case opMov:
		loadValue(value1);
		loadValue(value2);
		derefValue(value2);
		copyValue(value1, value2);
		return true;

	// Possibly join all jump variants into one opcode

	case opJmp:
		temp = _runningFunction->readUint32();
		debugCN(kDebugScript, "-> ofs = %08X\n", temp);
		_runningFunction->jumpAbsolute(temp);
		return true;

	case opJl:
		temp = _runningFunction->readUint32();
		if (_cmpFlags < 0) {
			debugCN(kDebugScript, "-> ofs = %08X\n", temp);
			_runningFunction->jumpAbsolute(temp);
		}
		return true;

	case opJle:
		temp = _runningFunction->readUint32();
		if (_cmpFlags <= 0) {
			debugCN(kDebugScript, "-> ofs = %08X\n", temp);
			_runningFunction->jumpAbsolute(temp);
		}
		return true;

	case opJg:
		temp = _runningFunction->readUint32();
		if (_cmpFlags > 0) {
			debugCN(kDebugScript, "-> ofs = %08X\n", temp);
			_runningFunction->jumpAbsolute(temp);
		}
		return true;

	case opJge:
		temp = _runningFunction->readUint32();
		if (_cmpFlags >= 0) {
			debugCN(kDebugScript, "-> ofs = %08X\n", temp);
			_runningFunction->jumpAbsolute(temp);
		}
		return true;

	case opJz:
		temp = _runningFunction->readUint32();
		if (_cmpFlags == 0) {
			debugCN(kDebugScript, "-> ofs = %08X\n", temp);
			_runningFunction->jumpAbsolute(temp);
		}
		return true;

	case opJnz:
		temp = _runningFunction->readUint32();
		if (_cmpFlags != 0) {
			debugCN(kDebugScript, "-> ofs = %08X\n", temp);
			_runningFunction->jumpAbsolute(temp);
		}
		return true;

	case opJmpByTable:
		temp = _runningFunction->readUint32();
		debugCN(kDebugScript, "-> index = %d\n", _registers[0].value);
		_runningFunction->jumpRelative(_registers[0].value * 4);
		temp = _runningFunction->readUint32();
		debugCN(kDebugScript, "-> ofs = %08X\n", temp);
		_runningFunction->jumpAbsolute(temp);
		return true;

	case opCmp:
		loadValue(value1);
		loadValue(value2);
		derefValue(value1);
		derefValue(value2);
		if (value1.type != kInteger || value2.type != kInteger)
			warning("ScriptInterpreter::execOpcode() Trying to compare non-integer values (%d, %d, line %d)", value1.type, value2.type, _lineNum);
		_cmpFlags = value1.value - value2.value;
		debugCN(kDebugScript, "-> cmp %d, %d\n", value1.value, value2.value);
		debugCN(kDebugScript, "-> _cmpFlags  = %d\n", _cmpFlags);
		return true;

	case opCall:
		temp = _runningFunction->readUint32();
		callFunction(temp);
		return true;

	case opCallKernel:
		temp = _runningFunction->readUint32();
		callKernelFunction(temp);
		return true;

	case opInc:
		loadValue(value1);
		value2 = value1;
		derefValue(value2);
		value2.value++;
		copyValue(value1, value2);
		return true;

	case opDec:
		loadValue(value1);
		value2 = value1;
		derefValue(value2);
		value2.value--;
		copyValue(value1, value2);
		return true;

	case opAdd:
		loadValue(value1);
		value3 = value1;
		loadValue(value2);
		derefValue(value3);
		derefValue(value2);
		value3.value += value2.value;
		copyValue(value1, value3);
		return true;

	case opSub:
		loadValue(value1);
		value3 = value1;
		loadValue(value2);
		derefValue(value3);
		derefValue(value2);
		value3.value -= value2.value;
		copyValue(value1, value3);
		return true;

	case opDebug:
		_lineNum = (int)_runningFunction->readUint32();
		return true;

	default:
		debugCN(kDebugScript, "Invalid opcode %d!\n", opcode);
		return false;

	}

}