|
@@ -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.
|