From 4a7f71dbd7d2d7eed08a8373f769963305abb648 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 7 Feb 2002 17:57:15 +0000 Subject: [PATCH] new docs --- panda/src/doc/ppremake-syntax.txt | 510 +++++++++++++++++++++++++++ panda/src/doc/ppremake-variables.txt | 9 +- 2 files changed, 518 insertions(+), 1 deletion(-) create mode 100644 panda/src/doc/ppremake-syntax.txt diff --git a/panda/src/doc/ppremake-syntax.txt b/panda/src/doc/ppremake-syntax.txt new file mode 100644 index 0000000000..b0f7e9a501 --- /dev/null +++ b/panda/src/doc/ppremake-syntax.txt @@ -0,0 +1,510 @@ +NAMED SCOPES + +Any discussion of ppremake script syntax must begin with an +introduction to ppremake's concept of named scopes. This concept is +relied on heavily within ppremake scripts and is the source of most of +the scripting language's power. + +Like many block-scoped languages, ppremake can support arbitrary +nesting levels of scopes. Each nested scope can access variables in +the outer scopes, and can define new variables that are local to that +scope. + +In ppremake, there is one (unnamed) global scope, in which all the +variables defined in Global.pp and related files are declared. There +are also a number of individually named scopes, one scope for each +directory in the source hierarchy that contains a Sources.pp file. +Each of these scopes is a child of the global scope, each of these +defines the varibles defined within its Sources.pp file. The name of +each scope is the name of the directory. + +For instance, imagine the following simple directory hierarchy: + + root + root/Package.pp + root/Sources.pp + root/apple + root/apple/Sources.pp + root/apple/pear + root/apple/pear/Sources.pp + root/banana + root/banana/Sources.pp + +In this example, there will be five scopes, ordered like this: + + global scope + | + +------+--+--+-----+ + | | | | + root/ apple/ pear/ banana/ + +That is, there is an unnamed global scope, and four named scopes, one +for each of the four Sources.pp files: "root/", "apple/", "pear/", and +"banana/". Each of the named scopes is a sibling of the others, with +no relation to the directory hierarchy; all of the named scopes are +children of the global scope. (The trailing slash is used to +differentiate these automatically-created named scopes from explicit +nested scopes, described below.) + +It is possible to access, from any one of the scopes, variables that +are defined in another scope. The syntax to do this is discussed in +more detail below, but for instance the expression $[FOO(apple/)] +returns the value of $[FOO] as if it were evaluated within the "apple" +scope. + +Although all of the automatically-created named scopes are given a +flat hierarchy, it is possible to define further nested scopes with +the #begin .. #end syntax (described below) within any of the +Sources.pp files. For instance, in the apple/Sources.pp file, you may +have the syntax: + + #define var1 abc + #define var2 def + + #begin foo + #define var2 123 + #define var3 456 + #end foo + +This adds a new named scope called "foo", which is a child of "apple/": + + global scope + | + +------+--+--+-----+ + | | | | + root/ apple/ pear/ banana/ + | + foo + +Within the apple scope, this new named scope can be referenced by the +name "foo"; within other scopes, it must be referenced explicitly as +"apple/foo". In the example, the value of $[var2(apple/)] is "def", +but the value of $[var2(apple/foo)] is "123". + + +PPREMAKE COMMANDS + +The following commands are available in ppremake scripts. The +commands are similar in syntax to C preprocessor directives: each +command must be given one per line, with a hash mark (#) as the first +non-blank character of the line. + +Simple commands: + + #format + + Defines the type of file that is to be generated by the next + #output command (see #output, below). The string must + evaluate to one of a number of strings that are predefined within + ppremake. Presently, this may be one of the following: + + straight - the output file is generated exactly as given, + without any additional formatting. + + collapse - multiple consecutive blank lines are collapsed into + one blank line, but otherwise the output is generated exactly + as given. + + makefile - the output file is a makefile. This implies that + multiple consecutive blank lines may be collapsed, and long + lines (particularly variable assignment lines) may be folded + with the backslash character for readability. + + #print + + Outputs the indicated text to standard error as soon as it is + encountered. This is primarily useful for debugging ppremake + scripts. + + #include + + Includes the named file. As in all the other commands given here, + the angle brackets are not part of the literal syntax; don't + confuse this with the C #include statement. Instead, + means any ppremake expression which can be evaluated to a string. + If the file does not exist, an error is generated. + + #sinclude + + Includes the named file if it exists, or quietly ignores it if it + does not. This can be used to include an optional configuration + file if it exists. + + #call + + Calls the named subroutine immediately. Here is the + name of the subroutine to call, and is the + comma-separated list of expressions to subsitute in for the + subroutine's formal parameters. The subroutine must have + previously been defined with the #defsub command (see below). + + #error + + Generates an error and immediately terminates ppremake, reporting + the indicated error message. Usually this appears within an #if + .. #endif block testing for an unexpected error condition. It may + also be used during debugging. + + #define + + Declares a new variable within the current scope with the + indicated name, and sets it to the indicated value. Variables and + expressions within are evaluated immediately, and the + resulting string is stored as the new variable's value. + + If there was already a variable within the current scope with this + name, that variable is replaced with the new value. However, if + there was a variable by the same name in an enclosing scope, the + variable in the scope above is left unchanged, and a new variable + is defined within the current scope, shadowing the variable above. + + Note that in the above does not include the dollar sign + and square bracket syntax. This syntax is used when evaluating + variables, not when referring to them by name. + + #defer + + Behaves the same as #define, but variables and expressions within + are not evaluated immediately. Instead, the + string is assigned to the variable exactly as it is now. When the + variable is evaluated later, expressions appearing within the + string will be evaluated at that time. This behaves kind of like + a simple function declaration: the variable's literal value + depends on the values of the expressions it depends on, which may + be modified at any subsequent point (thus changing the value of + the variable correspondingly). + + This operation is equivalent to VARIABLE = VALUE syntax in GNU + make (and in most makefile syntax). On the other hand, #define is + equivalent to VARIABLE := VALUE in GNU make. + + #set + + Changes the value of an existing variable to the indicated value. + Like #define, variables and expressions within are + evaluated immediately. + + This is different from #define in that (a) the variable must + already exist (i.e. it has appeared as the target of a previous + #define or #defer), and (b) it is possible to change the value of + a variable in an enclosing scope (as opposed to #define and + #defer, which can only shadow a variable in an enclosing scope, + but cannot change the parent variable itself). + + #map () + + Defines a new map variable. A map variable is a unique construct + in ppremake which associates scopes with named keys. See the + discussion on map variables, below. + + Note that, like #define, #defer, and #set, and + in the above do not include the dollar sign and + square bracket syntax. This syntax is used when evaluating + variables, not when referring to them by name. + + #addmap + + Adds a new entry to the indicated map variable, mapping the + indicated key string to the current scope. This command should + normally appear within a #forscopes .. #end block, to add a series + of keys for each of a number of different scopes. + + +Conditional commands: + + #if + ... + #elif + ... + #else + ... + #endif + + This defines a block of code that should only be executed if the + condition is met. The usual semantics apply: in the case of #if, + the immediately following code is executed only if + evaluates true; otherwise, the condition for any subsequent #elif + commands are tested, until one is found that evaluates true. If + no #elif condition evaluates true, the code under #else is + executed; in any case, normal evaluation resumes after #endif. + + #if conditions can be nested without limit, but each #endif must + match a corresponding #if. Error reporting for a mismatched #if + .. #endif pair is limited. + + As with ppremake in general, an expression is considered to be + true if it evaluates to a nonempty string, or false if it + evaluates to an empty string. + + +Block commands: + + Each of the following commands opens a block which should be closed + with a corresponding #end command. It is akin to the matching of + #if .. #endif. Block commands may be nested without limit. In + ppremake, each #end has a parameter, which must match the name on + the corresponding block command, as a visual aid to the programmer. + + #begin + .. + #end + + Begins a new nested scope. All the variables declared within this + block will be associated with the new scope of the indicated name, + which will be a child of the current scope. + + #foreach + .. + #end + + Executes the nested block of code repeatedly, once for each of the + space-separated words in . The represents the + name of a variable that will be created each time through the + loop, with the next value in sequence. + + #forscopes + .. + #end + + Executes the nested block of code repeatedly, once for each of the + scopes named by the space-separated list of names in . + Each time through the loop, the code will be re-evaluated within a + different named scope, potentially providing new values for all of + the variables referenced. Unlike #foreach, no iterator variable + is necessary. + + #formap + .. + #end + + Executes the nested block of code repeatedly, once for each key in + the map variable. Each time through the loop, a variable named + is created with the value of the current key, and the + code is also evaluated within the associated scope. + + #defsub + .. + #end + + Defines a new subroutine. The nested block of code will be + evaluated when #call is later invoked. The + list is a comma-delimited list of formal parameter names; these + names are the names of variables that will be filled in with the + corresponding actual parameters on the #call command. + + #defun + .. + #end + + Defines a new function. This is similar to a subroutine, except + that the function is invoked inline, like a variable: $[ + ], instead of with the #call command. + + All output generated within the function (that is, lines of text + between #defun and #end that are not part of a command) are + concatenated together into one string (newlines are removed) and + returned as the result of the function. + + #output + .. + #end + + Sends all output within the block (that is, lines of text between + #output and #end that are not part of a command) to the indicated + filename. The are an optional space-separated list of + keywords that modify the output behavior, presently the only + recognized flag is "notouch". + + If the file does not exist, it is created. If the file already + existed and its contents will be changed by this command, a + message is printed to the user and the file is rewritten. + + If the file already existed and its contents would not have been + changed by this command, nothing is printed to the user, although + the file is still rewritten (and the file modification timestamp + is correspondingly updated with the current time and date). + However, if the keyword "notouch" is included among the optional + following the filename, the file (and consequently its + timestamp) will not be modified unless the contents are actually + different. + + +VARIABLE REFERENCES + +The ppremake syntax supports three different kinds of variable +references: ordinary variables, map variables, and function calls. + +Ordinary variable references: + + Variables in ppremake are always referenced using a leading dollar + sign immediately followed by the name of the variable enclosed in + square brackets. This syntax was chosen to resemble the GNU make + variable syntax, but to be visually distinct to avoid confusion with + actual make variables (which we might be writing to a makefile). + + Note that the dollar sign and square brackets are not actually part + of the variable names, but are simply the syntax used to reference + the variable. However, this syntax is used throughout this document + to refer to variables, to clarify that we are referring to ppremake + variable names. + + Common ordinary variables that might be referenced in this way are + ppremake built-in variables like $[DIRNAME] or $[PLATFORM], or any + user-defined variable created with #define or #defer. Since + environment variables are also automatically pulled into the + ppremake variable space (similar to the behavior of make), + environment variables may also be referenced in this way, although + writing scripts that depend on environment variables is not + recommended as it is not as portable (not every platform gives the + user easy access to environment variables). + + There are also some fancy ways to expand ordinary variables. + + Inline pattern substitution: + + Borrowing more syntax from GNU make, ppremake allows you to + modify the contents of the variable according to a pattern-based + substitution, similar to the $[patsubst] function. The syntax + is $[varname:=], where and are filename + patterns each involving a percent sign (%). The percent sign + stands for the part of the filename that remains the same; the + rest is modified accordingly. For instance, $[file:%.c=%.o] + will expand the variable $[file] and automatically replace a .c + extension with .o. It is equivalent to $[patsubst + %.c,%.o,$[file]]. See ppremake-variables.txt. + + Inline foreign scoping: + + A special ppremake syntax exists to evaluate a variable within + one or more different named scopes. The syntax here is + $[varname()], where represents a + space-separated list of words that name the scope or scopes + within which the variable is to be evaluated. The result is the + space-separated concatenation of the values of the variable in + each of the named scopes. + + To make a contrived example, suppose you had a scope named + "foo", in which a variable $[LETTER] is defined to be the string + "alpha", and a scope named "bar", in which a variable $[LETTER] + is defined to be the string "beta". In the current scope, + however, $[LETTER] is defined as "none". + + In this example, the expression $[LETTER] evaluates to "none", + but $[LETTER(foo)] evaluates to "alpha" and $[LETTER(foo bar)] + evaluates to "alpha beta". + +Map variables: + + A map variable is a special ppremake construct to index into a table + of named scopes by key. The map variable is an indexed lookup into + a set of named scopes, to determine in which scope a given variable + has a particular value. + + To define a map variable, you need to have a set of named scopes, + and an ordinary "key" variable that has been declared in each of + them. The syntax is: + + #map () + + Where is the name of the map variable you are declaring, + is the name of the key variable that exists in each of + the scopes, and is the list of scope names over which + the map variable is being built. + + This builds up an index into based on the value of the + $[] within each scope. Within each scope, the + $[] variable is divided at the spaces into words, and + each word is added to the index as a key referencing this scope. + + + For example, consider the $[LETTER] example above. You could define + a simple map variable thus: + + #map letmap LETTER(foo bar) + + This defines a new map variable called "letmap" that maps into the + two named scopes "foo" and "bar", with the key being the value of + $[LETTER] in each of those two scopes. That is, evaluating letmap + with the string "alpha" will return the scope "foo", while + evaluating letmap with the string "beta" will return the scope + "bar". + + In other words, letmap is now a map variable with two key/value + pairs. The two keys are "alpha" and "beta", which map to the two + scopes "foo" and "bar", respectively. The keys represent the values + of the ordinary variable $[LETTER] as evaluated within the two + scopes. + + Note the similarity to the $[LETTER(foo bar)] syntax, which + incidentally returns the string "alpha beta"--the same two keys that + become part of the map variable. A map variable is a lot like an + inline foreign scoping reference, except it remembers which scope + each key came from. + + + To look up scopes in a map variable, use the syntax: + + $[ ,] + + This returns the value of as evaluated within whatever scope + is referenced by the string . To continue our example, + + $[letmap $[upcase $[LETTER]],alpha] + + will evaluate $[upcase $[LETTER]] in the "foo" scope--that is, the + scope associated with the key "alpha"--which incidentally returns + the string "ALPHA". + + It is also legal to look up multiple scopes at once. If + contains spaces, it is divided up into words at the spaces, and each + word is taken as a separate key. The result of the map variable + reference is the concatenation of all the evaluations of the + expressions in all the matched keys. + + + It is sometimes useful to ask whether a key is defined in a map + variable or not. The $[unmapped] function can do this; see + ppremake-variables.txt. Also, the $[closure] function is useful for + evaluating map variables recursively; see ppremake-variables.txt. + + +Function calls: + + Function calls are a little more conventional to other scripting + languages. User functions are defined with the syntax: + + #defun + .. + #end + + where is any arbitrary function name, and is an + optional list of comma-separated formal parameters. Any text that + appears between #defun and its matching #end (and is not part of + some other command) is returned as the result of the function. + + For instance: + + #defun updowncase abc,def + #if $[def] + $[upcase $[abc]] + #else + $[downcase $[abc]] + #endif + #end updowncase + + This defines a function with two parameters. If the second + parameter is true (nonempty), the result of the function is the + upcase of the first parameter; otherwise, the result of the function + is the downcase of the first parameter. + + To invoke the function, the syntax is somewhat like a variable + expansion: + + $[ ] + + E.g.: + + $[updowncase $[filename],] + + Many pre-defined functions are also available; see + ppremake-variables.txt. diff --git a/panda/src/doc/ppremake-variables.txt b/panda/src/doc/ppremake-variables.txt index fc7e6e2351..b9a8da1b39 100644 --- a/panda/src/doc/ppremake-variables.txt +++ b/panda/src/doc/ppremake-variables.txt @@ -5,6 +5,14 @@ heavily from that of GNU makefile syntax, with GNU make's parentheses replaced by square brackets to prevent confusion with actual makefile syntax. +Note that the dollar sign and square brackets are not actually part of +the variable names, but are simply the syntax used to reference the +variable. This syntax is included with each variable definition in +this document, because that is how you are most likely to see the +variable references. + + + The general convention is for variables that are built into ppremake, or defined by the system ppremake scripts in the $DTOOL root directory, should be defined with uppercase letters. User-defined @@ -14,7 +22,6 @@ lowercase letters. However, following the GNU makefile convention, all built-in function names are lowercase. - The following variables are built into the ppremake executable, and are always defined: