ref: 7d02e382d314d5bdde7978ccb7a64ea9201d03db
dir: /contrib/xclasses/xclasses.py/
import copy
import string
import sys
import time
import types
def capitalize(s):
return string.upper(s[0]) + s[1:]
def fprint(f, s):
print >> f, s
def fprintHeader(f, comment = "//"):
fprint(f, comment)
fprint(f, comment + " Generated by xclasses.py at " + time.strftime("%Y/%m/%d %H:%M:%S"))
fprint(f, comment)
fprint(f, comment)
fprint(f, "")
def fprintFooter(f, comment = "//"):
fprint(f, "")
fprint(f, "")
fprint(f, comment + " end of file")
fprint(f, "")
multicallCallTypeFunction = 0
multicallCallTypeMethod = 1
multicallCallTypeVirtualMethod = 2
multicallReturnTypeVoid = 0
multicallReturnTypeInteger = 16
multicallReturnTypeCstring = 32
multicallReturnTypeFloat = 48
multicallExplicitVtable = 512
ficlVmName = "ficlVm"
h_headers = []
def xAddHHeader(line):
h_headers.append(line)
h_footers = []
def xAddHFooter(line):
h_footers.append(line)
ficl_headers = []
def xAddFiclHeader(line):
ficl_headers.append(line)
ficl_footers = []
def xAddFiclFooter(line):
ficl_footers.append(line)
c_headers = []
def xAddCHeader(line):
c_headers.append(line)
c_footers = []
def xAddCFooter(line):
c_footers.append(line)
classes = []
class xVariable:
def __init__(self, name, typeCPP = None, cells = None, count = None, defaultValue = None, cstring = None):
self.comments = []
self.setName(name)
self.setCells(cells)
self.setCount(count)
self.setDefaultValue(defaultValue)
self.setCString(cstring)
self.setTypeCPP(typeCPP)
def setName(self, name):
self.name = name
return self
def setTypeCPP(self, typeCPP):
self.typeCPP = typeCPP
if (typeCPP == "char *"):
self.setCString(1)
return self
def setCells(self, cells):
if cells == None:
self.cells = 1
else:
self.cells = cells
return self
def setCString(self, cstring):
self.cstring = cstring
return self
def isCString(self):
return self.cstring
def getTotalSize(self):
return self.cells * self.count
def setCount(self, count):
if type(count) != types.IntType:
count = 1
self.count = count
return self
def setDefaultValue(self, defaultValue):
if (defaultValue != None) and (type(defaultValue) != types.StringType):
defaultValue = str(defaultValue)
self.defaultValue = defaultValue
return self
def addComment(self, c):
self.comments.append(c)
return self
def isFloat(self):
return self.typeCPP == "float"
def stringCPP(self, wantDefaultValues=1):
if (type(self.typeCPP) != types.StringType):
sys.exit("didn't set a CPP type on variable " + self.name + "!")
output = self.typeCPP
if (self.typeCPP[-1] != "*") and (self.typeCPP[-1] != "&"):
output += " "
output += self.name
if self.count > 1:
output += "[" + str(self.count) + "]"
if self.count == 0:
output += "[]"
if wantDefaultValues and (self.defaultValue != None):
output += " = " + self.defaultValue
return output
def printH(self, f):
if len(self.comments):
for comment in self.comments:
fprint(f, "\t" + "// " + comment)
fprint(f, "\t" + self.stringCPP() + ";")
def printF(self, f):
totalCells = self.count * self.cells
if (totalCells <= 1):
typeF = "cell:"
else:
typeF = str(totalCells) + " cells:"
if len(self.comments):
for comment in self.comments:
fprint(f, "\t" + "// " + comment)
fprint(f, "\t" + "S\" " + typeF + " ." + self.name + " \" evaluate")
class xMethod:
def __init__(self, name, returnType = None, virtual = None, static = None, body = None):
self.arguments = []
self.comments = []
self.setName(name)
self.setReturnType(returnType)
self.setVirtual(virtual)
self.setStatic(static)
self.setBody(body)
self.setThunkVariable(None)
self.vtableOffset = 0
def copy():
clone = xMethod(self.name, self.returnType, self.virtual, self.static)
clone.arguments = self.arguments
clone.comments = self.comments
def setName(self, name):
self.name = name
return self
def setReturnType(self, returnType):
if returnType.__class__ == xVariable:
self.returnType = returnType
elif type(returnType) == types.StringType:
self.returnType = xVariable("ignored", returnType)
else:
self.returnType = None
return self
def returnTypeIsVoid(self):
return(self.returnType == None) or (self.returnType.typeCPP == None) or (self.returnType.typeCPP == "") or (self.returnType.typeCPP == "void")
def setVirtual(self, virtual):
self.virtual = virtual
return self
def isVirtual(self):
return self.virtual > 0
def isPureVirtual(self):
return self.virtual > 1
def setStatic(self, static):
self.static = static
return self
def setThunkVariable(self, thunkVariable):
self.thunkVariable = thunkVariable
return self
def isStatic(self):
return self.static
# a constructor or a destructor
def isClassSpecial(self):
return (self.returnType == None) or (self.returnType.typeCPP == None) or (self.returnType.typeCPP == "")
def setBody(self, body):
self.body = body
return self
def addArgument(self, argument):
self.arguments.append(argument)
return self
def addComment(self, c):
self.comments.append(c)
return self
def prototype(self, isDefinition=None):
arguments = ""
for a in self.arguments:
if len(arguments):
arguments += ", "
arguments += a.stringCPP(not isDefinition)
if len(arguments) == 0:
arguments = "void"
className = ""
if (isDefinition):
className = self.memberOf.name + "::"
modifiers = ""
if self.virtual and (not isDefinition):
modifiers += "virtual "
if self.static and (not isDefinition):
modifiers += "static "
returnType = ""
name = self.name
if (name == "") or (name == "~"):
name += self.memberOf.name
if (self.returnType != None) and (len(self.returnType.typeCPP) > 0):
returnType = self.returnType.typeCPP + " "
return modifiers + returnType + className + name + "(" + arguments + ")"
def printH(self, f):
pureVirtual = ""
if (self.virtual > 1):
pureVirtual = " = 0"
suffix = ";"
modifiers = ""
if self.body != None:
modifiers = "inline "
suffix = " " + self.body
fprint(f, "\t" + modifiers + self.prototype() + pureVirtual + suffix)
def printF(self, f):
if not self.isVirtual():
return
if len(self.comments):
for comment in self.comments:
fprint(f, "\t" + "// " + comment)
flags = multicallReturnTypeInteger
if self.returnTypeIsVoid():
flags = multicallReturnTypeVoid
elif (self.returnType.isCString()):
flags = multicallReturnTypeCString
elif (self.returnType.typeCPP == "float"):
flags = multicallReturnTypeFloat
flags |= multicallCallTypeVirtualMethod
# move floating-point arguments from float stack
floatArgumentsBitfield = 0
cstringArgumentsBitfield = 0
argumentNumber = 0
cstrings = 0
name = self.name
if (self.memberOf.pureVirtual):
vtable = ""
else:
vtable = " drop [ " + self.memberOf.name + "-vtable literal ] "
flags |= multicallExplicitVtable
if (name == "") or (name == "~"):
name += self.memberOf.name
for a in self.arguments:
if a.isFloat():
floatArgumentsBitfield |= (1 << argumentNumber)
elif a.isCString():
cstringArgumentsBitfield |= (1 << argumentNumber)
cstrings += 1
argumentNumber += 1
fprint(f, "\tS\" : " + name + vtable + str(len(self.arguments) + cstrings) + " " + str(floatArgumentsBitfield) + " " + str(cstringArgumentsBitfield) + " " + str(self.vtableOffset) + " " + str(flags) + " multicall ; \" evaluate ")
def printCPP(self, f):
if (self.thunkVariable != None):
if (self.returnType != None) and (self.returnType.isCString()):
sys.exit("Can't thunk char * return values, sorry.")
fprint(f, "")
fprint(f, self.prototype(1))
fprint(f, "\t{")
fprint(f, "\tif (" + self.thunkVariable.name + " == NULL)")
if self.isClassSpecial() or self.returnTypeIsVoid():
fprint(f, "\t\treturn;")
elif (self.returnType.isFloat()):
fprint(f, "\t\treturn 0.0f;")
else:
fprint(f, "\t\treturn (" + self.returnType.typeCPP + ")0;")
fprint(f, "")
ficlVmName = self.memberOf.getFiclVmName()
## output stack-checking code! how cool is that? --lch
dataStackPush = 2 # why 2? we always push this and ficlClass.
dataStackPop = 0
floatStackPush = 0
floatStackPop = 0
for a in self.arguments:
if (a.isCString()):
dataStackPush = dataStackPush + 2
elif (a.isFloat()):
floatStackPush = floatStackPush + 1
else:
dataStackPush = dataStackPush + 1
if (not self.returnTypeIsVoid()):
if (self.returnType.isFloat()):
floatStackPop = 1
else:
dataStackPop = 1
if (dataStackPush or dataStackPop or floatStackPush or floatStackPop):
fprint(f, "#ifdef _DEBUG")
if (dataStackPush or dataStackPop):
fprint(f, "\tficlStackCheck(" + ficlVmName + "->dataStack, " + str(dataStackPush) + ", " + str(dataStackPop) + ");")
if (floatStackPush or floatStackPop):
fprint(f, "\tficlStackCheck(" + ficlVmName + "->floatStack, " + str(floatStackPush) + ", " + str(floatStackPop) + ");")
fprint(f, "#endif // _DEBUG")
reversedArguments = copy.copy(self.arguments)
reversedArguments.reverse()
for a in reversedArguments:
if (a.isCString()):
fprint(f, "\tficlStackPushPointer(" + ficlVmName + "->dataStack, " + a.name + ");")
fprint(f, "\tficlStackPushInteger(" + ficlVmName + "->dataStack, strlen(" + a.name + "));")
elif (a.isFloat()):
fprint(f, "\tficlStackPushFloat(" + ficlVmName + "->floatStack, " + a.name + ");")
else:
fprint(f, "\tficlStackPushInteger(" + ficlVmName + "->dataStack, (int)" + a.name + ");")
fprint(f, "\tficlStackPushPointer(" + ficlVmName + "->dataStack, this);")
fprint(f, "\tficlStackPushPointer(" + ficlVmName + "->dataStack, ficlClass);")
fprint(f, "\tficlVmExecuteXT(" + ficlVmName + ", " + self.thunkVariable.name + ");")
if (not self.returnTypeIsVoid()):
if (self.returnType.isFloat()):
fprint(f, "\treturn ficlStackPopFloat(" + ficlVmName + "->floatStack);")
else:
fprint(f, "\treturn (" + self.returnType.typeCPP + ")ficlStackPopInteger(" + ficlVmName + "->dataStack);")
fprint(f, "\t}")
fprint(f, "")
# don't do virtual functions
if self.isVirtual() or self.isClassSpecial():
return
name = self.name
if (name == "") or (name == "~"):
name += self.memberOf.name
fprint(f, "// " + self.memberOf.name + "::" + name)
if len(self.comments):
fprint(f, "\t" + "//")
for comment in self.comments:
fprint(f, "\t" + "// " + comment)
arguments = ""
for a in self.arguments:
if len(arguments):
arguments += ", "
arguments += a.stringCPP()
if len(arguments) == 0:
arguments = "void"
classModifier = self.memberOf.name + "::"
calltype = "FICL_MULTICALL_CALLTYPE_METHOD"
if self.isStatic():
classModifier = ""
calltype = "FICL_MULTICALL_CALLTYPE_FUNCTION"
returnString = "FICL_MULTICALL_RETURNTYPE_INTEGER"
if self.returnTypeIsVoid():
returnString = "FICL_MULTICALL_RETURNTYPE_VOID"
elif (self.returnType.typeCPP == "float"):
returnString = "FICL_MULTICALL_RETURNTYPE_FLOAT"
elif (self.returnType.isCString()):
returnString = "FICL_MULTICALL_RETURNTYPE_CSTRING"
# set bits in argumentFlags
floatArgumentsBitfield = 0
cstringArgumentsBitfield = 0
argumentNumber = 0
cstrings = 0
for a in self.arguments:
if a.isFloat():
floatArgumentsBitfield |= (1 << argumentNumber)
elif a.isCString():
cstringArgumentsBitfield |= (1 << argumentNumber)
cstrings += 1
argumentNumber += 1
uniqueSuffix = "_" + self.memberOf.name + "_" + name
# constructor is blank!
if (self.name == ""):
uniqueSuffix = "_" + self.memberOf.name + "_constructor"
# destructor is just a squiggle!
elif (self.name == "~"):
uniqueSuffix = "_" + self.memberOf.name + "_destructor"
printingHash = {}
printingHash["classname"] = "xMethod" + uniqueSuffix
printingHash["variablename"] = "instance" + uniqueSuffix
printingHash["address"] = self.returnType.typeCPP + " (" + classModifier + "*address)(" + arguments + ")"
printingHash["function"] = self.memberOf.name + "::" + name
printingHash["methodname"] = name
printingHash["argumentCount"] = str(len(self.arguments) + cstrings)
printingHash["floatArgumentsBitfield"] = str(floatArgumentsBitfield)
printingHash["cstringArgumentsBitfield"] = str(cstringArgumentsBitfield)
printingHash["flags"] = calltype + " | " + returnString
fprint(f, """
struct %(classname)s
{
char *name;
int argumentCount;
int floatArgumentBitfield;
int cstringArgumentBitfield;
int flags;
%(address)s;
int zero;
};
static %(classname)s %(variablename)s = { "%(methodname)s", %(argumentCount)s, %(floatArgumentsBitfield)s, %(cstringArgumentsBitfield)s, %(flags)s, %(function)s, 0 };
""" % printingHash)
class xClass:
def __init__(self, name):
self.members = []
self.methods = []
self.verbatim = []
self.name = name
self.superclass = None
self.superclassName = None
self.containsVtable = 0
self.vtableEntries = 0
self.firstMember = None
self.memberCellsTotal = 0
self.thunkedSubclass = None
self.pureVirtual = 0
self.setFiclVmName(None)
classes.append(self)
def subclassOf(self, superclass):
if type(superclass) == types.StringType:
self.superclassName = superclass
else:
self.superclass = superclass
self.superclassName = superclass.name
if superclass.containsVtable:
self.containsVtable = 2
self.pureVirtual = superclass.pureVirtual
self.vtableEntries = superclass.vtableEntries
else:
self.containsVtable = 0
return self
def thunkedSubclassOf(self, superclass):
self.subclassOf(superclass)
self.addMember(xVariable("ficlClass", "void *"))
for method in superclass.methods:
if not method.isClassSpecial() or method.isPureVirtual():
method = copy.deepcopy(method)
if method.isPureVirtual():
method.setVirtual(1)
self.addThunkedMethod(method)
self.constructor = xMethod("")
self.addMethod(self.constructor)
self.thunkedSubclass = 1
return self
def forwardDeclare(self):
xAddHHeader("class " + self.name + ";")
def addVerbatim(self, v):
self.verbatim.append(v)
return self
def addMember(self, variable):
self.members.append(variable)
self.memberCellsTotal += variable.getTotalSize()
if (self.firstMember == None):
self.firstMember = variable
return self
def removeMember(self, variable):
self.members.remove(variable)
self.memberCellsTotal -= variable.getTotalSize()
if (self.firstMember == variable):
self.firstMember = self.members[0]
return self
def addMemberArray(self, array):
map(self.addMember, copy.deepcopy(array))
def findPreviousInstanceOfVirtualMethod(self, name):
for method in self.methods:
if method.name == name:
return method
if (self.superclass != None) and (type(self.superclass) != types.StringType):
return self.superclass.findPreviousInstanceOfVirtualMethod(name)
return None
def setFiclVmName(self, name):
self.ficlVmName = name
return self
def getFiclVmName(self):
if self.ficlVmName != None:
return self.ficlVmName
global ficlVmName
return ficlVmName
def addMethod(self, method):
method.memberOf = self
if method.virtual:
previousInstance = self.findPreviousInstanceOfVirtualMethod(method.name)
if (previousInstance != None):
method.vtableOffset = previousInstance.vtableOffset
if previousInstance.isPureVirtual() and (not method.isPureVirtual()):
self.pureVirtual -= 1
else:
method.vtableOffset = self.vtableEntries
self.vtableEntries = self.vtableEntries + 1
if (not self.containsVtable):
self.containsVtable = 1
if method.isPureVirtual():
self.pureVirtual += 1
self.methods.append(method)
return self
def lookupMethod(self, methodName):
for m in self.methods:
if (m.name == methodName):
return m
return None
def removeMethod(self, method):
if (type(method) == types.StringType):
method = self.lookupMethod(method)
if method == None:
return None
method.memberOf = None
self.methods.remove(method)
if method.virtual:
previousInstance = self.findPreviousInstanceOfVirtualMethod(method.name)
if (previousInstance == None):
for m in self.methods:
if (m.vtableOffset >= method.vtableOffset):
m.vtableOffset = m.vtableOffset - 1
self.vtableEntries = self.vtableEntries - 1
if (self.vtableEntries == 0):
self.containsVtable = 0
if previousInstance.isPureVirtual() and (not method.isPureVirtual()):
self.pureVirtual += 1
else:
if method.isPureVirtual():
self.pureVirtual -= 1
if method.thunkVariable != None:
self.removeMember(method.thunkVariable)
return self
def addThunkedMethod(self, method):
method = copy.deepcopy(method)
self.addMethod(method)
name = capitalize(method.name)
if (method.isClassSpecial()):
if (name == ""):
name = "Constructor"
else:
name = "Destructor"
thunkVariable = xVariable("xt" + name, "ficlWord *")
self.addMember(thunkVariable)
method.setThunkVariable(thunkVariable)
return self
def addNoopConstructor(self):
self.addVerbatim(self.name + "() { }")
return self
def addConstructor(self, virtual = 0):
method = xMethod("")
method.setVirtual(virtual)
self.addMethod(method)
return method
def addDestructor(self, virtual = 0):
method = xMethod("~")
method.setVirtual(virtual)
self.addMethod(method)
return method
def addMemberWithAccessors(self, variable, writeBodiesToo = 1):
self.addMember(variable)
capitalizedName = capitalize(variable.name)
m = xMethod("set" + capitalizedName, "void").addArgument(variable)
if writeBodiesToo:
m.setBody("\t{ this->" + variable.name + " = " + variable.name + "; }")
self.addMethod(m)
m = xMethod("get" + capitalizedName, variable.typeCPP)
if writeBodiesToo:
m.setBody("\t{ return this->" + variable.name + "; }")
self.addMethod(m)
def addMethodArray(self, array):
map(self.addMethod, copy.deepcopy(array))
def addThunkedMethodArray(self, array):
map(self.addThunkedMethod, copy.deepcopy(array))
def printHforward(self, f):
fprint(f, "class " + self.name + ";")
def printH(self, f):
if (self.thunkedSubclass):
body = "\n\t\t{\n"
for m in self.methods:
if m.thunkVariable != None:
body += "\t\t" + m.thunkVariable.name + " = NULL;\n"
body += "\t\t}\n"
self.constructor.setBody(body)
s = ""
if self.superclassName != None:
s = " : public " + self.superclassName
fprint(f, "class " + self.name + s)
fprint(f, "\t" + "{")
fprint(f, "\t" + "public:")
fprint(f, "")
for member in self.members:
member.printH(f)
fprint(f, "")
for method in self.methods:
method.printH(f)
for v in self.verbatim:
fprint(f, "\t" + v + "\n")
fprint(f, "\t" + "};\n\n")
def printF(self, f):
s = self.superclassName
if s == None:
s = "object"
fprint(f, "")
fprint(f, "//")
fprint(f, "// " + self.name)
fprint(f, "//")
fprint(f, ": declare-" + self.name)
fprint(f, "\t" + "S\" " + s + " subclass " + self.name + " \" evaluate")
fprint(f, "")
if self.containsVtable == 1:
fprint(f, "\t" + "S\" cell: .vtable\" evaluate")
for member in self.members:
member.printF(f)
fprint(f, "")
if (self.firstMember == None):
fprint(f, "\t" + "S\" : default-init 2drop ; \" evaluate // no members!")
else:
storeFiclClass = ""
if (self.thunkedSubclass != None):
storeFiclClass = "this this my=> .ficlClass ! drop "
setVtable = ""
if self.containsVtable and (not self.pureVirtual):
setVtable = self.name + "-vtable this my=> .vtable ! "
fprint(f, "\t" + "S\" : default-init { 2:this -- } this my=> super my=> init this my=> ." + self.firstMember.name + " " + str(self.memberCellsTotal) + " cells 0 fill " + setVtable + storeFiclClass + "; \" evaluate")
fprint(f, "\t// " + self.name + " methods:")
fprint(f, "\t" + self.name + "-declare-methods")
for method in self.methods:
method.printF(f)
fprint(f, "\t;")
fprint(f, "")
fprint(f, ": end-" + self.name)
fprint(f, "\t" + "S\" end-class \" evaluate")
fprint(f, "\t" + "S\" " + self.name + " 2constant " + self.name + ".constant \" evaluate")
fprint(f, "\t;")
fprint(f, "")
def printCPP(self, f):
fprint(f, "//")
fprint(f, "// " + self.name)
fprint(f, "//")
for method in self.methods:
method.printCPP(f)
fprint(f, "")
fprint(f, "// " + self.name + " final structure")
fprint(f, "static xMethod *" + self.name + "_methods[] =")
fprint(f, "\t" + "{")
for method in self.methods:
if (method.isVirtual() or method.isClassSpecial()):
continue
fprint(f, "\t" + "(xMethod *)(&instance_" + self.name + "_" + method.name + "),")
fprint(f, "\t" + "NULL")
fprint(f, "\t" + "};")
if self.containsVtable and (not self.pureVirtual):
fprint(f, "")
fprint(f, "// " + self.name + " instance, so we can get the vtable")
fprint(f, "static " + self.name + " " + self.name + "_instance;" )
fprint(f, "")
def xclassesFooter():
f = open("xclasses.h", "wt")
fprintHeader(f)
fprint(f, "#ifndef __XCLASSES_H")
fprint(f, "#define __XCLASSES_H")
fprint(f, "")
fprint(f, "extern void xclassesDefineMethods(ficlVm *vm);")
fprint(f, "")
fprint(f, "enum xtype");
fprint(f, "\t{");
fprint(f, "\txtypeInvalid = 0,");
for c in classes:
fprint(f, "\txtype_" + c.name + ",");
fprint(f, "\txtypeLast,");
fprint(f, "\t};");
fprint(f, "");
for line in h_headers:
fprint(f, line)
fprint(f, "")
fprint(f, "")
for c in classes:
c.printH(f)
for line in h_footers:
fprint(f, line)
fprint(f, "")
fprint(f, "#endif // __XCLASSES_H")
fprintFooter(f)
f.close()
f = open("xclasses.f", "wt")
fprintHeader(f)
fprint(f, ": use-default-init S\" : init { 2:this } this my=> super my=> init this my=> default-init ; \" evaluate ;");
for line in ficl_headers:
fprint(f, line)
fprint(f, "")
for c in classes:
c.printF(f)
for line in ficl_footers:
fprint(f, line)
fprint(f, "")
fprintFooter(f)
f.close()
f = open("xclasses.cpp", "wt")
fprintHeader(f)
for line in c_headers:
fprint(f, line)
fprint(f, "")
fprint(f, "#include \"xclasses.h\"")
fprint(f, """
struct xMethod
{
char *name;
int argumentCount;
int floatArgumentBitfield;
int cstringArgumentBitfield;
int flags;
void *address;
int zero;
};
struct xClass
{
char *name;
xMethod **methods;
void **instance;
};
""")
for c in classes:
c.printCPP(f)
fprint(f, """
static xClass classes[] =
{
""")
for c in classes:
vtableVariable = "NULL"
if c.containsVtable and (not c.pureVirtual):
vtableVariable = "(void **)&" + c.name + "_instance"
fprint(f, "\t" + "{ \"" + c.name + "\", " + c.name + "_methods, " + vtableVariable + " },")
fprint(f, """
{ NULL, NULL }
};
void xclassesDefineMethods(ficlVm *vm)
{
char buffer[1024];
xClass *c;
xMethod **m;
for (c = classes; c->name != NULL; c++)
{
sprintf(buffer, " : %s-declare-methods ", c->name);
ficlVmEvaluate(vm, buffer);
for (m = c->methods; *m != NULL; m++)
{
xMethod *method = *m;
/* why is this here? I dunno, but MSVC seems to be packing my struct. So if address is zero, the next dword has the address. --lch */
if (method->address == NULL)
method->address = (void *)method->zero;
sprintf(buffer, " S\\" : %s drop %d %d %d %d %d multicall ; \\" evaluate ",
method->name,
method->argumentCount,
method->floatArgumentBitfield,
method->cstringArgumentBitfield,
method->address,
method->flags
);
ficlVmEvaluate(vm, buffer);
}
ficlVmEvaluate(vm, " ; ");
if (c->instance != NULL)
{
sprintf(buffer, "%s-vtable", c->name);
ficlDictionarySetConstantPointer(ficlVmGetDictionary(vm), buffer, *(c->instance));
}
}
}
""")
for line in c_footers:
fprint(f, line)
fprint(f, "")
fprintFooter(f)
f.close()