Update scripts (from donut onwards) are written in a new little 
 | 
scripting language ("edify") that is superficially somewhat similar to 
 | 
the old one ("amend").  This is a brief overview of the new language. 
 | 
  
 | 
- The entire script is a single expression. 
 | 
  
 | 
- All expressions are string-valued. 
 | 
  
 | 
- String literals appear in double quotes.  \n, \t, \", and \\ are 
 | 
  understood, as are hexadecimal escapes like \x4a. 
 | 
  
 | 
- String literals consisting of only letters, numbers, colons, 
 | 
  underscores, slashes, and periods don't need to be in double quotes. 
 | 
  
 | 
- The following words are reserved: 
 | 
  
 | 
       if    then    else   endif 
 | 
  
 | 
  They have special meaning when unquoted.  (In quotes, they are just 
 | 
  string literals.) 
 | 
  
 | 
- When used as a boolean, the empty string is "false" and all other 
 | 
  strings are "true". 
 | 
  
 | 
- All functions are actually macros (in the Lisp sense); the body of 
 | 
  the function can control which (if any) of the arguments are 
 | 
  evaluated.  This means that functions can act as control 
 | 
  structures. 
 | 
  
 | 
- Operators (like "&&" and "||") are just syntactic sugar for builtin 
 | 
  functions, so they can act as control structures as well. 
 | 
  
 | 
- ";" is a binary operator; evaluating it just means to first evaluate 
 | 
  the left side, then the right.  It can also appear after any 
 | 
  expression. 
 | 
  
 | 
- Comments start with "#" and run to the end of the line. 
 | 
  
 | 
  
 | 
  
 | 
Some examples: 
 | 
  
 | 
- There's no distinction between quoted and unquoted strings; the 
 | 
  quotes are only needed if you want characters like whitespace to 
 | 
  appear in the string.  The following expressions all evaluate to the 
 | 
  same string. 
 | 
  
 | 
     "a b" 
 | 
     a + " " + b 
 | 
     "a" + " " + "b" 
 | 
     "a\x20b" 
 | 
     a + "\x20b" 
 | 
     concat(a, " ", "b") 
 | 
     "concat"(a, " ", "b") 
 | 
  
 | 
  As shown in the last example, function names are just strings, 
 | 
  too.  They must be string *literals*, however.  This is not legal: 
 | 
  
 | 
     ("con" + "cat")(a, " ", b)         # syntax error! 
 | 
  
 | 
  
 | 
- The ifelse() builtin takes three arguments:  it evaluates exactly 
 | 
  one of the second and third, depending on whether the first one is 
 | 
  true.  There is also some syntactic sugar to make expressions that 
 | 
  look like if/else statements: 
 | 
  
 | 
     # these are all equivalent 
 | 
     ifelse(something(), "yes", "no") 
 | 
     if something() then yes else no endif 
 | 
     if something() then "yes" else "no" endif 
 | 
  
 | 
  The else part is optional. 
 | 
  
 | 
     if something() then "yes" endif    # if something() is false, 
 | 
                                        # evaluates to false 
 | 
  
 | 
     ifelse(condition(), "", abort())   # abort() only called if 
 | 
                                        # condition() is false 
 | 
  
 | 
  The last example is equivalent to: 
 | 
  
 | 
     assert(condition()) 
 | 
  
 | 
  
 | 
- The && and || operators can be used similarly; they evaluate their 
 | 
  second argument only if it's needed to determine the truth of the 
 | 
  expression.  Their value is the value of the last-evaluated 
 | 
  argument: 
 | 
  
 | 
     file_exists("/data/system/bad") && delete("/data/system/bad") 
 | 
  
 | 
     file_exists("/data/system/missing") || create("/data/system/missing") 
 | 
  
 | 
     get_it() || "xxx"     # returns value of get_it() if that value is 
 | 
                           # true, otherwise returns "xxx" 
 | 
  
 | 
  
 | 
- The purpose of ";" is to simulate imperative statements, of course, 
 | 
  but the operator can be used anywhere.  Its value is the value of 
 | 
  its right side: 
 | 
  
 | 
     concat(a;b;c, d, e;f)     # evaluates to "cdf" 
 | 
  
 | 
  A more useful example might be something like: 
 | 
  
 | 
     ifelse(condition(), 
 | 
            (first_step(); second_step();),   # second ; is optional 
 | 
            alternative_procedure()) 
 |