HomeForumSourceResearchGuide
Sign in to contribute to source. how it works
Component util.Compiler by barry
expand copy to clipboardexpand
uses util.compiler.CodeGen

component provides Compiler requires io.Output out, 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 {

	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"
		
		return "unix"
		}
	
	char[] getDefaulTargetChip()
		{
		if (sys.getPlatform().osCode == "x64")
			return "x86_64"
			else if (sys.getPlatform().osCode == "x86")
			return "x86_32"
		
		return "x86-64"
		}
	
	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)

				//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
		char targetOS[] = getDefaulTargetOS()
		char targetChip[] = getDefaulTargetChip()

		if (targetOS == "ubc")
			{
			osTarget = EnvelopeWriter.OS_UBC
			}
			else if (targetOS == "unix")
			{
			osTarget = EnvelopeWriter.OS_LINUX
			}
			else if (targetOS == "windows")
			{
			osTarget = EnvelopeWriter.OS_WINDOWS
			}

		IDC codeIDC = null
		Code codeHW = null
		
		if (fileSystem.exists("$(sys.getDanaHome())/components/util/compiler/hwi/Code_$(targetOS)_$(targetChip).o"))
			{
			codeIDC = rloader.load("$(sys.getDanaHome())/components/util/compiler/hwi/Code_$(targetOS)_$(targetChip).o").mainComponent
			codeHW = new Code() from codeIDC
			}
			else
			{
			throw new Exception("no code generation component found for $(targetOS)/$(targetChip)")
			}
		
		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
		}
	
	}
Revision history
To propose a new revision to this entity, use dana source put -uc your/new/version.dn -n util.Compiler -m "reason for update" -u yourUsername
Version 9 by barry
Version 8 by barry
Version 7 by barry
Version 6 by barry
Version 5 by barry
Version 4 (this version) by barry
Notes for this version: Re-applying update for server-side graph fix.
Version 3 by barry
Version 2 by barry
Version 1 by barry