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):

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 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: