sonnum/pysonnum/compiler.py
2025-09-20 23:53:16 +03:00

170 lines
No EOL
3.8 KiB
Python

from .sonnum import Sonnum
from .activity import Activity
from .soundnode import *
import random
class SonnumCompiler:
def __init__(self):
self.sonnum = Sonnum(self) # {order: name}
self.activities = []
def list_activities(self):
print('ACTIVITY LISTING')
for activity in self.activities:
print(activity)
def list_bytecode(self):
print('BYTECODE LISTING')
for activity in self.activities:
print(list(activity.to_bytes()))
def add_activity(self, name, tick_start, tick_end, src_node, trg_node, operands):
a = Activity(self.sonnum, name, tick_start, tick_end, src_node, trg_node, operands)
self.activities.append(a)
def transpile_snm_to_py(self, snm_src):
py_src = []
for ln in snm_src.split('\n'):
tablevel = 0
while ln.startswith('\t'):
tablevel += 1
ln = ln[1:]
if ln.startswith(';'):
if '=>' in ln:
name_src, name_trg = ln[1:].split('=>')
ln = f'self.add_activity("link", 0, 0, {name_src}, {name_trg}, [0, 1])'
elif '->' in ln:
name_src, name_trg = ln[1:].split('->')
ln = f'self.add_activity("link", 0, 0, {name_src}, {name_trg}, [0, 2])'
elif '=/>' in ln:
name_src, name_trg = ln[1:].split('=/>')
ln = f'self.add_activity("unlink", 0, 0, {name_src}, {name_trg}, [0, 1])'
elif '-/>' in ln:
name_src, name_trg = ln[1:].split('-/>')
ln = f'self.add_activity("unlink", 0, 0, {name_src}, {name_trg}, [0, 2])'
else:
ln = ln[1:]
tickdata, cmd = ln.split(' ',1)
if '-' in tickdata:
starttick, endtick = tickdata.split('-', 1)
else:
starttick = tickdata
endtick = starttick
cmdcore, cmdargs = cmd.split('(', 1)
cmdargs = cmdargs[:-1]
cmdparts = cmdcore.split('.')
operand = cmdparts.pop(-1)
nodenames = '.'.join(cmdparts)
if '>' in nodenames:
src_nodename, trg_nodename = nodenames.split('>')
else:
src_nodename = nodenames
trg_nodename = nodenames
if operand.startswith('@'):
operand = operand[1:]
ln = f'{src_nodename}.{operand}(sec({starttick}), sec({endtick}), [{cmdargs}])'
else:
ln = f'self.add_activity("{operand}", sec({starttick}), sec({endtick}), {src_nodename}, {trg_nodename}, [{cmdargs}])'
ln = tablevel*'\t' + ln
py_src.append(ln)
else:
ln = tablevel*'\t' + ln
py_src.append(ln)
print('\n'.join(py_src))
return '\n'.join(py_src)
def run_transpiled_code(self, py_src):
c = self
s = self.sonnum
exec(py_src)
def sort_activities(self):
new = []
to_delete = []
for activity in self.activities:
if activity.name == 'endtick':
new.append(activity)
to_delete.append(activity)
for activity in to_delete:
self.activities.remove(activity)
to_delete = []
for activity in self.activities:
if activity.name == 'create':
new.append(activity)
to_delete.append(activity)
for activity in to_delete:
self.activities.remove(activity)
to_delete = []
for activity in self.activities:
if activity.name in ('wire','air','pin'):
new.append(activity)
to_delete.append(activity)
for activity in to_delete:
self.activities.remove(activity)
self.activities.sort(key=lambda x: x.tick_start, reverse = False)
new.extend(self.activities)
self.activities = new
def compile_to_smnb(self, snm_src, fn):
py_src = self.transpile_snm_to_py(snm_src)
self.run_transpiled_code(py_src)
self.sort_activities()
self.list_activities()
bytecode = []
for activity in self.activities:
bytecode.append(activity.to_bytes())
with open(fn, 'wb') as fl:
fl.write(b''.join(bytecode))
#C = SonnumCompiler()
#snm = C.compile_to_smnb(TEST, '../zigsonnum/test.snmb')