1
|
1 import struct
|
|
2 from .errors import Error
|
|
3 from .nodes import *
|
|
4 from .builtin import integer, real, char, boolean, void
|
|
5 import os.path
|
|
6
|
|
7 """
|
|
8 File format for compiled modules.
|
|
9 * [11] magic identifier
|
|
10 * [STR] mod name
|
|
11 * [STR] signature, a md5 signature of the module.
|
|
12 * [I32] size of code
|
|
13 * code image
|
|
14 * [I32] entrypoint for initcode
|
|
15 * imported modules
|
|
16 ** [I32] num of imported modules
|
|
17 *** [STR] name of module
|
|
18 *** signature of the module
|
|
19 *** [I32] offset in the process image where the interface symbols must be placed
|
|
20 * public interface
|
|
21 ** [I32] num of interface elements
|
|
22 *** [STR] proc name
|
|
23 *** [I32] offset in code image
|
|
24 *** [type] return type
|
|
25 *** [I32] number of parameters
|
|
26 **** parameter
|
|
27 ***** parameter kind
|
|
28 ***** parameter name
|
|
29 ***** parameter type
|
|
30 """
|
|
31
|
|
32 MAGIC = b'LCFOSMODC'
|
|
33
|
|
34 loadedModules = []
|
|
35
|
|
36 def loadModule(modname):
|
|
37 """ returns a Module object specified by a name """
|
|
38 # Check if the module was already loaded:
|
|
39 for mod in loadedModules:
|
|
40 if mod.name == modname:
|
|
41 return mod
|
|
42
|
|
43 # Try to load the module from file:
|
|
44 srcfilename = modname + '.mod'
|
|
45 binfilename = modname + '.bin'
|
|
46 sourceExists = os.path.exists(srcfilename)
|
|
47 if os.path.exists(binfilename):
|
|
48 if sourceExists:
|
|
49 compileModule()
|
|
50 else:
|
|
51 return loadModuleFromFile(binfilename)
|
|
52 else:
|
|
53 Error("Cannot load module '{0}'!".format(modname))
|
|
54
|
|
55 def loadModuleFromFile(filename):
|
|
56 f = open(filename, 'rb')
|
|
57 magic = f.read(len(MAGIC))
|
|
58 assert(magic == MAGIC)
|
|
59
|
|
60 # Helper functions:
|
|
61 def readI32():
|
|
62 int32, = struct.unpack('<I', f.read(4))
|
|
63 return int32
|
|
64 def readSTR():
|
|
65 length = readI32()
|
|
66 b = f.read(length)
|
|
67 return b.decode(encoding='ascii')
|
|
68 def readType():
|
|
69 code, = f.read(1)
|
|
70 basetypes = {0x11:integer, 0x12:real, 0x13:char,0x14:boolean, 0x15:void}
|
|
71 if code in list(basetypes.keys()):
|
|
72 return basetypes[code]
|
|
73 elif code == 0x20:
|
|
74 dimension, elementType = readI32(), readType()
|
|
75 return ArrayType(dimension, elementType)
|
|
76 elif code == 0x21:
|
|
77 returntype = readType()
|
|
78 numparams = readI32()
|
|
79 parameters = []
|
|
80 kinds = {0x1:'value', 0x2:'var', 0x3:'const'}
|
|
81 for i in range(numparams):
|
|
82 byt, = f.read(1)
|
|
83 kind = kinds[byt]
|
|
84 name, typ = readSTR(), readType()
|
|
85 parameters.append(Parameter(kind, name, typ))
|
|
86 return ProcedureType(parameters, returntype)
|
|
87 else:
|
|
88 Error('Reading of this typ not supported')
|
|
89
|
|
90 # Begin of actual loading
|
|
91 modname = readSTR()
|
|
92 modsignature = readSTR()
|
|
93 codesize = readI32()
|
|
94 image = f.read(codesize)
|
|
95 initcodeentry = readI32()
|
|
96 # Check which modules this module loads:
|
|
97 numimports = readI32()
|
|
98 imports = []
|
|
99 for i in range(numimports):
|
|
100 modname = readSTR()
|
|
101 signature = readSTR()
|
|
102 symname = readSTR()
|
|
103 offset = readI32()
|
|
104 impsym = ImportedSymbol(modname, symname)
|
|
105 impsym.signature = signature
|
|
106 impsym.offset = offset
|
|
107 imports.append(impsym)
|
|
108 # Modules exported interface:
|
|
109 numexports = readI32()
|
|
110 exports = []
|
|
111 for i in range(numexports):
|
|
112 name = readSTR()
|
|
113 imageoffset = readI32() # Offset in image where symbol is located
|
|
114 typ = readType()
|
|
115 export = ExportedSymbol(name, typ)
|
|
116 export.imageoffset = imageoffset
|
|
117 exports.append(export)
|
|
118 f.close()
|
|
119
|
|
120 # Construct imported module object:
|
|
121 module = Module(modname)
|
|
122 module.signature = modsignature
|
|
123 module.exports = exports # Symbols provided to other modules
|
|
124 module.imports = imports # Symbols of others used by this module.
|
|
125 module.initcodeentry = initcodeentry
|
|
126 module.image = image # The binary blob
|
|
127 global loadedModules
|
|
128 loadedModules.append(module)
|
|
129 return module
|
|
130
|
|
131 def storeModule(mod, filename):
|
|
132 """ Class to store a module in a file """
|
|
133 f = open(filename, 'wb')
|
|
134
|
|
135 def writeI32(int32):
|
|
136 f.write( struct.pack('<I', int32) )
|
|
137 def writeSTR(s):
|
|
138 writeI32(len(s))
|
|
139 f.write(bytes(s, encoding='ascii'))
|
|
140 def writeType(typ):
|
|
141 if type(typ) is BaseType:
|
|
142 basetypecode = {'integer': 0x11, 'real': 0x12, 'char': 0x13, 'boolean':0x14, 'void':0x15}
|
|
143 code = basetypecode[typ.name]
|
|
144 f.write( bytes([code]))
|
|
145 elif type(typ) is ArrayType:
|
|
146 f.write(bytes([0x20]))
|
|
147 writeI32(typ.dimension)
|
|
148 writeType(typ.elementType)
|
|
149 elif type(typ) is ProcedureType:
|
|
150 f.write(bytes([0x21]))
|
|
151 writeType(typ.returntype)
|
|
152 writeI32(len(typ.parameters))
|
|
153 for parameter in typ.parameters:
|
|
154 kinds = {'value': 0x1, 'var': 0x2, 'const': 0x3}
|
|
155 kind = kinds[parameter.kind]
|
|
156 f.write(bytes([kind]))
|
|
157 writeSTR(parameter.name)
|
|
158 writeType(parameter.typ)
|
|
159 else:
|
|
160 Error('Type storage not implemented {0}'.format(typ))
|
|
161
|
|
162 # Begin of actual storage function
|
|
163 f.write(MAGIC)
|
|
164 writeSTR(mod.name)
|
|
165 writeSTR(mod.signature)
|
|
166 writeI32(len(mod.image))
|
|
167 f.write(bytes(mod.image))
|
|
168 writeI32(mod.initcodeentry)
|
|
169 # modules imported symbols:
|
|
170 writeI32(len(mod.imports))
|
|
171 for imp in mod.imports:
|
|
172 writeSTR(imp.modname)
|
|
173 writeSTR(imp.signature)
|
|
174 writeSTR(imp.name)
|
|
175 writeI32(imp.offset)
|
|
176 # modules provided interface
|
|
177 writeI32(len(mod.exports))
|
|
178 # Store exported symbols:
|
|
179 for sym in mod.exports:
|
|
180 writeSTR(sym.name) # proc name
|
|
181 writeI32(sym.imageoffset) # proc entry point
|
|
182 writeType(sym.typ) # Procedure type
|
|
183 f.close()
|
|
184
|
|
185 storeModuleInCache(mod)
|
|
186
|
|
187 def storeModuleInCache(newmod):
|
|
188 global loadedModules
|
|
189 for mod in loadedModules:
|
|
190 if newmod.name == mod.name:
|
|
191 return
|
|
192 loadedModules.append(newmod)
|
|
193
|