171 lines
5.9 KiB
Python
171 lines
5.9 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import importlib
|
|
|
|
from pycrate_csn1.trans import *
|
|
|
|
|
|
# local path, specifications name, python file header, python import prefix
|
|
PATH = os.path.dirname(os.path.abspath( __file__ )) + os.sep
|
|
SPECS = ['24008', '44018', '44060']
|
|
HEAD = open(PATH + 'header.txt').readlines()
|
|
IMPPREF = PATH.split(os.sep)[-2]
|
|
|
|
|
|
def build_py_path(spec, objname):
|
|
#path = (IMPPREF, spec, objname)
|
|
path = (IMPPREF, objname)
|
|
return '.'.join(path)
|
|
|
|
|
|
def process_file(spec, fn):
|
|
dbg = True
|
|
#
|
|
if dbg:
|
|
print('> %s/%s' % (spec, fn))
|
|
#
|
|
fd = open(PATH + spec + os.sep + fn)
|
|
lines = fd.readlines()
|
|
fd.close()
|
|
#
|
|
# 1) get infos (in CSN.1 comment in the 3 1st lines)
|
|
obj_name = lines[2][2:].strip()
|
|
pname = pythonize_name(obj_name)
|
|
# 2) create the header
|
|
header = HEAD[:]
|
|
header[-5] = header[-5][:-1] + pname + '.py' + '\n'
|
|
header[-4] = header[-4][:-1] + time.strftime('%Y-%m-%d') + '\n'
|
|
header.append('# specification: %s\n' % lines[0][2:].strip())
|
|
header.append('# section: %s\n' % lines[1][2:].strip())
|
|
header.append('# top-level object: %s\n' % obj_name)
|
|
#
|
|
# 3) compile the CSN.1 text
|
|
try:
|
|
objs, externs, pycode = translate_text(''.join(lines[3:]))
|
|
except Exception as exc:
|
|
print(' [ERR] %s/%s: unable to translate' % (spec, fn))
|
|
print(' Exception: %s' % exc)
|
|
raise(Exception('CSN.1 object translation error'))
|
|
#
|
|
return ''.join(header), externs, pycode, objs
|
|
|
|
|
|
def process(specs):
|
|
global PATH
|
|
# dict to collect all objects and Python code generated
|
|
Objs = {}
|
|
for spec in specs:
|
|
print('[o] %s: processing' % spec)
|
|
cnt = 0
|
|
# compile each .csn file in the spec directory
|
|
flist = os.listdir(PATH + spec + os.sep)
|
|
for fn in flist:
|
|
if fn[-4:] == '.csn':
|
|
header, externs, pycode, objs = process_file(spec, fn)
|
|
Objs[(spec, fn[:-4])] = [header, externs, pycode, objs]
|
|
cnt += len(objs)
|
|
print('[o] %s: done, %i files, %i definitions' % (spec, len(flist), cnt))
|
|
#
|
|
# resolve all imports
|
|
link(Objs, specs)
|
|
#
|
|
# try to load all generated file
|
|
for (spec, objname) in sorted(Objs.keys()):
|
|
load_py_file(spec, objname)
|
|
|
|
|
|
def link(Objs, specs):
|
|
# resolve imports
|
|
all_files = []
|
|
for (spec, objname), (header, externs, pycode, objs) in sorted(Objs.items()):
|
|
#
|
|
print('[o] %s/%s' % (spec, objname))
|
|
imp = []
|
|
other_specs = specs[:]
|
|
other_specs.remove(spec)
|
|
for ref in externs:
|
|
resolved = False
|
|
if (spec, ref) in Objs:
|
|
# 1) external ref, local spec, top-level obj
|
|
imp.append('from %s import %s' % (build_py_path(spec, ref), ref))
|
|
print(' [INF] external reference solved: %s/%s' % (spec, ref))
|
|
resolved = True
|
|
else:
|
|
for other_spec in other_specs:
|
|
if (other_spec, ref) in Objs:
|
|
# 2) external ref, other spec, top-level obj
|
|
imp.append('from %s import %s' % (build_py_path(other_spec, ref), ref))
|
|
print(' [INF] external reference solved: %s/%s' % (other_spec, ref))
|
|
resolved = True
|
|
break
|
|
if not resolved:
|
|
# 3) external ref, non-top-level obj
|
|
pot = []
|
|
for (o_spec, o_objname) in sorted(Objs.keys()):
|
|
# prioritize local spec reference
|
|
if o_spec == spec:
|
|
o_objs = set(Objs[(o_spec, o_objname)][3].keys())
|
|
if ref in o_objs:
|
|
pot.append( (o_spec, o_objname) )
|
|
if not pot:
|
|
for (o_spec, o_objname) in sorted(Objs.keys()):
|
|
if o_spec != spec:
|
|
o_objs = set(Objs[(o_spec, o_objname)][3].keys())
|
|
if ref in o_objs:
|
|
pot.append((o_spec, o_objname))
|
|
if len(pot) == 0:
|
|
# reference not found
|
|
print(' [ERR] %s/%s: unable to resolve reference %s' % (spec, objname, ref))
|
|
raise(Exception('CSN.1 object reference error'))
|
|
elif len(pot) > 1:
|
|
# too much references found
|
|
print(' [WNG] %s/%s: too much potential imports found for reference %s'\
|
|
% (spec, objname, ref))
|
|
print(' using the 1st one from %s/%s' % pot[0])
|
|
imp.append('from %s import %s' % (build_py_path(*pot[0]), ref))
|
|
print(' [INF] external reference solved: %s/%s/%s' % (pot[0][0], pot[0][1], ref))
|
|
else:
|
|
imp.append('from %s import %s' % (build_py_path(*pot[0]), ref))
|
|
print(' [INF] solved reference: %s/%s/%s' % (pot[0][0], pot[0][1], ref))
|
|
#
|
|
if imp:
|
|
imp.insert(0, '# external references')
|
|
create_py_file(spec, objname, header, '\n'.join(imp) + '\n', pycode)
|
|
|
|
|
|
def create_py_file(spec, objname, header, imports, pycode):
|
|
#fd = open(PATH + spec + os.sep + objname + '.py', 'w')
|
|
l = os.listdir(PATH)
|
|
fn = objname + '.py'
|
|
#if fn in l:
|
|
# raise(Exception('file %s alredy exists' % fn))
|
|
#
|
|
fd = open(PATH + fn, 'w')
|
|
fd.write(header)
|
|
fd.write('\n')
|
|
fd.write(imports)
|
|
fd.write('\n')
|
|
fd.write(pycode)
|
|
fd.write('\n')
|
|
fd.close()
|
|
|
|
|
|
def load_py_file(spec, objname):
|
|
imppath = build_py_path(spec, objname)
|
|
try:
|
|
importlib.import_module(imppath)
|
|
except Exception as exc:
|
|
print('[ERR] %s.%s: %s' % (spec, objname, exc))
|
|
else:
|
|
del sys.modules[imppath]
|
|
|
|
|
|
if __name__ == '__main__':
|
|
process(SPECS)
|
|
sys.exit(0)
|
|
|