feat: restructured code

This commit is contained in:
2020-02-03 19:38:10 +01:00
parent d4b4be940c
commit f290edd40c
8 changed files with 154 additions and 130 deletions

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -1,4 +1,4 @@
from .opcodes import INSTRUCTIONS from .opcodes_names import INSTRUCTIONS
class PJVMException(ValueError): class PJVMException(ValueError):

19
pjvm/mockimpl/__init__.py Normal file
View 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
View 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
View 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
View 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

View File

@@ -1,13 +1,14 @@
import struct
import sys
from logging import getLogger from logging import getLogger
from typing import Callable, Dict, List, Optional, Tuple, Union from typing import Callable, Dict, List, Optional, Tuple, Union
from pjvm.classloader import load_class from pjvm.classloader import load_class
from pjvm.clazz import Class, Code, Method from pjvm.clazz import Class, Code, Method
from . import utils 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 .exceptions import *
from .stackframe import Frame
OPCODE_TYPE = Callable[[int, "Frame"], Tuple[int, "JObj"]] OPCODE_TYPE = Callable[[int, "Frame"], Tuple[int, "JObj"]]
OPCODE_BOUND_TYPE = Callable[["PJVirtualMachine", 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__) 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: class Opcode:
opcodes: Dict[int, OPCODE_TYPE] = {} opcodes: Dict[int, OPCODE_TYPE] = {}
vm: "PJVirtualMachine" vm: "PJVirtualMachine"
@@ -287,22 +180,6 @@ class PJVirtualMachine:
classes: Dict[str, Class] = {} 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: []): def __init__(self, classpath: []):
self.classpath = classpath self.classpath = classpath
self.instructions = Opcode.get_opcodes(self) 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[ def execute_instance_method(self, class_name: str, method_name: str, args: List[JObj], this: JObj) -> Optional[
JObj]: JObj]:
mock_class = self.mock_instance_methods.get(class_name) mock_class = mock_instance_methods.get(class_name)
if mock_class: if mock_class:
mock_method = mock_class.get(method_name) mock_method = mock_class.get(method_name)
if mock_method: if mock_method:
@@ -382,7 +259,7 @@ class PJVirtualMachine:
self.stack[-1].stack.append(return_value) self.stack[-1].stack.append(return_value)
def get_static_field(self, class_name: str, field_name: str): 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: if mock_type:
mock_field = mock_type.get(field_name) mock_field = mock_type.get(field_name)
if mock_field: if mock_field: