Commits

Jason McKesson committed 2a37978

Style creation document.

Comments (0)

Files changed (2)

Style_Creation.wiki

 The style system is designed to be extensible and as simple as possible. That doesn't mean it's not somewhat complex.
+
+A {{{style}}} is a Lua table that contains a number of functions and tables. These functions will be called by the system to do specific things at specific times.
+
+You should not need to keep state between function invocations (the {{{pointer_c}}} style works completely statelessly, relying only on function arguments). However, you can use local variables to store state if you wish. The system will never ask your style to run twice (at least, not without a process restart).
+
+The {{{style}}} table will need two sub-tables named {{{source}}} and {{{header}}}. They contain functions for generating material for source and header files, respectively. Most of the functions are in these two sub-tables.
+
+<<<toc>>>
+
+==Naming convention==
+
+The system follows a strict naming convention for its parameters. Each name refers to an object or value with specific data. Here are the possibilities:
+
+**options**:
+
+The options data structure. It contains the options processed from the command-line. Among these is {{{extensions}}}, the list of extension names that are being explicitly written. You can tell which spec is being used with {{{options.spec}}}, but it's better to rely on the {{{spec}}} parameter as seen below.
+
+**hFile**:
+
+A {{{TabbedFile}}}. This is a special kind of Lua IO file. It supports all of the Lua IO methods (//DO NOT CLOSE IT!//), but it's designed to handle indentation. As such, it extends the Lua IO with specialized routines to auto-indent individual lines. This allows the system to determine the indention to use based on command-line options. The assumption with almost all of the writing functions is that each write is an individual line.
+
+Note that you must use it with Lua's member calling conventions ({{{hFile:write}}}, for example). If you try to use {{{io.write}}}, things will break.
+
+{{{hFile:inc}}} and {{{hFile:dec}}} are functions that increment/decrement the current indention level. The indention can be preserved with {{{hFile:push}}} and restored with {{{hFile:pop}}}.
+
+The {{{TabbedFile}}} also offers the ability to do string formatting directly into the write. {{{hFile:fmt}}} takes a format string and some parameters, forwards the parameters to {{{string.format}}}, then writes that string as a line.
+
+There are block writing functions, {{{hFile:writeblock}}} and {{{hFile:fmtblock}}}. These functions will split the written string into individual lines and indent each one.
+
+If you don't want indented writes, then use {{{hFile:rawwrite}}} and {{{hFile:rawfmt}}}.
+
+**specData**:
+
+This is the entire data containing every enumeration, typedef, function, etc for the specification (OpenGL, WGL, GLX). It is a massive struct, and it's format is complex.
+
+You can see what specData looks like by reading {{{glspecs/glspec.lua}}}. {{{specData}}} is derived from this table, but with some modifications. The modifications are detailed in the comments at the top of {{{modules/LoadLuaSpec.lua}}}. They're primarily convenience stuff, to make it easier to find an enum by its enumeration name and so forth.
+
+**spec**:
+
+This is a struct containing functions used to get specification-specific strings. This allows the style of writing to be mostly independent of things like whether it is writing to OpenGL or WGL. For example, if you have the base name of an enumeration, and you want to prefix it with the spec-defined prefix for enumerations, you do this:
+
+{{{spec.EnumNamePrefix() .. enumName}}}
+
+There are a number of spec functions that return prefix strings or other spec-based strings. You can find these in the {{{modules/Specs.lua}}} file, with a comment stating what each one returns.
+
+There are also some functions that provide general information: list of versions, list of core extensions, a string containing the definitions for the OpenGL function to load function pointers, etc. These lists are all stored in the {{{data}}} directory, using the file format {{{data/<specName>_spec<data>.lua}}}. 
+
+**extName**:
+
+The base name of an extension. Usually paired with {{{specData}}}, as the name alone isn't terribly useful. You can get the list of enumerators and functions defined by this extension with {{{specData[extName].enums/funcs}}}. These are not named of enumerators and functions; they're the actual part of the {{{specData}}} that defines everything about that enum/func.
+
+**enum**:
+
+This is an enumeration. Not the //name// of an enumeration; the enumeration itself. It contains the name {{{enum.name}}}, but it also contains versioning information and so forth. It is an entry from the {{{specData.enumerations}}} table.
+
+If you want to get the value of an enumerator, you cannot simply use {{{enum.value}}}. You need the {{{enum}}} and the {{{enumTable}}} (see below). Then, you use {{{common.ResolveEnumValue}}}, where {{{common}}} is the {{{CommonStyle}}} module table.
+
+**enumTable**:
+
+A table of {{{enum}}}s, indexed by enumeration name. It comes from {{{specData.enumtable}}}.
+
+**func**:
+
+This is a function. As with {{{enum}}}, it is not merely the name of a function (that's {{{func.name}}}); it is the function itself. It is an element taken from the {{{specData.funcData.functions}}} array. It contains many properties of a function.
+
+If you want to get the parameters (C-style) in a function, you can use {{{common.GetFuncParamList}}}, which requires a {{{typename}}} (see below). Otherwise, you would have to deal with the many difficulties of pulling a viable parameter list from a {{{func}}}.
+
+**typemap**:
+
+This is a mapping between types as defined in {{{func}}} (for parameters and values) and types as defined by C/C++, as well as the standard OpenGL/system typedefs and such. It is from {{{specData.typemap}}}.
+
+**version**:
+
+A //string// (remember this) that contains the version of interest. Since it's a string, you need to apply {{{tonumber}}} to it to get a proper number.
+
+==Library functions==
+
+There are a number of common operations that different styles will share. The {{{CommonStyle}}} module returns a table containing these operations. They are defined as follows:
+==Resolving conflicts==
+
+Your style may create global definitions and so forth that come into conflict with other things. Here are the rules you need to follow:
+
+* The user should be able to use different specs with the same style and link them together in the same program without conflicts. Files generated like this should coexist. This effectively means that you need to make sure that your names are prefixed with something spec-specific. The {{{spec}}} table has functions to get an appropriate prefix; the {{{spec.DeclPrefix}}} is the general prefix for declaration/definitions of things that can conflict at link time.
+* The user should be able to #include the standard headers for OpenGL/GLX/WGL //after// your generated header without incident. So you need to #define various values to prevent the inclusion of standard headers (or include them yourself).
+* If the user tries to #include the standard spec headers //before// your generated header, you should provide an appropriate compile-time error. So you need to test to see if standard variables are included, and fail with a {{{#error}}} if they are.
+* The user should be able to supply a prefix with the {{{-prefix}}} option. The user should be able to generate two separate source/header files with the //exact same options// with the exception of the prefixes. That is, the user can supply the same specification, version, extensions list, etc. And both files should be able to be linked together into a single program entirely without incident. Both loaders should be able to co-exist peacefully; loading function pointers for one should not impact the loading of function pointers for another\\Note: if your style does static linking, such as for Linux or OSX, then the part about loading pointers for one not impacting the other can be ignored.\\This rule effectively means that you must prefix every non-static definition. Namespace scoping would also work, if you use the prefix as the namespace (or prefix the namespace with it).\\The prefix string is in {{{options.prefix}}}. Note that it will always be present; if you want to test for a user-defined prefix, test it against the empty string.
+
+So prefix names that can conflict with the user-prefix //and// the spec's prefix.
+==File structure==
+
+A good way to understand the nature of the functions is to show how the functions will be called by the system to build the header/source file. Here is the structure of a header file, as far as the system is concerned. Each function call represents the system calling that function with those parameters one or more times.
+
+{{{header.CreateFile(basename, options) //Return the name of the file. header.WriteBeginIncludeGuard(hFile, spec, options) header.WriteStdTypedefs(hFile, specData, spec, options) header.WriteSpecTypedefs(hFile, specData, spec, options) header.WriteBeginDecl(hFile, spec, options) //For each user-specified extension header.WriteExtVariableDecl(hFile, extName, specData, spec, options) header.WriteExtVariableDecl(hFile, ..., specData, spec, options) ... header.WriteBeginEnumDeclBlock(hFile, spec, options) //For each enum to be written, in order of extensions/core //Will call one or the other. header.WriteEnumDecl(hFile, enum, enumTable, spec, options) header.WriteEnumPrevDecl(hFile, enum, enumTable, spec, options, extName) header.WriteEndEnumDeclBlock(hFile, spec, options) header.WriteBeginFuncDeclBlock(hFile, spec, options) //For each user-specified extension: header.WriteBeginExtFuncDeclBlock(hFile, extName, spec, options) //For each function in that extension header.WriteFuncDecl(hFile, func, typemap, spec, options) header.WriteFuncDecl(hFile, ..., typemap, spec, options) ... header.WriteEndExtFuncDeclBlock(hFile, extName, spec, options) //For each version, where applicable: //For each core extension that was not user-specified: header.WriteBeginExtFuncDeclBlock(hFile, extName, spec, options) header.WriteFuncDecl(hFile, func, typemap, spec, options) header.WriteFuncDecl(hFile, ..., typemap, spec, options) ... header.WriteEndExtFuncDeclBlock(hFile, extName, spec, options) //For each core function from this version *not* in a core extension. header.WriteFuncDecl(hFile, func, typemap, spec, options) header.WriteFuncDecl(hFile, ..., typemap, spec, options) ... header.WriteBeginFuncDeclBlock(hFile, spec, options) header.WriteUtilityDecls(hFile, spec, options) header.WriteMainLoaderFuncDecl(hFile, spec, options) header.WriteVersioningFuncDecls(hFile, spec, options) //Only if the spec has versions. header.WriteEndDecl(hFile, spec, options) header.WriteEndIncludeGuard(hFile, spec, options)}}}
+
+And here is the equivalent structure for the source files:
+
+{{{source.CreateFile(basename, options) //Name of the file. source.WriteIncludes(hFile, spec, options) #include "HEADER_FILENAME" source.WriteBeginDef(hFile, spec, options) //For each user-specified extension source.WriteExtVariableDef(hFile, extName, specData, spec, options) source.WriteExtVariableDef(hFile, ..., specData, spec, options) ... //For each user-specified extension: source.WriteBeginExtFuncDefBlock(hFile, extName, spec, options) //For each function in the extension: source.WriteFuncDef(hFile, func, typemap, spec, options) source.WriteFuncDef(hFile, ..., typemap, spec, options) ... source.WriteBeginExtLoaderBlock(hFile, extName, spec, options) //For each function in the extension source.WriteCoreFuncLoader(hFile, func, typemap, spec, options) source.WriteEndExtLoaderBlock(hFile, extName, spec, options) source.WriteEndExtFuncDefBlock(hFile, extName, spec, options) source.WriteBeginCoreFuncDefBlock(hFile, version, spec, options) //For each version, where applicable //For each core extension in that version which was not user-specified { //For each function in that core extension: source.WriteCoreFuncLoader(hFile, func, typemap, spec, options) source.WriteCoreFuncLoader(hFile, .., typemap, spec, options) ... } //For each function from that version not in a core extension: source.WriteCoreFuncLoader(hFile, func, typemap, spec, options) source.WriteCoreFuncLoader(hFile, .., typemap, spec, options) ... source.WriteBeginCoreLoaderBlock(hFile, version, spec, options) //For each version, where applicable //For each core extension in that version which was not user-specified { //For each function in that core extension: source.WriteCoreFuncLoader(hFile, func, typemap, spec, options) } //For each function from that version *not* in a core extension: source.WriteCoreFuncLoader(hFile, func, typemap, spec, options) source.WriteEndCoreLoaderBlock(hFile, version, spec, options) source.WriteEndCoreFuncDefBlock(hFile, version, spec, options) source.WriteUtilityDefs(hFile, specData, spec, options) source.WriteMainLoaderFunc(hFile, specData, spec, options) source.WriteVersioningFuncs(hFile, specData, spec, options) //Only if the spec has versions. source.WriteEndDef(hFile, spec, options)}}}
+
+==Style function reference==
+
+The reference documentation for style functions is available here.

Style_Pointer_C.wiki

 
 If the value is {{{LOAD_FAILED}}}, then the extension was not found in the extension string, so no attempt was made to load it. If the value is {{{LOAD_SUCCEEDED}}}, then the extension was loaded in its entirety (all function pointers accounted for). Otherwise, some number of function pointers failed to load. To get the number of functions that failed to load for the extension, take the integer value and subtract {{{LOAD_SUCCEEDED}}} from it.
 
-The return value for the function loader works the same way. It refers to the success or failure to load the core functions (obviously for WGL/GLX, there are no core functions, so it will always be successful). The attempt will always be made to load the core functions, so {{{LOAD_FAILED}}} is not a possibility.
+The return value for the function loader works mostly the same way. {{{LOAD_FAILED}}} does not signal the failure to load the core functions or some extensions. It signals the failure of the process to work //at all.// This is for something very basic, like the failure to get the function pointers needed to get the extension string. Without the extension string, we cannot detect what should and shouldn't be loaded. Therefore, if this is returned, //nothing// was loaded.
 
-Also, this style will generate functions to query version availability for core OpenGL. 
+For non-fail states, the value works like for the individual extension variables, except that the number that failed to load refer to core functions. So for specs that don't load core functions, it will always return {{{LOAD_SUCCEEDED}}}.
+
+Also, this style will generate functions to query the version of the OpenGL context.
 
 ==Compatibility==