diff ide/compiler/modules.py @ 1:92df07bc2081

Initial import of compiler
author windel
date Sun, 18 Sep 2011 19:00:29 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ide/compiler/modules.py	Sun Sep 18 19:00:29 2011 +0200
@@ -0,0 +1,193 @@
+import struct
+from .errors import Error
+from .nodes import *
+from .builtin import integer, real, char, boolean, void
+import os.path
+
+"""
+ File format for compiled modules.
+ * [11] magic identifier
+ * [STR] mod name
+ * [STR] signature, a md5 signature of the module.
+ * [I32] size of code
+ * code image
+ * [I32] entrypoint for initcode
+ * imported modules
+ ** [I32] num of imported modules
+ *** [STR] name of module
+ *** signature of the module
+ *** [I32] offset in the process image where the interface symbols must be placed
+ * public interface
+ ** [I32] num of interface elements
+ *** [STR] proc name
+ *** [I32] offset in code image 
+ *** [type] return type
+ *** [I32] number of parameters
+ **** parameter
+ ***** parameter kind
+ ***** parameter name
+ ***** parameter type
+"""
+
+MAGIC = b'LCFOSMODC'
+
+loadedModules = []
+
+def loadModule(modname):
+   """ returns a Module object specified by a name """
+   # Check if the module was already loaded:
+   for mod in loadedModules:
+      if mod.name == modname:
+         return mod
+
+   # Try to load the module from file:
+   srcfilename = modname + '.mod'
+   binfilename = modname + '.bin'
+   sourceExists = os.path.exists(srcfilename)
+   if os.path.exists(binfilename):
+      if sourceExists:
+         compileModule()
+      else:
+         return loadModuleFromFile(binfilename)
+   else:
+      Error("Cannot load module '{0}'!".format(modname))
+
+def loadModuleFromFile(filename):
+   f = open(filename, 'rb')
+   magic = f.read(len(MAGIC))
+   assert(magic == MAGIC)
+
+   # Helper functions:
+   def readI32():
+      int32, = struct.unpack('<I', f.read(4))
+      return int32
+   def readSTR():
+      length = readI32()
+      b = f.read(length)
+      return b.decode(encoding='ascii')
+   def readType():
+      code, = f.read(1)
+      basetypes = {0x11:integer, 0x12:real, 0x13:char,0x14:boolean, 0x15:void}
+      if code in list(basetypes.keys()):
+         return basetypes[code]
+      elif code == 0x20:
+         dimension, elementType = readI32(), readType()
+         return ArrayType(dimension, elementType)
+      elif code == 0x21:
+         returntype = readType()
+         numparams = readI32()
+         parameters = []
+         kinds = {0x1:'value', 0x2:'var', 0x3:'const'}
+         for i in range(numparams):
+            byt, = f.read(1)
+            kind = kinds[byt]
+            name, typ = readSTR(), readType()
+            parameters.append(Parameter(kind, name, typ))
+         return ProcedureType(parameters, returntype)
+      else:
+         Error('Reading of this typ not supported')
+
+   # Begin of actual loading
+   modname = readSTR()
+   modsignature = readSTR()
+   codesize = readI32()
+   image = f.read(codesize)
+   initcodeentry = readI32()
+   # Check which modules this module loads:
+   numimports = readI32()
+   imports = []
+   for i in range(numimports):
+      modname = readSTR()
+      signature = readSTR()
+      symname = readSTR()
+      offset = readI32()
+      impsym = ImportedSymbol(modname, symname)
+      impsym.signature = signature
+      impsym.offset = offset
+      imports.append(impsym)
+   # Modules exported interface:
+   numexports = readI32()
+   exports = []
+   for i in range(numexports):
+      name = readSTR()
+      imageoffset = readI32() # Offset in image where symbol is located
+      typ = readType()
+      export = ExportedSymbol(name, typ)
+      export.imageoffset = imageoffset
+      exports.append(export)
+   f.close()
+
+   # Construct imported module object:
+   module = Module(modname)
+   module.signature = modsignature
+   module.exports = exports # Symbols provided to other modules
+   module.imports = imports # Symbols of others used by this module.
+   module.initcodeentry = initcodeentry
+   module.image = image # The binary blob
+   global loadedModules
+   loadedModules.append(module)
+   return module
+
+def storeModule(mod, filename):
+   """ Class to store a module in a file """
+   f = open(filename, 'wb')
+
+   def writeI32(int32):
+      f.write( struct.pack('<I', int32) )
+   def writeSTR(s):
+      writeI32(len(s))
+      f.write(bytes(s, encoding='ascii'))
+   def writeType(typ):
+      if type(typ) is BaseType:
+         basetypecode = {'integer': 0x11, 'real': 0x12, 'char': 0x13, 'boolean':0x14, 'void':0x15}
+         code = basetypecode[typ.name]
+         f.write( bytes([code]))
+      elif type(typ) is ArrayType:
+         f.write(bytes([0x20]))
+         writeI32(typ.dimension)
+         writeType(typ.elementType)
+      elif type(typ) is ProcedureType:
+         f.write(bytes([0x21]))
+         writeType(typ.returntype)
+         writeI32(len(typ.parameters))
+         for parameter in typ.parameters:
+            kinds = {'value': 0x1, 'var': 0x2, 'const': 0x3}
+            kind = kinds[parameter.kind]
+            f.write(bytes([kind]))
+            writeSTR(parameter.name)
+            writeType(parameter.typ)
+      else:
+         Error('Type storage not implemented {0}'.format(typ))
+
+   # Begin of actual storage function
+   f.write(MAGIC)
+   writeSTR(mod.name)
+   writeSTR(mod.signature)
+   writeI32(len(mod.image))
+   f.write(bytes(mod.image))
+   writeI32(mod.initcodeentry)
+   # modules imported symbols:
+   writeI32(len(mod.imports))
+   for imp in mod.imports:
+      writeSTR(imp.modname)
+      writeSTR(imp.signature)
+      writeSTR(imp.name)
+      writeI32(imp.offset)
+   # modules provided interface
+   writeI32(len(mod.exports))
+   # Store exported symbols:
+   for sym in mod.exports:
+      writeSTR(sym.name) # proc name
+      writeI32(sym.imageoffset) # proc entry point
+      writeType(sym.typ) # Procedure type
+   f.close()
+
+   storeModuleInCache(mod)
+
+def storeModuleInCache(newmod):
+   global loadedModules
+   for mod in loadedModules:
+      if newmod.name == mod.name:
+         return
+   loadedModules.append(newmod)
+