feat: restructured code
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from .opcodes import INSTRUCTIONS
|
||||
from .opcodes_names import INSTRUCTIONS
|
||||
|
||||
|
||||
class PJVMException(ValueError):
|
||||
|
||||
19
pjvm/mockimpl/__init__.py
Normal file
19
pjvm/mockimpl/__init__.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from .system import JMockSystemIn, JMockSystemOut, mock_inputstream_read, mock_printstream_println
|
||||
|
||||
mock_static_objects = {
|
||||
'java/lang/System': {
|
||||
'out': JMockSystemOut(),
|
||||
'in': JMockSystemIn()
|
||||
}
|
||||
}
|
||||
|
||||
mock_instance_methods = {
|
||||
'java/io/PrintStream': {
|
||||
'println': mock_printstream_println
|
||||
},
|
||||
'java/io/InputStream': {
|
||||
'read': mock_inputstream_read
|
||||
}
|
||||
}
|
||||
|
||||
__all__ = ['mock_instance_methods', 'mock_static_objects']
|
||||
31
pjvm/mockimpl/system.py
Normal file
31
pjvm/mockimpl/system.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
In here the System module is partially implemented
|
||||
"""
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
from ..old_jtypes import JObj, JInteger
|
||||
|
||||
|
||||
class JMockSystemOut(JObj):
|
||||
type = "Ljava/io/PrintStream;"
|
||||
value = None
|
||||
|
||||
|
||||
class JMockSystemIn(JObj):
|
||||
type = "Ljava/io/InputStream;"
|
||||
value = None
|
||||
|
||||
|
||||
def mock_printstream_println(self: JObj, args: List[JObj]):
|
||||
if len(args) != 1:
|
||||
raise ValueError("Argument length mismatch")
|
||||
if args[0].type != 'java/lang/String':
|
||||
raise ValueError("Argument type mismatch")
|
||||
|
||||
print(args[0].value)
|
||||
|
||||
|
||||
def mock_inputstream_read(self: JObj, args: List[JObj]):
|
||||
character = sys.stdin.read(1).strip()
|
||||
return JInteger(ord(character))
|
||||
46
pjvm/old_jtypes.py
Normal file
46
pjvm/old_jtypes.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from typing import List
|
||||
|
||||
|
||||
class JObj:
|
||||
type = 'java/lang/Object'
|
||||
value = None
|
||||
|
||||
def instance_of(self, java_type: str):
|
||||
return self.type == java_type # todo inheritance
|
||||
|
||||
|
||||
class JInteger(JObj):
|
||||
type = "I"
|
||||
|
||||
def __init__(self, val: int):
|
||||
self.value = val
|
||||
|
||||
|
||||
class JCharacter(JObj):
|
||||
type = 'C'
|
||||
|
||||
def __init__(self, val: int):
|
||||
self.value = val
|
||||
|
||||
|
||||
class JGenericObj(JObj):
|
||||
generic_types: List[str]
|
||||
pass
|
||||
|
||||
|
||||
class JString(JObj):
|
||||
type = 'java/lang/String'
|
||||
value: str
|
||||
|
||||
def __init__(self, value: str):
|
||||
self.value = value
|
||||
|
||||
|
||||
class JArray(JGenericObj):
|
||||
type = 'java/lang/Array'
|
||||
generic_types: List[str]
|
||||
values: List
|
||||
|
||||
def __init__(self, generic_types: List[str], values: List):
|
||||
self.generic_types = generic_types
|
||||
self.values = values
|
||||
45
pjvm/stackframe.py
Normal file
45
pjvm/stackframe.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import struct
|
||||
from typing import List
|
||||
|
||||
from .clazz import Class, Method, Code
|
||||
from .exceptions import PJVMException
|
||||
from .old_jtypes import JObj
|
||||
|
||||
|
||||
class Frame:
|
||||
ip: int = 0
|
||||
clazz: Class
|
||||
method: Method
|
||||
code: Code
|
||||
stack: List[JObj]
|
||||
this: JObj
|
||||
local_variables: List
|
||||
|
||||
def __init__(self, clazz: Class, method: Method):
|
||||
self.clazz = clazz
|
||||
self.method = method
|
||||
self.code = self.method.code
|
||||
self.stack = []
|
||||
self.local_variables = [None for _ in range(self.code.max_locals)]
|
||||
|
||||
def get_byte(self, idx: int) -> int:
|
||||
return struct.unpack('>b', self.code.code[idx:idx + 1])[0]
|
||||
|
||||
def get_short(self, idx: int) -> int:
|
||||
return struct.unpack('>h', self.code.code[idx:idx + 2])[0]
|
||||
|
||||
def get_int(self, idx: int) -> int:
|
||||
return struct.unpack('>i', self.code.code[idx:idx + 4])[0]
|
||||
|
||||
def set_local(self, val: JObj, index: int):
|
||||
if index > self.code.max_locals:
|
||||
raise PJVMException("Local out of bound!")
|
||||
self.local_variables[index] = val
|
||||
|
||||
def get_local(self, index: int) ->JObj:
|
||||
if index > self.code.max_locals:
|
||||
raise PJVMException("Local out of bound!")
|
||||
val = self.local_variables[index]
|
||||
if val is None:
|
||||
raise PJVMException("Local not set")
|
||||
return val
|
||||
135
pjvm/vm.py
135
pjvm/vm.py
@@ -1,13 +1,14 @@
|
||||
import struct
|
||||
import sys
|
||||
from logging import getLogger
|
||||
from typing import Callable, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from pjvm.classloader import load_class
|
||||
from pjvm.clazz import Class, Code, Method
|
||||
from . import utils
|
||||
from .opcodes import INSTRUCTIONS
|
||||
from .mockimpl import mock_instance_methods, mock_static_objects
|
||||
from .old_jtypes import JObj, JInteger, JString, JArray
|
||||
from .opcodes_names import INSTRUCTIONS
|
||||
from .exceptions import *
|
||||
from .stackframe import Frame
|
||||
|
||||
OPCODE_TYPE = Callable[[int, "Frame"], Tuple[int, "JObj"]]
|
||||
OPCODE_BOUND_TYPE = Callable[["PJVirtualMachine", int, "Frame"], Tuple[int, "JObj"]]
|
||||
@@ -15,114 +16,6 @@ OPCODE_BOUND_TYPE = Callable[["PJVirtualMachine", int, "Frame"], Tuple[int, "JOb
|
||||
LOGGER = getLogger(__name__)
|
||||
|
||||
|
||||
class JObj:
|
||||
type = 'java/lang/Object'
|
||||
value = None
|
||||
|
||||
def instance_of(self, java_type: str):
|
||||
return self.type == java_type # todo inheritance
|
||||
|
||||
|
||||
class JInteger(JObj):
|
||||
type = "I"
|
||||
|
||||
def __init__(self, val: int):
|
||||
self.value = val
|
||||
|
||||
|
||||
class JCharacter(JObj):
|
||||
type = 'C'
|
||||
|
||||
def __init__(self, val: int):
|
||||
self.value = val
|
||||
|
||||
|
||||
class JGenericObj(JObj):
|
||||
generic_types: List[str]
|
||||
pass
|
||||
|
||||
|
||||
class JString(JObj):
|
||||
type = 'java/lang/String'
|
||||
value: str
|
||||
|
||||
def __init__(self, value: str):
|
||||
self.value = value
|
||||
|
||||
|
||||
class JArray(JGenericObj):
|
||||
type = 'java/lang/Array'
|
||||
generic_types: List[str]
|
||||
values: List
|
||||
|
||||
def __init__(self, generic_types: List[str], values: List):
|
||||
self.generic_types = generic_types
|
||||
self.values = values
|
||||
|
||||
|
||||
class JMockSystemOut(JObj):
|
||||
type = "Ljava/io/PrintStream;"
|
||||
value = None
|
||||
|
||||
|
||||
class JMockSystemIn(JObj):
|
||||
type = "Ljava/io/InputStream;"
|
||||
value = None
|
||||
|
||||
|
||||
def mock_printstream_println(self: JObj, args: List[JObj]):
|
||||
if len(args) != 1:
|
||||
raise ValueError("Argument length mismatch")
|
||||
if args[0].type != 'java/lang/String':
|
||||
raise ValueError("Argument type mismatch")
|
||||
|
||||
print(args[0].value)
|
||||
|
||||
|
||||
def mock_inputstream_read(self: JObj, args: List[JObj]):
|
||||
character = sys.stdin.read(1).strip()
|
||||
return JInteger(ord(character))
|
||||
|
||||
|
||||
class Frame:
|
||||
ip: int = 0
|
||||
clazz: Class
|
||||
method: Method
|
||||
code: Code
|
||||
stack: List[JObj]
|
||||
this: JObj
|
||||
local_variables: List
|
||||
|
||||
def __init__(self, clazz: Class, method: Method):
|
||||
self.clazz = clazz
|
||||
self.method = method
|
||||
self.code = self.method.code
|
||||
self.stack = []
|
||||
self.local_variables = [None for _ in range(self.code.max_locals)]
|
||||
|
||||
def get_byte(self, idx: int) -> int:
|
||||
return struct.unpack('>b', self.code.code[idx:idx + 1])[0]
|
||||
|
||||
def get_short(self, idx: int) -> int:
|
||||
return struct.unpack('>h', self.code.code[idx:idx + 2])[0]
|
||||
|
||||
def get_int(self, idx: int) -> int:
|
||||
return struct.unpack('>i', self.code.code[idx:idx + 4])[0]
|
||||
|
||||
def set_local(self, val: JObj, index: int):
|
||||
if index > self.code.max_locals:
|
||||
raise PJVMException("Local out of bound!")
|
||||
self.local_variables[index] = val
|
||||
|
||||
def get_local(self, index: int) ->JObj:
|
||||
if index > self.code.max_locals:
|
||||
raise PJVMException("Local out of bound!")
|
||||
val = self.local_variables[index]
|
||||
if val is None:
|
||||
raise PJVMException("Local not set")
|
||||
return val
|
||||
|
||||
|
||||
class Opcode:
|
||||
opcodes: Dict[int, OPCODE_TYPE] = {}
|
||||
vm: "PJVirtualMachine"
|
||||
@@ -287,22 +180,6 @@ class PJVirtualMachine:
|
||||
|
||||
classes: Dict[str, Class] = {}
|
||||
|
||||
mock_static_objects = {
|
||||
'java/lang/System': {
|
||||
'out': JMockSystemOut(),
|
||||
'in': JMockSystemIn()
|
||||
}
|
||||
}
|
||||
|
||||
mock_instance_methods = {
|
||||
'java/io/PrintStream': {
|
||||
'println': mock_printstream_println
|
||||
},
|
||||
'java/io/InputStream': {
|
||||
'read': mock_inputstream_read
|
||||
}
|
||||
}
|
||||
|
||||
def __init__(self, classpath: []):
|
||||
self.classpath = classpath
|
||||
self.instructions = Opcode.get_opcodes(self)
|
||||
@@ -341,7 +218,7 @@ class PJVirtualMachine:
|
||||
|
||||
def execute_instance_method(self, class_name: str, method_name: str, args: List[JObj], this: JObj) -> Optional[
|
||||
JObj]:
|
||||
mock_class = self.mock_instance_methods.get(class_name)
|
||||
mock_class = mock_instance_methods.get(class_name)
|
||||
if mock_class:
|
||||
mock_method = mock_class.get(method_name)
|
||||
if mock_method:
|
||||
@@ -382,7 +259,7 @@ class PJVirtualMachine:
|
||||
self.stack[-1].stack.append(return_value)
|
||||
|
||||
def get_static_field(self, class_name: str, field_name: str):
|
||||
mock_type = self.mock_static_objects.get(class_name, None)
|
||||
mock_type = mock_static_objects.get(class_name, None)
|
||||
if mock_type:
|
||||
mock_field = mock_type.get(field_name)
|
||||
if mock_field:
|
||||
|
||||
Reference in New Issue
Block a user