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
 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: