uses util.compiler.CodeGen
data DNILParam {
char type[]
}
data DNILFunction {
char name[]
char returnType[]
DNILParam parameters[]
}
data DNILProvides {
char package[]
char semantic[]
char alias[]
DNILFunction functions[]
}
data DNILRequires {
char package[]
char semantic[]
char alias[]
bool isNative
DNILFunction functions[]
}
data DNILRecord {
DNILProvides providedInterfaces[]
DNILRequires requiredInterfaces[]
}
data TargetOption {
char os[]
char chip[]
}
data ConInt {
int val
}
component provides Compiler requires io.Output out, data.IntUtil iu, io.File:mem, System sys, util.compiler.SyntaxParser, util.compiler.OpParser, util.compiler.TypeShaper, util.compiler.EnvelopeWriter, util.compiler.LiteralsTable, util.compiler.TypeTable, util.compiler.CodeGen, util.compiler.DNCUtil dncUtil, io.FileSystem fileSystem, composition.RecursiveLoader rloader, data.json.JSONEncoder jcoder {
String myPaths[]
void Compiler:setSearchPaths(store String paths[])
{
myPaths = paths
}
char[] getDefaulTargetOS()
{
if (sys.getPlatform().osCode == "deb")
return "unix"
else if (sys.getPlatform().osCode == "win")
return "windows"
else if (sys.getPlatform().osCode == "osx")
return "unix"
return "unix"
}
char[] getDefaulTargetChip()
{
if (sys.getPlatform().chipCode == "x64")
return "x86-64"
else if (sys.getPlatform().chipCode == "x86")
return "x86-32"
return "x86-64"
}
TargetOption getDefaultTarget(char danaHome[])
{
char os[] = getDefaulTargetOS()
char chip[] = getDefaulTargetChip()
if (fileSystem.exists("$(danaHome)/components/util/compiler/hwi/Code_$(os)_$(chip).o"))
{
return new TargetOption(os, chip)
}
else
{
//check for UBC
ConInt ci = new ConInt()
int aw_bits = dana.serial(ci).arrayLength * 8
chip = aw_bits.makeString()
os = "ubc"
if (fileSystem.exists("$(danaHome)/components/util/compiler/hwi/Code_$(os)_$(chip).o"))
{
return new TargetOption(os, chip)
}
}
return null
}
byte getOSTarget(char targetOS[])
{
if (targetOS == "ubc")
{
return EnvelopeWriter.OS_UBC
}
else if (targetOS == "unix")
{
return EnvelopeWriter.OS_LINUX
}
else if (targetOS == "windows")
{
return EnvelopeWriter.OS_WINDOWS
}
return EnvelopeWriter.OS_LINUX
}
char[] makeDNILContent(OpParseResult opResult)
{
DNILRecord result = new DNILRecord()
for (int i = 0; i < opResult.providedObjects.arrayLength; i++)
{
DNILProvides newProvides = new DNILProvides()
newProvides.package = opResult.providedObjects[i].mainInterface
newProvides.semantic = opResult.providedObjects[i].semantic
newProvides.alias = opResult.providedObjects[i].mainInterface
if (newProvides.semantic.arrayLength != 0) newProvides.alias = "$(newProvides.alias):$(newProvides.semantic)"
//newProvides.functions = TODO
result.providedInterfaces = new DNILProvides[](result.providedInterfaces, newProvides)
}
for (int i = 0; i < opResult.requiredInterfaces.arrayLength; i++)
{
DNILRequires newRequires = new DNILRequires()
newRequires.package = opResult.requiredInterfaces[i].name
newRequires.semantic = opResult.requiredInterfaces[i].semantic
newRequires.alias = opResult.requiredInterfaces[i].name
if (newRequires.semantic.arrayLength != 0) newRequires.alias = "$(newRequires.alias):$(newRequires.semantic)"
newRequires.isNative = opResult.requiredInterfaces[i].isNative
//newRequires.functions = TODO
result.requiredInterfaces = new DNILRequires[](result.requiredInterfaces, newRequires)
}
return jcoder.jsonFromData(result, new Map("native", "isNative"))
}
int getCallAddress(ProvidedObject po, ImplementedObject io, char impl[], char name[])
{
int res = INT_MAX
if (impl == null)
{
res = dncUtil.findFunctionIndex(po.localFunctions, name)
if (res != INT_MAX) return io.localFunctions[res].offset
for (int j = 0; j < po.interfaces.arrayLength; j++)
{
res = dncUtil.findFunctionIndex(po.interfaces[j].functions, name)
if (res != INT_MAX) return io.interfaces[j].functions[res].offset
}
}
for (int j = 0; j < po.interfaces.arrayLength; j++)
{
if (impl == po.interfaces[j].type)
{
res = dncUtil.findFunctionIndex(po.interfaces[j].functions, name)
if (res != INT_MAX) return io.interfaces[j].functions[res].offset
}
}
throw new Exception("unknown call offset for $impl:$name()")
}
ImplementedObject[] cloneIO(ImplementedObject array[])
{
ImplementedObject result[] = clone array
for (int i = 0; i < array.arrayLength; i++)
{
result[i] = clone result[i]
result[i].interfaces = clone result[i].interfaces
for (int j = 0; j < result[i].interfaces.arrayLength; j++)
{
result[i].interfaces[j] = clone result[i].interfaces[j]
result[i].interfaces[j].functions = clone result[i].interfaces[j].functions
for (int k = 0; k < result[i].interfaces[j].functions.arrayLength; k ++)
{
result[i].interfaces[j].functions[k] = clone result[i].interfaces[j].functions[k]
}
}
result[i].localFunctions = clone result[i].localFunctions
for (int k = 0; k < result[i].localFunctions.arrayLength; k ++)
{
result[i].localFunctions[k] = clone result[i].localFunctions[k]
}
result[i].initFunction = clone result[i].initFunction
}
return result
}
void compileFile(char sourceCode[], char sourceName[], File ofd, String searchPaths[], Code codeHW, byte targetPlatform, int targetAddressWidth, int hwidSet[], CompileResult cres)
{
//parse the given file
SyntaxParser parser = new SyntaxParser(searchPaths, targetAddressWidth)
ParseResult result = parser.parse(sourceCode, sourceName)
DanaToken tree = result.tree
DanaType types[] = parser.getTypes()
for (int i = 0; i < result.errors.arrayLength; i++)
{
cres.errors = new CompileError[](cres.errors, new CompileError(CompileError.ERROR, result.errors[i].file, true, result.errors[i].line, result.errors[i].message))
}
if (result.errors.arrayLength == 0)
{
OpParser opp = new OpParser(targetAddressWidth)
TypeShaper tshape = new TypeShaper()
DanaType flatTypes[] = tshape.shapeTypes(types, tree)
OpParseResult opResult = opp.parse(sourceName, tree, flatTypes)
for (int i = 0; i < opResult.errors.arrayLength; i++)
{
cres.errors = new CompileError[](cres.errors, new CompileError(CompileError.ERROR, opResult.errors[i].file, true, opResult.errors[i].line, opResult.errors[i].message))
}
for (int i = 0; i < opResult.warnings.arrayLength; i++)
{
cres.errors = new CompileError[](cres.errors, new CompileError(CompileError.WARNING, opResult.errors[i].file, true, opResult.errors[i].line, opResult.errors[i].message))
}
if (opResult.errors.arrayLength == 0)
{
//TODO: determine the host's native endianness for parameter 2
EnvelopeWriter env = new EnvelopeWriter(sourceName, targetAddressWidth, EnvelopeWriter.EM_LITTLE, targetPlatform)
LiteralsTable literals = new LiteralsTable()
TypeTable typeTable = new TypeTable()
CodeGen codeGen = new CodeGen()
CGResult cgr = null
//generate object file header information, type table, and literals table
ImplementedObject implObjects[] = cloneIO(env.prepareEnvelope(opResult, flatTypes, literals))
TypeMapping typeMap[] = env.getTypeMappings()
env.writeEnvelope(ofd, opResult, implObjects, flatTypes, literals, typeTable, 0, true)
FunctionInfo initInfo = env.writeFrameHeader(ofd, new ImplementedFunction(opResult.classInitFunction.name, opResult.classInitFunction), types, literals, env.getTextOffset())
cgr = codeGen.generate(ofd, codeHW, opResult.classInitFunction.instructions, flatTypes, literals, typeTable, typeMap, initInfo, env.getTextOffset(), env.getNNITableOffset(), hwidSet)
env.addRelocations(cgr.relocations)
for (int i = 0; i < opResult.providedObjects.arrayLength; i++)
{
CallRefAddress callRefs[] = null
for (int j = 0; j < opResult.providedObjects[i].interfaces.arrayLength; j++)
{
for (int k = 0; k < opResult.providedObjects[i].interfaces[j].functions.arrayLength; k++)
{
FunctionInfo info = env.writeFrameHeader(ofd, implObjects[i].interfaces[j].functions[k], types, literals, env.getTextOffset())
cgr = codeGen.generate(ofd, codeHW, opResult.providedObjects[i].interfaces[j].functions[k].instructions, flatTypes, literals, typeTable, typeMap, info, env.getTextOffset(), env.getNNITableOffset(), hwidSet)
implObjects[i].interfaces[j].functions[k].offset = info.textOffset
env.addRelocations(cgr.relocations)
callRefs = new CallRefAddress[](callRefs, cgr.callRefs)
}
}
for (int j = 0; j < opResult.providedObjects[i].localFunctions.arrayLength; j++)
{
FunctionInfo info = env.writeFrameHeader(ofd, implObjects[i].localFunctions[j], types, literals, env.getTextOffset())
cgr = codeGen.generate(ofd, codeHW, opResult.providedObjects[i].localFunctions[j].instructions, flatTypes, literals, typeTable, typeMap, info, env.getTextOffset(), env.getNNITableOffset(), hwidSet)
implObjects[i].localFunctions[j].offset = info.textOffset
env.addRelocations(cgr.relocations)
callRefs = new CallRefAddress[](callRefs, cgr.callRefs)
}
FunctionInfo info = env.writeFrameHeader(ofd, implObjects[i].initFunction, types, literals, env.getTextOffset())
cgr = codeGen.generate(ofd, codeHW, opResult.providedObjects[i].initFunction.instructions, flatTypes, literals, typeTable, typeMap, info, env.getTextOffset(), env.getNNITableOffset(), hwidSet)
implObjects[i].initFunction.offset = info.textOffset
env.addRelocations(cgr.relocations)
//iterate through local-call references, patching their offset addresses now that we know
for (int j = 0; j < callRefs.arrayLength; j++)
{
int addr = getCallAddress(opResult.providedObjects[i], implObjects[i], callRefs[j].intf, callRefs[j].name)
codeGen.patchCallAddress(ofd, codeHW, callRefs[j].refAddress, addr)
}
}
//note text-end, and write relocations
env.writeTextEnd(ofd)
env.writeRelocations(ofd)
//DNIL section
char json[] = makeDNILContent(opResult)
env.writeInfoSection(ofd, "DNIL", "json", json)
//now re-write the envelope, with function implementation offsets known
ofd.setPos(0)
env.writeEnvelope(ofd, opResult, implObjects, flatTypes, literals, typeTable, initInfo.textOffset, false)
cres.resultCode = CompileResult.OK
ofd.setPos(0)
cres.objectCode = ofd.read(ofd.getSize())
}
else
{
cres.resultCode = CompileResult.ERROR
}
}
else
{
cres.resultCode = CompileResult.ERROR
}
}
CompileResult Compiler:compile(char sourceName[], char sourceCode[])
{
byte osTarget = EnvelopeWriter.OS_LINUX
int addressWidth = 8
TargetOption target = getDefaultTarget(sys.getDanaHome())
if (target == null)
{
throw new Exception("no default code generation component found")
}
osTarget = getOSTarget(target.os)
IDC codeIDC = null
Code codeHW = null
if (fileSystem.exists("$(sys.getDanaHome())/components/util/compiler/hwi/Code_$(target.os)_$(target.chip).o"))
{
codeIDC = rloader.load("$(sys.getDanaHome())/components/util/compiler/hwi/Code_$(target.os)_$(target.chip).o").mainComponent
codeHW = new Code() from codeIDC
}
else
{
throw new Exception("no code generation component found for $(target.os)/$(target.chip)")
}
addressWidth = codeHW.getAddressWidth()
int hwidSet[] = codeHW.getHWIDSupport()
CompileResult cres = new CompileResult()
File ofd = new File:mem("tmp", File.CREATE)
compileFile(sourceCode, sourceName, ofd, myPaths, codeHW, osTarget, addressWidth, hwidSet, cres)
return cres
}
}