Commits

Jason McKesson committed a9e4e37

Schematic of the generation stuff done. Place for styles, specs, etc.
Started on header generation.

Comments (0)

Files changed (12)

+--[[Useful style utility functions. This file will contain commonly useful strings and such.
+
+]]
+
+local TabbedFile = require "_TabbedFile"
+
+local common = {}
+
+--Creates a tabbed file.
+function common.CreateFile(filename, indent)
+	local hFile = io.open(filename, "wt")
+	return TabbedFile.TabbedFile(hFile, indent)
+end
+
+return common
 
 MakeMainSourceFile("wgll_ext", wglSpecData, "WGL", "wgl", nil, wglPreceedData,
 	wglbaseData, nil);
-	
-	
+
+
 ---------------------------
 --Create GLX files.
 local glxSpecData = LoadLuaSpec(specFileLoc .. "glxspec.lua");

StylePointerC.lua

+
+local common = require "CommonStyle"
+
+
+local my_style = {}
+my_style.header = {}
+my_style.source = {}
+
+function my_style.header.CreateFile(basename, options)
+	return common.CreateFile(basename .. ".h", options.indent)
+end
+
+function my_style.header.MakeIncludeGuard(prefix, specIncl)
+	local str = "POINTER_C_GENERATED_HEADER_" .. specIncl .. "_H"
+	if(#prefix > 0) then
+		return prefix:upper() .. "_" .. str
+	end
+	
+	return str
+end
+
+
+--------------------------------------------------
+-- Style retrieval machinery
+local function DeepCopyTable(tbl)
+	local ret = {}
+	for key, value in pairs(tbl) do
+		if(type(value) == "table") then
+			ret[key] = DeepCopyTable(value)
+		else
+			ret[key] = value
+		end
+	end
+	return ret
+end
+
+local function Create()
+	return DeepCopyTable(my_style)
+end
+
+return { Create = Create }
+--[[ Exports a table containing the following functions:
+
+---- LoadSpec
+
+Given a specification type, it loads the spec and returns the spec data, exactly as from LoadLuaSpec.
+
+It is given the following parameters:
+
+- options: The options list, as culled from GetOptions.
+
+
+---- Generate
+
+It creates a header/source file pair in accord with a standard algorithm and with the options it is given.
+
+It is given the following parameters:
+
+- options: The options list, as culled from GetOptions.
+- specData: The data as loaded with LoadSpec
+]]
+
+local Specs = require "_Specs"
+local Styles = require "_Styles"
+require "_LoadLuaSpec"
+require "_util"
+
+local function BuildHeader(options, spec, style, specData, basename)
+	local header = style.header
+	local hFile = header.CreateFile(basename, options)
+	
+	--Start include-guards.
+	--IGs are built from style and spec data. The spec provides a string that
+	--the style uses in constructing it.
+	local inclGuard =
+		header.MakeIncludeGuard(options.prefix, spec.GetIncludeGuardString())
+	
+	hFile:fmt("#ifndef %s\n", inclGuard)
+	hFile:fmt("#define %s\n", inclGuard)
+	hFile:write("\n")
+	
+	--Spec-specific initialization comes next. Generally macros and #includes.
+	hFile:rawwrite(spec.GetHeaderInit())
+	
+	--Ending includeguard.
+	hFile:fmt("#endif //%s\n", inclGuard)
+	hFile:close()
+end
+
+local function Generate(options, specData)
+	--Extract the path and base-filename from the options.
+	local simplename = options.outname:match("([^\\/]+)$")
+	local dir = options.outname:match("^(.*[\\/])")
+	
+	assert(simplename,
+		"There is no filename in the path '" .. options.outname .. "'")
+
+	local spec = Specs.GetSpec(options.spec)
+	local style = Styles.GetStyle(options.style)
+
+	--Compute the filename, minus style-specific suffix.
+	local basename = dir .. spec:FilePrefix() .. simplename
+	
+	BuildHeader(options, spec, style, specData, basename)
+end
+
+local function LoadSpec(options)
+	local specfile =
+	{
+		gl = "glspec.lua",
+		glX = "glxspec.lua",
+		wgl = "wglspec.lua",
+	}
+	
+	local specFileLoc = GetSpecFilePath();
+	return LoadLuaSpec(specFileLoc .. specfile[options.spec])
+end
+
+
+
+return
+{
+	Generate = Generate,
+	LoadSpec = LoadSpec,
+}
 -		wgl: Uses the WGL "spec".
 - version: OpenGL version to export. All core features from that version and below will be exported. Will only be present when exporting "gl" loaders.
 - profile: OpenGL profile to use. Default is chosen based on GL version. One of the following:
--		core:
+-		core: Default
 -		compatibility:
 - extensions: A list of OpenGL extensions to export.
 - outname: The base filename of the file to create.
 - style: A string containing the particular style of binding. This can be:
 -		pointer_c: The default. The functions will be stored in pointers exposed to the user. #defines will be used to rename the pointers to the core GL function names.
 -		pointer_cpp: The functions will be stored in pointers, but the pointers and enumerators will be placed in the namespace "gl".
+- indent: A string that defines the indentation style for the output.
+-		tab: Uses tabs. Default.
+-		space: Uses 2 spaces.
 - prefix: A prefix to be added to the names of identifiers that must be global, while avoiding name clashes. This is useful if you want to have different sets of bindings to different APIs (like a GL 3.3 and 2.1 binding). Defaults to the empty string.
 ]]
 
 local cmd = require "_CmdLineOptions"
