David Rose 24 years ago
parent
commit
4a7f71dbd7
2 changed files with 518 additions and 1 deletions
  1. 510 0
      panda/src/doc/ppremake-syntax.txt
  2. 8 1
      panda/src/doc/ppremake-variables.txt

+ 510 - 0
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 <format>
+
+    Defines the type of file that is to be generated by the next
+    #output command (see #output, below).  The <format> 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 <text>
+
+    Outputs the indicated text to standard error as soon as it is
+    encountered.  This is primarily useful for debugging ppremake
+    scripts.
+
+  #include <filename>
+
+    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, <filename>
+    means any ppremake expression which can be evaluated to a string.
+    If the file does not exist, an error is generated.
+
+  #sinclude <filename>
+
+    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 <subroutine> <params>
+  
+    Calls the named subroutine immediately.  Here <subroutine> is the
+    name of the subroutine to call, and <params> 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 <text>
+
+    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 <varname> <value>
+
+    Declares a new variable within the current scope with the
+    indicated name, and sets it to the indicated value.  Variables and
+    expressions within <value> 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 <varname> 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 <varname> <value>
+
+    Behaves the same as #define, but variables and expressions within
+    <value> are not evaluated immediately.  Instead, the <value>
+    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 <varname> <value>
+
+    Changes the value of an existing variable to the indicated value.
+    Like #define, variables and expressions within <value> 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 <varname> <key_varname>(<scope_names>)
+
+    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, <varname> and
+    <key_varname> 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 <varname> <key>
+
+    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 <expr>
+    ...
+  #elif <expr>
+    ...
+  #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 <expr>
+    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 <scopename>
+    ..
+  #end <scopename>
+
+    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 <iterator> <values>
+    ..
+  #end <iterator>
+
+    Executes the nested block of code repeatedly, once for each of the
+    space-separated words in <values>.  The <iterator> represents the
+    name of a variable that will be created each time through the
+    loop, with the next value in sequence.
+
+  #forscopes <scopenames>
+    ..
+  #end <scopenames>
+
+    Executes the nested block of code repeatedly, once for each of the
+    scopes named by the space-separated list of names in <scopenames>.
+    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 <iterator> <mapvarname>
+    ..
+  #end <iterator>
+
+    Executes the nested block of code repeatedly, once for each key in
+    the map variable.  Each time through the loop, a variable named
+    <iterator> is created with the value of the current key, and the
+    code is also evaluated within the associated scope.
+
+  #defsub <subname> <params>
+    ..
+  #end <subname>
+
+    Defines a new subroutine.  The nested block of code will be
+    evaluated when #call <subname> is later invoked.  The <params>
+    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 <funcname> <params>
+    ..
+  #end <funcname>
+  
+    Defines a new function.  This is similar to a subroutine, except
+    that the function is invoked inline, like a variable: $[<funcname>
+    <params>], 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 <filename> <flags>
+    ..
+  #end <filename>
+
+    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 <flags> 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
+    <flags> 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:<from>=<to>], where <from> and <to> 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(<scope names>)], where <scope names> 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 <varname> <key_varname>(<scope_names>)
+
+  Where <varname> is the name of the map variable you are declaring,
+  <key_varname> is the name of the key variable that exists in each of
+  the scopes, and <scope_names> is the list of scope names over which
+  the map variable is being built.
+
+  This builds up an index into <scope_names> based on the value of the
+  $[<key_varname>] within each scope.  Within each scope, the
+  $[<key_varname>] 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:
+
+    $[<varname> <expr>,<key>]
+
+  This returns the value of <expr> as evaluated within whatever scope
+  is referenced by the string <key>.  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 <key>
+  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 <funcname> <params>
+      ..
+    #end <funcname>
+
+  where <funcname> is any arbitrary function name, and <params> 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:
+
+    $[<function> <params>]
+
+  E.g.:
+
+    $[updowncase $[filename],]
+
+  Many pre-defined functions are also available; see
+  ppremake-variables.txt.

+ 8 - 1
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
 replaced by square brackets to prevent confusion with actual makefile
 syntax.
 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,
 The general convention is for variables that are built into ppremake,
 or defined by the system ppremake scripts in the $DTOOL root
 or defined by the system ppremake scripts in the $DTOOL root
 directory, should be defined with uppercase letters.  User-defined
 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.
 all built-in function names are lowercase.
 
 
 
 
-
 The following variables are built into the ppremake executable, and
 The following variables are built into the ppremake executable, and
 are always defined:
 are always defined: