prog8/python/il65/codegen/tinyvm/generate.py
2018-08-07 22:49:01 +02:00

92 lines
3.7 KiB
Python

"""
Programming Language for 6502/6510 microprocessors, codename 'Sick'
This is the tinyvm stack based program generator.
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
"""
# @todo
import os
import datetime
import pickle
from typing import BinaryIO, List, Tuple, Dict, Optional
from ..shared import CodeGenerationError, sanitycheck
from ...plyparse import Module, Block, Scope, VarDef, Expression, LiteralValue
from ...datatypes import VarType, DataType
import tinyvm.core
import tinyvm.program
class AssemblyGenerator:
def __init__(self, module: Module, enable_floats: bool) -> None:
self.module = module
self.floats_enabled = enable_floats
def generate(self, filename: str) -> None:
with open(filename+".pickle", "wb") as stream:
self._generate(stream)
def _generate(self, out: BinaryIO) -> None:
sanitycheck(self.module)
program = self.header()
program.blocks = self.blocks(self.module.nodes[0], None) # type: ignore
pickle.dump(program, out, pickle.HIGHEST_PROTOCOL)
def header(self) -> tinyvm.program.Program:
return tinyvm.program.Program([])
def blocks(self, scope: Scope, parentblock_vm: Optional[tinyvm.program.Block]) -> List[tinyvm.program.Block]:
blocks = []
for node in scope.nodes:
if isinstance(node, Block):
variables = self.make_vars(node)
labels, instructions = self.make_instructions(node)
vmblock = tinyvm.program.Block(node.name, parentblock_vm, variables, instructions, labels)
print(vmblock)
blocks.append(vmblock)
vmblock.blocks = self.blocks(node.nodes[0], vmblock) # type: ignore
return blocks
def make_vars(self, block: Block) -> List[tinyvm.program.Variable]:
variables = []
for vardef in block.all_nodes(VarDef):
assert isinstance(vardef, VarDef)
dtype = self.translate_datatype(vardef.datatype)
value = self.translate_value(vardef.value, dtype)
if vardef.vartype == VarType.CONST:
const = True
elif vardef.vartype == VarType.VAR:
const = False
else:
raise CodeGenerationError("unsupported vartype", vardef.vartype)
variables.append(tinyvm.program.Variable(vardef.name, dtype, value, const))
return variables
def make_instructions(self, block: Block) -> Tuple[Dict[str, tinyvm.program.Instruction], List[tinyvm.program.Instruction]]:
# returns a dict with the labels (named instruction pointers),
# and a list of the program instructions.
return {}, []
def translate_datatype(self, datatype: DataType) -> tinyvm.core.DataType:
table = {
DataType.BYTE: tinyvm.core.DataType.BYTE,
DataType.WORD: tinyvm.core.DataType.WORD,
DataType.FLOAT: tinyvm.core.DataType.FLOAT,
DataType.BYTEARRAY: tinyvm.core.DataType.ARRAY_BYTE,
DataType.WORDARRAY: tinyvm.core.DataType.ARRAY_WORD,
DataType.MATRIX: tinyvm.core.DataType.MATRIX_BYTE
}
dt = table.get(datatype, None)
if dt:
return dt
raise CodeGenerationError("unsupported datatype", datatype)
def translate_value(self, expr: Expression, dtypehint: Optional[tinyvm.core.DataType]) -> tinyvm.program.Value:
if isinstance(expr, LiteralValue):
dtype = dtypehint or tinyvm.core.DataType.guess_datatype_for(expr.value)
return tinyvm.program.Value(dtype, expr.value)
else:
raise CodeGenerationError("cannot yet generate value for expression node", expr)