+local styles = require "_Styles"
 
 local function FixupExtensionName(ext)
 	return ext
 	"style",
 	"style",
 	{"Export style."},
-	{"pointer_c", "pointer_cpp"},
+	styles.GetStyleList(),
+	1)
+parseOpts:enum(
+	"indent",
+	"indent",
+	{"Indentation style."},
+	{"tab", "space"},
 	1)
 parseOpts:array(
 	"exts",
+--[[ This module contains all of the spec-specific constructs (except where specs and styles overlap. That is, where styles have to do spec-specific work).
+
+This module has a function called GetSpec which is given the spec name and returns a table containing functions/data that can be evaluated to do different jobs. This "class" contains:
+
+- FilePrefix: nullary function that returns the filename prefix for this spec type.
+
+- PlatformSetup: Takes a file and writes out platform-specific setup stuff.
+
+- GetHeaderInit: Nullary function that returns a string to be written to the beginning of a header, just after the include guards.
+]]
+
+require "_util"
+
+local gl_spec = {}
+local wgl_spec = {}
+local glx_spec = {}
+
+local specTbl =
+{
+	gl = gl_spec,
+	wgl = wgl_spec,
+	glX = glx_spec,
+}
+
+-------------------------------------------------
+-- Spec-specific functions.
+
+
+---FilePrefix
+function gl_spec.FilePrefix() return "gl_" end
+function wgl_spec.FilePrefix() return "wgl_" end
+function glx_spec.FilePrefix() return "glX_" end
+
+--Include-guard string.
+function gl_spec.GetIncludeGuardString() return "OPENGL" end
+function wgl_spec.GetIncludeGuardString() return "WINDOWSGL" end
+function glx_spec.GetIncludeGuardString() return "GLXWIN" end
+
+--Header initialization.
+function gl_spec.GetHeaderInit()
+	return dofile(GetDataFilePath() .. "gl_specinit.lua")
+end
+function wgl_spec.GetHeaderInit()
+	return dofile(GetDataFilePath() .. "wgl_specinit.lua")
+end
+function glx_spec.GetHeaderInit()
+	return dofile(GetDataFilePath() .. "glx_specinit.lua")
+end
+
+
+
+
+--------------------------------------------------
+-- Spec retrieval machinery
+local function CopyTable(tbl)
+	local ret = {}
+	for key, value in pairs(tbl) do
+		ret[key] = value
+	end
+	return ret
+end
+
+local function GetSpec(spec)
+	local spec_tbl = specTbl[spec]
+	assert(spec_tbl, "Unknown specification " .. spec)
+	return CopyTable(spec_tbl)
+end
+
+return { GetSpec = GetSpec }
+--[[This module is the interface to all of the style-based code generation facilities.
+
+The module has a function called GetStyleList, which returns a list of all available styles.
+
+This module has a function called GetStyle, which is given a style name. It will return a table of functions that can be evaluated to do different code generation tasks. This table contains:
+
+- header.CreateFile(basename, options)
+--		basename is the filename sans extension. It opens a TabbedFile from it, using the options in options.
+
+- header.MakeIncludeGuard(prefix, specIncl)
+--		specIncl is an include-guard string from the spec. It returns a string that includes the two strings, which is appropriate for use as an include-guard.
+
+
+
+
+If you want to extend this to new styles, then add a module for your style, import it, and register it's module table with the registry. Your module should export a function `Create` which takes no parameters and returns a table as defined above.
+]]
+
+local style_registry =
+{
+	pointer_c = require("StylePointerC"),
+}
+
+local default_style = "pointer_c"
+
+
+
+local function GetStyleList()
+	--Make sure the default is first.
+	local list = {default_style}
+	assert(style_registry[default_style], "Bad default style.")
+	
+	for style, data in pairs(style_registry) do
+		if(style ~= default_style) then
+			list[#list + 1] = style
+		end
+	end
+	
+	return list
+end
+
+local function GetStyle(name)
+	assert(style_registry[name], "Unknown style named " .. name)
+	
+	return style_registry[name].Create()
+end
+
+return{
+	GetStyleList = GetStyleList,
+	GetStyle = GetStyle,
+}
+--[[ Exports a table containing one function: TabbedFile. It wraps a regular Lua file-handle, providing extra functions. Tabs can either be a number of spaces or one tab. It provides the following functions, in addition to (or replacing) the Lua standard ones:
+
+- inc: Increments the tab count by the number given, or by 1 if nothing is given.
+- dec: Decrements the tab count by the number given, or by 1 if nothing is given.
+- fmt: As string.format followed by an indented write
+- write: An indented write; everything is written after the indent.
+- rawfmt: As string.format followed by a NON-indented write.
+- rawwrite: hFile:write.
+
+Each call to one of the non-raw writing functions will indent the text.
+]]
+
+local members = {}
+
+function members:inc(count)
+	count = count or 1
+	rawset(self, "_indent", self._indent + count)
+end
+
+function members:dec(count)
+	count = count or 1
+	rawset(self, "_indent", self._indent - count)
+end
+
+function members:fmt(fmt, ...)
+	self:_Indent()
+	local str = fmt:format(...)
+	rawget(self, "_hFile"):write(str)
+end
+
+function members:rawfmt(fmt, ...)
+	local str = fmt:format(...)
+	rawget(self, "_hFile"):write(str)
+end
+
+function members:write(...)
+	self:_Indent()
+	rawget(self, "_hFile"):write(...)
+end
+
+function members:rawwrite(...)
+	rawget(self, "_hFile"):write(...)
+end
+
+-----------------------------------------------------
+-- Standard members
+local fileMembers =
+{
+	"close",
+	"flush",
+	"lines",
+	"read",
+	"seek",
+	"setvbuf",
+	"write",
+}
+
+for _, fileMem in ipairs(fileMembers) do
+	if(not members[fileMem]) then
+		members[fileMem] = function(self, ...)
+			local hFile = rawget(self, "_hFile")
+			return hFile[fileMem](hFile, ...)
+		end
+	end
+end
+
+local metatable = {}
+
+function metatable.__index(self, key)
+	return members[key]
+end
+
+metatable.__newindex = {}
+
+local function IndentFunc(self)
+	self._hFile:write(string.rep(self._indentStr, self._indent))
+end
+
+local function TabbedFile(hFile, style, numSpaces)
+	numSpaces = numSpaces or 2
+	
+	local proxy =
+	{
+		_hFile = hFile,
+		_indent = 0,
+		_Indent = IndentFunc,
+	}
+	
+	if(style == "tab") then
+		proxy._indentStr = "\t"
+	elseif(style == "space") then
+		proxy._indentStr = string.rep(" ", numSpaces)
+	else
+		error("Unknown indent style " .. style)
+	end
+	
+	setmetatable(proxy, metatable)
+	
+	return proxy
+end
+
+return { TabbedFile = TabbedFile }

data/gl_specinit.lua

+--Initialization text for the 'gl' spec header.
+
+return [[
+#if defined(__gl_h_) || defined(__GL_H__)
+#error Attempt to include auto-generated header after including gl.h
+#endif
+#if defined(__glext_h_) || defined(__GLEXT_H_)
+#error Attempt to include auto-generated header after including glext.h
+#endif
+#if defined(__gl_ATI_h_)
+#error Attempt to include auto-generated header after including glATI.h
+#endif
+
+#define __gl_h_
+#define __GL_H__
+#define __glext_h_
+#define __GLEXT_H_
+#define __gl_ATI_h_
+
+#ifndef APIENTRY
+	#if defined(__MINGW32__)
+		#ifndef WIN32_LEAN_AND_MEAN
+			#define WIN32_LEAN_AND_MEAN 1
+		#endif
+		#ifndef NOMINMAX
+			#define NOMINMAX
+		#endif
+		#include <windows.h>
+	#elif (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__)
+		#ifndef WIN32_LEAN_AND_MEAN
+			#define WIN32_LEAN_AND_MEAN 1
+		#endif
+		#ifndef NOMINMAX
+			#define NOMINMAX
+		#endif
+		#include <windows.h>
+	#else
+		#define APIENTRY
+	#endif
+#endif //APIENTRY
+
+#ifndef GLE_FUNCPTR
+	#define GLE_REMOVE_FUNCPTR
+	#if defined(_WIN32)
+		#define GLE_FUNCPTR APIENTRY
+	#else
+		#define GLE_FUNCPTR
+	#endif
+#endif //GLE_FUNCPTR
+
+#ifndef GLAPI
+	#define GLAPI extern
+#endif
+
+]]

data/glx_specinit.lua

+--Initialization text for the 'glX' spec header.
+
+return [[
+#ifdef __glxext_h_
+#error Attempt to include glx_exts after including glxext.h
+#endif
+
+#define __glxext_h_
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <GL/glx.h>
+#define GLE_FUNCPTR
+
+]]

data/wgl_specinit.lua

+--Initialization text for the 'wgl' spec header.
+
+return [[
+#ifdef __wglext_h_
+#error Attempt to include auto-generated WGL header after wglext.h
+#endif
+
+#define __wglext_h_
+
+#ifndef WIN32_LEAN_AND_MEAN
+	#define WIN32_LEAN_AND_MEAN 1
+#endif
+#ifndef NOMINMAX
+	#define NOMINMAX
+#endif
+#include <windows.h>
+
+#ifdef GLE_FUNCPTR
+#undef GLE_FUNCPTR
+#endif //GLE_FUNCPTR
+#define GLE_FUNCPTR WINAPI
+
+]]

docs/Command Line Options.xml

                         <para><literal>pointer_cpp</literal></para>
                     </listitem>
                 </itemizedlist>
-                <para>The specific meaning of these parameters is explained elsewhere.</para>
+                <para>The specific meaning of these parameters is explained elsewhere. Note that the
+                    system is extensible; new styles can be added by modifying an appropriate script
+                    and hooking it into the right place in <filename>_Styles.lua</filename>.</para>
+            </glossdef>
+        </glossentry>
+        <glossentry>
+            <glossterm>-indent</glossterm>
+            <glossdef>
+                <para>The indentation style for the output text. It must be one of the
+                    following:</para>
+                <itemizedlist>
+                    <listitem>
+                        <para><literal>tab</literal>: default</para>
+                    </listitem>
+                    <listitem>
+                        <para><literal>space</literal>: Will use 2 spaces to indent.</para>
+                    </listitem>
+                </itemizedlist>
             </glossdef>
         </glossentry>
         <glossentry>