Initial version 1.0
authorali <ali@juiblex.co.uk>
Wed Oct 10 22:58:21 2012 +0100 (2012-10-10)
changeset 0bc8c9a11cbfc
child 1 fe592b4168f3
Initial version
.hgignore
COPYING
Makefile.am
bootstrap.sh
configure.ac
docs/reference/Makefile.am
docs/reference/implementation_defined_behaviour.xml
docs/reference/language_extensions.xml
docs/reference/libxexpr-docs.xml
docs/reference/version.xml.in
docs/reference/xexpr.xml
libxexpr/Makefile.am
libxexpr/extension.c
libxexpr/libxexpr.pc.in
libxexpr/xexpr.h
libxexpr/xexprdump.c
libxexpr/xexprdump.h
libxexpr/xexpreval.c
libxexpr/xexpreval.h
libxexpr/xexprparse.c
libxexpr/xexprparse.h
libxexpr/xexprprivate.h
libxexpr/xexprtypes.c
libxexpr/xexprtypes.h
src/Makefile.am
src/xexpr.c
test/Makefile.am
test/idb/Makefile.am
test/idb/arithmetic.sh
test/idb/arithmetic.xml
test/idb/bindings.sh
test/idb/bindings.xml
test/idb/builtin.sh
test/idb/builtin.xml
test/idb/comparison.sh
test/idb/comparison.xml
test/idb/define.sh
test/idb/define.xml
test/idb/get.sh
test/idb/get.xml
test/idb/namespaces.sh
test/idb/namespaces.xml
test/idb/numbers.sh
test/idb/numbers.xml
test/idb/pcdata.sh
test/idb/pcdata.xml
test/libxexpr/Makefile.am
test/libxexpr/atan.sh
test/libxexpr/atan.xml
test/libxexpr/exp.sh
test/libxexpr/exp.xml
test/libxexpr/log.sh
test/libxexpr/log.xml
test/libxexpr/pi.sh
test/libxexpr/pi.xml
test/libxexpr/pow.xml
test/libxexpr/sin.sh
test/libxexpr/sin.xml
test/spec/Makefile.am
test/spec/spectest11.sh
test/spec/spectest11.xml
test/spec/spectest12.sh
test/spec/spectest12.xml
test/spec/spectest13.sh
test/spec/spectest13.xml
test/spec/spectest14.sh
test/spec/spectest14.xml
test/spec/spectest15.sh
test/spec/spectest15.xml
test/spec/spectest16.sh
test/spec/spectest16.xml
test/spec/spectest17.sh
test/spec/spectest17.xml
test/spec/spectest19.sh
test/spec/spectest19.xml
test/spec/spectest20.sh
test/spec/spectest20.xml
test/spec/spectest21.sh
test/spec/spectest21.xml
test/spec/spectest24.sh
test/spec/spectest24.xml
test/spec/spectest26.sh
test/spec/spectest26.xml
test/spec/spectest27.sh
test/spec/spectest27.xml
test/spec/spectest28.sh
test/spec/spectest28.xml
test/spec/spectest29.sh
test/spec/spectest29.xml
test/spec/spectest3.sh
test/spec/spectest3.xml
test/spec/spectest31.sh
test/spec/spectest31.xml
test/spec/spectest32.sh
test/spec/spectest32.xml
test/spec/spectest33.sh
test/spec/spectest33.xml
test/spec/spectest34.sh
test/spec/spectest34.xml
test/spec/spectest35.sh
test/spec/spectest35.xml
test/spec/spectest36.sh
test/spec/spectest36.xml
test/spec/spectest38.sh
test/spec/spectest38.xml
test/spec/spectest39.sh
test/spec/spectest39.xml
test/spec/spectest4.sh
test/spec/spectest4.xml
test/spec/spectest40.sh
test/spec/spectest40.xml
test/spec/spectest42.sh
test/spec/spectest42.xml
test/spec/spectest43.sh
test/spec/spectest43.xml
test/spec/spectest45.sh
test/spec/spectest45.xml
test/spec/spectest46.sh
test/spec/spectest46.xml
test/spec/spectest48.sh
test/spec/spectest48.xml
test/spec/spectest49.sh
test/spec/spectest49.xml
test/spec/spectest5.sh
test/spec/spectest5.xml
test/spec/spectest6.sh
test/spec/spectest6.xml
test/spec/spectest7.sh
test/spec/spectest7.xml
test/spec/spectest8.sh
test/spec/spectest8.xml
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Wed Oct 10 22:58:21 2012 +0100
     1.3 @@ -0,0 +1,28 @@
     1.4 +.*\.o$
     1.5 +.*\.lo$
     1.6 +.*\.la$
     1.7 +.*\.pc$
     1.8 +/Makefile$
     1.9 +/Makefile.in$
    1.10 +^Makefile$
    1.11 +^Makefile.in$
    1.12 +^src/xexpr$
    1.13 +/\.libs/
    1.14 +/\.deps/
    1.15 +^configure$
    1.16 +^config\.
    1.17 +^config/
    1.18 +^libtool$
    1.19 +^gtk-doc\.make$
    1.20 +^autom4te\.cache/
    1.21 +^aclocal\.m4$
    1.22 +^stamp-h1$
    1.23 +^m4/
    1.24 +^docs/.*\.sgml$
    1.25 +^docs/.*\.stamp$
    1.26 +^docs/reference/html/
    1.27 +^docs/reference/xml/
    1.28 +^docs/reference/tmpl/
    1.29 +^docs/reference/version.xml
    1.30 +^docs/reference/libxexpr-*.txt
    1.31 +^docs/reference/libxexpr.*
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/COPYING	Wed Oct 10 22:58:21 2012 +0100
     2.3 @@ -0,0 +1,515 @@
     2.4 +
     2.5 +                  GNU LESSER GENERAL PUBLIC LICENSE
     2.6 +                       Version 2.1, February 1999
     2.7 +
     2.8 + Copyright (C) 1991, 1999 Free Software Foundation, Inc.
     2.9 +     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
    2.10 + Everyone is permitted to copy and distribute verbatim copies
    2.11 + of this license document, but changing it is not allowed.
    2.12 +
    2.13 +[This is the first released version of the Lesser GPL.  It also counts
    2.14 + as the successor of the GNU Library Public License, version 2, hence
    2.15 + the version number 2.1.]
    2.16 +
    2.17 +                            Preamble
    2.18 +
    2.19 +  The licenses for most software are designed to take away your
    2.20 +freedom to share and change it.  By contrast, the GNU General Public
    2.21 +Licenses are intended to guarantee your freedom to share and change
    2.22 +free software--to make sure the software is free for all its users.
    2.23 +
    2.24 +  This license, the Lesser General Public License, applies to some
    2.25 +specially designated software packages--typically libraries--of the
    2.26 +Free Software Foundation and other authors who decide to use it.  You
    2.27 +can use it too, but we suggest you first think carefully about whether
    2.28 +this license or the ordinary General Public License is the better
    2.29 +strategy to use in any particular case, based on the explanations
    2.30 +below.
    2.31 +
    2.32 +  When we speak of free software, we are referring to freedom of use,
    2.33 +not price.  Our General Public Licenses are designed to make sure that
    2.34 +you have the freedom to distribute copies of free software (and charge
    2.35 +for this service if you wish); that you receive source code or can get
    2.36 +it if you want it; that you can change the software and use pieces of
    2.37 +it in new free programs; and that you are informed that you can do
    2.38 +these things.
    2.39 +
    2.40 +  To protect your rights, we need to make restrictions that forbid
    2.41 +distributors to deny you these rights or to ask you to surrender these
    2.42 +rights.  These restrictions translate to certain responsibilities for
    2.43 +you if you distribute copies of the library or if you modify it.
    2.44 +
    2.45 +  For example, if you distribute copies of the library, whether gratis
    2.46 +or for a fee, you must give the recipients all the rights that we gave
    2.47 +you.  You must make sure that they, too, receive or can get the source
    2.48 +code.  If you link other code with the library, you must provide
    2.49 +complete object files to the recipients, so that they can relink them
    2.50 +with the library after making changes to the library and recompiling
    2.51 +it.  And you must show them these terms so they know their rights.
    2.52 +
    2.53 +  We protect your rights with a two-step method: (1) we copyright the
    2.54 +library, and (2) we offer you this license, which gives you legal
    2.55 +permission to copy, distribute and/or modify the library.
    2.56 +
    2.57 +  To protect each distributor, we want to make it very clear that
    2.58 +there is no warranty for the free library.  Also, if the library is
    2.59 +modified by someone else and passed on, the recipients should know
    2.60 +that what they have is not the original version, so that the original
    2.61 +author's reputation will not be affected by problems that might be
    2.62 +introduced by others.
    2.63 +^L
    2.64 +  Finally, software patents pose a constant threat to the existence of
    2.65 +any free program.  We wish to make sure that a company cannot
    2.66 +effectively restrict the users of a free program by obtaining a
    2.67 +restrictive license from a patent holder.  Therefore, we insist that
    2.68 +any patent license obtained for a version of the library must be
    2.69 +consistent with the full freedom of use specified in this license.
    2.70 +
    2.71 +  Most GNU software, including some libraries, is covered by the
    2.72 +ordinary GNU General Public License.  This license, the GNU Lesser
    2.73 +General Public License, applies to certain designated libraries, and
    2.74 +is quite different from the ordinary General Public License.  We use
    2.75 +this license for certain libraries in order to permit linking those
    2.76 +libraries into non-free programs.
    2.77 +
    2.78 +  When a program is linked with a library, whether statically or using
    2.79 +a shared library, the combination of the two is legally speaking a
    2.80 +combined work, a derivative of the original library.  The ordinary
    2.81 +General Public License therefore permits such linking only if the
    2.82 +entire combination fits its criteria of freedom.  The Lesser General
    2.83 +Public License permits more lax criteria for linking other code with
    2.84 +the library.
    2.85 +
    2.86 +  We call this license the "Lesser" General Public License because it
    2.87 +does Less to protect the user's freedom than the ordinary General
    2.88 +Public License.  It also provides other free software developers Less
    2.89 +of an advantage over competing non-free programs.  These disadvantages
    2.90 +are the reason we use the ordinary General Public License for many
    2.91 +libraries.  However, the Lesser license provides advantages in certain
    2.92 +special circumstances.
    2.93 +
    2.94 +  For example, on rare occasions, there may be a special need to
    2.95 +encourage the widest possible use of a certain library, so that it
    2.96 +becomes
    2.97 +a de-facto standard.  To achieve this, non-free programs must be
    2.98 +allowed to use the library.  A more frequent case is that a free
    2.99 +library does the same job as widely used non-free libraries.  In this
   2.100 +case, there is little to gain by limiting the free library to free
   2.101 +software only, so we use the Lesser General Public License.
   2.102 +
   2.103 +  In other cases, permission to use a particular library in non-free
   2.104 +programs enables a greater number of people to use a large body of
   2.105 +free software.  For example, permission to use the GNU C Library in
   2.106 +non-free programs enables many more people to use the whole GNU
   2.107 +operating system, as well as its variant, the GNU/Linux operating
   2.108 +system.
   2.109 +
   2.110 +  Although the Lesser General Public License is Less protective of the
   2.111 +users' freedom, it does ensure that the user of a program that is
   2.112 +linked with the Library has the freedom and the wherewithal to run
   2.113 +that program using a modified version of the Library.
   2.114 +
   2.115 +  The precise terms and conditions for copying, distribution and
   2.116 +modification follow.  Pay close attention to the difference between a
   2.117 +"work based on the library" and a "work that uses the library".  The
   2.118 +former contains code derived from the library, whereas the latter must
   2.119 +be combined with the library in order to run.
   2.120 +^L
   2.121 +                  GNU LESSER GENERAL PUBLIC LICENSE
   2.122 +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
   2.123 +
   2.124 +  0. This License Agreement applies to any software library or other
   2.125 +program which contains a notice placed by the copyright holder or
   2.126 +other authorized party saying it may be distributed under the terms of
   2.127 +this Lesser General Public License (also called "this License").
   2.128 +Each licensee is addressed as "you".
   2.129 +
   2.130 +  A "library" means a collection of software functions and/or data
   2.131 +prepared so as to be conveniently linked with application programs
   2.132 +(which use some of those functions and data) to form executables.
   2.133 +
   2.134 +  The "Library", below, refers to any such software library or work
   2.135 +which has been distributed under these terms.  A "work based on the
   2.136 +Library" means either the Library or any derivative work under
   2.137 +copyright law: that is to say, a work containing the Library or a
   2.138 +portion of it, either verbatim or with modifications and/or translated
   2.139 +straightforwardly into another language.  (Hereinafter, translation is
   2.140 +included without limitation in the term "modification".)
   2.141 +
   2.142 +  "Source code" for a work means the preferred form of the work for
   2.143 +making modifications to it.  For a library, complete source code means
   2.144 +all the source code for all modules it contains, plus any associated
   2.145 +interface definition files, plus the scripts used to control
   2.146 +compilation
   2.147 +and installation of the library.
   2.148 +
   2.149 +  Activities other than copying, distribution and modification are not
   2.150 +covered by this License; they are outside its scope.  The act of
   2.151 +running a program using the Library is not restricted, and output from
   2.152 +such a program is covered only if its contents constitute a work based
   2.153 +on the Library (independent of the use of the Library in a tool for
   2.154 +writing it).  Whether that is true depends on what the Library does
   2.155 +and what the program that uses the Library does.
   2.156 +
   2.157 +  1. You may copy and distribute verbatim copies of the Library's
   2.158 +complete source code as you receive it, in any medium, provided that
   2.159 +you conspicuously and appropriately publish on each copy an
   2.160 +appropriate copyright notice and disclaimer of warranty; keep intact
   2.161 +all the notices that refer to this License and to the absence of any
   2.162 +warranty; and distribute a copy of this License along with the
   2.163 +Library.
   2.164 +
   2.165 +  You may charge a fee for the physical act of transferring a copy,
   2.166 +and you may at your option offer warranty protection in exchange for a
   2.167 +fee.
   2.168 +
   2.169 +  2. You may modify your copy or copies of the Library or any portion
   2.170 +of it, thus forming a work based on the Library, and copy and
   2.171 +distribute such modifications or work under the terms of Section 1
   2.172 +above, provided that you also meet all of these conditions:
   2.173 +
   2.174 +    a) The modified work must itself be a software library.
   2.175 +
   2.176 +    b) You must cause the files modified to carry prominent notices
   2.177 +    stating that you changed the files and the date of any change.
   2.178 +
   2.179 +    c) You must cause the whole of the work to be licensed at no
   2.180 +    charge to all third parties under the terms of this License.
   2.181 +
   2.182 +    d) If a facility in the modified Library refers to a function or a
   2.183 +    table of data to be supplied by an application program that uses
   2.184 +    the facility, other than as an argument passed when the facility
   2.185 +    is invoked, then you must make a good faith effort to ensure that,
   2.186 +    in the event an application does not supply such function or
   2.187 +    table, the facility still operates, and performs whatever part of
   2.188 +    its purpose remains meaningful.
   2.189 +
   2.190 +    (For example, a function in a library to compute square roots has
   2.191 +    a purpose that is entirely well-defined independent of the
   2.192 +    application.  Therefore, Subsection 2d requires that any
   2.193 +    application-supplied function or table used by this function must
   2.194 +    be optional: if the application does not supply it, the square
   2.195 +    root function must still compute square roots.)
   2.196 +
   2.197 +These requirements apply to the modified work as a whole.  If
   2.198 +identifiable sections of that work are not derived from the Library,
   2.199 +and can be reasonably considered independent and separate works in
   2.200 +themselves, then this License, and its terms, do not apply to those
   2.201 +sections when you distribute them as separate works.  But when you
   2.202 +distribute the same sections as part of a whole which is a work based
   2.203 +on the Library, the distribution of the whole must be on the terms of
   2.204 +this License, whose permissions for other licensees extend to the
   2.205 +entire whole, and thus to each and every part regardless of who wrote
   2.206 +it.
   2.207 +
   2.208 +Thus, it is not the intent of this section to claim rights or contest
   2.209 +your rights to work written entirely by you; rather, the intent is to
   2.210 +exercise the right to control the distribution of derivative or
   2.211 +collective works based on the Library.
   2.212 +
   2.213 +In addition, mere aggregation of another work not based on the Library
   2.214 +with the Library (or with a work based on the Library) on a volume of
   2.215 +a storage or distribution medium does not bring the other work under
   2.216 +the scope of this License.
   2.217 +
   2.218 +  3. You may opt to apply the terms of the ordinary GNU General Public
   2.219 +License instead of this License to a given copy of the Library.  To do
   2.220 +this, you must alter all the notices that refer to this License, so
   2.221 +that they refer to the ordinary GNU General Public License, version 2,
   2.222 +instead of to this License.  (If a newer version than version 2 of the
   2.223 +ordinary GNU General Public License has appeared, then you can specify
   2.224 +that version instead if you wish.)  Do not make any other change in
   2.225 +these notices.
   2.226 +^L
   2.227 +  Once this change is made in a given copy, it is irreversible for
   2.228 +that copy, so the ordinary GNU General Public License applies to all
   2.229 +subsequent copies and derivative works made from that copy.
   2.230 +
   2.231 +  This option is useful when you wish to copy part of the code of
   2.232 +the Library into a program that is not a library.
   2.233 +
   2.234 +  4. You may copy and distribute the Library (or a portion or
   2.235 +derivative of it, under Section 2) in object code or executable form
   2.236 +under the terms of Sections 1 and 2 above provided that you accompany
   2.237 +it with the complete corresponding machine-readable source code, which
   2.238 +must be distributed under the terms of Sections 1 and 2 above on a
   2.239 +medium customarily used for software interchange.
   2.240 +
   2.241 +  If distribution of object code is made by offering access to copy
   2.242 +from a designated place, then offering equivalent access to copy the
   2.243 +source code from the same place satisfies the requirement to
   2.244 +distribute the source code, even though third parties are not
   2.245 +compelled to copy the source along with the object code.
   2.246 +
   2.247 +  5. A program that contains no derivative of any portion of the
   2.248 +Library, but is designed to work with the Library by being compiled or
   2.249 +linked with it, is called a "work that uses the Library".  Such a
   2.250 +work, in isolation, is not a derivative work of the Library, and
   2.251 +therefore falls outside the scope of this License.
   2.252 +
   2.253 +  However, linking a "work that uses the Library" with the Library
   2.254 +creates an executable that is a derivative of the Library (because it
   2.255 +contains portions of the Library), rather than a "work that uses the
   2.256 +library".  The executable is therefore covered by this License.
   2.257 +Section 6 states terms for distribution of such executables.
   2.258 +
   2.259 +  When a "work that uses the Library" uses material from a header file
   2.260 +that is part of the Library, the object code for the work may be a
   2.261 +derivative work of the Library even though the source code is not.
   2.262 +Whether this is true is especially significant if the work can be
   2.263 +linked without the Library, or if the work is itself a library.  The
   2.264 +threshold for this to be true is not precisely defined by law.
   2.265 +
   2.266 +  If such an object file uses only numerical parameters, data
   2.267 +structure layouts and accessors, and small macros and small inline
   2.268 +functions (ten lines or less in length), then the use of the object
   2.269 +file is unrestricted, regardless of whether it is legally a derivative
   2.270 +work.  (Executables containing this object code plus portions of the
   2.271 +Library will still fall under Section 6.)
   2.272 +
   2.273 +  Otherwise, if the work is a derivative of the Library, you may
   2.274 +distribute the object code for the work under the terms of Section 6.
   2.275 +Any executables containing that work also fall under Section 6,
   2.276 +whether or not they are linked directly with the Library itself.
   2.277 +^L
   2.278 +  6. As an exception to the Sections above, you may also combine or
   2.279 +link a "work that uses the Library" with the Library to produce a
   2.280 +work containing portions of the Library, and distribute that work
   2.281 +under terms of your choice, provided that the terms permit
   2.282 +modification of the work for the customer's own use and reverse
   2.283 +engineering for debugging such modifications.
   2.284 +
   2.285 +  You must give prominent notice with each copy of the work that the
   2.286 +Library is used in it and that the Library and its use are covered by
   2.287 +this License.  You must supply a copy of this License.  If the work
   2.288 +during execution displays copyright notices, you must include the
   2.289 +copyright notice for the Library among them, as well as a reference
   2.290 +directing the user to the copy of this License.  Also, you must do one
   2.291 +of these things:
   2.292 +
   2.293 +    a) Accompany the work with the complete corresponding
   2.294 +    machine-readable source code for the Library including whatever
   2.295 +    changes were used in the work (which must be distributed under
   2.296 +    Sections 1 and 2 above); and, if the work is an executable linked
   2.297 +    with the Library, with the complete machine-readable "work that
   2.298 +    uses the Library", as object code and/or source code, so that the
   2.299 +    user can modify the Library and then relink to produce a modified
   2.300 +    executable containing the modified Library.  (It is understood
   2.301 +    that the user who changes the contents of definitions files in the
   2.302 +    Library will not necessarily be able to recompile the application
   2.303 +    to use the modified definitions.)
   2.304 +
   2.305 +    b) Use a suitable shared library mechanism for linking with the
   2.306 +    Library.  A suitable mechanism is one that (1) uses at run time a
   2.307 +    copy of the library already present on the user's computer system,
   2.308 +    rather than copying library functions into the executable, and (2)
   2.309 +    will operate properly with a modified version of the library, if
   2.310 +    the user installs one, as long as the modified version is
   2.311 +    interface-compatible with the version that the work was made with.
   2.312 +
   2.313 +    c) Accompany the work with a written offer, valid for at
   2.314 +    least three years, to give the same user the materials
   2.315 +    specified in Subsection 6a, above, for a charge no more
   2.316 +    than the cost of performing this distribution.
   2.317 +
   2.318 +    d) If distribution of the work is made by offering access to copy
   2.319 +    from a designated place, offer equivalent access to copy the above
   2.320 +    specified materials from the same place.
   2.321 +
   2.322 +    e) Verify that the user has already received a copy of these
   2.323 +    materials or that you have already sent this user a copy.
   2.324 +
   2.325 +  For an executable, the required form of the "work that uses the
   2.326 +Library" must include any data and utility programs needed for
   2.327 +reproducing the executable from it.  However, as a special exception,
   2.328 +the materials to be distributed need not include anything that is
   2.329 +normally distributed (in either source or binary form) with the major
   2.330 +components (compiler, kernel, and so on) of the operating system on
   2.331 +which the executable runs, unless that component itself accompanies
   2.332 +the executable.
   2.333 +
   2.334 +  It may happen that this requirement contradicts the license
   2.335 +restrictions of other proprietary libraries that do not normally
   2.336 +accompany the operating system.  Such a contradiction means you cannot
   2.337 +use both them and the Library together in an executable that you
   2.338 +distribute.
   2.339 +^L
   2.340 +  7. You may place library facilities that are a work based on the
   2.341 +Library side-by-side in a single library together with other library
   2.342 +facilities not covered by this License, and distribute such a combined
   2.343 +library, provided that the separate distribution of the work based on
   2.344 +the Library and of the other library facilities is otherwise
   2.345 +permitted, and provided that you do these two things:
   2.346 +
   2.347 +    a) Accompany the combined library with a copy of the same work
   2.348 +    based on the Library, uncombined with any other library
   2.349 +    facilities.  This must be distributed under the terms of the
   2.350 +    Sections above.
   2.351 +
   2.352 +    b) Give prominent notice with the combined library of the fact
   2.353 +    that part of it is a work based on the Library, and explaining
   2.354 +    where to find the accompanying uncombined form of the same work.
   2.355 +
   2.356 +  8. You may not copy, modify, sublicense, link with, or distribute
   2.357 +the Library except as expressly provided under this License.  Any
   2.358 +attempt otherwise to copy, modify, sublicense, link with, or
   2.359 +distribute the Library is void, and will automatically terminate your
   2.360 +rights under this License.  However, parties who have received copies,
   2.361 +or rights, from you under this License will not have their licenses
   2.362 +terminated so long as such parties remain in full compliance.
   2.363 +
   2.364 +  9. You are not required to accept this License, since you have not
   2.365 +signed it.  However, nothing else grants you permission to modify or
   2.366 +distribute the Library or its derivative works.  These actions are
   2.367 +prohibited by law if you do not accept this License.  Therefore, by
   2.368 +modifying or distributing the Library (or any work based on the
   2.369 +Library), you indicate your acceptance of this License to do so, and
   2.370 +all its terms and conditions for copying, distributing or modifying
   2.371 +the Library or works based on it.
   2.372 +
   2.373 +  10. Each time you redistribute the Library (or any work based on the
   2.374 +Library), the recipient automatically receives a license from the
   2.375 +original licensor to copy, distribute, link with or modify the Library
   2.376 +subject to these terms and conditions.  You may not impose any further
   2.377 +restrictions on the recipients' exercise of the rights granted herein.
   2.378 +You are not responsible for enforcing compliance by third parties with
   2.379 +this License.
   2.380 +^L
   2.381 +  11. If, as a consequence of a court judgment or allegation of patent
   2.382 +infringement or for any other reason (not limited to patent issues),
   2.383 +conditions are imposed on you (whether by court order, agreement or
   2.384 +otherwise) that contradict the conditions of this License, they do not
   2.385 +excuse you from the conditions of this License.  If you cannot
   2.386 +distribute so as to satisfy simultaneously your obligations under this
   2.387 +License and any other pertinent obligations, then as a consequence you
   2.388 +may not distribute the Library at all.  For example, if a patent
   2.389 +license would not permit royalty-free redistribution of the Library by
   2.390 +all those who receive copies directly or indirectly through you, then
   2.391 +the only way you could satisfy both it and this License would be to
   2.392 +refrain entirely from distribution of the Library.
   2.393 +
   2.394 +If any portion of this section is held invalid or unenforceable under
   2.395 +any particular circumstance, the balance of the section is intended to
   2.396 +apply, and the section as a whole is intended to apply in other
   2.397 +circumstances.
   2.398 +
   2.399 +It is not the purpose of this section to induce you to infringe any
   2.400 +patents or other property right claims or to contest validity of any
   2.401 +such claims; this section has the sole purpose of protecting the
   2.402 +integrity of the free software distribution system which is
   2.403 +implemented by public license practices.  Many people have made
   2.404 +generous contributions to the wide range of software distributed
   2.405 +through that system in reliance on consistent application of that
   2.406 +system; it is up to the author/donor to decide if he or she is willing
   2.407 +to distribute software through any other system and a licensee cannot
   2.408 +impose that choice.
   2.409 +
   2.410 +This section is intended to make thoroughly clear what is believed to
   2.411 +be a consequence of the rest of this License.
   2.412 +
   2.413 +  12. If the distribution and/or use of the Library is restricted in
   2.414 +certain countries either by patents or by copyrighted interfaces, the
   2.415 +original copyright holder who places the Library under this License
   2.416 +may add an explicit geographical distribution limitation excluding those
   2.417 +countries, so that distribution is permitted only in or among
   2.418 +countries not thus excluded.  In such case, this License incorporates
   2.419 +the limitation as if written in the body of this License.
   2.420 +
   2.421 +  13. The Free Software Foundation may publish revised and/or new
   2.422 +versions of the Lesser General Public License from time to time.
   2.423 +Such new versions will be similar in spirit to the present version,
   2.424 +but may differ in detail to address new problems or concerns.
   2.425 +
   2.426 +Each version is given a distinguishing version number.  If the Library
   2.427 +specifies a version number of this License which applies to it and
   2.428 +"any later version", you have the option of following the terms and
   2.429 +conditions either of that version or of any later version published by
   2.430 +the Free Software Foundation.  If the Library does not specify a
   2.431 +license version number, you may choose any version ever published by
   2.432 +the Free Software Foundation.
   2.433 +^L
   2.434 +  14. If you wish to incorporate parts of the Library into other free
   2.435 +programs whose distribution conditions are incompatible with these,
   2.436 +write to the author to ask for permission.  For software which is
   2.437 +copyrighted by the Free Software Foundation, write to the Free
   2.438 +Software Foundation; we sometimes make exceptions for this.  Our
   2.439 +decision will be guided by the two goals of preserving the free status
   2.440 +of all derivatives of our free software and of promoting the sharing
   2.441 +and reuse of software generally.
   2.442 +
   2.443 +                            NO WARRANTY
   2.444 +
   2.445 +  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
   2.446 +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
   2.447 +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
   2.448 +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
   2.449 +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
   2.450 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   2.451 +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
   2.452 +LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
   2.453 +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
   2.454 +
   2.455 +  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
   2.456 +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
   2.457 +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
   2.458 +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
   2.459 +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
   2.460 +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
   2.461 +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
   2.462 +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
   2.463 +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
   2.464 +DAMAGES.
   2.465 +
   2.466 +                     END OF TERMS AND CONDITIONS
   2.467 +^L
   2.468 +           How to Apply These Terms to Your New Libraries
   2.469 +
   2.470 +  If you develop a new library, and you want it to be of the greatest
   2.471 +possible use to the public, we recommend making it free software that
   2.472 +everyone can redistribute and change.  You can do so by permitting
   2.473 +redistribution under these terms (or, alternatively, under the terms
   2.474 +of the ordinary General Public License).
   2.475 +
   2.476 +  To apply these terms, attach the following notices to the library.
   2.477 +It is safest to attach them to the start of each source file to most
   2.478 +effectively convey the exclusion of warranty; and each file should
   2.479 +have at least the "copyright" line and a pointer to where the full
   2.480 +notice is found.
   2.481 +
   2.482 +
   2.483 +    <one line to give the library's name and a brief idea of what it
   2.484 +does.>
   2.485 +    Copyright (C) <year>  <name of author>
   2.486 +
   2.487 +    This library is free software; you can redistribute it and/or
   2.488 +    modify it under the terms of the GNU Lesser General Public
   2.489 +    License as published by the Free Software Foundation; either
   2.490 +    version 2 of the License, or (at your option) any later version.
   2.491 +
   2.492 +    This library is distributed in the hope that it will be useful,
   2.493 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   2.494 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   2.495 +    Lesser General Public License for more details.
   2.496 +
   2.497 +    You should have received a copy of the GNU Lesser General Public
   2.498 +    License along with this library; if not, write to the Free Software
   2.499 +    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
   2.500 +
   2.501 +Also add information on how to contact you by electronic and paper
   2.502 +mail.
   2.503 +
   2.504 +You should also get your employer (if you work as a programmer) or
   2.505 +your
   2.506 +school, if any, to sign a "copyright disclaimer" for the library, if
   2.507 +necessary.  Here is a sample; alter the names:
   2.508 +
   2.509 +  Yoyodyne, Inc., hereby disclaims all copyright interest in the
   2.510 +  library `Frob' (a library for tweaking knobs) written by James
   2.511 +Random Hacker.
   2.512 +
   2.513 +  <signature of Ty Coon>, 1 April 1990
   2.514 +  Ty Coon, President of Vice
   2.515 +
   2.516 +That's all there is to it!
   2.517 +
   2.518 +
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/Makefile.am	Wed Oct 10 22:58:21 2012 +0100
     3.3 @@ -0,0 +1,5 @@
     3.4 +ACLOCAL_AMFLAGS=-I m4
     3.5 +
     3.6 +SUBDIRS=libxexpr src test docs/reference
     3.7 +
     3.8 +DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/bootstrap.sh	Wed Oct 10 22:58:21 2012 +0100
     4.3 @@ -0,0 +1,9 @@
     4.4 +#!/bin/sh
     4.5 +set -e
     4.6 +mkdir -p config
     4.7 +gtkdocize
     4.8 +autoheader
     4.9 +aclocal
    4.10 +libtoolize
    4.11 +automake --foreign --add-missing
    4.12 +autoconf
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/configure.ac	Wed Oct 10 22:58:21 2012 +0100
     5.3 @@ -0,0 +1,80 @@
     5.4 +#                                               -*- Autoconf -*-
     5.5 +# Process this file with autoconf to produce a configure script.
     5.6 +
     5.7 +AC_INIT([libxexpr],[1.0],[ali@juiblex.co.uk])
     5.8 +AC_PREREQ(2.59)
     5.9 +AC_CONFIG_MACRO_DIR([m4])
    5.10 +AC_CONFIG_AUX_DIR([config])
    5.11 +AC_CONFIG_SRCDIR([libxexpr/xexpr.h])
    5.12 +AC_CONFIG_HEADER([config.h])
    5.13 +AC_CONFIG_FILES([Makefile
    5.14 +libxexpr/Makefile
    5.15 +libxexpr/libxexpr.pc
    5.16 +src/Makefile
    5.17 +test/Makefile
    5.18 +test/spec/Makefile
    5.19 +test/idb/Makefile
    5.20 +test/libxexpr/Makefile
    5.21 +docs/reference/Makefile
    5.22 +docs/reference/version.xml
    5.23 +])
    5.24 +AM_INIT_AUTOMAKE(no-define)
    5.25 +AC_CANONICAL_HOST
    5.26 +AC_SUBST(HOST_OS,$host_os)
    5.27 +AC_SUBST(HOST_CPU,$host_cpu)
    5.28 +
    5.29 +# libtool versioning for libxexpr. For a release one of the following
    5.30 +# must apply:
    5.31 +#
    5.32 +# - If interfaces have been changed or added, but binary compatibility has
    5.33 +#   been preserved, increment CURRENT and AGE and set REVISION to 0.
    5.34 +# - If binary compatibility has been broken (eg removed or changed interfaces),
    5.35 +#   increment CURRENT and set AGE and REVISION to 0.
    5.36 +# - If the interface is the same as the previous version, increment REVISION.
    5.37 +#
    5.38 +lt_current=0
    5.39 +lt_revision=0
    5.40 +lt_age=0
    5.41 +LIBXEXPR_LT_VERSION_INFO="$lt_current:$lt_revision:$lt_age"
    5.42 +AC_SUBST(LIBXEXPR_LT_VERSION_INFO)
    5.43 +
    5.44 +##################################################
    5.45 +# Checks for programs.
    5.46 +##################################################
    5.47 +AC_PROG_CC
    5.48 +AC_LIBTOOL_WIN32_DLL
    5.49 +AC_PROG_LIBTOOL
    5.50 +PKG_PROG_PKG_CONFIG
    5.51 +GTK_DOC_CHECK([1.11],[--flavour no-tmpl])
    5.52 +
    5.53 +##################################################
    5.54 +# Checks for header files.
    5.55 +##################################################
    5.56 +AC_HEADER_STDC
    5.57 +
    5.58 +##################################################
    5.59 +# Checks for typedefs, structures, and compiler characteristics.
    5.60 +##################################################
    5.61 +
    5.62 +##################################################
    5.63 +# Checks for libraries.
    5.64 +##################################################
    5.65 +PKG_CHECK_MODULES(GLIB,[glib-2.0])
    5.66 +PKG_CHECK_MODULES(LIBXML,[libxml-2.0])
    5.67 +LIBXEXPR_CFLAGS="$LIBXML_CFLAGS $GLIB_CFLAGS"
    5.68 +LIBXEXPR_LIBS="$LIBXML_LIBS $GLIB_LIBS"
    5.69 +AC_SUBST(LIBXEXPR_CFLAGS)
    5.70 +AC_SUBST(LIBXEXPR_LIBS)
    5.71 +
    5.72 +##################################################
    5.73 +# Checks for library functions.
    5.74 +##################################################
    5.75 +
    5.76 +##################################################
    5.77 +# Checks for processor independent files.
    5.78 +##################################################
    5.79 +
    5.80 +##################################################
    5.81 +# Generate the various configured files
    5.82 +##################################################
    5.83 +AC_OUTPUT
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/docs/reference/Makefile.am	Wed Oct 10 22:58:21 2012 +0100
     6.3 @@ -0,0 +1,95 @@
     6.4 +## Process this file with automake to produce Makefile.in
     6.5 +
     6.6 +# We require automake 1.6 at least.
     6.7 +AUTOMAKE_OPTIONS=1.6
     6.8 +
     6.9 +# This is a blank Makefile.am for using gtk-doc.
    6.10 +# Copy this to your project's API docs directory and modify the variables to
    6.11 +# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
    6.12 +# of using the various options.
    6.13 +
    6.14 +# The name of the module, e.g. 'glib'.
    6.15 +DOC_MODULE=libxexpr
    6.16 +
    6.17 +# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
    6.18 +#DOC_MODULE_VERSION=2
    6.19 +
    6.20 +
    6.21 +# The top-level SGML file. You can change this if you want to.
    6.22 +DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
    6.23 +
    6.24 +# The directory containing the source code. Relative to $(srcdir).
    6.25 +# gtk-doc will search all .c & .h files beneath here for inline comments
    6.26 +# documenting the functions and macros.
    6.27 +# e.g. DOC_SOURCE_DIR=../../../gtk
    6.28 +DOC_SOURCE_DIR=../../libxexpr
    6.29 +
    6.30 +# Extra options to pass to gtkdoc-scangobj. Not normally needed.
    6.31 +SCANGOBJ_OPTIONS=
    6.32 +
    6.33 +# Extra options to supply to gtkdoc-scan.
    6.34 +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
    6.35 +SCAN_OPTIONS=--rebuild-types --rebuild-sections
    6.36 +
    6.37 +# Extra options to supply to gtkdoc-mkdb.
    6.38 +# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
    6.39 +MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space=xexpr
    6.40 +
    6.41 +# Extra options to supply to gtkdoc-mktmpl
    6.42 +# e.g. MKTMPL_OPTIONS=--only-section-tmpl
    6.43 +MKTMPL_OPTIONS=
    6.44 +
    6.45 +# Extra options to supply to gtkdoc-mkhtml
    6.46 +MKHTML_OPTIONS=
    6.47 +
    6.48 +# Extra options to supply to gtkdoc-fixref. Not normally needed.
    6.49 +# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
    6.50 +FIXXREF_OPTIONS=
    6.51 +
    6.52 +# Used for dependencies. The docs will be rebuilt if any of these change.
    6.53 +# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
    6.54 +# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
    6.55 +HFILE_GLOB=$(top_srcdir)/libxexpr/*.h
    6.56 +CFILE_GLOB=$(top_srcdir)/libxexpr/*.c
    6.57 +
    6.58 +# Header files to ignore when scanning.
    6.59 +# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
    6.60 +IGNORE_HFILES=xexpr.h xexprprivate.h
    6.61 +
    6.62 +# Images to copy into HTML directory.
    6.63 +# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
    6.64 +HTML_IMAGES=
    6.65 +
    6.66 +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
    6.67 +# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
    6.68 +content_files=version.xml implementation_defined_behaviour.xml \
    6.69 +    language_extensions.xml xexpr.xml
    6.70 +
    6.71 +# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
    6.72 +# These files must be listed here *and* in content_files
    6.73 +# e.g. expand_content_files=running.sgml
    6.74 +expand_content_files=
    6.75 +
    6.76 +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
    6.77 +# Only needed if you are using gtkdoc-scangobj to dynamically query widget
    6.78 +# signals and properties.
    6.79 +# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
    6.80 +# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
    6.81 +GTKDOC_CFLAGS=
    6.82 +GTKDOC_LIBS=
    6.83 +
    6.84 +# This includes the standard gtk-doc make rules, copied by gtkdocize.
    6.85 +include $(top_srcdir)/gtk-doc.make
    6.86 +
    6.87 +# Other files to distribute
    6.88 +# e.g. EXTRA_DIST += version.xml.in
    6.89 +EXTRA_DIST+=version.xml.in
    6.90 +
    6.91 +# Files not to distribute
    6.92 +# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
    6.93 +# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
    6.94 +DISTCLEANFILES=$(DOC_MODULE).types $(DOC_MODULE)-sections.txt
    6.95 +
    6.96 +# Comment this out if you want your docs-status tested during 'make check'
    6.97 +TESTS_ENVIRONMENT=cd $(srcdir) &&
    6.98 +TESTS=$(GTKDOC_CHECK)
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/docs/reference/implementation_defined_behaviour.xml	Wed Oct 10 22:58:21 2012 +0100
     7.3 @@ -0,0 +1,415 @@
     7.4 +<?xml version="1.0"?>
     7.5 +<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
     7.6 +               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
     7.7 +[
     7.8 +]>
     7.9 +<chapter id="implementation-defined-behaviour">
    7.10 +  <title>Implementation Defined Behaviour</title>
    7.11 +
    7.12 +  <para>
    7.13 +    The specification of the XEXPR language is laid out in a W3C note of
    7.14 +    <ulink url="http://www.w3.org/TR/2000/NOTE-xexpr-20001121">21 November
    7.15 +    2000</ulink>. However, the specification leaves quite a bit of
    7.16 +    information to be deduced from the examples and leaves other parts of
    7.17 +    the language loosly specified. This chapter documents the way that
    7.18 +    libxexpr implements the language and gives the rationale for each
    7.19 +    decision taken.
    7.20 +  </para>
    7.21 +
    7.22 +  <sect1 id="idb-numbers">
    7.23 +    <title>Numbers</title>
    7.24 +
    7.25 +    <para>
    7.26 +      Numbers are defined in pseudo-BNF as:
    7.27 +      <programlisting>
    7.28 +number         : whitespace sign simple-number whitespace
    7.29 +	       ;
    7.30 +
    7.31 +whitespace     : [ \t\n]*
    7.32 +	       ;
    7.33 +
    7.34 +sign           : [+-]?
    7.35 +	       ;
    7.36 +
    7.37 +simple-number  : 0x[0-9A-Fa-f]+
    7.38 +	       | [0-9]+
    7.39 +	       | [0-9]+\.[0-9]+
    7.40 +	       | [0-9]+\.[0-9]+[eE][+-][0-9]+
    7.41 +	       ;<!--
    7.42 +   --></programlisting>
    7.43 +      that is: they have an optional leading sign and may be surrounded with
    7.44 +      whitespace.
    7.45 +    </para>
    7.46 +
    7.47 +    <simplesect id="idb-numbers-rationale">
    7.48 +      <title>Rationale</title>
    7.49 +
    7.50 +      <para>
    7.51 +        While negative numbers can be created using &lt;subtract&gt; without
    7.52 +	the need for any signs, this seems overly cumbersome.
    7.53 +      </para>
    7.54 +
    7.55 +      <para>
    7.56 +	The examples in the specification make it clear that where two numbers
    7.57 +	are seperated by a space, this should be parsed as just two numbers
    7.58 +	and not two numbers plus an interveening string which a strict reading
    7.59 +	of the specification would imply.
    7.60 +      </para>
    7.61 +    </simplesect>
    7.62 +  </sect1>
    7.63 +
    7.64 +  <sect1 id="idb-bindings">
    7.65 +    <title>Bindings</title>
    7.66 +
    7.67 +    <para>
    7.68 +      Bindings are parsed as integers, floats or strings in that order (ie.,
    7.69 +      the first type that matches will be used). Thus the following pairs
    7.70 +      of expressions are equivalent:
    7.71 +      <programlisting>
    7.72 +&lt;func x="+01 "/&gt;
    7.73 +
    7.74 +&lt;func&gt;
    7.75 +  &lt;define name="x"&gt;&lt;integer&gt;1&lt;/integer&gt;&lt;/define&gt;
    7.76 +&lt;/func&gt;
    7.77 +
    7.78 +&lt;func x=" 14.0e-1"/&gt;
    7.79 +
    7.80 +&lt;func&gt;
    7.81 +  &lt;define name="x"&gt;&lt;float&gt;1.4&lt;/float&gt;&lt;/define&gt;
    7.82 +&lt;/func&gt;
    7.83 +
    7.84 +&lt;func x="Hello "/&gt;
    7.85 +
    7.86 +&lt;func&gt;
    7.87 +  &lt;define name="x"&gt;&lt;string&gt;Hello &lt;/string&gt;&lt;/define&gt;
    7.88 +&lt;/func&gt;<!--
    7.89 +   --></programlisting>
    7.90 +    </para>
    7.91 +    <simplesect id="idb-bindings-rationale">
    7.92 +      <title>Rationale</title>
    7.93 +
    7.94 +      <para>
    7.95 +	This seems to satisfy the doctrine of least-surpise.
    7.96 +      </para>
    7.97 +    </simplesect>
    7.98 +  </sect1>
    7.99 +
   7.100 +  <sect1 id="idb-pcdata">
   7.101 +    <title>Parsing of PCDATA</title>
   7.102 +
   7.103 +    <para>
   7.104 +      When numbers and strings are mixed in PCDATA, any whitespace surrounding
   7.105 +      the numbers is taken to be part of the numbers rather than the strings.
   7.106 +      Thus the following two expressions are equivalent:
   7.107 +      <programlisting>
   7.108 +&lt;foo&gt;This is the 0xdeadbeef constant.&lt;/foo&gt;
   7.109 +
   7.110 +&lt;foo&gt;
   7.111 +  &lt;string&gt;This is the&lt;/string&gt;
   7.112 +  &lt;integer&gt;0xdeadbeef&lt;/integer&gt;
   7.113 +  &lt;string&gt;constant.&lt;/string&gt;
   7.114 +&lt;/foo&gt;<!--
   7.115 +   --></programlisting>
   7.116 +    </para>
   7.117 +
   7.118 +    <simplesect id="idb-pcdata-rationale">
   7.119 +      <title>Rationale</title>
   7.120 +
   7.121 +      <para>
   7.122 +	This seems more consistent with spaces between numbers not being
   7.123 +	parsed as strings than the alternative.
   7.124 +      </para>
   7.125 +    </simplesect>
   7.126 +  </sect1>
   7.127 +
   7.128 +  <sect1 id="idb-define">
   7.129 +    <title>The &lt;define&gt; Function</title>
   7.130 +
   7.131 +    <para>
   7.132 +      The &lt;define&gt; function creates a new function in the environment in
   7.133 +      which it is invoked. This is different than the &lt;set&gt; function
   7.134 +      which will modify the definition of an existing function if such exists.
   7.135 +      Only if no such function is defined in any of the active environments will
   7.136 +      &lt;set&gt; create a new function (and then in the outermost, or global,
   7.137 +      environment).
   7.138 +    </para>
   7.139 +
   7.140 +    <simplesect id="idb-define-rationale">
   7.141 +      <title>Rationale</title>
   7.142 +
   7.143 +      <para>
   7.144 +	We know from the examples in the specification (eg., in
   7.145 +	<ulink url="http://www.w3.org/TR/xexpr/#id-0045">section 45</ulink>)
   7.146 +	that &lt;subtract&gt; changes the definition of its first argument
   7.147 +	in at least the grandfather environment. It makes sense that &lt;set&gt;
   7.148 +	should do the same. When we come to &lt;define&gt;, however, we
   7.149 +	know from <ulink url="http://www.w3.org/TR/xexpr/#id-0003">section
   7.150 +	3</ulink> that it is equivalent to an attribute on the parent element
   7.151 +	and so it makes sense that it should create a variable in the parent
   7.152 +	environment.
   7.153 +      </para>
   7.154 +    </simplesect>
   7.155 +  </sect1>
   7.156 +
   7.157 +  <sect1 id="idb-get">
   7.158 +    <title>The &lt;get&gt; Function</title>
   7.159 +
   7.160 +    <para>
   7.161 +      The following two expressions are equivalent:
   7.162 +      <programlisting>
   7.163 +&lt;get name="x"/&gt;
   7.164 +&lt;get&gt;x&lt;/get&gt;<!--
   7.165 +   --></programlisting>
   7.166 +      The expression &lt;x/&gt; has the same effect except in the case of
   7.167 +      &lt;add&gt; and &lt;subtract&gt; where these two expressions are
   7.168 +      different:
   7.169 +      <programlisting>
   7.170 +&lt;add&gt;&lt;x/&gt;1&lt;/add&gt;
   7.171 +&lt;add&gt;&lt;get&gt;x&lt;/get&gt;1&lt;/add&gt;<!--
   7.172 +   --></programlisting>
   7.173 +      The first changes the definition of &lt;x&gt;, the second does not.
   7.174 +    </para>
   7.175 +
   7.176 +    <para>
   7.177 +      Note that IDs are allowed to start with the dot (.) and hyphen (-)
   7.178 +      characters which are not valid as the first character in XML tags.
   7.179 +      Thus get must be used in the following:
   7.180 +      <programlisting>
   7.181 +&lt;expr&gt;
   7.182 +  &lt;define name=".net"&gt;4.5.50709&lt;/define&gt;
   7.183 +  &lt;print&gt;&lt;get&gt;.net&lt;/get&gt;&lt;/print&gt;
   7.184 +&lt;/expr&gt;<!--
   7.185 +   --></programlisting>
   7.186 +    </para>
   7.187 +
   7.188 +    <para>
   7.189 +      Since &lt;get&gt; returns a function definition (just like
   7.190 +      &lt;define&gt;), it is possible to define functions of this type that
   7.191 +      take arguments and even invoke them in a somewhat circuitous manner:
   7.192 +      <programlisting>
   7.193 +&lt;expr&gt;
   7.194 +  &lt;define name=".product" args="a b c d"&gt;
   7.195 +    &lt;add&gt;
   7.196 +      &lt;multiply&gt;
   7.197 +        &lt;a/&gt;
   7.198 +        &lt;b/&gt;
   7.199 +      &lt;/multiply&gt;
   7.200 +      &lt;multiply&gt;
   7.201 +        &lt;c/&gt;
   7.202 +        &lt;d/&gt;
   7.203 +      &lt;/multiply&gt;
   7.204 +    &lt;/add&gt;
   7.205 +  &lt;/define&gt;
   7.206 +
   7.207 +  &lt;expr&gt;
   7.208 +    &lt;define name="closure"/&gt;
   7.209 +    &lt;set name="closure"&gt;
   7.210 +      &lt;get&gt;.product&lt;/get&gt;
   7.211 +    &lt;/set&gt;
   7.212 +    &lt;closure&gt;1 2 3 4&lt;/closure&gt;
   7.213 +  &lt;/expr&gt;
   7.214 +&lt;/expr&gt;<!--
   7.215 +   --></programlisting>
   7.216 +    </para>
   7.217 +
   7.218 +    <simplesect id="idb-get-rationale">
   7.219 +      <title>Rationale</title>
   7.220 +
   7.221 +      <para>
   7.222 +	<ulink url="http://www.w3.org/TR/xexpr/#id-0014">Section 14</ulink>
   7.223 +	tells us that &lt;get&gt;x&lt;/get&gt; and &lt;x/&gt; have the same
   7.224 +	effect in most cases (and thus presumably not all cases) and it
   7.225 +	would seem surprising if &lt;get&gt; were not to insulate a
   7.226 +	function in this manner.
   7.227 +      </para>
   7.228 +    </simplesect>
   7.229 +  </sect1>
   7.230 +
   7.231 +  <sect1 id="idb-arithmetic">
   7.232 +    <title>Arithmetic Operators</title>
   7.233 +
   7.234 +    <para>
   7.235 +      The empty arithmetic operators (&lt;add/&gt;, &lt;subtract/&gt;,
   7.236 +      &lt;multiply/&gt; and &lt;divide/&gt;) all evaluate to &lt;nil/&gt;.
   7.237 +    </para>
   7.238 +
   7.239 +    <para>
   7.240 +      The &lt;add&gt; and &lt;subtract&gt; operators change their first
   7.241 +      argument in some circumstances as in this example from the specification:
   7.242 +      <programlisting>
   7.243 +&lt;while&gt;
   7.244 +  &lt;gt&gt;&lt;x/&gt; 0&lt;/gt&gt;
   7.245 +  &lt;expr&gt;
   7.246 +    &lt;print newline="true">&lt;x/&gt;&lt;print&gt;
   7.247 +    &lt;subtract&gt;&lt;x/&gt; 1&lt;/subtract&gt;
   7.248 +  &lt;/expr&gt;
   7.249 +&lt;/while&gt;<!--
   7.250 +   --></programlisting>
   7.251 +    </para>
   7.252 +
   7.253 +    <para>
   7.254 +      In general, the first agument will be modified if it is a function
   7.255 +      invocation that has no bindings and no arguments. Thus the following
   7.256 +      will print 9:
   7.257 +      <programlisting>
   7.258 +&lt;define name="x"&gt;&lt;multiply&gt;2 3&lt;/multiply&gt;&lt;/define&gt;
   7.259 +&lt;add&gt;&lt;x/&gt;3&lt;/add&gt;
   7.260 +&lt;print&gt;&lt;x/&gt;&lt;/print&gt;<!--
   7.261 +   --></programlisting>
   7.262 +      whereas this will print 6:
   7.263 +      <programlisting>
   7.264 +&lt;define name="x"&gt;&lt;multiply&gt;2 3&lt;/multiply&gt;&lt;/define&gt;
   7.265 +&lt;add&gt;&lt;x unused=""/&gt;3&lt;/add&gt;
   7.266 +&lt;print&gt;&lt;x/&gt;&lt;/print&gt;<!--
   7.267 +   --></programlisting>
   7.268 +    </para>
   7.269 +
   7.270 +    <para>
   7.271 +      Where arguments are modified, this occurs as the arguments are being
   7.272 +      evaluated. Thus this expression:
   7.273 +      <programlisting>
   7.274 +&lt;add&gt;&lt;x/&gt;&lt;x/&gt;&lt;x/&gt;&lt;/add&gt;<!--
   7.275 +   --></programlisting>
   7.276 +      will multiply &lt;x&gt; by 4 rather than by 3.
   7.277 +    </para>
   7.278 +
   7.279 +    <simplesect id="idb-arithmetic-rationale">
   7.280 +      <title>Rationale</title>
   7.281 +
   7.282 +      <para>
   7.283 +	The examples in the specification imply that &lt;add&gt; and
   7.284 +	&lt;subtract&gt; modify their first argument when it is a
   7.285 +	variable. The iterative example in
   7.286 +	<ulink url="http://www.w3.org/TR/xexpr/#id-0008">section 8</ulink>
   7.287 +	wouldn't work if &lt;multiply&gt; worked the same way (and the
   7.288 +	definition of &lt;2pi&gt; in <ulink
   7.289 +	url="http://www.w3.org/TR/xexpr/#id-0007">section 7</ulink> would
   7.290 +	not be expected to modify the definition of &lt;pi&gt; each time
   7.291 +	it is called). Note that this example is erroneous: IDs can't contain
   7.292 +	numbers.
   7.293 +      </para>
   7.294 +
   7.295 +      <para>
   7.296 +	It seems undesirable to modify functions that take arguments.
   7.297 +	Making the decision based on the invocation rather than the
   7.298 +	function definition makes expressions much easier to read.
   7.299 +      </para>
   7.300 +    </simplesect>
   7.301 +  </sect1>
   7.302 +
   7.303 +  <sect1 id="idb-comparison">
   7.304 +    <title>Comparison Functions</title>
   7.305 +
   7.306 +    <para>
   7.307 +      The empty comparison functions (&lt;eq/&gt;, &lt;neq/&gt;, &lt;leq/&gt;,
   7.308 +      &lt;geq/&gt;, &lt;lt/&gt; and &lt;gt/&gt;) and comparison functions with
   7.309 +      exactly one argument all evaluate to &lt;true/&gt;.
   7.310 +    </para>
   7.311 +
   7.312 +    <para>
   7.313 +      The ordered comparison functions (&lt;leq&gt;, &lt;geq&gt;, &lt;lt&gt;
   7.314 +      and &lt;gt&gt;) act as if the equivalent mathematical operator was
   7.315 +      inserted between their arguments. Thus:
   7.316 +      <programlisting>
   7.317 +&lt;lt&gt;
   7.318 +  1 2 3
   7.319 +&lt;/lt&gt;<!--
   7.320 +   --></programlisting>
   7.321 +      is equivalent to the mathematical expression:
   7.322 +      <screen>1 &lt; 2 &lt; 3</screen>
   7.323 +      and:
   7.324 +      <programlisting>
   7.325 +&lt;leq&gt;
   7.326 +  1 2 3
   7.327 +&lt;/leq&gt;<!--
   7.328 +   --></programlisting>
   7.329 +      is equivalent to the mathematical expression:
   7.330 +      <screen>1 ≤ 2 ≤ 3</screen>
   7.331 +    </para>
   7.332 +
   7.333 +    <para>
   7.334 +      When comparing objects of different types:
   7.335 +      <itemizedlist>
   7.336 +	<listitem>
   7.337 +	  Numbers will be implicitly cast between &lt;float&gt; and
   7.338 +	  &lt;integer&gt; where that involves no loss of precision
   7.339 +	</listitem>
   7.340 +	<listitem>
   7.341 +	  Strings will be compared byte-by-byte as UTF8 encoded strings
   7.342 +	</listitem>
   7.343 +	<listitem>
   7.344 +	  Functions will always be completely evaluated
   7.345 +	</listitem>
   7.346 +	<listitem>
   7.347 +	  Invocations of the constant functions are ordered as &lt;false/&gt;
   7.348 +	  &lt; &lt;nil/&gt; &lt; &lt;true/&gt;
   7.349 +	</listitem>
   7.350 +      </itemizedlist>
   7.351 +    </para>
   7.352 +
   7.353 +    <simplesect id="idb-comparison-rationale">
   7.354 +      <title>Rationale</title>
   7.355 +
   7.356 +      <para>
   7.357 +	The empty comparison functions equaluate to &lt;true&gt; by analogy
   7.358 +	with the comparison functions.
   7.359 +      </para>
   7.360 +
   7.361 +      <para>
   7.362 +	The ordering of the comparison functions is confused in the
   7.363 +	specification with the examples for &lt;lt&gt; and &lt;gt&gt; agreeing
   7.364 +	with libxexpr's behaviour and the examples for &lt;leq&gt; and
   7.365 +	&lt;geq&gt; doing the opposite. The choice was arbitary.
   7.366 +      </para>
   7.367 +    </simplesect>
   7.368 +  </sect1>
   7.369 +
   7.370 +  <sect1 id="idb-redefining-builtins">
   7.371 +    <title>Redefining Builtin Functions</title>
   7.372 +
   7.373 +    <para>
   7.374 +      Attempting to redefine a builtin function results in an error.
   7.375 +    </para>
   7.376 +
   7.377 +    <simplesect id="idb-redefining-builtins-rationale">
   7.378 +      <title>Rationale</title>
   7.379 +
   7.380 +      <para>
   7.381 +	While this could be implemented, there is no mention of it in the
   7.382 +	specification and it would complicate the implementation with no
   7.383 +	obvious benefit.
   7.384 +      </para>
   7.385 +    </simplesect>
   7.386 +  </sect1>
   7.387 +
   7.388 +  <sect1 id="idb-namespaces">
   7.389 +    <title>Namespaces</title>
   7.390 +
   7.391 +    <para>
   7.392 +      libxexpr considers an element's namespace to be part of its name
   7.393 +      and thus elements in a namespace other than the XEXPR namespace as
   7.394 +      are always distinct from functions defined by XEXPR. In addition,
   7.395 +      functions defined using &lt;define&gt; are defined in the
   7.396 +      XEXPR namespace.
   7.397 +    </para>
   7.398 +
   7.399 +    <para>
   7.400 +      libxexpr provides hooks for extending the XEXPR language by allowing
   7.401 +      handlers to be installed for other namespaces.
   7.402 +    </para>
   7.403 +
   7.404 +    <para>
   7.405 +      Elements which are in no namespace are treated as if they were in the
   7.406 +      XEXPR namespace.
   7.407 +    </para>
   7.408 +
   7.409 +    <simplesect id="idb-namespaces-rationale">
   7.410 +      <title>Rationale</title>
   7.411 +
   7.412 +      <para>
   7.413 +	Being able to extend the XEXPR language is vital for it to be useful
   7.414 +	and namespaces are the obvious way to do this.
   7.415 +      </para>
   7.416 +    </simplesect>
   7.417 +  </sect1>
   7.418 +</chapter>
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/docs/reference/language_extensions.xml	Wed Oct 10 22:58:21 2012 +0100
     8.3 @@ -0,0 +1,277 @@
     8.4 +<?xml version="1.0"?>
     8.5 +<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
     8.6 +               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
     8.7 +[
     8.8 +]>
     8.9 +<chapter id="language-extensions">
    8.10 +  <title>Language Extensions</title>
    8.11 +
    8.12 +  <para>
    8.13 +    These language extensions are provided in the following namespace URI:
    8.14 +    <screen>
    8.15 +http://www.juiblex.co.uk/ns/libxexpr
    8.16 +    </screen>
    8.17 +    People using this namespace are encouraged to use the libxexpr namespace
    8.18 +    prefix.
    8.19 +  </para>
    8.20 +
    8.21 +  <sect1 id="libxexpr-pi">
    8.22 +    <title>Function &lt;pi&gt;</title>
    8.23 +
    8.24 +    <simplesect>
    8.25 +      <title>Synopsis</title>
    8.26 +	<para>
    8.27 +	  &lt;pi&gt; returns the value of π.
    8.28 +	</para>
    8.29 +    </simplesect>
    8.30 +
    8.31 +    <simplesect>
    8.32 +      <title>Arguments</title>
    8.33 +	<para>
    8.34 +	  &lt;pi&gt; takes no arguments.
    8.35 +	</para>
    8.36 +    </simplesect>
    8.37 +
    8.38 +    <simplesect>
    8.39 +      <title>Return Values</title>
    8.40 +	<para>
    8.41 +	  &lt;pi&gt; returns the value of π.
    8.42 +	</para>
    8.43 +    </simplesect>
    8.44 +
    8.45 +    <example>
    8.46 +      <programlisting>
    8.47 +&lt;libxexpr:pi/&gt; ≅ &lt;float&gt;3.14&lt;/float&gt;<!--
    8.48 +   --></programlisting>
    8.49 +    </example>
    8.50 +  </sect1>
    8.51 +
    8.52 +  <sect1 id="libxexpr-sin">
    8.53 +    <title>Function &lt;sin&gt;</title>
    8.54 +
    8.55 +    <simplesect>
    8.56 +      <title>Synopsis</title>
    8.57 +	<para>
    8.58 +	  &lt;sin&gt; computes the sine function.
    8.59 +	</para>
    8.60 +    </simplesect>
    8.61 +
    8.62 +    <simplesect>
    8.63 +      <title>Arguments</title>
    8.64 +	<para>
    8.65 +	  &lt;sin&gt; takes one argument: x. If no argument is given, an error
    8.66 +	  occurs.
    8.67 +	</para>
    8.68 +    </simplesect>
    8.69 +
    8.70 +    <simplesect>
    8.71 +      <title>Return Values</title>
    8.72 +	<para>
    8.73 +	  &lt;sin&gt; returns the sine of its argument, given in radians.
    8.74 +	  If the argument does not evaluate to a finite number,
    8.75 +	  &lt;sin&gt; returns an indeterminate result.
    8.76 +	</para>
    8.77 +    </simplesect>
    8.78 +
    8.79 +    <example>
    8.80 +      <programlisting>
    8.81 +&lt;libxexpr:sin&gt;
    8.82 +  &lt;divide&gt;
    8.83 +    &lt;libxexpr:pi/&gt;
    8.84 +    2
    8.85 +  &lt;/divide&gt;
    8.86 +&lt;/libxexpr:sin&gt; --> &lt;float&gt;1&lt;/float&gt;<!--
    8.87 +   --></programlisting>
    8.88 +    </example>
    8.89 +  </sect1>
    8.90 +
    8.91 +  <sect1 id="libxexpr-atan">
    8.92 +    <title>Function &lt;atan&gt;</title>
    8.93 +
    8.94 +    <simplesect>
    8.95 +      <title>Synopsis</title>
    8.96 +	<para>
    8.97 +	  &lt;atan&gt; computes the arc tangent function.
    8.98 +	</para>
    8.99 +    </simplesect>
   8.100 +
   8.101 +    <simplesect>
   8.102 +      <title>Arguments</title>
   8.103 +	<para>
   8.104 +	  &lt;atan&gt; takes two arguments: x and y. The y argument defaults to
   8.105 +	  1. If the x argument is missing, an error occurs.
   8.106 +	</para>
   8.107 +    </simplesect>
   8.108 +
   8.109 +    <simplesect>
   8.110 +      <title>Return Values</title>
   8.111 +	<para>
   8.112 +	  &lt;atan&gt; returns the principal value of the arc tangent of its
   8.113 +	  argument(s) in radians. If either argument is indeterminate,
   8.114 +	  the result is also indeterminate.
   8.115 +	</para>
   8.116 +	
   8.117 +	<para>
   8.118 +	  If two arguments are given, &lt;atan&gt; returns the arc tangent of
   8.119 +	  y/x, using the signs of the two arguments to determine the quadrant
   8.120 +	  of the result which will be in the range [-π, π]. If both arguments
   8.121 +	  are 0, the result will also be 0.
   8.122 +	</para>
   8.123 +
   8.124 +	<para>
   8.125 +	  If only one argument is given, &lt;atan&gt; returns the arc tangent of
   8.126 +	  its argument. The result will be in the range [-π/2, π/2].
   8.127 +	</para>
   8.128 +    </simplesect>
   8.129 +
   8.130 +    <example>
   8.131 +      <programlisting>
   8.132 +&lt;libxexpr:atan&gt;1 0&lt;/libxexpr:atan&gt; --> &lt;float&gt;0&lt;/float&gt;<!--
   8.133 +   --></programlisting>
   8.134 +    </example>
   8.135 +  </sect1>
   8.136 +
   8.137 +  <sect1 id="libxexpr-exp">
   8.138 +    <title>Function &lt;exp&gt;</title>
   8.139 +
   8.140 +    <simplesect>
   8.141 +      <title>Synopsis</title>
   8.142 +	<para>
   8.143 +	  &lt;exp&gt; computes the base-e exponential function.
   8.144 +	</para>
   8.145 +    </simplesect>
   8.146 +
   8.147 +    <simplesect>
   8.148 +      <title>Arguments</title>
   8.149 +	<para>
   8.150 +	  &lt;exp&gt; takes zero or one argument: x.
   8.151 +	</para>
   8.152 +    </simplesect>
   8.153 +
   8.154 +    <simplesect>
   8.155 +      <title>Return Values</title>
   8.156 +	<para>
   8.157 +	  &lt;exp&gt; returns the value of e (the base of natural logarithms)
   8.158 +	  raised to the power of its argument (or just e if no argument is
   8.159 +	  supplied). If the argument does not evaluate to a finite number,
   8.160 +	  &lt;exp&gt; returns an indeterminate result.
   8.161 +	</para>
   8.162 +    </simplesect>
   8.163 +
   8.164 +    <example>
   8.165 +      <programlisting>
   8.166 +&lt;libxexpr:exp&gt;2&lt;/libxexpr:exp&gt; ≅ &lt;float&gt;7.389&lt;/float&gt;<!--
   8.167 +   --></programlisting>
   8.168 +    </example>
   8.169 +  </sect1>
   8.170 +
   8.171 +  <sect1 id="libxexpr-log">
   8.172 +    <title>Function &lt;log&gt;</title>
   8.173 +
   8.174 +    <simplesect>
   8.175 +      <title>Synopsis</title>
   8.176 +	<para>
   8.177 +	  &lt;log&gt; computes the natural logarithmic function.
   8.178 +	</para>
   8.179 +    </simplesect>
   8.180 +
   8.181 +    <simplesect>
   8.182 +      <title>Arguments</title>
   8.183 +	<para>
   8.184 +	  &lt;log&gt; takes one argument: x. If no argument is given, an error
   8.185 +	  occurs.
   8.186 +	</para>
   8.187 +    </simplesect>
   8.188 +
   8.189 +    <simplesect>
   8.190 +      <title>Return Values</title>
   8.191 +	<para>
   8.192 +	  &lt;log&gt; returns the natural logarithm of its argument.
   8.193 +	  If the argument does not evaluate to a positive finite number,
   8.194 +	  &lt;log&gt; returns an indeterminate result.
   8.195 +	</para>
   8.196 +    </simplesect>
   8.197 +
   8.198 +    <example>
   8.199 +      <programlisting>
   8.200 +&lt;libxexpr:log&gt;
   8.201 +  &lt;libxexpr:exp&gt;2&lt;/libxexpr:exp&gt;
   8.202 +&lt;/libxexpr:log&gt; --> &lt;float&gt;2&lt;/float&gt;<!--
   8.203 +   --></programlisting>
   8.204 +    </example>
   8.205 +  </sect1>
   8.206 +
   8.207 +  <sect1 id="libxexpr-pow">
   8.208 +    <title>Function &lt;pow&gt;</title>
   8.209 +
   8.210 +    <simplesect>
   8.211 +      <title>Synopsis</title>
   8.212 +	<para>
   8.213 +	  &lt;pow&gt; computes the value of its first argument raised to the
   8.214 +	  power of its second argument.
   8.215 +	</para>
   8.216 +    </simplesect>
   8.217 +
   8.218 +    <simplesect>
   8.219 +      <title>Arguments</title>
   8.220 +	<para>
   8.221 +	  &lt;pow&gt; takes two arguments: x and y. If fewer arguments are
   8.222 +	  given, an error occurs.
   8.223 +	</para>
   8.224 +    </simplesect>
   8.225 +
   8.226 +    <simplesect>
   8.227 +      <title>Return Values</title>
   8.228 +	<para>
   8.229 +	  &lt;pow&gt; returns the value of x (its first argument) raised to the
   8.230 +	  power of y (its second argument).
   8.231 +	</para>
   8.232 +
   8.233 +	<para>
   8.234 +	  If x is a finite value less than 0, and y is a finite non-integer,
   8.235 +	  &lt;pow&gt; returns an indeterminate result. 
   8.236 +	</para>
   8.237 +
   8.238 +	<para>
   8.239 +	  If the result overflows, &lt;pow&gt; returns an indeterminate result. 
   8.240 +	</para>
   8.241 +
   8.242 +	<para>
   8.243 +	  If result underflows, and is not representable, 0 is returned.
   8.244 +	</para>
   8.245 +
   8.246 +	<para>
   8.247 +	  Except as specified below, if either argument is indeterminate,
   8.248 +	  the result is also indeterminate.
   8.249 +	</para>
   8.250 +
   8.251 +	<para>
   8.252 +	  If x is 1, the result is 1 (even if y is indeterminate).
   8.253 +	</para>
   8.254 +
   8.255 +	<para>
   8.256 +	  If y is 0, the result is 1 (even if x is indeterminate).
   8.257 +	</para>
   8.258 +
   8.259 +	<para>
   8.260 +	  If x is 0, and y is an odd integer greater than 0, the result is 0.
   8.261 +	</para>
   8.262 +
   8.263 +	<para>
   8.264 +	  If x is 0, and y greater than 0 and not an odd integer, the result
   8.265 +	  is 0.
   8.266 +	</para>
   8.267 +
   8.268 +	<para>
   8.269 +	  If x is 0, and y is less than 0,
   8.270 +	  &lt;pow&gt; returns an indeterminate result. 
   8.271 +	</para>
   8.272 +    </simplesect>
   8.273 +
   8.274 +    <example>
   8.275 +      <programlisting>
   8.276 +  &lt;libxexpr:pow&gt;10 2&lt;/libxexpr:pow&gt; --> &lt;float&gt;100&lt;/float&gt;<!--
   8.277 +   --></programlisting>
   8.278 +    </example>
   8.279 +  </sect1>
   8.280 +</chapter>
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/docs/reference/libxexpr-docs.xml	Wed Oct 10 22:58:21 2012 +0100
     9.3 @@ -0,0 +1,41 @@
     9.4 +<?xml version="1.0"?>
     9.5 +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
     9.6 +               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
     9.7 +[
     9.8 +  <!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
     9.9 +  <!ENTITY version SYSTEM "version.xml">
    9.10 +]>
    9.11 +<book id="index">
    9.12 +  <bookinfo>
    9.13 +    <title>libxexpr Reference Manual</title>
    9.14 +    <releaseinfo>
    9.15 +      for libxexpr &version;
    9.16 +      The latest version of this documentation can be found on-line at
    9.17 +      <ulink role="online-location" url="http://www.juiblex.co.uk/libxexpr/docs/reference/index.html">http://www.juiblex.co.uk/libxexpr/docs/reference/</ulink>.
    9.18 +    </releaseinfo>
    9.19 +  </bookinfo>
    9.20 +
    9.21 +  <chapter>
    9.22 +    <title>Tools</title>
    9.23 +    <xi:include href="xexpr.xml"/>
    9.24 +  </chapter>
    9.25 +
    9.26 +  <chapter>
    9.27 +    <title>API Reference</title>
    9.28 +    <xi:include href="xml/xexprtypes.xml"/>
    9.29 +    <xi:include href="xml/xexpreval.xml"/>
    9.30 +    <xi:include href="xml/xexprparse.xml"/>
    9.31 +    <xi:include href="xml/xexprdump.xml"/>
    9.32 +  </chapter>
    9.33 +
    9.34 +  <xi:include href="implementation_defined_behaviour.xml"/>
    9.35 +
    9.36 +  <xi:include href="language_extensions.xml"/>
    9.37 +
    9.38 +  <index id="api-index-full">
    9.39 +    <title>API Index</title>
    9.40 +    <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
    9.41 +  </index>
    9.42 +
    9.43 +  <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
    9.44 +</book>
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/docs/reference/version.xml.in	Wed Oct 10 22:58:21 2012 +0100
    10.3 @@ -0,0 +1,1 @@
    10.4 +@VERSION@
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/docs/reference/xexpr.xml	Wed Oct 10 22:58:21 2012 +0100
    11.3 @@ -0,0 +1,97 @@
    11.4 +<refentry id="xexpr">
    11.5 +
    11.6 +<refmeta>
    11.7 +<refentrytitle>xexpr</refentrytitle>
    11.8 +<manvolnum>1</manvolnum>
    11.9 +<refmiscinfo class="manual">User Commands</refmiscinfo>
   11.10 +</refmeta>
   11.11 +
   11.12 +<refnamediv>
   11.13 +<refname>xexpr</refname>
   11.14 +<refpurpose>XEXPR Interpreter</refpurpose>
   11.15 +</refnamediv>
   11.16 +
   11.17 +<refsynopsisdiv>
   11.18 +<cmdsynopsis>
   11.19 +<command>xexpr</command>
   11.20 +<arg choice="opt" rep="repeat">OPTION</arg>
   11.21 +<arg>script</arg>
   11.22 +</cmdsynopsis>
   11.23 +</refsynopsisdiv>
   11.24 +
   11.25 +<refsect1><title>Description</title>
   11.26 +<para><command>xexpr</command> is an XEXPR interpreter. It loads and executes
   11.27 +XEXPR programs.
   11.28 +</para>
   11.29 +</refsect1>
   11.30 +
   11.31 +<refsect1><title>Options</title>
   11.32 +<variablelist>
   11.33 +
   11.34 +<varlistentry>
   11.35 +<term><option>-h</option>, <option>--help</option></term>
   11.36 +<listitem><para>
   11.37 +print help and exit
   11.38 +</para></listitem>
   11.39 +</varlistentry>
   11.40 +
   11.41 +<varlistentry>
   11.42 +<term><option>-d</option>, <option>--dump-tree</option></term>
   11.43 +<listitem><para>
   11.44 +Instead of executing the XEXPR program, dump the parsed tree after loading
   11.45 +</para></listitem>
   11.46 +</varlistentry>
   11.47 +
   11.48 +<varlistentry>
   11.49 +<term><option>-D</option>, <option>--dump-result</option></term>
   11.50 +<listitem><para>
   11.51 +After executing the XEXPR program, dump the result
   11.52 +</para></listitem>
   11.53 +</varlistentry>
   11.54 +
   11.55 +<varlistentry>
   11.56 +<term><option>-t</option>, <option>--test-result</option></term>
   11.57 +<listitem><para>
   11.58 +After executing the XEXPR program, test the result and exit 0 if it evaluates
   11.59 +to &lt;true/&gt; and non-zero if it evaluates to &lt;false/&gt;
   11.60 +</para></listitem>
   11.61 +</varlistentry>
   11.62 +
   11.63 +<varlistentry>
   11.64 +<term><option>-T=<replaceable>id</replaceable></option>, <option>--trace <replaceable>id</replaceable></option></term>
   11.65 +<listitem><para>
   11.66 +Adds <replaceable>id</replaceable> to the set of symbols to trace.
   11.67 +
   11.68 +When variables with the name of a traced symbol are created or changed,
   11.69 +<command>xexpr</command> will output a suitable tracing message and a stack
   11.70 +dump
   11.71 +</para></listitem>
   11.72 +</varlistentry>
   11.73 +
   11.74 +<varlistentry>
   11.75 +<term><option>--xinclude</option></term>
   11.76 +<listitem><para>
   11.77 +Do XInclude processing
   11.78 +</para></listitem>
   11.79 +</varlistentry>
   11.80 +
   11.81 +<varlistentry>
   11.82 +<term><option>--param <replaceable>name</replaceable>,<replaceable>number</replaceable></option></term>
   11.83 +<listitem><para>
   11.84 +Set a global XEXPR variable of the given <replaceable>name</replaceable> with a
   11.85 +numeric value of <replaceable>number</replaceable>. A float or integer type
   11.86 +will be selected automatically.
   11.87 +</para></listitem>
   11.88 +</varlistentry>
   11.89 +
   11.90 +<varlistentry>
   11.91 +<term><option>--stringparam <replaceable>name</replaceable>,<replaceable>value</replaceable></option></term>
   11.92 +<listitem><para>
   11.93 +Set a global XEXPR variable of the given <replaceable>name</replaceable> with a
   11.94 +string value of <replaceable>value</replaceable>.
   11.95 +</para></listitem>
   11.96 +</varlistentry>
   11.97 +
   11.98 +</variablelist>
   11.99 +</refsect1>
  11.100 +</refentry>
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/libxexpr/Makefile.am	Wed Oct 10 22:58:21 2012 +0100
    12.3 @@ -0,0 +1,14 @@
    12.4 +AM_CFLAGS=-g $(LIBXEXPR_CFLAGS)
    12.5 +LIBS=$(LIBXEXPR_LIBS)
    12.6 +INCLUDES=-I$(top_srcdir)
    12.7 +AM_LDFLAGS=-no-undefined -version-info $(LIBXEXPR_LT_VERSION_INFO)
    12.8 +
    12.9 +pkginclude_HEADERS=xexprdump.h xexpreval.h xexprparse.h xexprtypes.h \
   12.10 +    xexpr.h
   12.11 +
   12.12 +lib_LTLIBRARIES=libxexpr.la
   12.13 +libxexpr_la_SOURCES=xexprdump.c xexpreval.c xexprparse.c xexprtypes.c \
   12.14 +    extension.c xexprprivate.h $(pkginclude_HEADERS)
   12.15 +
   12.16 +pkgconfigdir=$(libdir)/pkgconfig
   12.17 +pkgconfig_DATA=libxexpr.pc
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/libxexpr/extension.c	Wed Oct 10 22:58:21 2012 +0100
    13.3 @@ -0,0 +1,209 @@
    13.4 +#include <stdlib.h>
    13.5 +#include <string.h>
    13.6 +#include <math.h>
    13.7 +#include <xexpr.h>
    13.8 +#include "xexprprivate.h"
    13.9 +
   13.10 +static XexprConstant *xexpr_do_pi(Xexpr *xexpr,GSList *bindings,GSList *args,
   13.11 +  GError **err)
   13.12 +{
   13.13 +    return xexpr_new_number(M_PI);
   13.14 +}
   13.15 +
   13.16 +static XexprConstant *xexpr_do_sin(Xexpr *xexpr,GSList *bindings,GSList *args,
   13.17 +  GError **err)
   13.18 +{
   13.19 +    XexprConstant *x;
   13.20 +    x=xexpr_bindings_get(bindings,"x");
   13.21 +    if (!x)
   13.22 +    {
   13.23 +	if (args)
   13.24 +	{
   13.25 +	    x=args->data;
   13.26 +	    args=args->next;
   13.27 +	}
   13.28 +	else
   13.29 +	{
   13.30 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
   13.31 +	      "Missing \"x\" argument to \"libxexpr:sin\"");
   13.32 +	    return NULL;
   13.33 +	}
   13.34 +    }
   13.35 +    if (!xexpr_constant_cast(x,XEXPR_TYPE_NUMBER))
   13.36 +	return xexpr_new_number(0.0/0.0);
   13.37 +    if (!isfinite(x->u.number))
   13.38 +	return xexpr_new_number(0.0/0.0);
   13.39 +    else
   13.40 +	return xexpr_new_number(sin(x->u.number));
   13.41 +}
   13.42 +
   13.43 +static XexprConstant *xexpr_do_atan(Xexpr *xexpr,GSList *bindings,GSList *args,
   13.44 +  GError **err)
   13.45 +{
   13.46 +    XexprConstant *x,*y;
   13.47 +    x=xexpr_bindings_get(bindings,"x");
   13.48 +    if (!x)
   13.49 +    {
   13.50 +	if (args)
   13.51 +	{
   13.52 +	    x=args->data;
   13.53 +	    args=args->next;
   13.54 +	}
   13.55 +	else
   13.56 +	{
   13.57 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
   13.58 +	      "Missing \"x\" argument to \"libxexpr:atan\"");
   13.59 +	    return NULL;
   13.60 +	}
   13.61 +    }
   13.62 +    if (!xexpr_constant_cast(x,XEXPR_TYPE_NUMBER))
   13.63 +	return xexpr_new_number(0.0/0.0);
   13.64 +    y=xexpr_bindings_get(bindings,"y");
   13.65 +    if (!y && args)
   13.66 +    {
   13.67 +	y=args->data;
   13.68 +	args=args->next;
   13.69 +    }
   13.70 +    if (y && !xexpr_constant_cast(y,XEXPR_TYPE_NUMBER))
   13.71 +	return xexpr_new_number(0.0/0.0);
   13.72 +    if (!isfinite(x->u.number) || y && !isfinite(y->u.number))
   13.73 +	return xexpr_new_number(0.0/0.0);
   13.74 +    else if (y)
   13.75 +	return xexpr_new_number(atan2(y->u.number,x->u.number));
   13.76 +    else
   13.77 +	return xexpr_new_number(atan(x->u.number));
   13.78 +}
   13.79 +
   13.80 +static XexprConstant *xexpr_do_exp(Xexpr *xexpr,GSList *bindings,GSList *args,
   13.81 +  GError **err)
   13.82 +{
   13.83 +    XexprConstant *x;
   13.84 +    x=xexpr_bindings_get(bindings,"x");
   13.85 +    if (!x && args)
   13.86 +    {
   13.87 +	x=args->data;
   13.88 +	args=args->next;
   13.89 +    }
   13.90 +    if (x && !xexpr_constant_cast(x,XEXPR_TYPE_NUMBER))
   13.91 +	return xexpr_new_number(0.0/0.0);
   13.92 +    if (x && !isfinite(x->u.number))
   13.93 +	return xexpr_new_number(0.0/0.0);
   13.94 +    else
   13.95 +	return xexpr_new_number(x?exp(x->u.number):exp(1.0));
   13.96 +}
   13.97 +
   13.98 +static XexprConstant *xexpr_do_log(Xexpr *xexpr,GSList *bindings,GSList *args,
   13.99 +  GError **err)
  13.100 +{
  13.101 +    XexprConstant *x;
  13.102 +    x=xexpr_bindings_get(bindings,"x");
  13.103 +    if (!x)
  13.104 +    {
  13.105 +	if (args)
  13.106 +	{
  13.107 +	    x=args->data;
  13.108 +	    args=args->next;
  13.109 +	}
  13.110 +	else
  13.111 +	{
  13.112 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  13.113 +	      "Missing \"x\" argument to \"libxexpr:log\"");
  13.114 +	    return NULL;
  13.115 +	}
  13.116 +    }
  13.117 +    if (!xexpr_constant_cast(x,XEXPR_TYPE_NUMBER))
  13.118 +	return xexpr_new_number(0.0/0.0);
  13.119 +    if (!isfinite(x->u.number))
  13.120 +	return xexpr_new_number(0.0/0.0);
  13.121 +    else
  13.122 +	return xexpr_new_number(log(x->u.number));
  13.123 +}
  13.124 +
  13.125 +static XexprConstant *xexpr_do_pow(Xexpr *xexpr,GSList *bindings,GSList *args,
  13.126 +  GError **err)
  13.127 +{
  13.128 +    XexprConstant *x,*y;
  13.129 +    x=xexpr_bindings_get(bindings,"x");
  13.130 +    if (!x)
  13.131 +    {
  13.132 +	if (args)
  13.133 +	{
  13.134 +	    x=args->data;
  13.135 +	    args=args->next;
  13.136 +	}
  13.137 +	else
  13.138 +	{
  13.139 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  13.140 +	      "Missing \"x\" argument to \"libxexpr:atan\"");
  13.141 +	    return NULL;
  13.142 +	}
  13.143 +    }
  13.144 +    if (!xexpr_constant_cast(x,XEXPR_TYPE_NUMBER))
  13.145 +	return xexpr_new_number(0.0/0.0);
  13.146 +    y=xexpr_bindings_get(bindings,"y");
  13.147 +    if (!y)
  13.148 +    {
  13.149 +	if (args)
  13.150 +	{
  13.151 +	    y=args->data;
  13.152 +	    args=args->next;
  13.153 +	}
  13.154 +	else
  13.155 +	{
  13.156 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  13.157 +	      "Missing \"y\" argument to \"libxexpr:pow\"");
  13.158 +	    return NULL;
  13.159 +	}
  13.160 +    }
  13.161 +    if (!xexpr_constant_cast(y,XEXPR_TYPE_NUMBER))
  13.162 +	return xexpr_new_number(0.0/0.0);
  13.163 +    if (x->u.number==1 || y->u.number==0)
  13.164 +	return xexpr_new_number(1.0);
  13.165 +    else if (!isfinite(x->u.number) || !isfinite(y->u.number))
  13.166 +	return xexpr_new_number(0.0/0.0);
  13.167 +    else
  13.168 +	return xexpr_new_number(pow(x->u.number,y->u.number));
  13.169 +}
  13.170 +
  13.171 +static struct libxexpr_function {
  13.172 +    char *id;
  13.173 +    XexprConstant *(*func)(Xexpr *xexpr,GSList *bindings,GSList *args,
  13.174 +      GError **err);
  13.175 +} libxexpr_functions[]={
  13.176 +    { "pi",		xexpr_do_pi },
  13.177 +    { "sin",		xexpr_do_sin },
  13.178 +    { "atan",		xexpr_do_atan },
  13.179 +    { "exp",		xexpr_do_exp },
  13.180 +    { "log",		xexpr_do_log },
  13.181 +    { "pow",		xexpr_do_pow },
  13.182 +};
  13.183 +
  13.184 +XexprConstant *_xexpr_libxexpr_function_evaluate(Xexpr *xexpr,const char *ns,
  13.185 +  const char *id,GSList *bindings,GSList *args,GError **err)
  13.186 +{
  13.187 +    int func;
  13.188 +    XexprConstant *value,*result;
  13.189 +    GSList *evaluated_args=NULL;
  13.190 +    for(func=0;func<G_N_ELEMENTS(libxexpr_functions);func++)
  13.191 +	if (!strcmp(libxexpr_functions[func].id,id))
  13.192 +	    break;
  13.193 +    if (func==G_N_ELEMENTS(libxexpr_functions))
  13.194 +    {
  13.195 +	g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  13.196 +	  "Undefined function: \"libxexpr:%s\"",id);
  13.197 +	return NULL;
  13.198 +    }
  13.199 +    while(args)
  13.200 +    {
  13.201 +	value=xexpr_constant_evaluate(xexpr,args->data,err);
  13.202 +	if (!value)
  13.203 +	    return NULL;
  13.204 +	evaluated_args=g_slist_prepend(evaluated_args,value);
  13.205 +	args=args->next;
  13.206 +    }
  13.207 +    evaluated_args=g_slist_reverse(evaluated_args);
  13.208 +    result=libxexpr_functions[func].func(xexpr,bindings,evaluated_args,err);
  13.209 +    g_slist_foreach(evaluated_args,(GFunc)xexpr_constant_free,NULL);
  13.210 +    g_slist_free(evaluated_args);
  13.211 +    return result;
  13.212 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/libxexpr/libxexpr.pc.in	Wed Oct 10 22:58:21 2012 +0100
    14.3 @@ -0,0 +1,11 @@
    14.4 +prefix=@prefix@
    14.5 +exec_prefix=@exec_prefix@
    14.6 +libdir=@libdir@
    14.7 +includedir=@includedir@
    14.8 +
    14.9 +Name: libxexpr
   14.10 +Description: An implementation of XEXPR - http://www.w3.org/TR/xexpr
   14.11 +Version: @VERSION@
   14.12 +Requires: libxml-2.0 glib-2.0
   14.13 +Libs: -L${libdir} -lxexpr
   14.14 +Cflags: -I${includedir}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/libxexpr/xexpr.h	Wed Oct 10 22:58:21 2012 +0100
    15.3 @@ -0,0 +1,11 @@
    15.4 +#ifndef __XEXPER_H__
    15.5 +#define __XEXPER_H__
    15.6 +
    15.7 +#define XEXPR_NS	"http://www.ebt.com/xexpr"
    15.8 +#define LIBXEXPR_NS	"http://www.juiblex.co.uk/ns/libxexpr"
    15.9 +
   15.10 +#include <libxexpr/xexprparse.h>
   15.11 +#include <libxexpr/xexpreval.h>
   15.12 +#include <libxexpr/xexprdump.h>
   15.13 +
   15.14 +#endif /* __XEXPER_H__ */
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/libxexpr/xexprdump.c	Wed Oct 10 22:58:21 2012 +0100
    16.3 @@ -0,0 +1,299 @@
    16.4 +#include <stdlib.h>
    16.5 +#include <string.h>
    16.6 +#include <math.h>
    16.7 +#include <xexpr.h>
    16.8 +
    16.9 +/**
   16.10 + * SECTION:xexprdump
   16.11 + * @short_description: Functions to dump XEXPR objects
   16.12 + * @stability: Stable
   16.13 + * @include: libxexpr/xexpr.h
   16.14 + *
   16.15 + * A set of functions to dump
   16.16 + * <ulink url="http://www.w3.org/TR/2000/NOTE-xexpr-20001121">XEXPR</ulink>
   16.17 + * objects.
   16.18 + */
   16.19 +
   16.20 +static void xexpr_attribute_dump_string(XexprConstant *constant,GString *str)
   16.21 +{
   16.22 +    const char *s;
   16.23 +    gunichar c;
   16.24 +    switch(constant->type)
   16.25 +    {
   16.26 +	default:
   16.27 +	    return xexpr_constant_dump_string(constant,str);
   16.28 +	    break;
   16.29 +	case XEXPR_TYPE_STRING:
   16.30 +	    if (strchr(constant->u.string,'"'))
   16.31 +	    {
   16.32 +		if (strchr(constant->u.string,'\''))
   16.33 +		{
   16.34 +		    g_string_append_c(str,'"');
   16.35 +		    for(s=constant->u.string;s;s=g_utf8_next_char(s))
   16.36 +		    {
   16.37 +			c=g_utf8_get_char(s);
   16.38 +			if (c=='"')
   16.39 +			    g_string_append_c(str,'\\');
   16.40 +			g_string_append_unichar(str,c);
   16.41 +		    }
   16.42 +		    g_string_append_c(str,'"');
   16.43 +		}
   16.44 +		else
   16.45 +		{
   16.46 +		    g_string_append_c(str,'\'');
   16.47 +		    g_string_append(str,constant->u.string);
   16.48 +		    g_string_append_c(str,'\'');
   16.49 +		}
   16.50 +	    }
   16.51 +	    else
   16.52 +	    {
   16.53 +		g_string_append_c(str,'"');
   16.54 +		g_string_append(str,constant->u.string);
   16.55 +		g_string_append_c(str,'"');
   16.56 +	    }
   16.57 +	    break;
   16.58 +	case XEXPR_TYPE_INTEGER:
   16.59 +	    g_string_append_printf(str,"\"%lld\"",constant->u.integer);
   16.60 +	    break;
   16.61 +	case XEXPR_TYPE_NUMBER:
   16.62 +	    g_string_append_printf(str,"\"%lg\"",constant->u.number);
   16.63 +	    break;
   16.64 +    }
   16.65 +}
   16.66 +
   16.67 +/**
   16.68 + * xexpr_constant_dump_string:
   16.69 + * @constant: an #XexprConstant to dump
   16.70 + * @str: the string to dump to
   16.71 + *
   16.72 + * Dumps @constant to the given @str in XML format. For invocation, string
   16.73 + * and numeric types, XEXPR itself is used as the dump format (with explicit
   16.74 + * type tags). Function definitions cannot be expressed in XEXPR (which
   16.75 + * requires that functions be given a name), so we get as close as we can
   16.76 + * and use a &lt;define&gt; element without the required name attribute.
   16.77 + */
   16.78 +void xexpr_constant_dump_string(XexprConstant *constant,GString *str)
   16.79 +{
   16.80 +    int i;
   16.81 +    gchar *s;
   16.82 +    XexprBinding *binding;
   16.83 +    GSList *lnk;
   16.84 +    GQuark prefix;
   16.85 +    switch(constant->type)
   16.86 +    {
   16.87 +	case XEXPR_TYPE_FUNCTION:
   16.88 +	    g_string_append(str,"<define");
   16.89 +	    if (constant->u.function->args)
   16.90 +	    {
   16.91 +		g_string_append(str," args=\"");
   16.92 +		for(lnk=constant->u.function->args;lnk;lnk=lnk->next)
   16.93 +		{
   16.94 +		    g_string_append(str,lnk->data);
   16.95 +		    if (lnk->next)
   16.96 +			g_string_append_c(str,' ');
   16.97 +		}
   16.98 +		g_string_append_c(str,'"');
   16.99 +	    }
  16.100 +	    g_string_append_c(str,'>');
  16.101 +	    for(lnk=constant->u.function->constants;lnk;lnk=lnk->next)
  16.102 +		xexpr_constant_dump_string(lnk->data,str);
  16.103 +	    g_string_append(str,"</define>");
  16.104 +	    break;
  16.105 +	case XEXPR_TYPE_INVOCATION:
  16.106 +	    g_string_append_c(str,'<');
  16.107 +	    if (!constant->u.invocation->ns)
  16.108 +		prefix=0;
  16.109 +	    else if (!strcmp(constant->u.invocation->ns,LIBXEXPR_NS))
  16.110 +		prefix=g_quark_from_static_string("libxexpr");
  16.111 +	    else
  16.112 +	    {
  16.113 +		for(i=0;;i++)
  16.114 +		{
  16.115 +		    s=g_strdup_printf("x%d",i);
  16.116 +		    if (!g_quark_try_string(s))
  16.117 +		    {
  16.118 +			prefix=g_quark_from_string(s);
  16.119 +			g_free(s);
  16.120 +			break;
  16.121 +		    }
  16.122 +		    g_free(s);
  16.123 +		}
  16.124 +	    }
  16.125 +	    if (prefix)
  16.126 +	    {
  16.127 +		g_string_append(str,g_quark_to_string(prefix));
  16.128 +		g_string_append_c(str,':');
  16.129 +	    }
  16.130 +	    g_string_append(str,constant->u.invocation->function);
  16.131 +	    if (prefix && prefix!=g_quark_from_static_string("libxexpr"))
  16.132 +	    {
  16.133 +		g_string_append(str," xmlns:");
  16.134 +		g_string_append(str,g_quark_to_string(prefix));
  16.135 +		g_string_append(str,"=\"");
  16.136 +		g_string_append(str,constant->u.invocation->ns);
  16.137 +		g_string_append_c(str,'"');
  16.138 +	    }
  16.139 +	    for(lnk=constant->u.invocation->bindings;lnk;lnk=lnk->next)
  16.140 +	    {
  16.141 +		binding=lnk->data;
  16.142 +		g_string_append_c(str,' ');
  16.143 +		g_string_append(str,binding->id);
  16.144 +		g_string_append_c(str,'=');
  16.145 +		xexpr_attribute_dump_string(binding->value,str);
  16.146 +	    }
  16.147 +	    if (constant->u.invocation->constants)
  16.148 +	    {
  16.149 +		g_string_append_c(str,'>');
  16.150 +		xexpr_constants_dump_string(constant->u.invocation->constants,
  16.151 +		  str);
  16.152 +		g_string_append(str,"</");
  16.153 +		if (prefix)
  16.154 +		{
  16.155 +		    g_string_append(str,g_quark_to_string(prefix));
  16.156 +		    g_string_append_c(str,':');
  16.157 +		}
  16.158 +		g_string_append(str,constant->u.invocation->function);
  16.159 +		g_string_append_c(str,'>');
  16.160 +	    }
  16.161 +	    else
  16.162 +		g_string_append(str,"/>");
  16.163 +	    break;
  16.164 +	case XEXPR_TYPE_STRING:
  16.165 +	    g_string_append(str,"<string>");
  16.166 +	    g_string_append(str,constant->u.string);
  16.167 +	    g_string_append(str,"</string>");
  16.168 +	    break;
  16.169 +	case XEXPR_TYPE_INTEGER:
  16.170 +	    g_string_append_printf(str,"<integer>%lld</integer>",
  16.171 +	      constant->u.integer);
  16.172 +	    break;
  16.173 +	case XEXPR_TYPE_NUMBER:
  16.174 +	    g_string_append_printf(str,"<float>%lg</float>",constant->u.number);
  16.175 +	    break;
  16.176 +    }
  16.177 +}
  16.178 +
  16.179 +/**
  16.180 + * xexpr_constants_dump_string:
  16.181 + * @constants: (transfer none) (element-type XexprConstant): a list of
  16.182 + *     #XexprConstant constants to dump
  16.183 + * @str: the string to dump to
  16.184 + *
  16.185 + * Dumps @constants to the given @str in XML format one after the other,
  16.186 + * thus forming an XML fragment.
  16.187 + *
  16.188 + * See xexpr_constant_dump_string() for details of the XML format used.
  16.189 + */
  16.190 +void xexpr_constants_dump_string(GSList *constants,GString *str)
  16.191 +{
  16.192 +    XexprConstant *constant;
  16.193 +    GSList *lnk;
  16.194 +    for(lnk=constants;lnk;lnk=lnk->next)
  16.195 +    {
  16.196 +	constant=lnk->data;
  16.197 +	xexpr_constant_dump_string(constant,str);
  16.198 +    }
  16.199 +}
  16.200 +
  16.201 +/**
  16.202 + * xexpr_dump_string:
  16.203 + * @xexpr: an #Xexpr to dump
  16.204 + * @str: the string to dump to
  16.205 + *
  16.206 + * Dumps @xexpr to the given @str in XML format. If @xexpr contains multiple
  16.207 + * constants, this will result in an XML fragment.
  16.208 + *
  16.209 + * See xexpr_constant_dump_string() for details of the XML format used.
  16.210 + */
  16.211 +void xexpr_dump_string(Xexpr *xexpr,GString *str)
  16.212 +{
  16.213 +    xexpr_constants_dump_string(xexpr->constants,str);
  16.214 +}
  16.215 +
  16.216 +/**
  16.217 + * xexpr_constant_dump:
  16.218 + * @constant: an #XexprConstant to dump
  16.219 + * @fp: the <type>FILE</type> to dump to
  16.220 + *
  16.221 + * Dumps @constant to the given @fp in XML format.
  16.222 + *
  16.223 + * See xexpr_constant_dump_string() for details of the XML format used.
  16.224 + */
  16.225 +void xexpr_constant_dump(XexprConstant *constant,FILE *fp)
  16.226 +{
  16.227 +    GString *str=g_string_new(NULL);
  16.228 +    xexpr_constant_dump_string(constant,str);
  16.229 +    fputs(str->str,fp);
  16.230 +    g_string_free(str,TRUE);
  16.231 +}
  16.232 +
  16.233 +/**
  16.234 + * xexpr_constants_dump:
  16.235 + * @constants: (transfer none) (element-type XexprConstant): a list of
  16.236 + *     #XexprConstant constants to dump
  16.237 + * @fp: the <type>FILE</type> to dump to
  16.238 + *
  16.239 + * Dumps @constants to the given @fp in XML format one after the other,
  16.240 + * thus forming an XML fragment.
  16.241 + *
  16.242 + * See xexpr_constant_dump_string() for details of the XML format used.
  16.243 + */
  16.244 +void xexpr_constants_dump(GSList *constants,FILE *fp)
  16.245 +{
  16.246 +    GString *str=g_string_new(NULL);
  16.247 +    xexpr_constants_dump_string(constants,str);
  16.248 +    fputs(str->str,fp);
  16.249 +    g_string_free(str,TRUE);
  16.250 +}
  16.251 +
  16.252 +/**
  16.253 + * xexpr_dump:
  16.254 + * @xexpr: an #Xexpr to dump
  16.255 + * @fp: the <type>FILE</type> to dump to
  16.256 + *
  16.257 + * Dumps @xexpr to the given @fp in XML format. If @xexpr contains multiple
  16.258 + * constants, this will result in an XML fragment.
  16.259 + *
  16.260 + * See xexpr_constant_dump_string() for details of the XML format used.
  16.261 + */
  16.262 +void xexpr_dump(Xexpr *xexpr,FILE *fp)
  16.263 +{
  16.264 +    xexpr_constants_dump(xexpr->constants,fp);
  16.265 +}
  16.266 +
  16.267 +/**
  16.268 + * xexpr_stack_dump:
  16.269 + * @xexpr: an #Xexpr whose stack you wish to dump
  16.270 + * @fp: the <type>FILE</type> to dump to
  16.271 + *
  16.272 + * Dumps the current stack of @xexpr to the given @fp in human readable format.
  16.273 + * The environments of the various invoked functions will be given in order
  16.274 + * starting with the innermost (\#0). For each environment, the variables
  16.275 + * defined there will be given along with their current values. Global
  16.276 + * variables are contained in the outermost environment.
  16.277 + */
  16.278 +void xexpr_stack_dump(Xexpr *xexpr,FILE *fp)
  16.279 +{
  16.280 +    int i;
  16.281 +    GSList *lnk;
  16.282 +    XexprBinding *binding;
  16.283 +    XexprEnvironment *environment=xexpr_get_environment(xexpr);
  16.284 +    for(i=0;environment;environment=environment->outer,i++)
  16.285 +    {
  16.286 +	fprintf(fp,"#%-2d ",i);
  16.287 +	if (environment->function)
  16.288 +	    fprintf(fp,"%s",environment->function);
  16.289 +	else
  16.290 +	    fprintf(fp,"%p",environment);
  16.291 +	fprintf(fp," (");
  16.292 +	for(lnk=environment->bindings;lnk;lnk=lnk->next)
  16.293 +	{
  16.294 +	    binding=lnk->data;
  16.295 +	    fprintf(fp,"%s = ",binding->id);
  16.296 +	    xexpr_constant_dump(binding->value,fp);
  16.297 +	    if (lnk->next)
  16.298 +		fprintf(fp,", ");
  16.299 +	}
  16.300 +	fprintf(fp,")\n");
  16.301 +    }
  16.302 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/libxexpr/xexprdump.h	Wed Oct 10 22:58:21 2012 +0100
    17.3 @@ -0,0 +1,19 @@
    17.4 +#ifndef __XEXPER_DUMP_H__
    17.5 +#define __XEXPER_DUMP_H__
    17.6 +
    17.7 +#include <stdio.h>
    17.8 +#include "xexprtypes.h"
    17.9 +
   17.10 +G_BEGIN_DECLS
   17.11 +
   17.12 +void xexpr_constant_dump_string(XexprConstant *constant,GString *str);
   17.13 +void xexpr_constants_dump_string(GSList *constants,GString *str);
   17.14 +void xexpr_dump_string(Xexpr *xexpr,GString *str);
   17.15 +void xexpr_constant_dump(XexprConstant *constant,FILE *fp);
   17.16 +void xexpr_constants_dump(GSList *constants,FILE *fp);
   17.17 +void xexpr_dump(Xexpr *xexpr,FILE *fp);
   17.18 +void xexpr_stack_dump(Xexpr *xexpr,FILE *fp);
   17.19 +
   17.20 +G_END_DECLS
   17.21 +
   17.22 +#endif	/* __XEXPER_DUMP_H__ */
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/libxexpr/xexpreval.c	Wed Oct 10 22:58:21 2012 +0100
    18.3 @@ -0,0 +1,1621 @@
    18.4 +#include <stdlib.h>
    18.5 +#include <string.h>
    18.6 +#include <math.h>
    18.7 +#include <xexpr.h>
    18.8 +#include "xexprprivate.h"
    18.9 +
   18.10 +/**
   18.11 + * SECTION:xexpreval
   18.12 + * @short_description: An evaluator for the XEXPR language
   18.13 + * @stability: Stable
   18.14 + * @include: libxexpr/xexpr.h
   18.15 + *
   18.16 + * An evaluator for the
   18.17 + * <ulink url="http://www.w3.org/TR/2000/NOTE-xexpr-20001121">XEXPR</ulink>
   18.18 + * language.
   18.19 + */
   18.20 +
   18.21 +GSList *xexpr_extensions=NULL;
   18.22 +
   18.23 +static XexprExtension libxexpr_extension={
   18.24 +    LIBXEXPR_NS,_xexpr_libxexpr_function_evaluate
   18.25 +};
   18.26 +
   18.27 +static XexprConstant *xexpr_do_string(Xexpr *xexpr,GSList *bindings,
   18.28 +  GSList *args,GError **err);
   18.29 +static gboolean xexpr_defineable_id(const char *id,GError **err);
   18.30 +
   18.31 +/**
   18.32 + * xexpr_eval_error_quark:
   18.33 + *
   18.34 + * Registers an error quark for the libxexpr evaluator if necessary.
   18.35 + *
   18.36 + * Return value: The error quark used for libxexpr evaluator errors.
   18.37 + */
   18.38 +GQuark xexpr_eval_error_quark(void)
   18.39 +{
   18.40 +    static GQuark quark;
   18.41 +    if (!quark)
   18.42 +	quark=g_quark_from_static_string("xexpr_eval_error");
   18.43 +    return quark;
   18.44 +}
   18.45 +
   18.46 +/**
   18.47 + * xexpr_register_extension:
   18.48 + * @extension: (transfer none): an #XexprExtension
   18.49 + *
   18.50 + * Registers an extension to handle the evaluation of functions and retrieval
   18.51 + * of variables in a new namespace.
   18.52 + *
   18.53 + * Return value: %TRUE if the extension was successfully registered
   18.54 + */
   18.55 +gboolean xexpr_register_extension(XexprExtension *extension)
   18.56 +{
   18.57 +    GSList *lnk;
   18.58 +    XexprExtension *ext;
   18.59 +    static GStaticMutex mutex=G_STATIC_MUTEX_INIT;
   18.60 +    g_static_mutex_lock(&mutex);
   18.61 +    if (!xexpr_extensions)
   18.62 +	xexpr_extensions=g_slist_prepend(xexpr_extensions,&libxexpr_extension);
   18.63 +    if (!extension || !extension->ns || !*extension->ns ||
   18.64 +      !strcmp(extension->ns,XEXPR_NS))
   18.65 +    {
   18.66 +	g_static_mutex_unlock(&mutex);
   18.67 +	return FALSE;
   18.68 +    }
   18.69 +    for(lnk=xexpr_extensions;lnk;lnk=lnk->next)
   18.70 +    {
   18.71 +	ext=lnk->data;
   18.72 +	if (!strcmp(ext->ns,extension->ns))
   18.73 +	{
   18.74 +	    g_static_mutex_unlock(&mutex);
   18.75 +	    return FALSE;
   18.76 +	}
   18.77 +    }
   18.78 +    extension=g_memdup(extension,sizeof(*extension));
   18.79 +    extension->ns=g_strdup(extension->ns);
   18.80 +    xexpr_extensions=g_slist_prepend(xexpr_extensions,extension);
   18.81 +    g_static_mutex_unlock(&mutex);
   18.82 +    return TRUE;
   18.83 +}
   18.84 +
   18.85 +/*
   18.86 + * Returned constant should be freed iff evaluate is TRUE
   18.87 + */
   18.88 +static XexprConstant *xexpr_get_argument(Xexpr *xexpr,GSList *bindings,
   18.89 +  GSList **args,const char *func,const char *id,gboolean evaluate,GError **err)
   18.90 +{
   18.91 +    XexprConstant *arg;
   18.92 +    arg=xexpr_bindings_get(bindings,id);
   18.93 +    if (!arg)
   18.94 +    {
   18.95 +	if (*args)
   18.96 +	{
   18.97 +	    arg=(*args)->data;
   18.98 +	    *args=(*args)->next;
   18.99 +	}
  18.100 +	else
  18.101 +	{
  18.102 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.103 +	      "Missing \"%s\" argument to \"%s\"",id,func);
  18.104 +	    return NULL;
  18.105 +	}
  18.106 +    }
  18.107 +    if (arg && evaluate)
  18.108 +	arg=xexpr_constant_evaluate(xexpr,arg,err);
  18.109 +    return arg;
  18.110 +}
  18.111 +
  18.112 +static XexprConstant *xexpr_do_define(Xexpr *xexpr,GSList *bindings,
  18.113 +  GSList *args,GError **err)
  18.114 +{
  18.115 +    int i;
  18.116 +    gchar **vector=NULL;
  18.117 +    GSList *parameters=NULL;
  18.118 +    XexprConstant *name,*params,*value,*arg;
  18.119 +    XexprEnvironment *frame;
  18.120 +    name=xexpr_get_argument(xexpr,bindings,&args,"define","name",TRUE,err);
  18.121 +    if (!name)
  18.122 +	return NULL;
  18.123 +    if (name->type!=XEXPR_TYPE_STRING)
  18.124 +    {
  18.125 +	args=g_slist_prepend(NULL,name);
  18.126 +	arg=xexpr_do_string(xexpr,NULL,args,NULL);
  18.127 +	g_slist_free(args);
  18.128 +	if (arg)
  18.129 +	{
  18.130 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.131 +	      "Attempt to define a function with a non-string name \"%s\"",
  18.132 +	      arg->u.string);
  18.133 +	    xexpr_constant_free(arg);
  18.134 +	}
  18.135 +	else
  18.136 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.137 +	      "Attempt to define a function with a non-string name");
  18.138 +	xexpr_constant_free(name);
  18.139 +	return NULL;
  18.140 +    }
  18.141 +    else if (!_xexpr_validate_id(name->u.string,err) ||
  18.142 +      !xexpr_defineable_id(name->u.string,err))
  18.143 +    {
  18.144 +	xexpr_constant_free(name);
  18.145 +	return NULL;
  18.146 +    }
  18.147 +    params=xexpr_bindings_get(bindings,"args");
  18.148 +    if (params)
  18.149 +    {
  18.150 +	params=xexpr_constant_evaluate(xexpr,params,err);
  18.151 +	if (params->type!=XEXPR_TYPE_STRING)
  18.152 +	{
  18.153 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.154 +	      "Attempt to define a function with non-string argument names");
  18.155 +	    xexpr_constant_free(params);
  18.156 +	    xexpr_constant_free(name);
  18.157 +	    return NULL;
  18.158 +	}
  18.159 +	vector=g_strsplit_set(params->u.string," \t\n\r",-1);
  18.160 +	for(i=0;vector[i];i++)
  18.161 +	{
  18.162 +	    if (vector[i][0]>='0' && vector[i][0]<='9' ||
  18.163 +	      (vector[i][0]=='+' || vector[i][0]=='-') &&
  18.164 +	      vector[i][1]>='0' && vector[i][1]<='9')
  18.165 +	    {
  18.166 +		g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.167 +		 "Attempt to define a function with non-string argument names");
  18.168 +		xexpr_constant_free(params);
  18.169 +		xexpr_constant_free(name);
  18.170 +		g_strfreev(vector);
  18.171 +		g_slist_free(parameters);
  18.172 +		return NULL;
  18.173 +	    }
  18.174 +	    parameters=g_slist_prepend(parameters,vector[i]);
  18.175 +	}
  18.176 +	parameters=g_slist_reverse(parameters);
  18.177 +    }
  18.178 +    value=xexpr_new_function(parameters,args);
  18.179 +    g_slist_free(parameters);
  18.180 +    if (vector)
  18.181 +	g_strfreev(vector);
  18.182 +    frame=xexpr->environment;
  18.183 +    xexpr->environment=frame->outer;
  18.184 +    xexpr_var_new(xexpr,name->u.string,value);
  18.185 +    xexpr->environment=frame;
  18.186 +    xexpr_constant_free(name);
  18.187 +    return value;
  18.188 +}
  18.189 +
  18.190 +static XexprConstant *xexpr_do_print(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.191 +  GError **err)
  18.192 +{
  18.193 +    gboolean newline=FALSE;
  18.194 +    GSList *lnk;
  18.195 +    XexprConstant *arg;
  18.196 +    arg=xexpr_bindings_get(bindings,"newline");
  18.197 +    if (arg && arg->type==XEXPR_TYPE_STRING && !strcmp(arg->u.string,"true"))
  18.198 +	newline=TRUE;
  18.199 +    for(lnk=args;lnk;lnk=lnk->next)
  18.200 +    {
  18.201 +	arg=lnk->data;
  18.202 +	switch(arg->type)
  18.203 +	{
  18.204 +	    case XEXPR_TYPE_FUNCTION:
  18.205 +		/*
  18.206 +		 * http://www.w3.org/TR/xexpr/#id-0003 implies that
  18.207 +		 * function objects are ignored in <print>.
  18.208 +		 */
  18.209 +		break;
  18.210 +	    case XEXPR_TYPE_INVOCATION:
  18.211 +		printf("<%s/>",arg->u.invocation->function);
  18.212 +		break;
  18.213 +	    case XEXPR_TYPE_STRING:
  18.214 +		fputs(arg->u.string,stdout);
  18.215 +		break;
  18.216 +	    case XEXPR_TYPE_INTEGER:
  18.217 +		printf("%lld",arg->u.integer);
  18.218 +		break;
  18.219 +	    case XEXPR_TYPE_NUMBER:
  18.220 +		printf("%lg",arg->u.number);
  18.221 +		break;
  18.222 +	}
  18.223 +    }
  18.224 +    if (newline)
  18.225 +	putchar('\n');
  18.226 +    return xexpr_new_invocation(NULL,"true",NULL,NULL);
  18.227 +}
  18.228 +
  18.229 +static XexprConstant *xexpr_do_println(Xexpr *xexpr,GSList *bindings,
  18.230 +  GSList *args,GError **err)
  18.231 +{
  18.232 +    putchar('\n');
  18.233 +    return xexpr_new_invocation(NULL,"true",NULL,NULL);
  18.234 +}
  18.235 +
  18.236 +static XexprConstant *xexpr_do_get(Xexpr *xexpr,GSList *bindings,
  18.237 +  GSList *args,GError **err)
  18.238 +{
  18.239 +    XexprConstant *name,*value;
  18.240 +    name=xexpr_get_argument(xexpr,bindings,&args,"get","name",FALSE,err);
  18.241 +    if (!name)
  18.242 +	return NULL;
  18.243 +    if (name->type==XEXPR_TYPE_STRING)
  18.244 +	value=xexpr_var_get(xexpr,name->u.string);
  18.245 +    else
  18.246 +	value=NULL;
  18.247 +    if (value)
  18.248 +	value=xexpr_constant_dup(value);
  18.249 +    else
  18.250 +	value=xexpr_new_invocation(NULL,"nil",NULL,NULL);
  18.251 +    return value;
  18.252 +}
  18.253 +
  18.254 +static XexprConstant *xexpr_do_set(Xexpr *xexpr,GSList *bindings,
  18.255 +  GSList *args,GError **err)
  18.256 +{
  18.257 +    XexprConstant *name,*value;
  18.258 +    name=xexpr_get_argument(xexpr,bindings,&args,"set","name",FALSE,err);
  18.259 +    if (!name)
  18.260 +	return NULL;
  18.261 +    if (name->type!=XEXPR_TYPE_STRING)
  18.262 +    {
  18.263 +	g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.264 +	  "Attempt to bind a value a non-string name");
  18.265 +	xexpr_constant_free(name);
  18.266 +	return NULL;
  18.267 +    }
  18.268 +    else if (!_xexpr_validate_id(name->u.string,err) ||
  18.269 +      !xexpr_defineable_id(name->u.string,err))
  18.270 +    {
  18.271 +	xexpr_constant_free(name);
  18.272 +	return NULL;
  18.273 +    }
  18.274 +    value=xexpr_get_argument(xexpr,bindings,&args,"set","value",FALSE,err);
  18.275 +    if (!value)
  18.276 +	return NULL;
  18.277 +    xexpr_var_set(xexpr,name->u.string,value);
  18.278 +    return xexpr_constant_dup(value);
  18.279 +}
  18.280 +
  18.281 +static XexprConstant *xexpr_do_expr(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.282 +  GError **err)
  18.283 +{
  18.284 +    if (!args)
  18.285 +	return xexpr_new_invocation(NULL,"nil",NULL,NULL);
  18.286 +    while(args->next)
  18.287 +	args=args->next;
  18.288 +    return xexpr_constant_dup(args->data);
  18.289 +}
  18.290 +
  18.291 +static XexprConstant *xexpr_do_return(Xexpr *xexpr,GSList *bindings,
  18.292 +  GSList *args,GError **err)
  18.293 +{
  18.294 +    XexprConstant *retval;
  18.295 +    if (!args)
  18.296 +	retval=xexpr_new_invocation(NULL,"nil",NULL,NULL);
  18.297 +    while(args->next)
  18.298 +	args=args->next;
  18.299 +    retval=xexpr_constant_dup(args->data);
  18.300 +    return xexpr_new_invocation_take_ownership(NULL,g_strdup("return"),NULL,
  18.301 +      g_slist_prepend(NULL,retval));
  18.302 +}
  18.303 +
  18.304 +static XexprConstant *xexpr_do_string(Xexpr *xexpr,GSList *bindings,
  18.305 +  GSList *args,GError **err)
  18.306 +{
  18.307 +    XexprConstant *arg;
  18.308 +    GString *str=g_string_new(NULL);
  18.309 +    while(args)
  18.310 +    {
  18.311 +	arg=args->data;
  18.312 +	switch(arg->type)
  18.313 +	{
  18.314 +	    case XEXPR_TYPE_FUNCTION:
  18.315 +		g_warn_if_reached();
  18.316 +		break;
  18.317 +	    case XEXPR_TYPE_INVOCATION:
  18.318 +		g_string_append_printf(str,"<%s/>",arg->u.invocation->function);
  18.319 +		break;
  18.320 +	    case XEXPR_TYPE_STRING:
  18.321 +		g_string_append(str,arg->u.string);
  18.322 +		break;
  18.323 +	    case XEXPR_TYPE_INTEGER:
  18.324 +		g_string_append_printf(str,"%lld",arg->u.integer);
  18.325 +		break;
  18.326 +	    case XEXPR_TYPE_NUMBER:
  18.327 +		g_string_append_printf(str,"%lg",arg->u.number);
  18.328 +		break;
  18.329 +	}
  18.330 +	args=args->next;
  18.331 +    }
  18.332 +    return xexpr_new_string_take_ownership(g_string_free(str,FALSE));
  18.333 +}
  18.334 +
  18.335 +static XexprConstant *xexpr_do_integer(Xexpr *xexpr,GSList *bindings,
  18.336 +  GSList *args,GError **err)
  18.337 +{
  18.338 +    XexprConstant *arg;
  18.339 +    double d;
  18.340 +    long long int value=0;
  18.341 +    while(args)
  18.342 +    {
  18.343 +	arg=args->data;
  18.344 +	switch(arg->type)
  18.345 +	{
  18.346 +	    case XEXPR_TYPE_FUNCTION:
  18.347 +		g_warn_if_reached();
  18.348 +		break;
  18.349 +	    case XEXPR_TYPE_INVOCATION:
  18.350 +		g_warn_if_reached();
  18.351 +		break;
  18.352 +	    case XEXPR_TYPE_STRING:
  18.353 +		value=g_ascii_strtoll(arg->u.string,NULL,0);
  18.354 +		if (value==LLONG_MIN || value==LLONG_MAX)
  18.355 +		{
  18.356 +		    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.357 +		      "Integer overflow on %s",arg->u.string);
  18.358 +		    return NULL;
  18.359 +		}
  18.360 +		break;
  18.361 +	    case XEXPR_TYPE_INTEGER:
  18.362 +		value=arg->u.integer;
  18.363 +		break;
  18.364 +	    case XEXPR_TYPE_NUMBER:
  18.365 +		if (!isfinite(arg->u.number))
  18.366 +		{
  18.367 +		    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.368 +		      "%lg is not finite",arg->u.number);
  18.369 +		    return NULL;
  18.370 +		}
  18.371 +		d=nearbyint(arg->u.number);
  18.372 +		if (d<=LLONG_MIN || d>=LLONG_MAX)
  18.373 +		{
  18.374 +		    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.375 +		      "Integer overflow on %lg",arg->u.number);
  18.376 +		    return NULL;
  18.377 +		}
  18.378 +		value=(long long int)d;
  18.379 +		break;
  18.380 +	}
  18.381 +	args=args->next;
  18.382 +    }
  18.383 +    return xexpr_new_integer(value);
  18.384 +}
  18.385 +
  18.386 +static XexprConstant *xexpr_do_float(Xexpr *xexpr,GSList *bindings,
  18.387 +  GSList *args,GError **err)
  18.388 +{
  18.389 +    XexprConstant *arg;
  18.390 +    double value=0.0/0.0;
  18.391 +    while(args)
  18.392 +    {
  18.393 +	arg=args->data;
  18.394 +	switch(arg->type)
  18.395 +	{
  18.396 +	    case XEXPR_TYPE_FUNCTION:
  18.397 +		g_warn_if_reached();
  18.398 +		break;
  18.399 +	    case XEXPR_TYPE_INVOCATION:
  18.400 +		g_warn_if_reached();
  18.401 +		break;
  18.402 +	    case XEXPR_TYPE_STRING:
  18.403 +		value=g_ascii_strtod(arg->u.string,NULL);
  18.404 +		if (value==HUGE_VAL || value==-HUGE_VAL)
  18.405 +		{
  18.406 +		    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.407 +		      "Numeric overflow on %s",arg->u.string);
  18.408 +		    return NULL;
  18.409 +		}
  18.410 +		break;
  18.411 +	    case XEXPR_TYPE_INTEGER:
  18.412 +		if (arg->u.integer<-DBL_MAX || arg->u.integer>DBL_MAX)
  18.413 +		{
  18.414 +		    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.415 +		      "Numeric overflow on %lld",arg->u.integer);
  18.416 +		    return NULL;
  18.417 +		}
  18.418 +		value=(double)arg->u.integer;
  18.419 +		break;
  18.420 +	    case XEXPR_TYPE_NUMBER:
  18.421 +		value=arg->u.number;
  18.422 +		break;
  18.423 +	}
  18.424 +	args=args->next;
  18.425 +    }
  18.426 +    return xexpr_new_number(value);
  18.427 +}
  18.428 +
  18.429 +static XexprConstant *xexpr_do_true(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.430 +  GError **err)
  18.431 +{
  18.432 +    return xexpr_new_invocation(NULL,"true",NULL,NULL);
  18.433 +}
  18.434 +
  18.435 +static XexprConstant *xexpr_do_false(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.436 +  GError **err)
  18.437 +{
  18.438 +    return xexpr_new_invocation(NULL,"false",NULL,NULL);
  18.439 +}
  18.440 +
  18.441 +static XexprConstant *xexpr_do_nil(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.442 +  GError **err)
  18.443 +{
  18.444 +    return xexpr_new_invocation(NULL,"nil",NULL,NULL);
  18.445 +}
  18.446 +
  18.447 +typedef struct xexpr_accumulator {
  18.448 +    gboolean first;
  18.449 +    Xexpr *xexpr;
  18.450 +    GSList *args;
  18.451 +    const char *result_binding;
  18.452 +    XexprConstant *arg,*result;
  18.453 +} XexprAccumulator;
  18.454 +
  18.455 +static gboolean xexpr_accumulator_init(XexprAccumulator *accumulator,
  18.456 +  Xexpr *xexpr,GSList *args,gboolean bind_result,GError **err)
  18.457 +{
  18.458 +    XexprConstant *arg;
  18.459 +    accumulator->xexpr=xexpr;
  18.460 +    accumulator->args=args;
  18.461 +    accumulator->arg=NULL;
  18.462 +    accumulator->first=TRUE;
  18.463 +    if (!accumulator->args)
  18.464 +    {
  18.465 +	accumulator->result_binding=NULL;
  18.466 +	accumulator->result=xexpr_new_invocation(NULL,"nil",NULL,NULL);
  18.467 +	return TRUE;
  18.468 +    }
  18.469 +    arg=accumulator->args->data;
  18.470 +    /*
  18.471 +     * If arg invokes a function with no bindings and no arguments
  18.472 +     * then the result is accumulated in the function itself.
  18.473 +     * This allows constructs such as:
  18.474 +     *	<subtract><x/>1</subtract>
  18.475 +     * as a shorthand for:
  18.476 +     *	<set name="x"><subtract><get><x/></get>1</subtract></set>
  18.477 +     * This is implied by http://www.w3.org/TR/xexpr/#id-0045
  18.478 +     *
  18.479 +     * Note that since the value accumulates:
  18.480 +     *	<add x="1"><x/><x/><x/></add>
  18.481 +     * results in 4 rather than 3.
  18.482 +     */
  18.483 +    if (bind_result && arg->type==XEXPR_TYPE_INVOCATION &&
  18.484 +      !arg->u.invocation->bindings && !arg->u.invocation->constants)
  18.485 +	accumulator->result_binding=arg->u.invocation->function;
  18.486 +    else
  18.487 +	accumulator->result_binding=NULL;
  18.488 +    accumulator->result=xexpr_constant_evaluate(xexpr,arg,err);
  18.489 +    while(accumulator->result && accumulator->result->type==XEXPR_TYPE_FUNCTION)
  18.490 +    {
  18.491 +	arg=xexpr_constant_evaluate(xexpr,accumulator->result,err);
  18.492 +	xexpr_constant_free(accumulator->result);
  18.493 +	accumulator->result=arg;
  18.494 +    }
  18.495 +    return !!accumulator->result;
  18.496 +}
  18.497 +
  18.498 +static gboolean xexpr_accumulator_next(XexprAccumulator *accumulator)
  18.499 +{
  18.500 +    if (accumulator->result_binding && !accumulator->first)
  18.501 +    {
  18.502 +	xexpr_var_set(accumulator->xexpr,accumulator->result_binding,
  18.503 +	  accumulator->result);
  18.504 +	if (xexpr_is_tracing(accumulator->xexpr,accumulator->result_binding))
  18.505 +	{
  18.506 +	    printf("\nChanged variable %s\n",accumulator->result_binding);
  18.507 +	    xexpr_stack_dump(accumulator->xexpr,stdout);
  18.508 +	}
  18.509 +    }
  18.510 +    accumulator->args=accumulator->args->next;
  18.511 +    accumulator->first=FALSE;
  18.512 +    return !!accumulator->args;
  18.513 +}
  18.514 +
  18.515 +static XexprConstant *xexpr_accumulator_get(XexprAccumulator *accumulator,
  18.516 +  GError **err)
  18.517 +{
  18.518 +    if (accumulator->arg)
  18.519 +	xexpr_constant_free(accumulator->arg);
  18.520 +    accumulator->arg=xexpr_constant_evaluate(accumulator->xexpr,
  18.521 +      accumulator->args->data,err);
  18.522 +    return accumulator->arg;
  18.523 +}
  18.524 +
  18.525 +static XexprConstant *xexpr_accumulator_finish(XexprAccumulator *accumulator)
  18.526 +{
  18.527 +    if (accumulator->arg)
  18.528 +	xexpr_constant_free(accumulator->arg);
  18.529 +    return accumulator->result;
  18.530 +}
  18.531 +
  18.532 +static void xexpr_accumulator_abort(XexprAccumulator *accumulator)
  18.533 +{
  18.534 +    xexpr_constant_free(xexpr_accumulator_finish(accumulator));
  18.535 +}
  18.536 +
  18.537 +static XexprConstant *xexpr_do_add(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.538 +  GError **err)
  18.539 +{
  18.540 +    XexprConstant *arg;
  18.541 +    gchar *str;
  18.542 +    XexprAccumulator accumulator;
  18.543 +    if (!xexpr_accumulator_init(&accumulator,xexpr,args,TRUE,err))
  18.544 +	return NULL;
  18.545 +    while(xexpr_accumulator_next(&accumulator))
  18.546 +    {
  18.547 +	arg=xexpr_accumulator_get(&accumulator,err);
  18.548 +	if (!arg)
  18.549 +	{
  18.550 +	    xexpr_accumulator_abort(&accumulator);
  18.551 +	    return NULL;
  18.552 +	}
  18.553 +	switch(accumulator.result->type)
  18.554 +	{
  18.555 +	    case XEXPR_TYPE_INVOCATION:
  18.556 +	    case XEXPR_TYPE_FUNCTION:
  18.557 +		g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.558 +		  "Attempt to perform arithmetic op on a function");
  18.559 +		xexpr_accumulator_abort(&accumulator);
  18.560 +		return NULL;
  18.561 +		break;
  18.562 +	    case XEXPR_TYPE_STRING:
  18.563 +		switch(arg->type)
  18.564 +		{
  18.565 +		    case XEXPR_TYPE_FUNCTION:
  18.566 +		    case XEXPR_TYPE_INVOCATION:
  18.567 +			g_set_error(err,XEXPR_EVAL_ERROR,
  18.568 +			  XEXPR_EVAL_ERROR_FAILED,
  18.569 +			  "Attempt to perform arithmetic op on a function");
  18.570 +			xexpr_accumulator_abort(&accumulator);
  18.571 +			return NULL;
  18.572 +		    case XEXPR_TYPE_STRING:
  18.573 +			str=g_strconcat(accumulator.result->u.string,
  18.574 +			  arg->u.string,NULL);
  18.575 +			g_free(accumulator.result->u.string);
  18.576 +			accumulator.result->u.string=str;
  18.577 +			break;
  18.578 +		    case XEXPR_TYPE_INTEGER:
  18.579 +			str=g_strdup_printf("%s%lld",
  18.580 +			  accumulator.result->u.string,arg->u.integer);
  18.581 +			g_free(accumulator.result->u.string);
  18.582 +			accumulator.result->u.string=str;
  18.583 +			break;
  18.584 +		    case XEXPR_TYPE_NUMBER:
  18.585 +			str=g_strdup_printf("%s%lg",
  18.586 +			  accumulator.result->u.string,arg->u.number);
  18.587 +			g_free(accumulator.result->u.string);
  18.588 +			accumulator.result->u.string=str;
  18.589 +			break;
  18.590 +		}
  18.591 +		break;
  18.592 +	    case XEXPR_TYPE_INTEGER:
  18.593 +		if (arg->type==XEXPR_TYPE_INTEGER)
  18.594 +		{
  18.595 +		    accumulator.result->u.integer+=arg->u.integer;
  18.596 +		    break;
  18.597 +		}
  18.598 +		else if (arg->type==XEXPR_TYPE_NUMBER)
  18.599 +		{
  18.600 +		    accumulator.result->type=XEXPR_TYPE_NUMBER;
  18.601 +		    accumulator.result->u.number=accumulator.result->u.integer;
  18.602 +		}
  18.603 +		/* Fall through */
  18.604 +	    case XEXPR_TYPE_NUMBER:
  18.605 +		if (arg->type==XEXPR_TYPE_INTEGER)
  18.606 +		    accumulator.result->u.number+=arg->u.integer;
  18.607 +		else if (arg->type==XEXPR_TYPE_NUMBER)
  18.608 +		    accumulator.result->u.number+=arg->u.number;
  18.609 +		else
  18.610 +		{
  18.611 +		    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.612 +		      "Attempt to add non-numeric to numeric quantity");
  18.613 +		    xexpr_accumulator_abort(&accumulator);
  18.614 +		    return NULL;
  18.615 +		}
  18.616 +		break;
  18.617 +	}
  18.618 +    }
  18.619 +    return xexpr_accumulator_finish(&accumulator);
  18.620 +}
  18.621 +
  18.622 +static XexprConstant *xexpr_do_subtract(Xexpr *xexpr,GSList *bindings,
  18.623 +  GSList *args,GError **err)
  18.624 +{
  18.625 +    XexprConstant *arg;
  18.626 +    XexprAccumulator accumulator;
  18.627 +    if (!xexpr_accumulator_init(&accumulator,xexpr,args,TRUE,err))
  18.628 +	return NULL;
  18.629 +    while(xexpr_accumulator_next(&accumulator))
  18.630 +    {
  18.631 +	arg=xexpr_accumulator_get(&accumulator,err);
  18.632 +	if (!arg)
  18.633 +	{
  18.634 +	    xexpr_accumulator_abort(&accumulator);
  18.635 +	    return NULL;
  18.636 +	}
  18.637 +	if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER)
  18.638 +	{
  18.639 +invalid_args:
  18.640 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.641 +	      "Attempt to perform subtraction on a non-numeric quantity");
  18.642 +	    xexpr_accumulator_abort(&accumulator);
  18.643 +	    return NULL;
  18.644 +	}
  18.645 +	switch(accumulator.result->type)
  18.646 +	{
  18.647 +	    case XEXPR_TYPE_INTEGER:
  18.648 +		if (arg->type==XEXPR_TYPE_INTEGER)
  18.649 +		{
  18.650 +		    accumulator.result->u.integer-=arg->u.integer;
  18.651 +		    break;
  18.652 +		}
  18.653 +		else
  18.654 +		{
  18.655 +		    accumulator.result->type=XEXPR_TYPE_NUMBER;
  18.656 +		    accumulator.result->u.number=accumulator.result->u.integer;
  18.657 +		}
  18.658 +		/* Fall through */
  18.659 +	    case XEXPR_TYPE_NUMBER:
  18.660 +		if (accumulator.arg->type==XEXPR_TYPE_INTEGER)
  18.661 +		    accumulator.result->u.number-=arg->u.integer;
  18.662 +		else
  18.663 +		    accumulator.result->u.number-=arg->u.number;
  18.664 +		break;
  18.665 +	    default:
  18.666 +		goto invalid_args;
  18.667 +	}
  18.668 +    }
  18.669 +    return xexpr_accumulator_finish(&accumulator);
  18.670 +}
  18.671 +
  18.672 +static XexprConstant *xexpr_do_multiply(Xexpr *xexpr,GSList *bindings,
  18.673 +  GSList *args,GError **err)
  18.674 +{
  18.675 +    XexprConstant *arg;
  18.676 +    XexprAccumulator accumulator;
  18.677 +    if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
  18.678 +	return NULL;
  18.679 +    while(xexpr_accumulator_next(&accumulator))
  18.680 +    {
  18.681 +	arg=xexpr_accumulator_get(&accumulator,err);
  18.682 +	if (!arg)
  18.683 +	{
  18.684 +	    xexpr_accumulator_abort(&accumulator);
  18.685 +	    return NULL;
  18.686 +	}
  18.687 +	if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER)
  18.688 +	{
  18.689 +	    GString *str=g_string_new(NULL);
  18.690 +invalid_args:
  18.691 +	    xexpr_constant_dump_string(arg,str);
  18.692 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.693 +	      "Attempt to perform multiply on a non-numeric quantity: %s",
  18.694 +	      str->str);
  18.695 +	    g_string_free(str,TRUE);
  18.696 +	    xexpr_accumulator_abort(&accumulator);
  18.697 +	    return NULL;
  18.698 +	}
  18.699 +	switch(accumulator.result->type)
  18.700 +	{
  18.701 +	    case XEXPR_TYPE_INTEGER:
  18.702 +		if (arg->type==XEXPR_TYPE_INTEGER)
  18.703 +		{
  18.704 +		    accumulator.result->u.integer*=arg->u.integer;
  18.705 +		    break;
  18.706 +		}
  18.707 +		else
  18.708 +		{
  18.709 +		    accumulator.result->type=XEXPR_TYPE_NUMBER;
  18.710 +		    accumulator.result->u.number=accumulator.result->u.integer;
  18.711 +		}
  18.712 +		/* Fall through */
  18.713 +	    case XEXPR_TYPE_NUMBER:
  18.714 +		if (arg->type==XEXPR_TYPE_INTEGER)
  18.715 +		    accumulator.result->u.number*=arg->u.integer;
  18.716 +		else
  18.717 +		    accumulator.result->u.number*=arg->u.number;
  18.718 +		break;
  18.719 +	    default:
  18.720 +		goto invalid_args;
  18.721 +	}
  18.722 +    }
  18.723 +    return xexpr_accumulator_finish(&accumulator);
  18.724 +}
  18.725 +
  18.726 +static XexprConstant *xexpr_do_divide(Xexpr *xexpr,GSList *bindings,
  18.727 +  GSList *args,GError **err)
  18.728 +{
  18.729 +    XexprConstant *arg;
  18.730 +    long long int r;
  18.731 +    XexprAccumulator accumulator;
  18.732 +    if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
  18.733 +	return NULL;
  18.734 +    while(xexpr_accumulator_next(&accumulator))
  18.735 +    {
  18.736 +	arg=xexpr_accumulator_get(&accumulator,err);
  18.737 +	if (!arg)
  18.738 +	{
  18.739 +	    xexpr_accumulator_abort(&accumulator);
  18.740 +	    return NULL;
  18.741 +	}
  18.742 +	if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER)
  18.743 +	{
  18.744 +invalid_args:
  18.745 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
  18.746 +	      "Attempt to perform divide on a non-numeric quantity");
  18.747 +	    xexpr_accumulator_abort(&accumulator);
  18.748 +	    return NULL;
  18.749 +	}
  18.750 +	switch(accumulator.result->type)
  18.751 +	{
  18.752 +	    case XEXPR_TYPE_INTEGER:
  18.753 +		if (arg->type==XEXPR_TYPE_INTEGER)
  18.754 +		{
  18.755 +		    r=accumulator.result->u.integer/arg->u.integer;
  18.756 +		    if (r*arg->u.integer==accumulator.result->u.integer)
  18.757 +		    {
  18.758 +			accumulator.result->u.integer=r;
  18.759 +			break;
  18.760 +		    }
  18.761 +		}
  18.762 +		accumulator.result->type=XEXPR_TYPE_NUMBER;
  18.763 +		accumulator.result->u.number=accumulator.result->u.integer;
  18.764 +		/* Fall through */
  18.765 +	    case XEXPR_TYPE_NUMBER:
  18.766 +		if (arg->type==XEXPR_TYPE_INTEGER)
  18.767 +		    accumulator.result->u.number/=arg->u.integer;
  18.768 +		else
  18.769 +		    accumulator.result->u.number/=arg->u.number;
  18.770 +		break;
  18.771 +	    default:
  18.772 +		goto invalid_args;
  18.773 +	}
  18.774 +    }
  18.775 +    return xexpr_accumulator_finish(&accumulator);
  18.776 +}
  18.777 +
  18.778 +/**
  18.779 + * xexpr_constant_cast:
  18.780 + * @constant: an #XexprConstant to cast
  18.781 + * @to: type to cast @constant to
  18.782 + *
  18.783 + * Attempt to perform an implicit cast of @constant to the given type @to.
  18.784 + * Implicit casting can only be performed between the two numeric types
  18.785 + * and then only where the quantity can be represented without loss of
  18.786 + * precision.
  18.787 + *
  18.788 + * Return value: %TRUE if @constant is now of type @to.
  18.789 + */
  18.790 +gboolean xexpr_constant_cast(XexprConstant *constant,XexprType to)
  18.791 +{
  18.792 +    double dummy;
  18.793 +    if (constant->type==to)
  18.794 +	return TRUE;
  18.795 +    if (constant->type==XEXPR_TYPE_NUMBER && to==XEXPR_TYPE_INTEGER &&
  18.796 +      constant->u.number>=LLONG_MIN && constant->u.number<=LLONG_MAX &&
  18.797 +      !modf(constant->u.number,&dummy))
  18.798 +    {
  18.799 +	constant->type=XEXPR_TYPE_INTEGER;
  18.800 +	constant->u.integer=constant->u.number;
  18.801 +	return TRUE;
  18.802 +    }
  18.803 +    else if (constant->type==XEXPR_TYPE_INTEGER && to==XEXPR_TYPE_NUMBER &&
  18.804 +      constant->u.integer+1.0!=(double)constant->u.integer &&
  18.805 +      constant->u.integer-1.0!=(double)constant->u.integer)
  18.806 +    {
  18.807 +	constant->type=XEXPR_TYPE_NUMBER;
  18.808 +	constant->u.number=constant->u.integer;
  18.809 +	return TRUE;
  18.810 +    }
  18.811 +    else
  18.812 +	return FALSE;
  18.813 +}
  18.814 +
  18.815 +static gboolean xexpr_constant_boolean(Xexpr *xexpr,XexprConstant *constant,
  18.816 +  GError **err)
  18.817 +{
  18.818 +    gboolean retval;
  18.819 +    XexprConstant *result;
  18.820 +    switch (constant->type)
  18.821 +    {
  18.822 +	case XEXPR_TYPE_NUMBER:
  18.823 +	    return !(constant->u.number==0);
  18.824 +	case XEXPR_TYPE_INTEGER:
  18.825 +	    return !!constant->u.integer;
  18.826 +	case XEXPR_TYPE_STRING:
  18.827 +	    return !!*constant->u.string;
  18.828 +	case XEXPR_TYPE_INVOCATION:
  18.829 +	    return strcmp(constant->u.invocation->function,"false") &&
  18.830 +	      strcmp(constant->u.invocation->function,"nil");
  18.831 +	case XEXPR_TYPE_FUNCTION:
  18.832 +	    /*
  18.833 +	     * See http://www.w3.org/TR/xexpr/#id-0038
  18.834 +	     */
  18.835 +	    result=xexpr_constant_evaluate(xexpr,constant,err);
  18.836 +	    if (!result)
  18.837 +		return FALSE;
  18.838 +	    retval=xexpr_constant_boolean(xexpr,result,err);
  18.839 +	    xexpr_constant_free(result);
  18.840 +	    return retval;
  18.841 +    }
  18.842 +    return FALSE;
  18.843 +}
  18.844 +
  18.845 +/*
  18.846 + * Returns: 0 if equal, <0 if value1 < value2, >0 if value1 > value2,
  18.847 + *          NaN if value1 is not comparible with value2.
  18.848 + */
  18.849 +static double xexpr_constant_compare(Xexpr *xexpr,XexprConstant *v1,
  18.850 +  XexprConstant *v2)
  18.851 +{
  18.852 +    double retval=0.0/0.0;
  18.853 +    XexprConstant *value1,*value2;
  18.854 +    value1=xexpr_constant_evaluate(xexpr,v1,NULL);
  18.855 +    if (!value1)
  18.856 +	value1=xexpr_constant_dup(v1);
  18.857 +    while(value1->type==XEXPR_TYPE_FUNCTION)
  18.858 +    {
  18.859 +	v1=xexpr_constant_evaluate(xexpr,value1,NULL);
  18.860 +	if (v1)
  18.861 +	{
  18.862 +	    xexpr_constant_free(value1);
  18.863 +	    value1=v1;
  18.864 +	}
  18.865 +	else
  18.866 +	    break;
  18.867 +    }
  18.868 +    value2=xexpr_constant_evaluate(xexpr,v2,NULL);
  18.869 +    if (!value2)
  18.870 +	value2=xexpr_constant_dup(v2);
  18.871 +    while(value2->type==XEXPR_TYPE_FUNCTION)
  18.872 +    {
  18.873 +	v2=xexpr_constant_evaluate(xexpr,value2,NULL);
  18.874 +	if (v2)
  18.875 +	{
  18.876 +	    xexpr_constant_free(value2);
  18.877 +	    value2=v2;
  18.878 +	}
  18.879 +	else
  18.880 +	    break;
  18.881 +    }
  18.882 +    if (value1->type!=value2->type)
  18.883 +    {
  18.884 +	if (!xexpr_constant_cast(value1,value2->type) &&
  18.885 +	  !xexpr_constant_cast(value2,value1->type))
  18.886 +	{
  18.887 +	    xexpr_constant_free(value1);
  18.888 +	    xexpr_constant_free(value2);
  18.889 +	    return 0.0/0.0;
  18.890 +	}
  18.891 +    }
  18.892 +    switch(value1->type)
  18.893 +    {
  18.894 +	case XEXPR_TYPE_FUNCTION:
  18.895 +	    g_warn_if_reached();
  18.896 +	    break;
  18.897 +	case XEXPR_TYPE_INVOCATION:
  18.898 +	    g_warn_if_fail(value1->u.invocation->bindings==NULL);
  18.899 +	    g_warn_if_fail(value2->u.invocation->bindings==NULL);
  18.900 +	    g_warn_if_fail(value1->u.invocation->constants==NULL);
  18.901 +	    g_warn_if_fail(value2->u.invocation->constants==NULL);
  18.902 +	    retval=strcmp(value1->u.invocation->function,
  18.903 +	      value2->u.invocation->function);
  18.904 +	    break;
  18.905 +	case XEXPR_TYPE_STRING:
  18.906 +	    retval=strcmp(value1->u.string,value2->u.string);
  18.907 +	    break;
  18.908 +	case XEXPR_TYPE_INTEGER:
  18.909 +	    retval=value1->u.integer-value2->u.integer;
  18.910 +	    break;
  18.911 +	case XEXPR_TYPE_NUMBER:
  18.912 +	    retval=value1->u.number-value2->u.number;
  18.913 +	    break;
  18.914 +    }
  18.915 +    xexpr_constant_free(value1);
  18.916 +    xexpr_constant_free(value2);
  18.917 +    return retval;
  18.918 +}
  18.919 +
  18.920 +static XexprConstant *xexpr_do_eq(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.921 +  GError **err)
  18.922 +{
  18.923 +    XexprConstant *arg,*standard=NULL;
  18.924 +    while(args)
  18.925 +    {
  18.926 +	arg=args->data;
  18.927 +	if (!standard)
  18.928 +	    standard=arg;
  18.929 +	else if (xexpr_constant_compare(xexpr,standard,arg))
  18.930 +	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
  18.931 +	args=args->next;
  18.932 +    }
  18.933 +    return xexpr_new_invocation(NULL,"true",NULL,NULL);
  18.934 +}
  18.935 +
  18.936 +static XexprConstant *xexpr_do_neq(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.937 +  GError **err)
  18.938 +{
  18.939 +    XexprConstant *arg;
  18.940 +    GSList *lnk;
  18.941 +    while(args)
  18.942 +    {
  18.943 +	arg=args->data;
  18.944 +	for(lnk=args->next;lnk;lnk=lnk->next)
  18.945 +	    if (!xexpr_constant_compare(xexpr,arg,lnk->data))
  18.946 +		return xexpr_new_invocation(NULL,"false",NULL,NULL);
  18.947 +	args=args->next;
  18.948 +    }
  18.949 +    return xexpr_new_invocation(NULL,"true",NULL,NULL);
  18.950 +}
  18.951 +
  18.952 +static XexprConstant *xexpr_do_leq(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.953 +  GError **err)
  18.954 +{
  18.955 +    XexprConstant *arg,*standard=NULL;
  18.956 +    while(args)
  18.957 +    {
  18.958 +	arg=args->data;
  18.959 +	if (standard && !(xexpr_constant_compare(xexpr,standard,arg)<=0))
  18.960 +	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
  18.961 +	standard=arg;
  18.962 +	args=args->next;
  18.963 +    }
  18.964 +    return xexpr_new_invocation(NULL,"true",NULL,NULL);
  18.965 +}
  18.966 +
  18.967 +static XexprConstant *xexpr_do_geq(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.968 +  GError **err)
  18.969 +{
  18.970 +    XexprConstant *arg,*standard=NULL;
  18.971 +    while(args)
  18.972 +    {
  18.973 +	arg=args->data;
  18.974 +	if (standard && !(xexpr_constant_compare(xexpr,standard,arg)>=0))
  18.975 +	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
  18.976 +	standard=arg;
  18.977 +	args=args->next;
  18.978 +    }
  18.979 +    return xexpr_new_invocation(NULL,"true",NULL,NULL);
  18.980 +}
  18.981 +
  18.982 +static XexprConstant *xexpr_do_lt(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.983 +  GError **err)
  18.984 +{
  18.985 +    XexprConstant *arg,*standard=NULL;
  18.986 +    while(args)
  18.987 +    {
  18.988 +	arg=args->data;
  18.989 +	if (standard && !(xexpr_constant_compare(xexpr,standard,arg)<0))
  18.990 +	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
  18.991 +	standard=arg;
  18.992 +	args=args->next;
  18.993 +    }
  18.994 +    return xexpr_new_invocation(NULL,"true",NULL,NULL);
  18.995 +}
  18.996 +
  18.997 +static XexprConstant *xexpr_do_gt(Xexpr *xexpr,GSList *bindings,GSList *args,
  18.998 +  GError **err)
  18.999 +{
 18.1000 +    XexprConstant *arg,*standard=NULL;
 18.1001 +    while(args)
 18.1002 +    {
 18.1003 +	arg=args->data;
 18.1004 +	if (standard && !(xexpr_constant_compare(xexpr,standard,arg)>0))
 18.1005 +	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
 18.1006 +	standard=arg;
 18.1007 +	args=args->next;
 18.1008 +    }
 18.1009 +    return xexpr_new_invocation(NULL,"true",NULL,NULL);
 18.1010 +}
 18.1011 +
 18.1012 +static XexprConstant *xexpr_do_and(Xexpr *xexpr,GSList *bindings,GSList *args,
 18.1013 +  GError **err)
 18.1014 +{
 18.1015 +    GError *tmp_err=NULL;
 18.1016 +    XexprConstant *arg;
 18.1017 +    XexprAccumulator accumulator;
 18.1018 +    if (!args)
 18.1019 +	return xexpr_new_invocation(NULL,"true",NULL,NULL);
 18.1020 +    if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
 18.1021 +	return NULL;
 18.1022 +    if (!xexpr_constant_boolean(xexpr,accumulator.result,&tmp_err))
 18.1023 +    {
 18.1024 +	xexpr_accumulator_abort(&accumulator);
 18.1025 +	if (tmp_err)
 18.1026 +	{
 18.1027 +	    g_propagate_error(err,tmp_err);
 18.1028 +	    return NULL;
 18.1029 +	}
 18.1030 +	else
 18.1031 +	    return xexpr_new_invocation(NULL,"false",NULL,NULL);
 18.1032 +    }
 18.1033 +    while(xexpr_accumulator_next(&accumulator))
 18.1034 +    {
 18.1035 +	arg=xexpr_accumulator_get(&accumulator,err);
 18.1036 +	if (!arg)
 18.1037 +	{
 18.1038 +	    xexpr_accumulator_abort(&accumulator);
 18.1039 +	    return NULL;
 18.1040 +	}
 18.1041 +	if (!xexpr_constant_boolean(xexpr,arg,&tmp_err))
 18.1042 +	{
 18.1043 +	    xexpr_accumulator_abort(&accumulator);
 18.1044 +	    if (tmp_err)
 18.1045 +	    {
 18.1046 +		g_propagate_error(err,tmp_err);
 18.1047 +		return NULL;
 18.1048 +	    }
 18.1049 +	    else
 18.1050 +		return xexpr_new_invocation(NULL,"false",NULL,NULL);
 18.1051 +	}
 18.1052 +    }
 18.1053 +    xexpr_accumulator_abort(&accumulator);
 18.1054 +    return xexpr_new_invocation(NULL,"true",NULL,NULL);
 18.1055 +}
 18.1056 +
 18.1057 +static XexprConstant *xexpr_do_or(Xexpr *xexpr,GSList *bindings,GSList *args,
 18.1058 +  GError **err)
 18.1059 +{
 18.1060 +    GError *tmp_err=NULL;
 18.1061 +    XexprConstant *arg;
 18.1062 +    XexprAccumulator accumulator;
 18.1063 +    if (!args)
 18.1064 +	return xexpr_new_invocation(NULL,"true",NULL,NULL);
 18.1065 +    if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err))
 18.1066 +	return NULL;
 18.1067 +    if (xexpr_constant_boolean(xexpr,accumulator.result,&tmp_err))
 18.1068 +    {
 18.1069 +	xexpr_accumulator_abort(&accumulator);
 18.1070 +	return xexpr_new_invocation(NULL,"true",NULL,NULL);
 18.1071 +    }
 18.1072 +    else if (tmp_err)
 18.1073 +    {
 18.1074 +	xexpr_accumulator_abort(&accumulator);
 18.1075 +	g_propagate_error(err,tmp_err);
 18.1076 +	return NULL;
 18.1077 +    }
 18.1078 +    while(xexpr_accumulator_next(&accumulator))
 18.1079 +    {
 18.1080 +	arg=xexpr_accumulator_get(&accumulator,err);
 18.1081 +	if (!arg)
 18.1082 +	{
 18.1083 +	    xexpr_accumulator_abort(&accumulator);
 18.1084 +	    return NULL;
 18.1085 +	}
 18.1086 +	if (xexpr_constant_boolean(xexpr,arg,&tmp_err))
 18.1087 +	{
 18.1088 +	    xexpr_accumulator_abort(&accumulator);
 18.1089 +	    return xexpr_new_invocation(NULL,"true",NULL,NULL);
 18.1090 +	}
 18.1091 +	else if (tmp_err)
 18.1092 +	{
 18.1093 +	    xexpr_accumulator_abort(&accumulator);
 18.1094 +	    g_propagate_error(err,tmp_err);
 18.1095 +	    return NULL;
 18.1096 +	}
 18.1097 +    }
 18.1098 +    xexpr_accumulator_abort(&accumulator);
 18.1099 +    return xexpr_new_invocation(NULL,"false",NULL,NULL);
 18.1100 +}
 18.1101 +
 18.1102 +/*
 18.1103 + * <not> is a misnomer, http://www.w3.org/TR/xexpr/#id-0040
 18.1104 + * makes it clear that, except in the trivial case of no arguments,
 18.1105 + * <not> is simply the negation of <and>.
 18.1106 + */
 18.1107 +static XexprConstant *xexpr_do_not(Xexpr *xexpr,GSList *bindings,GSList *args,
 18.1108 +  GError **err)
 18.1109 +{
 18.1110 +    gboolean test;
 18.1111 +    XexprConstant *result;
 18.1112 +    if (!args)
 18.1113 +	return xexpr_new_invocation(NULL,"true",NULL,NULL);
 18.1114 +    result=xexpr_do_and(xexpr,bindings,args,err);
 18.1115 +    if (!result)
 18.1116 +	return NULL;
 18.1117 +    test=xexpr_constant_boolean(xexpr,result,NULL);
 18.1118 +    xexpr_constant_free(result);
 18.1119 +    return xexpr_new_invocation(NULL,test?"false":"true",NULL,NULL);
 18.1120 +}
 18.1121 +
 18.1122 +static XexprConstant *xexpr_do_if(Xexpr *xexpr,GSList *bindings,GSList *args,
 18.1123 +  GError **err)
 18.1124 +{
 18.1125 +    GError *tmp_err=NULL;
 18.1126 +    gboolean test;
 18.1127 +    XexprConstant *arg;
 18.1128 +    if (g_slist_length(args)<2)
 18.1129 +    {
 18.1130 +	g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
 18.1131 +	  "<if> requires at least 2 arguments to be passed");
 18.1132 +	return NULL;
 18.1133 +    }
 18.1134 +    arg=xexpr_constant_evaluate(xexpr,args->data,err);
 18.1135 +    if (!arg)
 18.1136 +	return NULL;
 18.1137 +    test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
 18.1138 +    if (tmp_err)
 18.1139 +    {
 18.1140 +	g_propagate_error(err,tmp_err);
 18.1141 +	return NULL;
 18.1142 +    }
 18.1143 +    xexpr_constant_free(arg);
 18.1144 +    if (test)
 18.1145 +	return xexpr_constant_evaluate(xexpr,args->next->data,err);
 18.1146 +    else if (args->next->next)
 18.1147 +	return xexpr_constant_evaluate(xexpr,args->next->next->data,err);
 18.1148 +    else
 18.1149 +	return xexpr_new_invocation(NULL,"nil",NULL,NULL);
 18.1150 +}
 18.1151 +
 18.1152 +static XexprConstant *xexpr_do_switch(Xexpr *xexpr,GSList *bindings,
 18.1153 +  GSList *args,GError **err)
 18.1154 +{
 18.1155 +    GError *tmp_err=NULL;
 18.1156 +    gboolean test;
 18.1157 +    XexprConstant *case_arg,*arg;
 18.1158 +    GSList *lnk;
 18.1159 +    while(args)
 18.1160 +    {
 18.1161 +	case_arg=args->data;
 18.1162 +	if (case_arg->type!=XEXPR_TYPE_INVOCATION ||
 18.1163 +	  strcmp(case_arg->u.invocation->function,"case"))
 18.1164 +	{
 18.1165 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
 18.1166 +	      "<switch> requires a list of <case> expressions");
 18.1167 +	    return NULL;
 18.1168 +	}
 18.1169 +	lnk=case_arg->u.invocation->constants;
 18.1170 +	if (!lnk)
 18.1171 +	{
 18.1172 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
 18.1173 +	      "<case> requires a test expression");
 18.1174 +	    return NULL;
 18.1175 +	}
 18.1176 +	arg=xexpr_constant_evaluate(xexpr,lnk->data,err);
 18.1177 +	if (!arg)
 18.1178 +	    return NULL;
 18.1179 +	test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
 18.1180 +	if (tmp_err)
 18.1181 +	{
 18.1182 +	    g_propagate_error(err,tmp_err);
 18.1183 +	    return NULL;
 18.1184 +	}
 18.1185 +	xexpr_constant_free(arg);
 18.1186 +	if (test)
 18.1187 +	{
 18.1188 +	    arg=NULL;
 18.1189 +	    while(lnk)
 18.1190 +	    {
 18.1191 +		if (arg)
 18.1192 +		    xexpr_constant_free(arg);
 18.1193 +		arg=xexpr_constant_evaluate(xexpr,lnk->data,err);
 18.1194 +		if (!arg)
 18.1195 +		    return NULL;
 18.1196 +		lnk=lnk->next;
 18.1197 +	    }
 18.1198 +	    if (!arg)
 18.1199 +	       arg=xexpr_new_invocation(NULL,"nil",NULL,NULL);
 18.1200 +	    return arg;
 18.1201 +	}
 18.1202 +	args=args->next;
 18.1203 +    }
 18.1204 +    return xexpr_new_invocation(NULL,"nil",NULL,NULL);
 18.1205 +}
 18.1206 +
 18.1207 +static XexprConstant *xexpr_do_while(Xexpr *xexpr,GSList *bindings,GSList *args,
 18.1208 +  GError **err)
 18.1209 +{
 18.1210 +    GError *tmp_err=NULL;
 18.1211 +    gboolean test;
 18.1212 +    XexprConstant *arg,*result;
 18.1213 +    if (g_slist_length(args)!=2)
 18.1214 +    {
 18.1215 +	g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
 18.1216 +	  "<while> takes 2 arguments");
 18.1217 +	return NULL;
 18.1218 +    }
 18.1219 +    result=xexpr_new_invocation(NULL,"nil",NULL,NULL);
 18.1220 +    do
 18.1221 +    {
 18.1222 +	arg=xexpr_constant_evaluate(xexpr,args->data,err);
 18.1223 +	if (!arg)
 18.1224 +	{
 18.1225 +	    xexpr_constant_free(result);
 18.1226 +	    return NULL;
 18.1227 +	}
 18.1228 +	test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
 18.1229 +	if (tmp_err)
 18.1230 +	{
 18.1231 +	    g_propagate_error(err,tmp_err);
 18.1232 +	    return NULL;
 18.1233 +	}
 18.1234 +	xexpr_constant_free(arg);
 18.1235 +	if (test)
 18.1236 +	{
 18.1237 +	    xexpr_constant_free(result);
 18.1238 +	    result=xexpr_constant_evaluate(xexpr,args->next->data,err);
 18.1239 +	    if (!result)
 18.1240 +		return NULL;
 18.1241 +	}
 18.1242 +    } while(test);
 18.1243 +    return result;
 18.1244 +}
 18.1245 +
 18.1246 +static XexprConstant *xexpr_do_do(Xexpr *xexpr,GSList *bindings,GSList *args,
 18.1247 +  GError **err)
 18.1248 +{
 18.1249 +    GError *tmp_err=NULL;
 18.1250 +    gboolean test;
 18.1251 +    XexprConstant *arg,*result;
 18.1252 +    if (g_slist_length(args)!=2)
 18.1253 +    {
 18.1254 +	g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
 18.1255 +	  "<do> takes 2 arguments");
 18.1256 +	return NULL;
 18.1257 +    }
 18.1258 +    result=NULL;
 18.1259 +    do
 18.1260 +    {
 18.1261 +	if (result)
 18.1262 +	    xexpr_constant_free(result);
 18.1263 +	result=xexpr_constant_evaluate(xexpr,args->data,err);
 18.1264 +	if (!result)
 18.1265 +	    return NULL;
 18.1266 +	arg=xexpr_constant_evaluate(xexpr,args->next->data,err);
 18.1267 +	if (!arg)
 18.1268 +	{
 18.1269 +	    xexpr_constant_free(result);
 18.1270 +	    return NULL;
 18.1271 +	}
 18.1272 +	test=xexpr_constant_boolean(xexpr,arg,&tmp_err);
 18.1273 +	if (tmp_err)
 18.1274 +	{
 18.1275 +	    g_propagate_error(err,tmp_err);
 18.1276 +	    return NULL;
 18.1277 +	}
 18.1278 +	xexpr_constant_free(arg);
 18.1279 +    } while(test);
 18.1280 +    return result;
 18.1281 +}
 18.1282 +
 18.1283 +static struct xexpr_builtin {
 18.1284 +    char *id;
 18.1285 +    gboolean evaluate_args;
 18.1286 +    XexprConstant *(*func)(Xexpr *xexpr,GSList *bindings,GSList *args,
 18.1287 +      GError **err);
 18.1288 +} xexpr_builtins[]={
 18.1289 +    { "define",		FALSE,	xexpr_do_define },
 18.1290 +    { "print",		TRUE,	xexpr_do_print },
 18.1291 +    { "println",	TRUE,	xexpr_do_println },
 18.1292 +    { "get",		TRUE,	xexpr_do_get },
 18.1293 +    { "set",		TRUE,	xexpr_do_set },
 18.1294 +    { "expr",		TRUE,	xexpr_do_expr },
 18.1295 +    { "xexpr",		TRUE,	xexpr_do_expr },
 18.1296 +    { "return",		TRUE,	xexpr_do_return },
 18.1297 +    { "string",		TRUE,	xexpr_do_string },
 18.1298 +    { "integer",	TRUE,	xexpr_do_integer },
 18.1299 +    { "float",		TRUE,	xexpr_do_float },
 18.1300 +    { "true",		TRUE,	xexpr_do_true },
 18.1301 +    { "false",		TRUE,	xexpr_do_false },
 18.1302 +    { "nil",		TRUE,	xexpr_do_nil },
 18.1303 +    { "add",		FALSE,	xexpr_do_add },
 18.1304 +    { "subtract",	FALSE,	xexpr_do_subtract },
 18.1305 +    { "multiply",	FALSE,	xexpr_do_multiply },
 18.1306 +    { "divide",		FALSE,	xexpr_do_divide },
 18.1307 +    { "eq",		TRUE,	xexpr_do_eq },
 18.1308 +    { "neq",		TRUE,	xexpr_do_neq },
 18.1309 +    { "leq",		TRUE,	xexpr_do_leq },
 18.1310 +    { "geq",		TRUE,	xexpr_do_geq },
 18.1311 +    { "lt",		TRUE,	xexpr_do_lt },
 18.1312 +    { "gt",		TRUE,	xexpr_do_gt },
 18.1313 +    { "and",		FALSE,	xexpr_do_and },
 18.1314 +    { "or",		FALSE,	xexpr_do_or },
 18.1315 +    { "not",		FALSE,	xexpr_do_not },
 18.1316 +    { "if",		FALSE,	xexpr_do_if },
 18.1317 +    { "switch",		FALSE,	xexpr_do_switch },
 18.1318 +    { "while",		FALSE,	xexpr_do_while },
 18.1319 +    { "do",		FALSE,	xexpr_do_do },
 18.1320 +};
 18.1321 +
 18.1322 +static gboolean xexpr_defineable_id(const char *id,GError **err)
 18.1323 +{
 18.1324 +    int i;
 18.1325 +    for(i=0;i<G_N_ELEMENTS(xexpr_builtins);i++)
 18.1326 +	if (!strcmp(xexpr_builtins[i].id,id))
 18.1327 +	{
 18.1328 +	    g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_EVAL_ERROR_FAILED,
 18.1329 +	      "Can't define reserved XEXPR ID \"%s\"",id);
 18.1330 +	    return FALSE;
 18.1331 +	}
 18.1332 +    return TRUE;
 18.1333 +}
 18.1334 +
 18.1335 +static XexprConstant *xexpr_closure(Xexpr *xexpr,XexprConstant *constant,
 18.1336 +  GError **err)
 18.1337 +{
 18.1338 +    GSList *lnk;
 18.1339 +    XexprConstant *result,*tmp;
 18.1340 +    g_return_val_if_fail(constant->type==XEXPR_TYPE_FUNCTION,NULL);
 18.1341 +    result=NULL;
 18.1342 +    for(lnk=constant->u.function->constants;lnk;lnk=lnk->next)
 18.1343 +    {
 18.1344 +	if (result)
 18.1345 +	    xexpr_constant_free(result);
 18.1346 +	result=xexpr_constant_evaluate(xexpr,lnk->data,err);
 18.1347 +	if (!result)
 18.1348 +	    return NULL;
 18.1349 +	if (result->type==XEXPR_TYPE_INVOCATION &&
 18.1350 +	  !strcmp(result->u.invocation->function,"return"))
 18.1351 +	{
 18.1352 +	    lnk=g_slist_last(result->u.invocation->constants);
 18.1353 +	    tmp=xexpr_constant_dup(lnk->data);
 18.1354 +	    xexpr_constant_free(result);
 18.1355 +	    result=tmp;
 18.1356 +	    break;
 18.1357 +	}
 18.1358 +    }
 18.1359 +    if (!result)
 18.1360 +       result=xexpr_new_invocation(NULL,"nil",NULL,NULL);
 18.1361 +    return result;
 18.1362 +}
 18.1363 +
 18.1364 +static XexprConstant *xexpr_function_evaluate(Xexpr *xexpr,const char *ns,
 18.1365 +  const char *id,GSList *bindings,GSList *args,GError **err)
 18.1366 +{
 18.1367 +    int builtin;
 18.1368 +    gboolean evaluate_args;
 18.1369 +    XexprBinding *binding;
 18.1370 +    XexprExtension *ext;
 18.1371 +    XexprConstant *value,*function_def,*result;
 18.1372 +    const char *unbound_parameter;
 18.1373 +    GSList *unbound_args=args,*lnk,*actual,*unbound_parameters;
 18.1374 +    if (ns)
 18.1375 +    {
 18.1376 +	for(lnk=xexpr_extensions;lnk;lnk=lnk->next)
 18.1377 +	{
 18.1378 +	    ext=lnk->data;
 18.1379 +	    if (!strcmp(ext->ns,ns))
 18.1380 +		return ext->function_evaluate(xexpr,ns,id,bindings,args,err);
 18.1381 +	}
 18.1382 +	g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
 18.1383 +	  "Unknown namespace \"%s\"",ns);
 18.1384 +	return NULL;
 18.1385 +    }
 18.1386 +    for(builtin=0;builtin<G_N_ELEMENTS(xexpr_builtins);builtin++)
 18.1387 +	if (!strcmp(xexpr_builtins[builtin].id,id))
 18.1388 +	{
 18.1389 +	    evaluate_args=xexpr_builtins[builtin].evaluate_args;
 18.1390 +	    break;
 18.1391 +	}
 18.1392 +    if (builtin==G_N_ELEMENTS(xexpr_builtins))
 18.1393 +    {
 18.1394 +	function_def=xexpr_var_get(xexpr,id);
 18.1395 +	if (!function_def)
 18.1396 +	{
 18.1397 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
 18.1398 +	      "Undefined function: \"%s\"",id);
 18.1399 +	    return NULL;
 18.1400 +	}
 18.1401 +	else if (function_def->type!=XEXPR_TYPE_FUNCTION)
 18.1402 +	    return xexpr_constant_evaluate(xexpr,function_def,err);
 18.1403 +	unbound_parameters=g_slist_copy(function_def->u.function->args);
 18.1404 +	evaluate_args=TRUE;
 18.1405 +    }
 18.1406 +    else
 18.1407 +    {
 18.1408 +	function_def=NULL;
 18.1409 +	unbound_parameters=NULL;
 18.1410 +    }
 18.1411 +    for(lnk=bindings;lnk;lnk=lnk->next)
 18.1412 +    {
 18.1413 +	binding=lnk->data;
 18.1414 +	actual=g_slist_find_custom(unbound_parameters,binding->id,
 18.1415 +	  (GCompareFunc)strcmp);
 18.1416 +	if (actual)
 18.1417 +	    unbound_parameters=g_slist_delete_link(unbound_parameters,actual);
 18.1418 +	xexpr_var_new(xexpr,binding->id,binding->value);
 18.1419 +    }
 18.1420 +    if (evaluate_args)
 18.1421 +    {
 18.1422 +	for(lnk=unbound_parameters;lnk;lnk=lnk->next)
 18.1423 +	{
 18.1424 +	    unbound_parameter=lnk->data;
 18.1425 +	    value=xexpr_var_get(xexpr,unbound_parameter);
 18.1426 +	    if (value)
 18.1427 +		xexpr_var_new(xexpr,unbound_parameter,value);
 18.1428 +	    else
 18.1429 +	    {
 18.1430 +		value=xexpr_new_invocation(NULL,"nil",NULL,NULL);
 18.1431 +		xexpr_var_new(xexpr,unbound_parameter,value);
 18.1432 +		xexpr_constant_free(value);
 18.1433 +	    }
 18.1434 +	}
 18.1435 +    }
 18.1436 +    while(unbound_parameters)
 18.1437 +    {
 18.1438 +	unbound_parameter=unbound_parameters->data;
 18.1439 +	if (unbound_args)
 18.1440 +	{
 18.1441 +	    if (evaluate_args)
 18.1442 +	    {
 18.1443 +		value=xexpr_constant_evaluate(xexpr,unbound_args->data,err);
 18.1444 +		if (!value)
 18.1445 +		{
 18.1446 +		    g_slist_free(unbound_parameters);
 18.1447 +		    return NULL;
 18.1448 +		}
 18.1449 +		xexpr_var_set(xexpr,unbound_parameter,value);
 18.1450 +		xexpr_constant_free(value);
 18.1451 +	    }
 18.1452 +	    else
 18.1453 +	    {
 18.1454 +		value=unbound_args->data;
 18.1455 +		xexpr_var_new(xexpr,unbound_parameter,value);
 18.1456 +	    }
 18.1457 +	    unbound_args=unbound_args->next;
 18.1458 +	    unbound_parameters=
 18.1459 +	      g_slist_delete_link(unbound_parameters,unbound_parameters);
 18.1460 +	}
 18.1461 +	else
 18.1462 +	{
 18.1463 +	    g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED,
 18.1464 +	      "No actual value to bind to parameter %s of function %s",
 18.1465 +	      unbound_parameter,id);
 18.1466 +	    g_slist_free(unbound_parameters);
 18.1467 +	    return NULL;
 18.1468 +	}
 18.1469 +    }
 18.1470 +    if (evaluate_args)
 18.1471 +    {
 18.1472 +	args=NULL;
 18.1473 +	while(unbound_args)
 18.1474 +	{
 18.1475 +	    value=xexpr_constant_evaluate(xexpr,unbound_args->data,err);
 18.1476 +	    if (!value)
 18.1477 +		return NULL;
 18.1478 +	    args=g_slist_prepend(args,value);
 18.1479 +	    unbound_args=unbound_args->next;
 18.1480 +	}
 18.1481 +	args=g_slist_reverse(args);
 18.1482 +    }
 18.1483 +    if (function_def)
 18.1484 +	result=xexpr_closure(xexpr,function_def,err);
 18.1485 +    else
 18.1486 +	result=xexpr_builtins[builtin].func(xexpr,bindings,args,err);
 18.1487 +    if (evaluate_args)
 18.1488 +    {
 18.1489 +	g_slist_foreach(args,(GFunc)xexpr_constant_free,NULL);
 18.1490 +	g_slist_free(args);
 18.1491 +    }
 18.1492 +    return result;
 18.1493 +}
 18.1494 +
 18.1495 +/**
 18.1496 + * xexpr_constant_evaluate:
 18.1497 + * @xexpr: an #Xexpr
 18.1498 + * @constant: the #XexprConstant to evaluate
 18.1499 + * @err: (allow-none): location to store error, or %NULL
 18.1500 + *
 18.1501 + * Evaluate an XEXPR expression. Typically, an expression will evaluate to
 18.1502 + * one of the basic types: string, integer or float. However, the XEXPR
 18.1503 + * language specification states that &lt;define&gt; returns a function
 18.1504 + * object (ie., an #XexprConstant with type %XEXPR_TYPE_FUNCTION).
 18.1505 + * If such a function object is passed to xexpr_constant_evaluate(), then
 18.1506 + * the function definition will be evaluated. If the function takes
 18.1507 + * arguments, then these will be taken as &lt;nil&gt;.
 18.1508 + *
 18.1509 + * The returned expresion should be freed with xexpr_constant_free()
 18.1510 + * when no longer needed.
 18.1511 + *
 18.1512 + * Return value: (transfer full): The evaluated result, or %NULL on error
 18.1513 + */
 18.1514 +XexprConstant *xexpr_constant_evaluate(Xexpr *xexpr,XexprConstant *constant,
 18.1515 +  GError **err)
 18.1516 +{
 18.1517 +    GSList *lnk;
 18.1518 +    XexprConstant *result,*tmp;
 18.1519 +    switch(constant->type)
 18.1520 +    {
 18.1521 +	case XEXPR_TYPE_FUNCTION:
 18.1522 +	    /*
 18.1523 +	     * It's not clear how function objects should be evaluated.
 18.1524 +	     * We choose to invoke them with all arguments as <nil/>.
 18.1525 +	     * Note that this means that <get>x</get> will not error
 18.1526 +	     * out if x is defined as taking arguments whereas <x/>
 18.1527 +	     * will. http://www.w3.org/TR/xexpr/#id-0014 states that
 18.1528 +	     * these have the same effect in _most_ cases which implies
 18.1529 +	     * that there are differences in some cases.
 18.1530 +	     */
 18.1531 +	    _xexpr_push_environment(xexpr,NULL);
 18.1532 +	    tmp=xexpr_new_invocation(NULL,"nil",NULL,NULL);
 18.1533 +	    for(lnk=constant->u.function->args;lnk;lnk=lnk->next)
 18.1534 +		xexpr_var_new(xexpr,lnk->data,tmp);
 18.1535 +	    xexpr_constant_free(tmp);
 18.1536 +	    result=xexpr_closure(xexpr,constant,err);
 18.1537 +	    _xexpr_pop_environment(xexpr);
 18.1538 +	    return result;
 18.1539 +	    break;
 18.1540 +	case XEXPR_TYPE_INVOCATION:
 18.1541 +	    _xexpr_push_environment(xexpr,constant->u.invocation->function);
 18.1542 +	    result=xexpr_function_evaluate(xexpr,
 18.1543 +	      constant->u.invocation->ns,
 18.1544 +	      constant->u.invocation->function,
 18.1545 +	      constant->u.invocation->bindings,
 18.1546 +	      constant->u.invocation->constants,err);
 18.1547 +	    _xexpr_pop_environment(xexpr);
 18.1548 +	    return result;
 18.1549 +	    break;
 18.1550 +	case XEXPR_TYPE_STRING:
 18.1551 +	    return xexpr_new_string(constant->u.string,-1);
 18.1552 +	    break;
 18.1553 +	case XEXPR_TYPE_INTEGER:
 18.1554 +	    return xexpr_new_integer(constant->u.integer);
 18.1555 +	    break;
 18.1556 +	case XEXPR_TYPE_NUMBER:
 18.1557 +	    return xexpr_new_number(constant->u.number);
 18.1558 +	    break;
 18.1559 +    }
 18.1560 +    return NULL;
 18.1561 +}
 18.1562 +
 18.1563 +/**
 18.1564 + * xexpr_evaluate:
 18.1565 + * @xexpr: an #Xexpr to evaluate
 18.1566 + * @err: (allow-none): location to store error, or %NULL
 18.1567 + *
 18.1568 + * Evaluate an XEXPR expression. Typically, an expression will evaluate to
 18.1569 + * one of the basic types: string, integer or float. However, the XEXPR
 18.1570 + * language specification states that &lt;define&gt; returns a function
 18.1571 + * object (ie., an #XexprConstant with type %XEXPR_TYPE_FUNCTION).
 18.1572 + * If such a function object is passed to xexpr_evaluate(), then
 18.1573 + * the function definition will be evaluated. If the function takes
 18.1574 + * arguments, then these will be taken as &lt;nil&gt;.
 18.1575 + *
 18.1576 + * The returned expresion should be freed with xexpr_free()
 18.1577 + * when no longer needed.
 18.1578 + *
 18.1579 + * Return value: (transfer full): The evaluated result, or %NULL on error
 18.1580 + */
 18.1581 +Xexpr *xexpr_evaluate(Xexpr *xexpr,GError **err)
 18.1582 +{
 18.1583 +    Xexpr *results;
 18.1584 +    XexprConstant *constant,*result;
 18.1585 +    GSList *lnk;
 18.1586 +    results=xexpr_sub(xexpr);
 18.1587 +    for(lnk=xexpr->constants;lnk;lnk=lnk->next)
 18.1588 +    {
 18.1589 +	constant=lnk->data;
 18.1590 +	result=xexpr_constant_evaluate(xexpr,constant,err);
 18.1591 +	if (!result)
 18.1592 +	{
 18.1593 +	    xexpr_free(results);
 18.1594 +	    return NULL;
 18.1595 +	}
 18.1596 +	else
 18.1597 +	    results->constants=g_slist_prepend(results->constants,result);
 18.1598 +    }
 18.1599 +    results->constants=g_slist_reverse(results->constants);
 18.1600 +    return results;
 18.1601 +}
 18.1602 +
 18.1603 +/**
 18.1604 + * xexpr_test:
 18.1605 + * @xexpr: an #Xexpr to test
 18.1606 + * @err: (allow-none): location to store error, or %NULL
 18.1607 + *
 18.1608 + * Test an expression by looking at the last constant in the expression.
 18.1609 + * Numerical constants are treated as &lt;true&gt; if they are non-zero,
 18.1610 + * string constants are treated as &lt;true&gt; if they are non-empty,
 18.1611 + * function invocations are treated as &lt;true&gt; unless they are
 18.1612 + * &lt;false&gt; or &lt;nil&gt;, function definitions are recursively
 18.1613 + * evaluated before they are tested.
 18.1614 + *
 18.1615 + * Return value: %TRUE if the expression is equivalent to &lt;true&gt;.
 18.1616 + */
 18.1617 +gboolean xexpr_test(Xexpr *xexpr,GError **err)
 18.1618 +{
 18.1619 +    GSList *lnk;
 18.1620 +    XexprConstant *constant;
 18.1621 +    lnk=g_slist_last(xexpr->constants);
 18.1622 +    constant=lnk->data;
 18.1623 +    return xexpr_constant_boolean(xexpr,constant,err);
 18.1624 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/libxexpr/xexpreval.h	Wed Oct 10 22:58:21 2012 +0100
    19.3 @@ -0,0 +1,37 @@
    19.4 +#ifndef __XEXPER_EVAL_H__
    19.5 +#define __XEXPER_EVAL_H__
    19.6 +
    19.7 +#include <glib.h>
    19.8 +#include "xexprtypes.h"
    19.9 +
   19.10 +G_BEGIN_DECLS
   19.11 +
   19.12 +/**
   19.13 + * XEXPR_EVAL_ERROR:
   19.14 + *
   19.15 + * Used to get the #GError quark for libxexpr evaluator errors.
   19.16 + */
   19.17 +#define XEXPR_EVAL_ERROR		xexpr_eval_error_quark()
   19.18 +
   19.19 +/**
   19.20 + * XexprEvalError:
   19.21 + * @XEXPR_EVAL_ERROR_FAILED: Indicates a generic failure.
   19.22 + *
   19.23 + * Enum values for evaluator errors.
   19.24 + */
   19.25 +typedef enum
   19.26 +{
   19.27 +    XEXPR_EVAL_ERROR_FAILED
   19.28 +} XexprEvalError;
   19.29 +
   19.30 +GQuark xexpr_eval_error_quark(void);
   19.31 +gboolean xexpr_register_extension(XexprExtension *extension);
   19.32 +XexprConstant *xexpr_constant_evaluate(Xexpr *xexpr,XexprConstant *constant,
   19.33 +  GError **err);
   19.34 +Xexpr *xexpr_evaluate(Xexpr *xexpr,GError **err);
   19.35 +gboolean xexpr_constant_cast(XexprConstant *constant,XexprType to);
   19.36 +gboolean xexpr_test(Xexpr *xexpr,GError **err);
   19.37 +
   19.38 +G_END_DECLS
   19.39 +
   19.40 +#endif	/* __XEXPER_EVAL_H__ */
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/libxexpr/xexprparse.c	Wed Oct 10 22:58:21 2012 +0100
    20.3 @@ -0,0 +1,320 @@
    20.4 +#include <stdlib.h>
    20.5 +#include <string.h>
    20.6 +#include <math.h>
    20.7 +#include "xexprparse.h"
    20.8 +
    20.9 +/**
   20.10 + * SECTION:xexprparse
   20.11 + * @short_description: A parser for the XEXPR language
   20.12 + * @stability: Stable
   20.13 + * @include: libxexpr/xexpr.h
   20.14 + *
   20.15 + * A parser for the
   20.16 + * <ulink url="http://www.w3.org/TR/2000/NOTE-xexpr-20001121">XEXPR</ulink>
   20.17 + * language.
   20.18 + */
   20.19 +
   20.20 +/**
   20.21 + * xexpr_parse_error_quark:
   20.22 + *
   20.23 + * Registers an error quark for the libxexpr parser if necessary.
   20.24 + *
   20.25 + * Return value: The error quark used for libxexpr parser errors.
   20.26 + */
   20.27 +GQuark xexpr_parse_error_quark(void)
   20.28 +{
   20.29 +    static GQuark quark;
   20.30 +    if (!quark)
   20.31 +	quark=g_quark_from_static_string("xexpr_parse_error");
   20.32 +    return quark;
   20.33 +}
   20.34 +
   20.35 +gboolean _xexpr_validate_id(const char *id,GError **err)
   20.36 +{
   20.37 +    int i;
   20.38 +    for(i=0;id[i];i++)
   20.39 +	if (!g_ascii_isalpha(id[i]) && id[i]!='-' && id[i]!='.')
   20.40 +	{
   20.41 +	    g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED,
   20.42 +	      "Invalid XEXPR ID: \"%s\"",id);
   20.43 +	    return FALSE;
   20.44 +	}
   20.45 +    return TRUE;
   20.46 +}
   20.47 +
   20.48 +static gboolean xexpr_parse_pcdata(Xexpr *xexpr,xmlNode *node,xmlChar *pcdata,
   20.49 +  GError **err)
   20.50 +{
   20.51 +    int n;
   20.52 +    const char *s,*t;
   20.53 +    xmlChar *text;
   20.54 +    gchar *str;
   20.55 +    gboolean is_integer;
   20.56 +    long long int integer;
   20.57 +    double number;
   20.58 +    s=(const char *)pcdata;
   20.59 +    if (node->type==XML_TEXT_NODE &&
   20.60 +      (!node->prev || node->prev->type!=XML_TEXT_NODE))
   20.61 +	while(g_ascii_isspace(*s))
   20.62 +	    s++;
   20.63 +    while(*s)
   20.64 +    {
   20.65 +	t=strpbrk(s,"+-0123456789");
   20.66 +	/* All numbers start with [+-]?[0-9] (possibly with leading WS) */
   20.67 +	if (t && (t[0]!='+' && t[0]!='-' || t[1]!='+' && t[1]!='-'))
   20.68 +	{
   20.69 +	    while(t>s && g_ascii_isspace(t[-1]))
   20.70 +		t--;
   20.71 +	    if (t>s)
   20.72 +		xexpr->constants=g_slist_prepend(xexpr->constants,
   20.73 +		  xexpr_new_string(s,t-s));
   20.74 +	    s=t;
   20.75 +	    while(g_ascii_isspace(*s))
   20.76 +		s++;
   20.77 +	    if (*s=='+' || *s=='-')
   20.78 +		s++;
   20.79 +	    if (s[0]=='0' && s[1]=='x' &&
   20.80 +	      (n=strspn(s+2,"0123456789ABCDEFabcdef"))>0)
   20.81 +	    {
   20.82 +		s+=2+n;
   20.83 +		is_integer=TRUE;
   20.84 +	    }
   20.85 +	    else
   20.86 +	    {
   20.87 +		s+=strspn(s,"0123456789");
   20.88 +		if (*s=='.' && (n=strspn(s+1,"0123456789"))>0)
   20.89 +		{
   20.90 +		    s+=1+n;
   20.91 +		    if ((s[0]=='e' || s[0]=='E') && (s[1]=='+' || s[1]=='-') &&
   20.92 +		      (n=strspn(s+2,"0123456789"))>0)
   20.93 +			s+=2+n;
   20.94 +		    is_integer=FALSE;
   20.95 +		}
   20.96 +		else
   20.97 +		    is_integer=TRUE;
   20.98 +	    }
   20.99 +	    while(g_ascii_isspace(*s))
  20.100 +		s++;
  20.101 +	    str=g_strndup(t,s-t);
  20.102 +	    if (is_integer)
  20.103 +	    {
  20.104 +		integer=g_ascii_strtoll(str,NULL,0);
  20.105 +		if (integer==LLONG_MIN || integer==LLONG_MAX)
  20.106 +		{
  20.107 +		    text=xmlGetNodePath(node);
  20.108 +		    g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED,
  20.109 +		      "Integer overflow on %s at %s",str,(const char *)text);
  20.110 +		    xmlFree(text);
  20.111 +		    g_free(str);
  20.112 +		    return FALSE;
  20.113 +		}
  20.114 +		else
  20.115 +		    xexpr->constants=g_slist_prepend(xexpr->constants,
  20.116 +		      xexpr_new_integer(integer));
  20.117 +	    }
  20.118 +	    else
  20.119 +	    {
  20.120 +		number=g_ascii_strtod(str,NULL);
  20.121 +		if (number==HUGE_VAL || number==-HUGE_VAL)
  20.122 +		{
  20.123 +		    text=xmlGetNodePath(node);
  20.124 +		    g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED,
  20.125 +		      "Numeric overflow on %s at %s",str,(const char *)text);
  20.126 +		    xmlFree(text);
  20.127 +		    g_free(str);
  20.128 +		    return FALSE;
  20.129 +		}
  20.130 +		else
  20.131 +		    xexpr->constants=g_slist_prepend(xexpr->constants,
  20.132 +		      xexpr_new_number(number));
  20.133 +	    }
  20.134 +	    g_free(str);
  20.135 +	}
  20.136 +	else
  20.137 +	{
  20.138 +	    n=strlen(s);
  20.139 +	    if (node->type==XML_TEXT_NODE &&
  20.140 +	      (!node->next || node->next->type!=XML_TEXT_NODE))
  20.141 +		while(n && g_ascii_isspace(s[n-1]))
  20.142 +		    n--;
  20.143 +	    xexpr->constants=g_slist_prepend(xexpr->constants,
  20.144 +	      xexpr_new_string(s,n));
  20.145 +	    break;
  20.146 +	}
  20.147 +    }
  20.148 +    return TRUE;
  20.149 +}
  20.150 +
  20.151 +static gboolean xexpr_parse_string(Xexpr *xexpr,xmlNode *xml,GError **err)
  20.152 +{
  20.153 +    xmlNode *node;
  20.154 +    xmlChar *text;
  20.155 +    GString *str=g_string_new(NULL);
  20.156 +    for(node=xml;node;node=node->next)
  20.157 +    {
  20.158 +	if (node->type==XML_ELEMENT_NODE)
  20.159 +	{
  20.160 +	    text=xmlGetNodePath(node);
  20.161 +	    g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED,
  20.162 +	      "No markup can occur within <string> at %s",(const char *)text);
  20.163 +	    xmlFree(text);
  20.164 +	    return FALSE;
  20.165 +	}
  20.166 +	else if (node->type==XML_TEXT_NODE)
  20.167 +	    g_string_append(str,(const char *)node->content);
  20.168 +	else if (node->type!=XML_COMMENT_NODE)
  20.169 +	{
  20.170 +	    text=xmlGetNodePath(node);
  20.171 +	    g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED,
  20.172 +	      "Unexpected node type %d at %s",node->type,(const char *)text);
  20.173 +	    xmlFree(text);
  20.174 +	    return FALSE;
  20.175 +	}
  20.176 +    }
  20.177 +    xexpr->constants=g_slist_append(xexpr->constants,
  20.178 +      xexpr_new_string_take_ownership(g_string_free(str,FALSE)));
  20.179 +    return TRUE;
  20.180 +}
  20.181 +
  20.182 +/**
  20.183 + * xexpr_parse_node:
  20.184 + * @xexpr: an #Xexpr
  20.185 + * @node: the #xmlNode to parse
  20.186 + * @err: (allow-none): location to store error, or %NULL.
  20.187 + *
  20.188 + * Parse an XEXPR expression whose root is @node.
  20.189 + *
  20.190 + * Typical usage of this function might be:
  20.191 + * |[
  20.192 + *    doc=xmlReadFile(filename,NULL,0);
  20.193 + *    if (doc && !xexpr_parse_node(xexpr,xmlDocGetRootElement(doc),&err))
  20.194 + *    {
  20.195 + *        fprintf(stderr,"%s: %s\n",filename,err->message);
  20.196 + *        exit(1);
  20.197 + *    }
  20.198 + * ]|
  20.199 + *
  20.200 + * Return value: %TRUE if @node was successfully parsed.
  20.201 + */
  20.202 +gboolean xexpr_parse_node(Xexpr *xexpr,xmlNode *node,GError **err)
  20.203 +{
  20.204 +    XexprConstant *constant;
  20.205 +    XexprBinding *binding;
  20.206 +    Xexpr *sub,*binding_xexpr;
  20.207 +    xmlAttr *attr;
  20.208 +    xmlChar *prop;
  20.209 +    GSList *bindings;
  20.210 +    char *ns;
  20.211 +    sub=xexpr_sub(xexpr);
  20.212 +    if (!strcmp((const char *)node->name,"string"))
  20.213 +    {
  20.214 +	if (!xexpr_parse_string(sub,node->children,err))
  20.215 +	{
  20.216 +	    xexpr_free(sub);
  20.217 +	    return FALSE;
  20.218 +	}
  20.219 +    }
  20.220 +    else if (!_xexpr_validate_id((const char *)node->name,err) ||
  20.221 +      !xexpr_parse_fragment(sub,node->children,err))
  20.222 +    {
  20.223 +	xexpr_free(sub);
  20.224 +	return FALSE;
  20.225 +    }
  20.226 +    bindings=NULL;
  20.227 +    for(attr=node->properties;attr;attr=attr->next)
  20.228 +    {
  20.229 +	if (!_xexpr_validate_id((const char *)attr->name,err))
  20.230 +	{
  20.231 +	    g_slist_foreach(bindings,(GFunc)xexpr_binding_free,NULL);
  20.232 +	    g_slist_free(bindings);
  20.233 +	    xexpr_free(sub);
  20.234 +	    return FALSE;
  20.235 +	}
  20.236 +	prop=xmlGetProp(node,attr->name);
  20.237 +	binding_xexpr=xexpr_sub(xexpr);
  20.238 +	if (!xexpr_parse_pcdata(binding_xexpr,(xmlNode *)attr,prop,err))
  20.239 +	{
  20.240 +	    xmlFree(prop);
  20.241 +	    g_slist_foreach(bindings,(GFunc)xexpr_binding_free,NULL);
  20.242 +	    g_slist_free(bindings);
  20.243 +	    xexpr_free(binding_xexpr);
  20.244 +	    xexpr_free(sub);
  20.245 +	    return FALSE;
  20.246 +	}
  20.247 +	binding=g_slice_new(XexprBinding);
  20.248 +	binding->id=g_strdup((const char *)attr->name);
  20.249 +	if (!binding_xexpr->constants || binding_xexpr->constants->next)
  20.250 +	    binding->value=xexpr_new_string((const char *)prop,-1);
  20.251 +	else
  20.252 +	{
  20.253 +	    binding->value=binding_xexpr->constants->data;
  20.254 +	    g_slist_free(binding_xexpr->constants);
  20.255 +	    binding_xexpr->constants=NULL;
  20.256 +	}
  20.257 +	xexpr_free(binding_xexpr);
  20.258 +	xmlFree(prop);
  20.259 +	bindings=g_slist_prepend(bindings,binding);
  20.260 +    }
  20.261 +    bindings=g_slist_reverse(bindings);
  20.262 +    if (node->ns)
  20.263 +	ns=g_strdup((const char *)node->ns->href);
  20.264 +    else
  20.265 +	ns=NULL;
  20.266 +    constant=xexpr_new_invocation_take_ownership(ns,
  20.267 +      g_strdup((const char *)node->name),bindings,sub->constants);
  20.268 +    sub->constants=NULL;
  20.269 +    xexpr_free(sub);
  20.270 +    xexpr->constants=g_slist_prepend(xexpr->constants,constant);
  20.271 +    return TRUE;
  20.272 +}
  20.273 +
  20.274 +/**
  20.275 + * xexpr_parse_fragment:
  20.276 + * @xexpr: an #Xexpr
  20.277 + * @xml: the first #xmlNode to parse
  20.278 + * @err: (allow-none): location to store error, or %NULL.
  20.279 + *
  20.280 + * Parse an XEXPR expression consisting of @xml and its siblings.
  20.281 + *
  20.282 + * Typical usage of this function might be:
  20.283 + * |[
  20.284 + *    xpathObj=xmlXPathEvalExpression(BAD_CAST "//params/setting",xpathCtx);
  20.285 + *    xml=xpathObj?xpathObj->nodesetval->nodeTab[0]:NULL;
  20.286 + *    if (xml && !xexpr_parse_fragment(xexpr,xml->children,&err))
  20.287 + *    {
  20.288 + *        fprintf(stderr,"%s: %s\n",filename,err->message);
  20.289 + *        exit(1);
  20.290 + *    }
  20.291 + * ]|
  20.292 + *
  20.293 + * Return value: %TRUE if @xml was successfully parsed.
  20.294 + */
  20.295 +gboolean xexpr_parse_fragment(Xexpr *xexpr,xmlNode *xml,GError **err)
  20.296 +{
  20.297 +    xmlNode *node;
  20.298 +    xmlChar *text;
  20.299 +    xexpr->constants=g_slist_reverse(xexpr->constants);
  20.300 +    for(node=xml;node;node=node->next)
  20.301 +    {
  20.302 +	if (node->type==XML_ELEMENT_NODE)
  20.303 +	{
  20.304 +	    if (!xexpr_parse_node(xexpr,node,err))
  20.305 +		return FALSE;
  20.306 +	}
  20.307 +	else if (node->type==XML_TEXT_NODE)
  20.308 +	{
  20.309 +	    if (!xexpr_parse_pcdata(xexpr,node,node->content,err))
  20.310 +		return FALSE;
  20.311 +	}
  20.312 +	else if (node->type!=XML_COMMENT_NODE)
  20.313 +	{
  20.314 +	    text=xmlGetNodePath(node);
  20.315 +	    g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED,
  20.316 +	      "Unexpected node type %d at %s",node->type,(const char *)text);
  20.317 +	    xmlFree(text);
  20.318 +	    return FALSE;
  20.319 +	}
  20.320 +    }
  20.321 +    xexpr->constants=g_slist_reverse(xexpr->constants);
  20.322 +    return TRUE;
  20.323 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/libxexpr/xexprparse.h	Wed Oct 10 22:58:21 2012 +0100
    21.3 @@ -0,0 +1,34 @@
    21.4 +#ifndef __XEXPER_PARSE_H__
    21.5 +#define __XEXPER_PARSE_H__
    21.6 +
    21.7 +#include <glib.h>
    21.8 +#include <libxml/tree.h>
    21.9 +#include "xexprtypes.h"
   21.10 +
   21.11 +G_BEGIN_DECLS
   21.12 +
   21.13 +/**
   21.14 + * XEXPR_PARSE_ERROR:
   21.15 + *
   21.16 + * Used to get the #GError quark for libxexpr parser errors.
   21.17 + */
   21.18 +#define XEXPR_PARSE_ERROR		xexpr_parse_error_quark()
   21.19 +
   21.20 +/**
   21.21 + * XexprParseError:
   21.22 + * @XEXPR_PARSE_ERROR_FAILED: Indicates a generic failure.
   21.23 + *
   21.24 + * Enum values for parser errors.
   21.25 + */
   21.26 +typedef enum
   21.27 +{
   21.28 +    XEXPR_PARSE_ERROR_FAILED
   21.29 +} XexprParseError;
   21.30 +
   21.31 +GQuark xexpr_parse_error_quark(void);
   21.32 +gboolean xexpr_parse_fragment(Xexpr *xexpr,xmlNode *xml,GError **err);
   21.33 +gboolean xexpr_parse_node(Xexpr *xexpr,xmlNode *node,GError **err);
   21.34 +
   21.35 +G_END_DECLS
   21.36 +
   21.37 +#endif	/* __XEXPER_PARSE_H__ */
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/libxexpr/xexprprivate.h	Wed Oct 10 22:58:21 2012 +0100
    22.3 @@ -0,0 +1,5 @@
    22.4 +gboolean _xexpr_validate_id(const char *id,GError **err);
    22.5 +void _xexpr_push_environment(Xexpr *xexpr,const char *id);
    22.6 +void _xexpr_pop_environment(Xexpr *xexpr);
    22.7 +XexprConstant *_xexpr_libxexpr_function_evaluate(Xexpr *xexpr,const char *ns,
    22.8 +  const char *id,GSList *bindings,GSList *args,GError **err);
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/libxexpr/xexprtypes.c	Wed Oct 10 22:58:21 2012 +0100
    23.3 @@ -0,0 +1,705 @@
    23.4 +#include <stdlib.h>
    23.5 +#include <string.h>
    23.6 +#include <math.h>
    23.7 +#include <xexpr.h>
    23.8 +#include "xexprprivate.h"
    23.9 +
   23.10 +/**
   23.11 + * SECTION:xexprtypes
   23.12 + * @short_description: Types defined in libxexpr
   23.13 + * @stability: Stable
   23.14 + * @include: libxexpr/xexpr.h
   23.15 + *
   23.16 + * The various types defined in libxexpr and the functions that support them.
   23.17 + */
   23.18 +
   23.19 +static XexprEnvironment *xexpr_environment_new(const char *function,
   23.20 +  XexprEnvironment *outer);
   23.21 +
   23.22 +/**
   23.23 + * xexpr_binding_free:
   23.24 + * @binding: an #XexprBinding
   23.25 + *
   23.26 + * Frees the memory allocated for the #XexprBinding.
   23.27 + */
   23.28 +void xexpr_binding_free(XexprBinding *binding)
   23.29 +{
   23.30 +    g_free(binding->id);
   23.31 +    xexpr_constant_free(binding->value);
   23.32 +    g_slice_free(XexprBinding,binding);
   23.33 +}
   23.34 +
   23.35 +/**
   23.36 + * xexpr_environment_free:
   23.37 + * @environment: an #XexprEnvironment
   23.38 + *
   23.39 + * Frees the memory allocated for the #XexprEnvironment.
   23.40 + */
   23.41 +static void xexpr_environment_free(XexprEnvironment *environment)
   23.42 +{
   23.43 +    g_warn_if_fail(environment->refcount==1);
   23.44 +    if (environment->outer)
   23.45 +	environment->outer->refcount--;
   23.46 +    g_free(environment->function);
   23.47 +    g_slist_foreach(environment->bindings,(GFunc)xexpr_binding_free,NULL);
   23.48 +    g_slist_free(environment->bindings);
   23.49 +    g_slice_free(XexprEnvironment,environment);
   23.50 +}
   23.51 +
   23.52 +/*
   23.53 + * xexpr_invocation_free:
   23.54 + * @invocation: an #XexprInvocation
   23.55 + *
   23.56 + * Frees the memory allocated for the #XexprInvocation.
   23.57 + */
   23.58 +static void xexpr_invocation_free(XexprInvocation *invocation)
   23.59 +{
   23.60 +    g_free(invocation->function);
   23.61 +    g_slist_foreach(invocation->bindings,(GFunc)xexpr_binding_free,NULL);
   23.62 +    g_slist_free(invocation->bindings);
   23.63 +    g_slist_foreach(invocation->constants,(GFunc)xexpr_constant_free,NULL);
   23.64 +    g_slist_free(invocation->constants);
   23.65 +    g_slice_free(XexprInvocation,invocation);
   23.66 +}
   23.67 +
   23.68 +/*
   23.69 + * xexpr_function_free:
   23.70 + * @function: an #XexprFunction
   23.71 + *
   23.72 + * Frees the memory allocated for the #XexprFunction.
   23.73 + */
   23.74 +static void xexpr_function_free(XexprFunction *function)
   23.75 +{
   23.76 +    g_slist_foreach(function->args,(GFunc)g_free,NULL);
   23.77 +    g_slist_free(function->args);
   23.78 +    g_slist_foreach(function->constants,(GFunc)xexpr_constant_free,NULL);
   23.79 +    g_slist_free(function->constants);
   23.80 +    g_slice_free(XexprFunction,function);
   23.81 +}
   23.82 +
   23.83 +/**
   23.84 + * xexpr_constant_free:
   23.85 + * @constant: an #XexprConstant
   23.86 + *
   23.87 + * Frees the memory allocated for the #XexprConstant.
   23.88 + */
   23.89 +void xexpr_constant_free(XexprConstant *constant)
   23.90 +{
   23.91 +    switch(constant->type)
   23.92 +    {
   23.93 +	case XEXPR_TYPE_INVOCATION:
   23.94 +	    xexpr_invocation_free(constant->u.invocation);
   23.95 +	    break;
   23.96 +	case XEXPR_TYPE_FUNCTION:
   23.97 +	    xexpr_function_free(constant->u.function);
   23.98 +	    break;
   23.99 +	case XEXPR_TYPE_STRING:
  23.100 +	    g_free(constant->u.string);
  23.101 +	    break;
  23.102 +	case XEXPR_TYPE_INTEGER:
  23.103 +	case XEXPR_TYPE_NUMBER:
  23.104 +	    break;
  23.105 +    }
  23.106 +    g_slice_free(XexprConstant,constant);
  23.107 +}
  23.108 +
  23.109 +/**
  23.110 + * xexpr_free:
  23.111 + * @xexpr: an #Xexpr
  23.112 + *
  23.113 + * Frees the memory allocated for the #Xexpr.
  23.114 + */
  23.115 +void xexpr_free(Xexpr *xexpr)
  23.116 +{
  23.117 +    g_slist_foreach(xexpr->tracing,(GFunc)g_free,NULL);
  23.118 +    g_slist_free(xexpr->tracing);
  23.119 +    g_slist_foreach(xexpr->constants,(GFunc)xexpr_constant_free,NULL);
  23.120 +    g_slist_free(xexpr->constants);
  23.121 +    g_slice_free(Xexpr,xexpr);
  23.122 +}
  23.123 +
  23.124 +/**
  23.125 + * xexpr_new:
  23.126 + *
  23.127 + * Creates a new #Xexpr.
  23.128 + *
  23.129 + * Returns: the new #Xexpr
  23.130 + */
  23.131 +Xexpr *xexpr_new(void)
  23.132 +{
  23.133 +    xexpr_register_extension(NULL);
  23.134 +    return g_slice_new0(Xexpr);
  23.135 +}
  23.136 +
  23.137 +/**
  23.138 + * xexpr_sub:
  23.139 + * @xexpr: an #Xexpr to copy the initial options from
  23.140 + *
  23.141 + * Creates a new #Xexpr, copying options from @xexpr.
  23.142 + *
  23.143 + * Returns: the new #Xexpr
  23.144 + */
  23.145 +Xexpr *xexpr_sub(Xexpr *xexpr)
  23.146 +{
  23.147 +    GSList *lnk;
  23.148 +    Xexpr *sub=xexpr_new();
  23.149 +    sub->tracing=g_slist_copy(xexpr->tracing);
  23.150 +    for(lnk=sub->tracing;lnk;lnk=lnk->next)
  23.151 +	lnk->data=g_strdup(lnk->data);
  23.152 +    return sub;
  23.153 +}
  23.154 +
  23.155 +/**
  23.156 + * xexpr_is_tracing:
  23.157 + * @xexpr: an #Xexpr
  23.158 + * @id: the symbol to test for
  23.159 + *
  23.160 + * Checks if a symbol is currently being traced, returning %TRUE if it is.
  23.161 + *
  23.162 + * Returns: %TRUE if @id is being traced
  23.163 + */
  23.164 +gboolean xexpr_is_tracing(Xexpr *xexpr,const char *id)
  23.165 +{
  23.166 +    return !!g_slist_find_custom(xexpr->tracing,id,(GCompareFunc)g_strcmp0);
  23.167 +}
  23.168 +
  23.169 +/**
  23.170 + * xexpr_start_tracing:
  23.171 + * @xexpr: an #Xexpr
  23.172 + * @id: the symbol to trace
  23.173 + *
  23.174 + * Adds @id to the set of symbols to trace.
  23.175 + *
  23.176 + * When variables with the name of a traced symbol are created or changed,
  23.177 + * the evaluator will output a suitable tracing message and a stack dump.
  23.178 + *
  23.179 + * <example>
  23.180 + *   <title>Example Tracing Output</title>
  23.181 + *   <screen>
  23.182 + *     Created new variable x in frame \#0
  23.183 + *     \#0  test1 (x = &lt;nil/&gt;)
  23.184 + *     \#1  eq ()
  23.185 + *     \#2  if ()
  23.186 + *     \#3  and ()
  23.187 + *     \#4  expr ()
  23.188 + *     
  23.189 + *     Set variable x
  23.190 + *     \#0  test1 (x = &lt;integer&gt;1&lt;/integer&gt;)
  23.191 + *     \#1  eq ()
  23.192 + *     \#2  if ()
  23.193 + *     \#3  and ()
  23.194 + *     \#4  expr ()
  23.195 + *   </screen>
  23.196 + * </example>
  23.197 + */
  23.198 +void xexpr_start_tracing(Xexpr *xexpr,const char *id)
  23.199 +{
  23.200 +    if (!xexpr_is_tracing(xexpr,id))
  23.201 +	xexpr->tracing=g_slist_prepend(xexpr->tracing,g_strdup(id));
  23.202 +}
  23.203 +
  23.204 +/**
  23.205 + * xexpr_get_environment:
  23.206 + * @xexpr: an #Xexpr
  23.207 + *
  23.208 + * Gets the #XexprEnvironment of the given #Xexpr.
  23.209 + *
  23.210 + * Returns: (transfer none): the innermost environment
  23.211 + */
  23.212 +XexprEnvironment *xexpr_get_environment(Xexpr *xexpr)
  23.213 +{
  23.214 +    if (!xexpr->environment)
  23.215 +	xexpr->environment=xexpr_environment_new(NULL,NULL);
  23.216 +    return xexpr->environment;
  23.217 +}
  23.218 +
  23.219 +/**
  23.220 + * xexpr_set_constants_take_ownership:
  23.221 + * @xexpr: an #Xexpr
  23.222 + * @constants: (transfer full) (element-type XexprConstant): A list of 
  23.223 + *   constants to use, replacing any existing constants
  23.224 + *
  23.225 + * Sets the list of constants which make up the expression.
  23.226 + */
  23.227 +void xexpr_set_constants_take_ownership(Xexpr *xexpr,GSList *constants)
  23.228 +{
  23.229 +    g_slist_foreach(xexpr->constants,(GFunc)xexpr_constant_free,NULL);
  23.230 +    g_slist_free(xexpr->constants);
  23.231 +    xexpr->constants=constants;
  23.232 +}
  23.233 +
  23.234 +/**
  23.235 + * xexpr_set_constants:
  23.236 + * @xexpr: an #Xexpr
  23.237 + * @constants: (transfer none) (element-type XexprConstant): A list of 
  23.238 + *   constants to use, replacing any existing constants
  23.239 + *
  23.240 + * Sets the list of constants which make up the expression.
  23.241 + */
  23.242 +void xexpr_set_constants(Xexpr *xexpr,GSList *constants)
  23.243 +{
  23.244 +    GSList *lnk,*copy=NULL;
  23.245 +    for(lnk=constants;lnk;lnk=lnk->next)
  23.246 +	copy=g_slist_prepend(copy,xexpr_constant_dup(lnk->data));
  23.247 +    copy=g_slist_reverse(copy);
  23.248 +    xexpr_set_constants_take_ownership(xexpr,copy);
  23.249 +}
  23.250 +
  23.251 +void _xexpr_push_environment(Xexpr *xexpr,const char *id)
  23.252 +{
  23.253 +    xexpr->environment=xexpr_environment_new(id,xexpr_get_environment(xexpr));
  23.254 +}
  23.255 +
  23.256 +void _xexpr_pop_environment(Xexpr *xexpr)
  23.257 +{
  23.258 +    XexprEnvironment *outer=xexpr->environment->outer;
  23.259 +    if (outer)
  23.260 +    {
  23.261 +	xexpr_environment_free(xexpr->environment);
  23.262 +	xexpr->environment=outer;
  23.263 +    }
  23.264 +}
  23.265 +
  23.266 +/**
  23.267 + * xexpr_new_invocation_take_ownership:
  23.268 + * @ns: (transfer full): the namespace to which @function belongs, or %NULL
  23.269 + * @function: (transfer full): the name of the function to be invoked
  23.270 + * @bindings: (transfer full) (element-type XexprBinding): the pre-bound
  23.271 + *   arguments
  23.272 + * @constants: (transfer full) (element-type XexprConstant): the other
  23.273 + *   arguments
  23.274 + *
  23.275 + * Create a new #XexprConstant that invokes @function with pre-bound arguments
  23.276 + * @bindings and with @constants as further arguments. Functions with named
  23.277 + * parameters will use the pre-bound arguments first if present, otherwise
  23.278 + * the other arguments will be bound to the unbound parameters as needed.
  23.279 + *
  23.280 + * @ns should be %NULL, the empty string or %XEXPR_NS for XEXPR functions.
  23.281 + *
  23.282 + * Returns: (transfer full): the new #XexprConstant
  23.283 + */
  23.284 +XexprConstant *xexpr_new_invocation_take_ownership(char *ns,char *function,
  23.285 +  GSList *bindings,GSList *constants)
  23.286 +{
  23.287 +    XexprConstant *constant;
  23.288 +    constant=g_slice_new(XexprConstant);
  23.289 +    constant->type=XEXPR_TYPE_INVOCATION;
  23.290 +    constant->u.invocation=g_slice_new(XexprInvocation);
  23.291 +    if (ns && (!*ns || !strcmp(ns,XEXPR_NS)))
  23.292 +    {
  23.293 +	g_free(ns);
  23.294 +	ns=NULL;
  23.295 +    }
  23.296 +    constant->u.invocation->ns=ns;
  23.297 +    constant->u.invocation->function=function;
  23.298 +    constant->u.invocation->bindings=bindings;
  23.299 +    constant->u.invocation->constants=constants;
  23.300 +    return constant;
  23.301 +}
  23.302 +
  23.303 +/**
  23.304 + * xexpr_new_invocation:
  23.305 + * @ns: (transfer none): the namespace to which @function belongs, or %NULL
  23.306 + * @function: (transfer none): the name of the function to be invoked
  23.307 + * @bindings: (transfer none) (element-type XexprBinding): the pre-bound
  23.308 + *   arguments
  23.309 + * @constants: (transfer none) (element-type XexprConstant): the other
  23.310 + *   arguments
  23.311 + *
  23.312 + * Create a new #XexprConstant that invokes @function with pre-bound arguments
  23.313 + * @bindings and with @constants as further arguments. Functions with named
  23.314 + * parameters will use the pre-bound arguments first if present, otherwise
  23.315 + * the other arguments will be bound to the unbound parameters as needed.
  23.316 + *
  23.317 + * @ns should be %NULL, the empty string or %XEXPR_NS for XEXPR functions.
  23.318 + *
  23.319 + * Returns: (transfer full): the new #XexprConstant
  23.320 + */
  23.321 +XexprConstant *xexpr_new_invocation(const char *ns,const char *function,
  23.322 +  GSList *bindings,GSList *constants)
  23.323 +{
  23.324 +    GSList *list,*lnk;
  23.325 +    list=g_slist_copy(constants);
  23.326 +    for(lnk=list;lnk;lnk=lnk->next)
  23.327 +	lnk->data=xexpr_constant_dup(lnk->data);
  23.328 +    if (ns && (!*ns || !strcmp(ns,XEXPR_NS)))
  23.329 +	ns=NULL;
  23.330 +    return xexpr_new_invocation_take_ownership(g_strdup(ns),g_strdup(function),
  23.331 +      xexpr_bindings_dup(bindings),list);
  23.332 +}
  23.333 +
  23.334 +/**
  23.335 + * xexpr_new_function_take_ownership:
  23.336 + * @args: (transfer full) (element-type utf8): the parameter names
  23.337 + * @constants: (transfer full) (element-type XexprConstant): the constants
  23.338 + *   which will be evaluated when the function is invoked
  23.339 + *
  23.340 + * Create a new #XexprConstant that defines an unnamed function. Creating a
  23.341 + * function definition is the first step in defining a function. The second
  23.342 + * step is to bind the definition to a name, eg., using xexpr_var_new().
  23.343 + *
  23.344 + * Returns: (transfer full): the new #XexprConstant
  23.345 + */
  23.346 +XexprConstant *xexpr_new_function_take_ownership(GSList *args,GSList *constants)
  23.347 +{
  23.348 +    XexprConstant *constant;
  23.349 +    constant=g_slice_new(XexprConstant);
  23.350 +    constant->type=XEXPR_TYPE_FUNCTION;
  23.351 +    constant->u.function=g_slice_new(XexprFunction);
  23.352 +    constant->u.function->args=args;
  23.353 +    constant->u.function->constants=constants;
  23.354 +    return constant;
  23.355 +}
  23.356 +
  23.357 +/**
  23.358 + * xexpr_new_function:
  23.359 + * @args: (transfer none) (element-type utf8): the parameter names
  23.360 + * @constants: (transfer none) (element-type XexprConstant): the constants
  23.361 + *   which will be evaluated when the function is invoked
  23.362 + *
  23.363 + * Create a new #XexprConstant that defines an unnamed function. Creating a
  23.364 + * function definition is the first step in defining a function. The second
  23.365 + * step is to bind the definition to a name, eg., using xexpr_var_new().
  23.366 + *
  23.367 + * Returns: (transfer full): the new #XexprConstant
  23.368 + */
  23.369 +XexprConstant *xexpr_new_function(GSList *args,GSList *constants)
  23.370 +{
  23.371 +    GSList *lnk;
  23.372 +    args=g_slist_copy(args);
  23.373 +    for(lnk=args;lnk;lnk=lnk->next)
  23.374 +	lnk->data=g_strdup(lnk->data);
  23.375 +    constants=g_slist_copy(constants);
  23.376 +    for(lnk=constants;lnk;lnk=lnk->next)
  23.377 +	lnk->data=xexpr_constant_dup(lnk->data);
  23.378 +    return xexpr_new_function_take_ownership(args,constants);
  23.379 +}
  23.380 +
  23.381 +/**
  23.382 + * xexpr_new_string_take_ownership:
  23.383 + * @s: (transfer full): the string
  23.384 + *
  23.385 + * Create a new #XexprConstant that consists of the given string.
  23.386 + *
  23.387 + * Returns: (transfer full): the new #XexprConstant
  23.388 + */
  23.389 +XexprConstant *xexpr_new_string_take_ownership(char *s)
  23.390 +{
  23.391 +    XexprConstant *constant;
  23.392 +    constant=g_slice_new(XexprConstant);
  23.393 +    constant->type=XEXPR_TYPE_STRING;
  23.394 +    constant->u.string=s;
  23.395 +    return constant;
  23.396 +}
  23.397 +
  23.398 +/**
  23.399 + * xexpr_new_string:
  23.400 + * @s: (transfer none): the string
  23.401 + * @len: length of @s to use, or -1 to treat @s as nul-terminated
  23.402 + *
  23.403 + * Create a new #XexprConstant that consists of the given string.
  23.404 + *
  23.405 + * Returns: (transfer full): the new #XexprConstant
  23.406 + */
  23.407 +XexprConstant *xexpr_new_string(const char *s,gssize len)
  23.408 +{
  23.409 +    if (len<0)
  23.410 +	len=strlen(s);
  23.411 +    return xexpr_new_string_take_ownership(g_strndup(s,len));
  23.412 +}
  23.413 +
  23.414 +/**
  23.415 + * xexpr_new_integer:
  23.416 + * @integer: the integer
  23.417 + *
  23.418 + * Create a new #XexprConstant that consists of the given integer.
  23.419 + *
  23.420 + * Returns: (transfer full): the new #XexprConstant
  23.421 + */
  23.422 +XexprConstant *xexpr_new_integer(long long int integer)
  23.423 +{
  23.424 +    XexprConstant *constant;
  23.425 +    constant=g_slice_new(XexprConstant);
  23.426 +    constant->type=XEXPR_TYPE_INTEGER;
  23.427 +    constant->u.integer=integer;
  23.428 +    return constant;
  23.429 +}
  23.430 +
  23.431 +/**
  23.432 + * xexpr_new_number:
  23.433 + * @number: the number
  23.434 + *
  23.435 + * Create a new #XexprConstant that consists of the given floating-point number.
  23.436 + *
  23.437 + * Returns: (transfer full): the new #XexprConstant
  23.438 + */
  23.439 +XexprConstant *xexpr_new_number(double number)
  23.440 +{
  23.441 +    XexprConstant *constant;
  23.442 +    constant=g_slice_new(XexprConstant);
  23.443 +    constant->type=XEXPR_TYPE_NUMBER;
  23.444 +    constant->u.number=number;
  23.445 +    return constant;
  23.446 +}
  23.447 +
  23.448 +static XexprEnvironment *xexpr_environment_new(const char *function,
  23.449 +  XexprEnvironment *outer)
  23.450 +{
  23.451 +    XexprEnvironment *environment=g_slice_new0(XexprEnvironment);
  23.452 +    environment->function=g_strdup(function);
  23.453 +    environment->refcount=1;
  23.454 +    environment->outer=outer;
  23.455 +    if (outer)
  23.456 +	outer->refcount++;
  23.457 +    return environment;
  23.458 +}
  23.459 +
  23.460 +/**
  23.461 + * xexpr_environment_foreach:
  23.462 + * @environment: an #XexprEnvironment
  23.463 + * @func: the function to call with each active variable
  23.464 + * @user_data: user data to pass to the function
  23.465 + *
  23.466 + * Calls a function for each active variable in an #XexprEnvironment.
  23.467 + */
  23.468 +void xexpr_environment_foreach(XexprEnvironment *environment,GTraverseFunc func,
  23.469 +  gpointer user_data)
  23.470 +{
  23.471 +    GSList *lnk;
  23.472 +    GSList *environments=NULL;
  23.473 +    GTree *active;
  23.474 +    XexprBinding *binding;
  23.475 +    while(environment)
  23.476 +    {
  23.477 +	environments=g_slist_prepend(environments,environment);
  23.478 +	environment=environment->outer;
  23.479 +    }
  23.480 +    active=g_tree_new((GCompareFunc)strcmp);
  23.481 +    while(environments)
  23.482 +    {
  23.483 +	environment=environments->data;
  23.484 +	environments=g_slist_delete_link(environments,environments);
  23.485 +	for(lnk=environment->bindings;lnk;lnk=lnk->next)
  23.486 +	{
  23.487 +	    binding=lnk->data;
  23.488 +	    g_tree_insert(active,binding->id,binding->value);
  23.489 +	}
  23.490 +    }
  23.491 +    g_tree_foreach(active,func,user_data);
  23.492 +    g_tree_destroy(active);
  23.493 +}
  23.494 +
  23.495 +/**
  23.496 + * xexpr_bindings_get:
  23.497 + * @bindings: (transfer none) (element-type XexprBinding): the bindings to
  23.498 + *   search
  23.499 + * @id: the symbol to search for
  23.500 + *
  23.501 + * Look for a binding of symbol @id in @bindings and return the value if
  23.502 + * found.
  23.503 + *
  23.504 + * Returns: (transfer none): the found #XexprConstant or %NULL
  23.505 + */
  23.506 +XexprConstant *xexpr_bindings_get(GSList *bindings,const char *id)
  23.507 +{
  23.508 +    GSList *lnk;
  23.509 +    XexprBinding *binding;
  23.510 +    for(lnk=bindings;lnk;lnk=lnk->next)
  23.511 +    {
  23.512 +	binding=lnk->data;
  23.513 +	if (!strcmp(binding->id,id))
  23.514 +	    return binding->value;
  23.515 +    }
  23.516 +    return NULL;
  23.517 +}
  23.518 +
  23.519 +/**
  23.520 + * xexpr_bindings_set:
  23.521 + * @bindings: (transfer none) (element-type XexprBinding): the bindings to
  23.522 + *   update
  23.523 + * @id: an existing symbol to set
  23.524 + * @value: (transfer none): the new value
  23.525 + *
  23.526 + * Update an existing binding of symbol @id in @bindings with the new value
  23.527 + * @value. If no existing binding is found, return %FALSE.
  23.528 + *
  23.529 + * Returns: %TRUE if @id was found and updated
  23.530 + */
  23.531 +gboolean xexpr_bindings_set(GSList *bindings,const char *id,
  23.532 +  XexprConstant *value)
  23.533 +{
  23.534 +    GSList *lnk;
  23.535 +    XexprBinding *binding;
  23.536 +    for(lnk=bindings;lnk;lnk=lnk->next)
  23.537 +    {
  23.538 +	binding=lnk->data;
  23.539 +	if (!strcmp(binding->id,id))
  23.540 +	{
  23.541 +	    xexpr_constant_free(binding->value);
  23.542 +	    binding->value=xexpr_constant_dup(value);
  23.543 +	    return TRUE;
  23.544 +	}
  23.545 +    }
  23.546 +    return FALSE;
  23.547 +}
  23.548 +
  23.549 +/**
  23.550 + * xexpr_bindings_new:
  23.551 + * @bindings: (transfer full) (element-type XexprBinding): the bindings to
  23.552 + *   modify
  23.553 + * @id: a symbol to set or create
  23.554 + * @value: (transfer none): the new value
  23.555 + *
  23.556 + * Update an existing binding of symbol @id or create a new one in @bindings
  23.557 + * with the new value @value.
  23.558 + *
  23.559 + * Returns: (transfer full) (element-type XexprBinding): the new bindings list
  23.560 + */
  23.561 +GSList *xexpr_bindings_new(GSList *bindings,const char *id,XexprConstant *value)
  23.562 +{
  23.563 +    XexprBinding *binding;
  23.564 +    if (!xexpr_bindings_set(bindings,id,value))
  23.565 +    {
  23.566 +	binding=g_slice_new(XexprBinding);
  23.567 +	binding->id=g_strdup(id);
  23.568 +	binding->value=xexpr_constant_dup(value);
  23.569 +	bindings=g_slist_prepend(bindings,binding);
  23.570 +    }
  23.571 +    return bindings;
  23.572 +}
  23.573 +
  23.574 +/**
  23.575 + * xexpr_var_get:
  23.576 + * @xexpr: an #Xexpr
  23.577 + * @id: a symbol to look up
  23.578 + *
  23.579 + * Look for a definition of symbol @id in @xexpr and return its value. If
  23.580 + * no definition exists, return %NULL.
  23.581 + *
  23.582 + * Returns: (transfer none): the bound value, or %NULL if not found.
  23.583 + */
  23.584 +XexprConstant *xexpr_var_get(Xexpr *xexpr,const char *id)
  23.585 +{
  23.586 +    XexprConstant *value=NULL;
  23.587 +    XexprEnvironment *environment=xexpr_get_environment(xexpr);
  23.588 +    while(environment && !value)
  23.589 +    {
  23.590 +	value=xexpr_bindings_get(environment->bindings,id);
  23.591 +	environment=environment->outer;
  23.592 +    }
  23.593 +    return value;
  23.594 +}
  23.595 +
  23.596 +/**
  23.597 + * xexpr_var_new:
  23.598 + * @xexpr: an #Xexpr
  23.599 + * @id: a symbol to set or create
  23.600 + * @value: (transfer none): the new value
  23.601 + *
  23.602 + * Update an existing binding of symbol @id in the innermost environment of
  23.603 + * @xexpr or create a new one with the new value @value.
  23.604 + */
  23.605 +void xexpr_var_new(Xexpr *xexpr,const char *id,XexprConstant *value)
  23.606 +{
  23.607 +    XexprEnvironment *environment=xexpr_get_environment(xexpr);
  23.608 +    environment->bindings=xexpr_bindings_new(environment->bindings,id,value);
  23.609 +    if (xexpr_is_tracing(xexpr,id))
  23.610 +    {
  23.611 +	printf("\nCreated new variable %s in frame #0\n",id);
  23.612 +	xexpr_stack_dump(xexpr,stdout);
  23.613 +    }
  23.614 +}
  23.615 +
  23.616 +/**
  23.617 + * xexpr_var_set:
  23.618 + * @xexpr: an #Xexpr
  23.619 + * @id: a symbol to set or create
  23.620 + * @value: (transfer none): the new value
  23.621 + *
  23.622 + * Update the active binding of symbol @id in @xexpr if such exists or create 
  23.623 + * create a new one in the outermost environment with the new value @value.
  23.624 + */
  23.625 +void xexpr_var_set(Xexpr *xexpr,const char *id,XexprConstant *value)
  23.626 +{
  23.627 +    XexprEnvironment *environment=xexpr_get_environment(xexpr);
  23.628 +    while(environment)
  23.629 +    {
  23.630 +	if (xexpr_bindings_set(environment->bindings,id,value))
  23.631 +	{
  23.632 +	    if (xexpr_is_tracing(xexpr,id))
  23.633 +	    {
  23.634 +		printf("\nSet variable %s\n",id);
  23.635 +		xexpr_stack_dump(xexpr,stdout);
  23.636 +	    }
  23.637 +	    return;
  23.638 +	}
  23.639 +	if (environment->outer)
  23.640 +	    environment=environment->outer;
  23.641 +	else
  23.642 +	    break;
  23.643 +    }
  23.644 +    environment->bindings=xexpr_bindings_new(environment->bindings,id,value);
  23.645 +    if (xexpr_is_tracing(xexpr,id))
  23.646 +    {
  23.647 +	printf("\nCreated new global variable %s\n",id);
  23.648 +	xexpr_stack_dump(xexpr,stdout);
  23.649 +    }
  23.650 +}
  23.651 +
  23.652 +/**
  23.653 + * xexpr_constant_dup:
  23.654 + * @constant: an #XexprConstant to duplicate
  23.655 + *
  23.656 + * Duplicate @constant.
  23.657 + *
  23.658 + * Returns: (transfer full): the new #XexprConstant
  23.659 + */
  23.660 +XexprConstant *xexpr_constant_dup(XexprConstant *constant)
  23.661 +{
  23.662 +    switch(constant->type)
  23.663 +    {
  23.664 +	case XEXPR_TYPE_INVOCATION:
  23.665 +	    return xexpr_new_invocation(constant->u.invocation->ns,
  23.666 +	      constant->u.invocation->function,constant->u.invocation->bindings,
  23.667 +	      constant->u.invocation->constants);
  23.668 +	    break;
  23.669 +	case XEXPR_TYPE_FUNCTION:
  23.670 +	    return xexpr_new_function(constant->u.function->args,
  23.671 +	      constant->u.function->constants);
  23.672 +	    break;
  23.673 +	case XEXPR_TYPE_STRING:
  23.674 +	    return xexpr_new_string(constant->u.string,-1);
  23.675 +	    break;
  23.676 +	case XEXPR_TYPE_INTEGER:
  23.677 +	    return xexpr_new_integer(constant->u.integer);
  23.678 +	    break;
  23.679 +	case XEXPR_TYPE_NUMBER:
  23.680 +	    return xexpr_new_number(constant->u.number);
  23.681 +	    break;
  23.682 +    }
  23.683 +    return NULL;
  23.684 +}
  23.685 +
  23.686 +/**
  23.687 + * xexpr_bindings_dup:
  23.688 + * @bindings: (transfer none) (element-type XexprBinding): a list of bindings
  23.689 + *   to duplicate
  23.690 + *
  23.691 + * Duplicate @bindings.
  23.692 + *
  23.693 + * Returns: (transfer full) (element-type XexprBinging): the new bindings list
  23.694 + */
  23.695 +GSList *xexpr_bindings_dup(GSList *bindings)
  23.696 +{
  23.697 +    GSList *lnk,*list=NULL;
  23.698 +    XexprBinding *binding,*dup;
  23.699 +    for(lnk=bindings;lnk;lnk=lnk->next)
  23.700 +    {
  23.701 +	binding=lnk->data;
  23.702 +	dup=g_slice_new(XexprBinding);
  23.703 +	dup->id=g_strdup(binding->id);
  23.704 +	dup->value=xexpr_constant_dup(binding->value);
  23.705 +	list=g_slist_prepend(list,dup);
  23.706 +    }
  23.707 +    return g_slist_reverse(list);
  23.708 +}
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/libxexpr/xexprtypes.h	Wed Oct 10 22:58:21 2012 +0100
    24.3 @@ -0,0 +1,176 @@
    24.4 +#ifndef __XEXPER_TYPES_H__
    24.5 +#define __XEXPER_TYPES_H__
    24.6 +
    24.7 +#include <glib.h>
    24.8 +#include <libxml/tree.h>
    24.9 +
   24.10 +G_BEGIN_DECLS
   24.11 +
   24.12 +/**
   24.13 + * XexprInvocation:
   24.14 + * @ns: the namespace to which @function belongs, or %NULL
   24.15 + * @function: the function to be invoked
   24.16 + * @bindings: (element-type XexprBinding): the pre-bound arguments
   24.17 + * @constants: (element-type XexprConstant): the other arguments
   24.18 + *
   24.19 + * A structure describing the invocation of a function.
   24.20 + */
   24.21 +typedef struct xexpr_invocation {
   24.22 +    char *ns;
   24.23 +    char *function;
   24.24 +    GSList *bindings;
   24.25 +    GSList *constants;
   24.26 +} XexprInvocation;
   24.27 +
   24.28 +/**
   24.29 + * XexprFunction:
   24.30 + * @args: (element-type utf8): the parameter names
   24.31 + * @constants: (element-type XexprConstant): the constants
   24.32 + *   which will be evaluated when the function is invoked
   24.33 + *
   24.34 + * A structure describing the definition of a function.
   24.35 + */
   24.36 +typedef struct xexpr_function {
   24.37 +    GSList *args;
   24.38 +    GSList *constants;
   24.39 +} XexprFunction;
   24.40 +
   24.41 +typedef struct xexpr_constant XexprConstant;
   24.42 +
   24.43 +/**
   24.44 + * XexprBinding:
   24.45 + * @id: the bound name
   24.46 + * @value: the expresion bound to @id
   24.47 + *
   24.48 + * A structure describing the binding of a value to a name.
   24.49 + */
   24.50 +typedef struct xexpr_binding {
   24.51 +    char *id;
   24.52 +    XexprConstant *value;
   24.53 +} XexprBinding;
   24.54 +
   24.55 +/**
   24.56 + * XexprType:
   24.57 + * @XEXPR_TYPE_INVOCATION: a function invocation
   24.58 + * @XEXPR_TYPE_FUNCTION: a function definition
   24.59 + * @XEXPR_TYPE_STRING: a string
   24.60 + * @XEXPR_TYPE_INTEGER: an integer
   24.61 + * @XEXPR_TYPE_NUMBER: a floating-point number
   24.62 + *
   24.63 + * Enum values for the type, to specify the type of expression.
   24.64 + */
   24.65 +typedef enum {
   24.66 +    XEXPR_TYPE_INVOCATION=1,
   24.67 +    XEXPR_TYPE_FUNCTION,
   24.68 +    XEXPR_TYPE_STRING,
   24.69 +    XEXPR_TYPE_INTEGER,
   24.70 +    XEXPR_TYPE_NUMBER
   24.71 +} XexprType;
   24.72 +
   24.73 +/**
   24.74 + * XexprConstant:
   24.75 + * @type: the type of expression
   24.76 + * @u: type-specific parameters
   24.77 + *
   24.78 + * A structure describing an XEXPR expression
   24.79 + */
   24.80 +struct xexpr_constant {
   24.81 +    XexprType type;
   24.82 +    union {
   24.83 +	XexprInvocation *invocation;
   24.84 +	XexprFunction *function;
   24.85 +	char *string;
   24.86 +	long long int integer;
   24.87 +	double number;
   24.88 +    } u;
   24.89 +};
   24.90 +
   24.91 +/**
   24.92 + * XexprEnvironment:
   24.93 + * @function: the name of the function to which the environment belongs,
   24.94 + *   or %NULL if this is the outermost environment
   24.95 + * @outer: the next environment in the chain from innermost to outermost,
   24.96 + *   or %NULL if this is the outermost environment
   24.97 + * @bindings: (element-type XexprBinding): the variables set in this environment
   24.98 + *
   24.99 + * A structure describing an XEXPR environment
  24.100 + */
  24.101 +typedef struct xexpr_environment {
  24.102 +    /*< private >*/
  24.103 +    int refcount;
  24.104 +    /*< public >*/
  24.105 +    char *function;
  24.106 +    struct xexpr_environment *outer;
  24.107 +    GSList *bindings;
  24.108 +} XexprEnvironment;
  24.109 +
  24.110 +/**
  24.111 + * Xexpr:
  24.112 + * @constants: (element-type XexprConstant): the constants that make up this
  24.113 + *   expression
  24.114 + * @environment: the innermost environment
  24.115 + *
  24.116 + * A structure describing an XEXPR expression
  24.117 + */
  24.118 +typedef struct xexpr {
  24.119 +    /*< private >*/
  24.120 +    GSList *tracing;
  24.121 +    /*< public >*/
  24.122 +    GSList *constants;
  24.123 +    XexprEnvironment *environment;
  24.124 +} Xexpr;
  24.125 +
  24.126 +/**
  24.127 + * XexprExtension:
  24.128 + * @ns: the namespace of the extension
  24.129 + * @function_evaluate: evaluates functions defined in the extension
  24.130 + *
  24.131 + * A structure describing an XEXPR extension
  24.132 + */
  24.133 +typedef struct xexpr_extension {
  24.134 +    char *ns;
  24.135 +    XexprConstant *(*function_evaluate)(Xexpr *xexpr,const char *ns,
  24.136 +      const char *id,GSList *bindings,GSList *args,GError **err);
  24.137 +} XexprExtension;
  24.138 +
  24.139 +XexprConstant *xexpr_new_string(const char *s,gssize len);
  24.140 +XexprConstant *xexpr_new_string_take_ownership(char *s);
  24.141 +XexprConstant *xexpr_new_integer(long long int integer);
  24.142 +XexprConstant *xexpr_new_number(double number);
  24.143 +XexprConstant *xexpr_new_invocation(const char *ns,const char *function,
  24.144 +  GSList *bindings,GSList *constants);
  24.145 +XexprConstant *xexpr_new_invocation_take_ownership(char *ns,char *function,
  24.146 +  GSList *bindings,GSList *constants);
  24.147 +XexprConstant *xexpr_new_function_take_ownership(GSList *args,
  24.148 +  GSList *constants);
  24.149 +XexprConstant *xexpr_new_function(GSList *args,GSList *constants);
  24.150 +XexprConstant *xexpr_constant_dup(XexprConstant *constant);
  24.151 +void xexpr_constant_free(XexprConstant *constant);
  24.152 +
  24.153 +void xexpr_binding_free(XexprBinding *binding);
  24.154 +
  24.155 +XexprConstant *xexpr_bindings_get(GSList *bindings,const char *id);
  24.156 +gboolean xexpr_bindings_set(GSList *bindings,const char *id,
  24.157 +  XexprConstant *value);
  24.158 +GSList *xexpr_bindings_new(GSList *bindings,const char *id,
  24.159 +  XexprConstant *value);
  24.160 +GSList *xexpr_bindings_dup(GSList *bindings);
  24.161 +
  24.162 +Xexpr *xexpr_new(void);
  24.163 +Xexpr *xexpr_sub(Xexpr *xexpr);
  24.164 +void xexpr_var_new(Xexpr *xexpr,const char *id,XexprConstant *value);
  24.165 +void xexpr_var_set(Xexpr *xexpr,const char *id,XexprConstant *value);
  24.166 +XexprConstant *xexpr_var_get(Xexpr *xexpr,const char *id);
  24.167 +void xexpr_start_tracing(Xexpr *xexpr,const char *id);
  24.168 +gboolean xexpr_is_tracing(Xexpr *xexpr,const char *id);
  24.169 +void xexpr_free(Xexpr *xexpr);
  24.170 +XexprEnvironment *xexpr_get_environment(Xexpr *xexpr);
  24.171 +void xexpr_set_constants(Xexpr *xexpr,GSList *constants);
  24.172 +void xexpr_set_constants_take_ownership(Xexpr *xexpr,GSList *constants);
  24.173 +
  24.174 +void xexpr_environment_foreach(XexprEnvironment *environment,GTraverseFunc func,
  24.175 +  gpointer user_data);
  24.176 +
  24.177 +G_END_DECLS
  24.178 +
  24.179 +#endif	/* __XEXPER_TYPES_H__ */
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/Makefile.am	Wed Oct 10 22:58:21 2012 +0100
    25.3 @@ -0,0 +1,4 @@
    25.4 +AM_CFLAGS=$(LIBXEXPR_CFLAGS) -g -I$(top_srcdir)
    25.5 +LDADD=../libxexpr/libxexpr.la $(LIBXEXPR_LIBS)
    25.6 +
    25.7 +bin_PROGRAMS=xexpr
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/xexpr.c	Wed Oct 10 22:58:21 2012 +0100
    26.3 @@ -0,0 +1,193 @@
    26.4 +#include <stdlib.h>
    26.5 +#include <string.h>
    26.6 +#include <math.h>
    26.7 +#include <glib.h>
    26.8 +#include <libxml/parser.h>
    26.9 +#include <libxexpr/xexpr.h>
   26.10 +
   26.11 +gboolean dump_tree,dump_result,test_result,do_xinclude;
   26.12 +gchar **files;
   26.13 +
   26.14 +gboolean trace_symbol(const gchar *option_name,const gchar *value,gpointer data,
   26.15 +  GError **err)
   26.16 +{
   26.17 +    Xexpr *xexpr=data;
   26.18 +    xexpr_start_tracing(xexpr,value);
   26.19 +    return TRUE;
   26.20 +}
   26.21 +
   26.22 +gboolean set_param(const gchar *option_name,const gchar *value,gpointer data,
   26.23 +  GError **err)
   26.24 +{
   26.25 +    const char *s;
   26.26 +    char *endptr;
   26.27 +    double d,integer;
   26.28 +    gchar *name;
   26.29 +    XexprConstant *arg;
   26.30 +    Xexpr *xexpr=data;
   26.31 +    s=strchr(value,',');
   26.32 +    if (!s)
   26.33 +    {
   26.34 +	g_set_error(err,G_OPTION_ERROR,G_OPTION_ERROR_BAD_VALUE,
   26.35 +	  "No comma found in --param argument \"%s\"",value);
   26.36 +	return FALSE;
   26.37 +    }
   26.38 +    name=g_strndup(value,s-value);
   26.39 +    d=strtod(s+1,&endptr);
   26.40 +    if (!d || *endptr)
   26.41 +    {
   26.42 +	g_set_error(err,G_OPTION_ERROR,G_OPTION_ERROR_BAD_VALUE,
   26.43 +	  "Invalid number in --param argument: \"%s\"",s);
   26.44 +	return FALSE;
   26.45 +    }
   26.46 +    if (!modf(d,&integer))
   26.47 +	arg=xexpr_new_integer(integer);
   26.48 +    else
   26.49 +	arg=xexpr_new_number(d);
   26.50 +    xexpr_var_set(xexpr,name,arg);
   26.51 +    xexpr_constant_free(arg);
   26.52 +    return TRUE;
   26.53 +}
   26.54 +
   26.55 +gboolean set_string_param(const gchar *option_name,const gchar *value,
   26.56 +  gpointer data,GError **err)
   26.57 +{
   26.58 +    const char *s;
   26.59 +    char *endptr;
   26.60 +    double d,integer;
   26.61 +    gchar *name;
   26.62 +    XexprConstant *arg;
   26.63 +    Xexpr *xexpr=data;
   26.64 +    s=strchr(value,',');
   26.65 +    if (!s)
   26.66 +    {
   26.67 +	g_set_error(err,G_OPTION_ERROR,G_OPTION_ERROR_BAD_VALUE,
   26.68 +	  "No comma found in --stringparam argument \"%s\"",value);
   26.69 +	return FALSE;
   26.70 +    }
   26.71 +    name=g_strndup(value,s-value);
   26.72 +    arg=xexpr_new_string(s+1,-1);
   26.73 +    xexpr_var_set(xexpr,name,arg);
   26.74 +    xexpr_constant_free(arg);
   26.75 +    return TRUE;
   26.76 +}
   26.77 +
   26.78 +static GOptionEntry entries[]={
   26.79 +    { "dump-tree",'d',0,G_OPTION_ARG_NONE,&dump_tree,"Dump parsed file",NULL },
   26.80 +    { "dump-result",'D',0,G_OPTION_ARG_NONE,&dump_result,"Dump result",NULL },
   26.81 +    { "test-result",'t',0,G_OPTION_ARG_NONE,&test_result,"Test result",NULL },
   26.82 +    { "trace",'T',0,G_OPTION_ARG_CALLBACK,trace_symbol,"Trace symbol",NULL },
   26.83 +    { G_OPTION_REMAINING,0,0,G_OPTION_ARG_FILENAME_ARRAY,&files,NULL,
   26.84 +      "[<input>]" },
   26.85 +    { "xinclude",0,0,G_OPTION_ARG_NONE,&do_xinclude,"Do XInclude processing",
   26.86 +      NULL },
   26.87 +    { "param",0,0,G_OPTION_ARG_CALLBACK,set_param,
   26.88 +      "Pass a (parameter,number) pair",NULL },
   26.89 +    { "stringparam",0,0,G_OPTION_ARG_CALLBACK,set_string_param,
   26.90 +      "Pass a (parameter,string) pair",NULL },
   26.91 +    { NULL }
   26.92 +};
   26.93 +
   26.94 +gboolean set_variable(gpointer key,gpointer value,gpointer data)
   26.95 +{
   26.96 +    xexpr_var_set(data,key,value);
   26.97 +    return FALSE;
   26.98 +}
   26.99 +
  26.100 +gboolean run_xexpr(Xexpr *xexpr,xmlDocPtr doc,const char *filename)
  26.101 +{
  26.102 +    gboolean retval=TRUE;
  26.103 +    GError *err=NULL;
  26.104 +    Xexpr *sub,*result;
  26.105 +    sub=xexpr_sub(xexpr);
  26.106 +    xexpr_environment_foreach(xexpr_get_environment(xexpr),set_variable,sub);
  26.107 +    if (!xexpr_parse_node(sub,xmlDocGetRootElement(doc),&err))
  26.108 +    {
  26.109 +	fprintf(stderr,"%s: %s\n",filename,err->message);
  26.110 +	exit(1);
  26.111 +    }
  26.112 +    if (dump_tree)
  26.113 +    {
  26.114 +	xexpr_dump(sub,stdout);
  26.115 +	putchar('\n');
  26.116 +    }
  26.117 +    else
  26.118 +    {
  26.119 +	result=xexpr_evaluate(sub,&err);
  26.120 +	if (err)
  26.121 +	{
  26.122 +	    fprintf(stderr,"%s: %s\n",filename,err->message);
  26.123 +	    g_clear_error(&err);
  26.124 +	    xexpr_free(sub);
  26.125 +	    return FALSE;
  26.126 +	}
  26.127 +	if (dump_result)
  26.128 +	{
  26.129 +	    printf("\nResult: ");
  26.130 +	    xexpr_dump(result,stdout);
  26.131 +	    putchar('\n');
  26.132 +	}
  26.133 +	if (test_result)
  26.134 +	    retval=xexpr_test(result,NULL);
  26.135 +	xexpr_free(result);
  26.136 +    }
  26.137 +    xexpr_free(sub);
  26.138 +    return retval;
  26.139 +}
  26.140 +
  26.141 +int main(int argc,char **argv)
  26.142 +{
  26.143 +    int i;
  26.144 +    xmlDocPtr doc;
  26.145 +    int xml_options=XML_PARSE_NOENT;
  26.146 +    gboolean result=TRUE;
  26.147 +    GError *err=NULL;
  26.148 +    GOptionGroup *group;
  26.149 +    GOptionContext *context;
  26.150 +    Xexpr *xexpr;
  26.151 +    xexpr=xexpr_new();
  26.152 +    context=g_option_context_new("- XEXPR interpreter");
  26.153 +    group=g_option_group_new(NULL,NULL,NULL,xexpr,NULL);
  26.154 +    g_option_group_add_entries(group,entries);
  26.155 +    g_option_context_set_main_group(context,group);
  26.156 +    if (!g_option_context_parse(context,&argc,&argv,&err))
  26.157 +    {
  26.158 +	fprintf(stderr,"%s\n",err->message);
  26.159 +	exit(1);
  26.160 +    }
  26.161 +    if (do_xinclude)
  26.162 +	xml_options|=XML_PARSE_XINCLUDE|XML_PARSE_NOXINCNODE;
  26.163 +    if (files && files[0])
  26.164 +    {
  26.165 +	for(i=0;files[i];i++)
  26.166 +	{
  26.167 +	    doc=xmlReadFile(files[i],NULL,xml_options);
  26.168 +	    if (!doc)
  26.169 +		result=FALSE;
  26.170 +	    else
  26.171 +	    {
  26.172 +		if (do_xinclude && xmlXIncludeProcessFlags(doc,xml_options)<0)
  26.173 +		    result=FALSE;
  26.174 +		else if (!run_xexpr(xexpr,doc,files[i]))
  26.175 +		    result=FALSE;
  26.176 +		xmlFreeDoc(doc);
  26.177 +	    }
  26.178 +	}
  26.179 +    }
  26.180 +    else
  26.181 +    {
  26.182 +	doc=xmlReadFd(0,NULL,NULL,xml_options);
  26.183 +	if (!doc)
  26.184 +	    result=FALSE;
  26.185 +	else
  26.186 +	{
  26.187 +	    if (do_xinclude && xmlXIncludeProcessFlags(doc,xml_options)<0)
  26.188 +		result=FALSE;
  26.189 +	    else if (!run_xexpr(xexpr,doc,"stdin"))
  26.190 +		result=FALSE;
  26.191 +	    xmlFreeDoc(doc);
  26.192 +	}
  26.193 +    }
  26.194 +    xexpr_free(xexpr);
  26.195 +    exit(result?0:1);
  26.196 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/test/Makefile.am	Wed Oct 10 22:58:21 2012 +0100
    27.3 @@ -0,0 +1,1 @@
    27.4 +SUBDIRS=spec idb libxexpr
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/test/idb/Makefile.am	Wed Oct 10 22:58:21 2012 +0100
    28.3 @@ -0,0 +1,11 @@
    28.4 +TESTS_ENVIRONMENT=top_builddir="$(top_builddir)"
    28.5 +check_SCRIPTS=numbers bindings pcdata define get arithmetic comparison \
    28.6 +    builtin namespaces
    28.7 +TESTS=$(check_SCRIPTS)
    28.8 +
    28.9 +%:	%.sh
   28.10 +	cp $(srcdir)/$*.sh $@
   28.11 +	chmod +x $@
   28.12 +
   28.13 +EXTRA_DIST=$(check_SCRIPTS:%=%.sh) $(check_SCRIPTS:%=%.xml)
   28.14 +CLEANFILES=$(check_SCRIPTS)
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/test/idb/arithmetic.sh	Wed Oct 10 22:58:21 2012 +0100
    29.3 @@ -0,0 +1,11 @@
    29.4 +#!/bin/sh
    29.5 +$top_builddir/src/xexpr $srcdir/arithmetic.xml > arithmetic.out
    29.6 +cat <<-EOF > arithmetic.ref
    29.7 +9
    29.8 +6
    29.9 +20
   29.10 +EOF
   29.11 +cmp arithmetic.out arithmetic.ref
   29.12 +retval=$?
   29.13 +rm -f arithmetic.out arithmetic.ref
   29.14 +exit $retval
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/test/idb/arithmetic.xml	Wed Oct 10 22:58:21 2012 +0100
    30.3 @@ -0,0 +1,15 @@
    30.4 +<expr>
    30.5 +  <define name="x"><multiply>2 3</multiply></define>
    30.6 +  <add><x/>3</add>
    30.7 +  <print><x/></print>
    30.8 +  <println/>
    30.9 +
   30.10 +  <define name="x"><multiply>2 3</multiply></define>
   30.11 +  <add><x unused=""/>3</add>
   30.12 +  <print><x/></print>
   30.13 +  <println/>
   30.14 +
   30.15 +  <set name="x">5</set>
   30.16 +  <add><x/><x/><x/></add>
   30.17 +  <print newline="true"><x/></print>
   30.18 +</expr>
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/test/idb/bindings.sh	Wed Oct 10 22:58:21 2012 +0100
    31.3 @@ -0,0 +1,2 @@
    31.4 +#!/bin/sh
    31.5 +$top_builddir/src/xexpr --test-result $srcdir/bindings.xml
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/test/idb/bindings.xml	Wed Oct 10 22:58:21 2012 +0100
    32.3 @@ -0,0 +1,47 @@
    32.4 +<expr>
    32.5 +  <define name="func" args="x"><x/></define>
    32.6 +
    32.7 +  <and>
    32.8 +    <if>
    32.9 +      <eq>
   32.10 +      <func x="+01 "/>
   32.11 +      <func>
   32.12 +	<define name="x"><integer>1</integer></define>
   32.13 +      </func>
   32.14 +      </eq>
   32.15 +      <print newline="true">PASS</print>
   32.16 +      <expr>
   32.17 +	<print newline="true">FAIL</print>
   32.18 +	<false/>
   32.19 +      </expr>
   32.20 +    </if>
   32.21 +
   32.22 +    <if>
   32.23 +      <eq>
   32.24 +	<func x=" 14.0e-1"/>
   32.25 +	<func>
   32.26 +	  <define name="x"><float>1.4</float></define>
   32.27 +	</func>
   32.28 +      </eq>
   32.29 +      <print newline="true">PASS</print>
   32.30 +      <expr>
   32.31 +	<print newline="true">FAIL</print>
   32.32 +	<false/>
   32.33 +      </expr>
   32.34 +    </if>
   32.35 +
   32.36 +    <if>
   32.37 +      <eq>
   32.38 +	<func x="Hello "/>
   32.39 +	<func>
   32.40 +	  <define name="x"><string>Hello </string></define>
   32.41 +	</func>
   32.42 +      </eq>
   32.43 +      <print newline="true">PASS</print>
   32.44 +      <expr>
   32.45 +	<print newline="true">FAIL</print>
   32.46 +	<false/>
   32.47 +      </expr>
   32.48 +    </if>
   32.49 +  </and>
   32.50 +</expr>
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/test/idb/builtin.sh	Wed Oct 10 22:58:21 2012 +0100
    33.3 @@ -0,0 +1,3 @@
    33.4 +#!/bin/sh
    33.5 +$top_builddir/src/xexpr $srcdir/builtin.xml >& /dev/null && exit 1
    33.6 +exit 0
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/test/idb/builtin.xml	Wed Oct 10 22:58:21 2012 +0100
    34.3 @@ -0,0 +1,4 @@
    34.4 +<expr>
    34.5 +  <define name="println"><print newline="true"/></define>
    34.6 +  <println/>
    34.7 +</expr>
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/test/idb/comparison.sh	Wed Oct 10 22:58:21 2012 +0100
    35.3 @@ -0,0 +1,2 @@
    35.4 +#!/bin/sh
    35.5 +$top_builddir/src/xexpr --test-result $srcdir/comparison.xml
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/test/idb/comparison.xml	Wed Oct 10 22:58:21 2012 +0100
    36.3 @@ -0,0 +1,224 @@
    36.4 +<and>
    36.5 +  <if>
    36.6 +    <eq>
    36.7 +      <eq/>
    36.8 +      <true/>
    36.9 +    </eq>
   36.10 +    <print newline="true">PASS</print>
   36.11 +    <expr>
   36.12 +      <print newline="true">FAIL</print>
   36.13 +      <false/>
   36.14 +    </expr>
   36.15 +  </if>
   36.16 +
   36.17 +  <if>
   36.18 +    <eq>
   36.19 +      <neq/>
   36.20 +      <true/>
   36.21 +    </eq>
   36.22 +    <print newline="true">PASS</print>
   36.23 +    <expr>
   36.24 +      <print newline="true">FAIL</print>
   36.25 +      <false/>
   36.26 +    </expr>
   36.27 +  </if>
   36.28 +
   36.29 +  <if>
   36.30 +    <eq>
   36.31 +      <leq/>
   36.32 +      <true/>
   36.33 +    </eq>
   36.34 +    <print newline="true">PASS</print>
   36.35 +    <expr>
   36.36 +      <print newline="true">FAIL</print>
   36.37 +      <false/>
   36.38 +    </expr>
   36.39 +  </if>
   36.40 +
   36.41 +  <if>
   36.42 +    <eq>
   36.43 +      <geq/>
   36.44 +      <true/>
   36.45 +    </eq>
   36.46 +    <print newline="true">PASS</print>
   36.47 +    <expr>
   36.48 +      <print newline="true">FAIL</print>
   36.49 +      <false/>
   36.50 +    </expr>
   36.51 +  </if>
   36.52 +
   36.53 +  <if>
   36.54 +    <eq>
   36.55 +      <lt/>
   36.56 +      <true/>
   36.57 +    </eq>
   36.58 +    <print newline="true">PASS</print>
   36.59 +    <expr>
   36.60 +      <print newline="true">FAIL</print>
   36.61 +      <false/>
   36.62 +    </expr>
   36.63 +  </if>
   36.64 +
   36.65 +  <if>
   36.66 +    <eq>
   36.67 +      <gt/>
   36.68 +      <true/>
   36.69 +    </eq>
   36.70 +    <print newline="true">PASS</print>
   36.71 +    <expr>
   36.72 +      <print newline="true">FAIL</print>
   36.73 +      <false/>
   36.74 +    </expr>
   36.75 +  </if>
   36.76 +
   36.77 +  <if>
   36.78 +    <eq>
   36.79 +      <eq><false/></eq>
   36.80 +      <true/>
   36.81 +    </eq>
   36.82 +    <print newline="true">PASS</print>
   36.83 +    <expr>
   36.84 +      <print newline="true">FAIL</print>
   36.85 +      <false/>
   36.86 +    </expr>
   36.87 +  </if>
   36.88 +
   36.89 +  <if>
   36.90 +    <eq>
   36.91 +      <neq><string>Hello</string></neq>
   36.92 +      <true/>
   36.93 +    </eq>
   36.94 +    <print newline="true">PASS</print>
   36.95 +    <expr>
   36.96 +      <print newline="true">FAIL</print>
   36.97 +      <false/>
   36.98 +    </expr>
   36.99 +  </if>
  36.100 +
  36.101 +  <if>
  36.102 +    <eq>
  36.103 +      <leq><float>27.2</float></leq>
  36.104 +      <true/>
  36.105 +    </eq>
  36.106 +    <print newline="true">PASS</print>
  36.107 +    <expr>
  36.108 +      <print newline="true">FAIL</print>
  36.109 +      <false/>
  36.110 +    </expr>
  36.111 +  </if>
  36.112 +
  36.113 +  <if>
  36.114 +    <eq>
  36.115 +      <geq><define name="x">0</define></geq>
  36.116 +      <true/>
  36.117 +    </eq>
  36.118 +    <print newline="true">PASS</print>
  36.119 +    <expr>
  36.120 +      <print newline="true">FAIL</print>
  36.121 +      <false/>
  36.122 +    </expr>
  36.123 +  </if>
  36.124 +
  36.125 +  <if>
  36.126 +    <eq>
  36.127 +      <lt><integer>3</integer></lt>
  36.128 +      <true/>
  36.129 +    </eq>
  36.130 +    <print newline="true">PASS</print>
  36.131 +    <expr>
  36.132 +      <print newline="true">FAIL</print>
  36.133 +      <false/>
  36.134 +    </expr>
  36.135 +  </if>
  36.136 +
  36.137 +  <if>
  36.138 +    <eq>
  36.139 +      <gt><get name="x"/></gt>
  36.140 +      <true/>
  36.141 +    </eq>
  36.142 +    <print newline="true">PASS</print>
  36.143 +    <expr>
  36.144 +      <print newline="true">FAIL</print>
  36.145 +      <false/>
  36.146 +    </expr>
  36.147 +  </if>
  36.148 +
  36.149 +  <if>
  36.150 +    <eq>
  36.151 +      <lt>1 2 3</lt>
  36.152 +      <true/>
  36.153 +    </eq>
  36.154 +    <print newline="true">PASS</print>
  36.155 +    <expr>
  36.156 +      <print newline="true">FAIL</print>
  36.157 +      <false/>
  36.158 +    </expr>
  36.159 +  </if>
  36.160 +
  36.161 +  <if>
  36.162 +    <eq>
  36.163 +      <leq>1 2 3</leq>
  36.164 +      <true/>
  36.165 +    </eq>
  36.166 +    <print newline="true">PASS</print>
  36.167 +    <expr>
  36.168 +      <print newline="true">FAIL</print>
  36.169 +      <false/>
  36.170 +    </expr>
  36.171 +  </if>
  36.172 +
  36.173 +  <if>
  36.174 +    <eq>
  36.175 +      <eq><float>35</float><integer>35</integer></eq>
  36.176 +      <true/>
  36.177 +    </eq>
  36.178 +    <print newline="true">PASS</print>
  36.179 +    <expr>
  36.180 +      <print newline="true">FAIL</print>
  36.181 +      <false/>
  36.182 +    </expr>
  36.183 +  </if>
  36.184 +
  36.185 +  <if>
  36.186 +    <eq>
  36.187 +      <gt><string>œ</string><string>æ</string></gt>
  36.188 +      <true/>
  36.189 +    </eq>
  36.190 +    <print newline="true">PASS</print>
  36.191 +    <expr>
  36.192 +      <print newline="true">FAIL</print>
  36.193 +      <false/>
  36.194 +    </expr>
  36.195 +  </if>
  36.196 +
  36.197 +  <if>
  36.198 +    <eq>
  36.199 +      <lt>
  36.200 +        <define name="x"><define name="y">2</define></define>
  36.201 +        <define name="z">3</define>
  36.202 +      </lt>
  36.203 +      <true/>
  36.204 +    </eq>
  36.205 +    <print newline="true">PASS</print>
  36.206 +    <expr>
  36.207 +      <print newline="true">FAIL</print>
  36.208 +      <false/>
  36.209 +    </expr>
  36.210 +  </if>
  36.211 +
  36.212 +  <if>
  36.213 +    <eq>
  36.214 +      <lt>
  36.215 +        <false/>
  36.216 +        <nil/>
  36.217 +        <true/>
  36.218 +      </lt>
  36.219 +      <true/>
  36.220 +    </eq>
  36.221 +    <print newline="true">PASS</print>
  36.222 +    <expr>
  36.223 +      <print newline="true">FAIL</print>
  36.224 +      <false/>
  36.225 +    </expr>
  36.226 +  </if>
  36.227 +</and>
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/test/idb/define.sh	Wed Oct 10 22:58:21 2012 +0100
    37.3 @@ -0,0 +1,2 @@
    37.4 +#!/bin/sh
    37.5 +$top_builddir/src/xexpr --test-result $srcdir/define.xml
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/test/idb/define.xml	Wed Oct 10 22:58:21 2012 +0100
    38.3 @@ -0,0 +1,35 @@
    38.4 +<expr>
    38.5 +  <define name="x">1</define>
    38.6 +
    38.7 +  <and>
    38.8 +    <if>
    38.9 +      <eq>
   38.10 +      <expr>
   38.11 +	<define name="x"><integer>2</integer></define>
   38.12 +	<x/>
   38.13 +      </expr>
   38.14 +      <x/>
   38.15 +      </eq>
   38.16 +      <expr>
   38.17 +	<print newline="true">FAIL</print>
   38.18 +	<false/>
   38.19 +      </expr>
   38.20 +      <print newline="true">PASS</print>
   38.21 +    </if>
   38.22 +
   38.23 +    <if>
   38.24 +      <eq>
   38.25 +      <expr>
   38.26 +	<set name="x"><integer>2</integer></set>
   38.27 +	<x/>
   38.28 +      </expr>
   38.29 +      <x/>
   38.30 +      </eq>
   38.31 +      <print newline="true">PASS</print>
   38.32 +      <expr>
   38.33 +	<print newline="true">FAIL</print>
   38.34 +	<false/>
   38.35 +      </expr>
   38.36 +    </if>
   38.37 +  </and>
   38.38 +</expr>
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/test/idb/get.sh	Wed Oct 10 22:58:21 2012 +0100
    39.3 @@ -0,0 +1,2 @@
    39.4 +#!/bin/sh
    39.5 +$top_builddir/src/xexpr --test-result $srcdir/get.xml
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/test/idb/get.xml	Wed Oct 10 22:58:21 2012 +0100
    40.3 @@ -0,0 +1,80 @@
    40.4 +<expr>
    40.5 +  <define name="x">1</define>
    40.6 +  <define name=".product" args="a b c d">
    40.7 +    <add>
    40.8 +      <multiply>
    40.9 +	<a/>
   40.10 +	<b/>
   40.11 +      </multiply>
   40.12 +      <multiply>
   40.13 +	<c/>
   40.14 +	<d/>
   40.15 +      </multiply>
   40.16 +    </add>
   40.17 +  </define>
   40.18 +
   40.19 +  <and>
   40.20 +    <if>
   40.21 +      <eq>
   40.22 +	<get name="x"/>
   40.23 +	<get>x</get>
   40.24 +      </eq>
   40.25 +      <print newline="true">PASS</print>
   40.26 +      <expr>
   40.27 +	<print newline="true">FAIL</print>
   40.28 +	<false/>
   40.29 +      </expr>
   40.30 +    </if>
   40.31 +
   40.32 +    <if>
   40.33 +      <eq>
   40.34 +	<expr>
   40.35 +	  <set name="x">1</set>
   40.36 +	  <add><x/>1</add>
   40.37 +	  <x/>
   40.38 +	</expr>
   40.39 +	<expr>
   40.40 +	  <set name="x">1</set>
   40.41 +	  <add><get>x</get>1</add>
   40.42 +	  <x/>
   40.43 +	</expr>
   40.44 +      </eq>
   40.45 +      <expr>
   40.46 +	<print newline="true">FAIL</print>
   40.47 +	<false/>
   40.48 +      </expr>
   40.49 +      <print newline="true">PASS</print>
   40.50 +    </if>
   40.51 +
   40.52 +    <if>
   40.53 +      <eq>
   40.54 +	<define name=".net">4.5.50709</define>
   40.55 +	<get>.net</get>
   40.56 +      </eq>
   40.57 +      <print newline="true">PASS</print>
   40.58 +      <expr>
   40.59 +	<print newline="true">FAIL</print>
   40.60 +	<false/>
   40.61 +      </expr>
   40.62 +    </if>
   40.63 +
   40.64 +    <if>
   40.65 +      <eq>
   40.66 +	<expr>
   40.67 +	  <define name="closure"/>
   40.68 +	  <set name="closure">
   40.69 +	    <get>.product</get>
   40.70 +	  </set>
   40.71 +	  <closure>1 2 3 4</closure>
   40.72 +	</expr>
   40.73 +	14
   40.74 +      </eq>
   40.75 +      <print newline="true">PASS</print>
   40.76 +      <expr>
   40.77 +	<print newline="true">FAIL</print>
   40.78 +	<false/>
   40.79 +      </expr>
   40.80 +    </if>
   40.81 +
   40.82 +  </and>
   40.83 +</expr>
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/test/idb/namespaces.sh	Wed Oct 10 22:58:21 2012 +0100
    41.3 @@ -0,0 +1,2 @@
    41.4 +#!/bin/sh
    41.5 +$top_builddir/src/xexpr --test-result $srcdir/namespaces.xml
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/test/idb/namespaces.xml	Wed Oct 10 22:58:21 2012 +0100
    42.3 @@ -0,0 +1,10 @@
    42.4 +<expr xmlns:xexpr="http://www.ebt.com/xexpr">
    42.5 +  <if>
    42.6 +    <xexpr:true/>
    42.7 +    <print newline="true">PASS</print>
    42.8 +    <expr>
    42.9 +      <print newline="true">FAIL</print>
   42.10 +      <false/>
   42.11 +    </expr>
   42.12 +  </if>
   42.13 +</expr>
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/test/idb/numbers.sh	Wed Oct 10 22:58:21 2012 +0100
    43.3 @@ -0,0 +1,2 @@
    43.4 +#!/bin/sh
    43.5 +$top_builddir/src/xexpr --test-result $srcdir/numbers.xml
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/test/idb/numbers.xml	Wed Oct 10 22:58:21 2012 +0100
    44.3 @@ -0,0 +1,25 @@
    44.4 +<and>
    44.5 +  <if>
    44.6 +    <eq>
    44.7 +      <integer>-1</integer>
    44.8 +      <subtract>0 1</subtract>
    44.9 +    </eq>
   44.10 +    <print newline="true">PASS</print>
   44.11 +    <expr>
   44.12 +      <print newline="true">FAIL</print>
   44.13 +      <false/>
   44.14 +    </expr>
   44.15 +  </if>
   44.16 +
   44.17 +  <if>
   44.18 +    <eq>
   44.19 +      <float>+1.7</float>
   44.20 +      1.7
   44.21 +    </eq>
   44.22 +    <print newline="true">PASS</print>
   44.23 +    <expr>
   44.24 +      <print newline="true">FAIL</print>
   44.25 +      <false/>
   44.26 +    </expr>
   44.27 +  </if>
   44.28 +</and>
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/test/idb/pcdata.sh	Wed Oct 10 22:58:21 2012 +0100
    45.3 @@ -0,0 +1,2 @@
    45.4 +#!/bin/sh
    45.5 +$top_builddir/src/xexpr --test-result $srcdir/pcdata.xml
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/test/idb/pcdata.xml	Wed Oct 10 22:58:21 2012 +0100
    46.3 @@ -0,0 +1,19 @@
    46.4 +<expr>
    46.5 +  <define name="foo" args="x y z"><x/><y/><z/></define>
    46.6 +
    46.7 +  <if>
    46.8 +    <eq>
    46.9 +      <foo>This is the 0xdeadbeef constant.</foo>
   46.10 +      <foo>
   46.11 +        <string>This is the</string>
   46.12 +	<integer>0xdeadbeef</integer>
   46.13 +	<string>constant.</string>
   46.14 +      </foo>
   46.15 +    </eq>
   46.16 +    <print newline="true">PASS</print>
   46.17 +    <expr>
   46.18 +      <print newline="true">FAIL</print>
   46.19 +      <false/>
   46.20 +    </expr>
   46.21 +  </if>
   46.22 +</expr>
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/test/libxexpr/Makefile.am	Wed Oct 10 22:58:21 2012 +0100
    47.3 @@ -0,0 +1,10 @@
    47.4 +TESTS_ENVIRONMENT=top_builddir="$(top_builddir)"
    47.5 +check_SCRIPTS=pi sin atan exp log
    47.6 +TESTS=$(check_SCRIPTS)
    47.7 +
    47.8 +%:	%.sh
    47.9 +	cp $(srcdir)/$*.sh $@
   47.10 +	chmod +x $@
   47.11 +
   47.12 +EXTRA_DIST=$(check_SCRIPTS:%=%.sh) $(check_SCRIPTS:%=%.xml)
   47.13 +CLEANFILES=$(check_SCRIPTS)
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/test/libxexpr/atan.sh	Wed Oct 10 22:58:21 2012 +0100
    48.3 @@ -0,0 +1,2 @@
    48.4 +#!/bin/sh
    48.5 +$top_builddir/src/xexpr --test-result $srcdir/atan.xml
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/test/libxexpr/atan.xml	Wed Oct 10 22:58:21 2012 +0100
    49.3 @@ -0,0 +1,26 @@
    49.4 +<expr xmlns="http://www.ebt.com/xexpr"
    49.5 +  xmlns:libxexpr="http://www.juiblex.co.uk/ns/libxexpr">
    49.6 +  <if>
    49.7 +    <eq>
    49.8 +      <libxexpr:atan>1 0</libxexpr:atan> 
    49.9 +      <float>0</float>
   49.10 +    </eq>
   49.11 +    <print newline="true">PASS</print>
   49.12 +    <expr>
   49.13 +      <print newline="true">FAIL</print>
   49.14 +      <false/>
   49.15 +    </expr>
   49.16 +  </if>
   49.17 +
   49.18 +  <if>
   49.19 +    <eq>
   49.20 +      <libxexpr:atan x="1" y="0"/>
   49.21 +      <float>0</float>
   49.22 +    </eq>
   49.23 +    <print newline="true">PASS</print>
   49.24 +    <expr>
   49.25 +      <print newline="true">FAIL</print>
   49.26 +      <false/>
   49.27 +    </expr>
   49.28 +  </if>
   49.29 +</expr>
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/test/libxexpr/exp.sh	Wed Oct 10 22:58:21 2012 +0100
    50.3 @@ -0,0 +1,2 @@
    50.4 +#!/bin/sh
    50.5 +$top_builddir/src/xexpr --test-result $srcdir/exp.xml
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/test/libxexpr/exp.xml	Wed Oct 10 22:58:21 2012 +0100
    51.3 @@ -0,0 +1,15 @@
    51.4 +<expr xmlns="http://www.ebt.com/xexpr"
    51.5 +  xmlns:libxexpr="http://www.juiblex.co.uk/ns/libxexpr">
    51.6 +  <if>
    51.7 +    <leq>
    51.8 +      <float>7.389</float>
    51.9 +      <libxexpr:exp>2</libxexpr:exp> 
   51.10 +      <float>7.390</float>
   51.11 +    </leq>
   51.12 +    <print newline="true">PASS</print>
   51.13 +    <expr>
   51.14 +      <print newline="true">FAIL</print>
   51.15 +      <false/>
   51.16 +    </expr>
   51.17 +  </if>
   51.18 +</expr>
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/test/libxexpr/log.sh	Wed Oct 10 22:58:21 2012 +0100
    52.3 @@ -0,0 +1,2 @@
    52.4 +#!/bin/sh
    52.5 +$top_builddir/src/xexpr --test-result $srcdir/log.xml
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/test/libxexpr/log.xml	Wed Oct 10 22:58:21 2012 +0100
    53.3 @@ -0,0 +1,16 @@
    53.4 +<expr xmlns="http://www.ebt.com/xexpr"
    53.5 +  xmlns:libxexpr="http://www.juiblex.co.uk/ns/libxexpr">
    53.6 +  <if>
    53.7 +    <eq>
    53.8 +      <libxexpr:log>
    53.9 +        <libxexpr:exp>2</libxexpr:exp>
   53.10 +      </libxexpr:log> 
   53.11 +      <float>2</float>
   53.12 +    </eq>
   53.13 +    <print newline="true">PASS</print>
   53.14 +    <expr>
   53.15 +      <print newline="true">FAIL</print>
   53.16 +      <false/>
   53.17 +    </expr>
   53.18 +  </if>
   53.19 +</expr>
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/test/libxexpr/pi.sh	Wed Oct 10 22:58:21 2012 +0100
    54.3 @@ -0,0 +1,2 @@
    54.4 +#!/bin/sh
    54.5 +$top_builddir/src/xexpr --test-result $srcdir/pi.xml
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/test/libxexpr/pi.xml	Wed Oct 10 22:58:21 2012 +0100
    55.3 @@ -0,0 +1,17 @@
    55.4 +<expr xmlns="http://www.ebt.com/xexpr"
    55.5 +  xmlns:libxexpr="http://www.juiblex.co.uk/ns/libxexpr">
    55.6 +  <if>
    55.7 +    <eq>
    55.8 +      <libxexpr:pi/>
    55.9 +      <multiply>
   55.10 +	<libxexpr:atan>1</libxexpr:atan>
   55.11 +	4
   55.12 +      </multiply>
   55.13 +    </eq>
   55.14 +    <print newline="true">PASS</print>
   55.15 +    <expr>
   55.16 +      <print newline="true">FAIL</print>
   55.17 +      <false/>
   55.18 +    </expr>
   55.19 +  </if>
   55.20 +</expr>
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/test/libxexpr/pow.xml	Wed Oct 10 22:58:21 2012 +0100
    56.3 @@ -0,0 +1,14 @@
    56.4 +<expr xmlns="http://www.ebt.com/xexpr"
    56.5 +  xmlns:libxexpr="http://www.juiblex.co.uk/ns/libxexpr">
    56.6 +  <if>
    56.7 +    <eq>
    56.8 +      <libxexpr:pow>10 2</libxexpr:pow> 
    56.9 +      <float>100</float>
   56.10 +    </eq>
   56.11 +    <print newline="true">PASS</print>
   56.12 +    <expr>
   56.13 +      <print newline="true">FAIL</print>
   56.14 +      <false/>
   56.15 +    </expr>
   56.16 +  </if>
   56.17 +</expr>
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/test/libxexpr/sin.sh	Wed Oct 10 22:58:21 2012 +0100
    57.3 @@ -0,0 +1,2 @@
    57.4 +#!/bin/sh
    57.5 +$top_builddir/src/xexpr --test-result $srcdir/sin.xml
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/test/libxexpr/sin.xml	Wed Oct 10 22:58:21 2012 +0100
    58.3 @@ -0,0 +1,19 @@
    58.4 +<expr xmlns="http://www.ebt.com/xexpr"
    58.5 +  xmlns:libxexpr="http://www.juiblex.co.uk/ns/libxexpr">
    58.6 +  <if>
    58.7 +    <eq>
    58.8 +      <libxexpr:sin>
    58.9 +	<divide>
   58.10 +	  <libxexpr:pi/>
   58.11 +	  2
   58.12 +	</divide>
   58.13 +      </libxexpr:sin> 
   58.14 +      <float>1</float>
   58.15 +    </eq>
   58.16 +    <print newline="true">PASS</print>
   58.17 +    <expr>
   58.18 +      <print newline="true">FAIL</print>
   58.19 +      <false/>
   58.20 +    </expr>
   58.21 +  </if>
   58.22 +</expr>
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/test/spec/Makefile.am	Wed Oct 10 22:58:21 2012 +0100
    59.3 @@ -0,0 +1,15 @@
    59.4 +TESTS_ENVIRONMENT=top_builddir="$(top_builddir)"
    59.5 +check_SCRIPTS=spectest3 spectest4 spectest5 spectest6 spectest7 spectest8 \
    59.6 +    spectest11 spectest12 spectest13 spectest14 spectest15 spectest16 \
    59.7 +    spectest17 spectest19 spectest20 spectest21 spectest24 spectest26 \
    59.8 +    spectest27 spectest28 spectest29 spectest31 spectest32 spectest33 \
    59.9 +    spectest34 spectest35 spectest36 spectest38 spectest39 spectest40 \
   59.10 +    spectest42 spectest43 spectest45 spectest46 spectest48 spectest49
   59.11 +TESTS=$(check_SCRIPTS)
   59.12 +
   59.13 +%:	%.sh
   59.14 +	cp $(srcdir)/$*.sh $@
   59.15 +	chmod +x $@
   59.16 +
   59.17 +EXTRA_DIST=$(check_SCRIPTS:%=%.sh) $(check_SCRIPTS:%=%.xml)
   59.18 +CLEANFILES=$(check_SCRIPTS)
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/test/spec/spectest11.sh	Wed Oct 10 22:58:21 2012 +0100
    60.3 @@ -0,0 +1,2 @@
    60.4 +#!/bin/sh
    60.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest11.xml
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/test/spec/spectest11.xml	Wed Oct 10 22:58:21 2012 +0100
    61.3 @@ -0,0 +1,71 @@
    61.4 +<expr>
    61.5 +  <define name="pi">3.14</define>
    61.6 +
    61.7 +  <define name="times-two" args="x">
    61.8 +    <multiply><get name="x"/>2</multiply>
    61.9 +  </define>
   61.10 +
   61.11 +  <and>
   61.12 +    <if>
   61.13 +      <eq>
   61.14 +	<pi/>
   61.15 +	<float>3.14</float>
   61.16 +      </eq>
   61.17 +      <print newline="true">PASS</print>
   61.18 +      <expr>
   61.19 +	<print newline="true">FAIL</print>
   61.20 +	<false/>
   61.21 +      </expr>
   61.22 +    </if>
   61.23 +
   61.24 +    <if>
   61.25 +      <eq>
   61.26 +	<times-two>10</times-two>
   61.27 +	<integer>20</integer>
   61.28 +      </eq>
   61.29 +      <print newline="true">PASS</print>
   61.30 +      <expr>
   61.31 +	<print newline="true">FAIL</print>
   61.32 +	<false/>
   61.33 +      </expr>
   61.34 +    </if>
   61.35 +
   61.36 +    <if>
   61.37 +      <eq>
   61.38 +	<times-two>
   61.39 +	  2
   61.40 +	  <set name="x">4</set>
   61.41 +	</times-two>
   61.42 +	<integer>8</integer>
   61.43 +      </eq>
   61.44 +      <print newline="true">PASS</print>
   61.45 +      <expr>
   61.46 +	<print newline="true">FAIL</print>
   61.47 +	<false/>
   61.48 +      </expr>
   61.49 +    </if>
   61.50 +
   61.51 +    <print newline="true">
   61.52 +	<string>Times two returns: </string>
   61.53 +	<times-two>
   61.54 +	  2
   61.55 +	  <define name="x">5</define>
   61.56 +	</times-two>
   61.57 +    </print>
   61.58 +
   61.59 +    <if>
   61.60 +      <eq>
   61.61 +	<times-two>
   61.62 +	  2
   61.63 +	  <define name="x">5</define>
   61.64 +	</times-two>
   61.65 +	<integer>10</integer>
   61.66 +      </eq>
   61.67 +      <print newline="true">PASS</print>
   61.68 +      <expr>
   61.69 +	<print newline="true">FAIL</print>
   61.70 +	<false/>
   61.71 +      </expr>
   61.72 +    </if>
   61.73 +  </and>
   61.74 +</expr>
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/test/spec/spectest12.sh	Wed Oct 10 22:58:21 2012 +0100
    62.3 @@ -0,0 +1,8 @@
    62.4 +#!/bin/sh
    62.5 +set -e
    62.6 +$top_builddir/src/xexpr --test-result $srcdir/spectest12.xml > spectest12.out
    62.7 +echo "4Hello World" > spectest12.ref
    62.8 +cmp spectest12.out spectest12.ref
    62.9 +retval=$?
   62.10 +rm -f spectest12.out spectest12.ref
   62.11 +exit $retval
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/test/spec/spectest12.xml	Wed Oct 10 22:58:21 2012 +0100
    63.3 @@ -0,0 +1,5 @@
    63.4 +<and>
    63.5 +  <print><add>2 2</add></print>
    63.6 +  <print>Hello World</print>
    63.7 +  <print newline="true"/>
    63.8 +</and>
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/test/spec/spectest13.sh	Wed Oct 10 22:58:21 2012 +0100
    64.3 @@ -0,0 +1,8 @@
    64.4 +#!/bin/sh
    64.5 +set -e
    64.6 +$top_builddir/src/xexpr --test-result $srcdir/spectest13.xml > spectest13.out
    64.7 +echo "" > spectest13.ref
    64.8 +cmp spectest13.out spectest13.ref
    64.9 +retval=$?
   64.10 +rm -f spectest13.out spectest13.ref
   64.11 +exit $retval
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/test/spec/spectest13.xml	Wed Oct 10 22:58:21 2012 +0100
    65.3 @@ -0,0 +1,1 @@
    65.4 +<println/>
    66.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    66.2 +++ b/test/spec/spectest14.sh	Wed Oct 10 22:58:21 2012 +0100
    66.3 @@ -0,0 +1,2 @@
    66.4 +#!/bin/sh
    66.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest14.xml
    67.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    67.2 +++ b/test/spec/spectest14.xml	Wed Oct 10 22:58:21 2012 +0100
    67.3 @@ -0,0 +1,31 @@
    67.4 +<expr>
    67.5 +  <define name="x">1</define>
    67.6 +
    67.7 +  <and>
    67.8 +    <if>
    67.9 +      <eq>
   67.10 +	<get name="x"/>
   67.11 +	<get>x</get>
   67.12 +	<x/>
   67.13 +      </eq>
   67.14 +      <print newline="true">PASS</print>
   67.15 +      <expr>
   67.16 +	<print newline="true">FAIL</print>
   67.17 +	<false/>
   67.18 +      </expr>
   67.19 +    </if>
   67.20 +
   67.21 +    <if>
   67.22 +      <eq>
   67.23 +	<get name="y"/>
   67.24 +	<get>y</get>
   67.25 +	<nil/>
   67.26 +      </eq>
   67.27 +      <print newline="true">PASS</print>
   67.28 +      <expr>
   67.29 +	<print newline="true">FAIL</print>
   67.30 +	<false/>
   67.31 +      </expr>
   67.32 +    </if>
   67.33 +  </and>
   67.34 +</expr>
    68.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    68.2 +++ b/test/spec/spectest15.sh	Wed Oct 10 22:58:21 2012 +0100
    68.3 @@ -0,0 +1,2 @@
    68.4 +#!/bin/sh
    68.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest15.xml
    69.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    69.2 +++ b/test/spec/spectest15.xml	Wed Oct 10 22:58:21 2012 +0100
    69.3 @@ -0,0 +1,37 @@
    69.4 +<and>
    69.5 +  <if>
    69.6 +    <eq>
    69.7 +      <set name="x" value="hello"/>
    69.8 +      <string>hello</string>
    69.9 +    </eq>
   69.10 +    <print newline="true">PASS</print>
   69.11 +    <expr>
   69.12 +      <print newline="true">FAIL</print>
   69.13 +      <false/>
   69.14 +    </expr>
   69.15 +  </if>
   69.16 +
   69.17 +  <if>
   69.18 +    <eq>
   69.19 +      <set name="x">hello</set>
   69.20 +      <string>hello</string>
   69.21 +    </eq>
   69.22 +    <print newline="true">PASS</print>
   69.23 +    <expr>
   69.24 +      <print newline="true">FAIL</print>
   69.25 +      <false/>
   69.26 +    </expr>
   69.27 +  </if>
   69.28 +
   69.29 +  <if>
   69.30 +    <eq>
   69.31 +      <set>hello 123</set>
   69.32 +      <integer>123</integer>
   69.33 +    </eq>
   69.34 +    <print newline="true">PASS</print>
   69.35 +    <expr>
   69.36 +      <print newline="true">FAIL</print>
   69.37 +      <false/>
   69.38 +    </expr>
   69.39 +  </if>
   69.40 +</and>
    70.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    70.2 +++ b/test/spec/spectest16.sh	Wed Oct 10 22:58:21 2012 +0100
    70.3 @@ -0,0 +1,8 @@
    70.4 +#!/bin/sh
    70.5 +set -e
    70.6 +$top_builddir/src/xexpr --test-result $srcdir/spectest16.xml > spectest16.out
    70.7 +echo -n "3" > spectest16.ref
    70.8 +cmp spectest16.out spectest16.ref
    70.9 +retval=$?
   70.10 +rm -f spectest16.out spectest16.ref
   70.11 +exit $retval
    71.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    71.2 +++ b/test/spec/spectest16.xml	Wed Oct 10 22:58:21 2012 +0100
    71.3 @@ -0,0 +1,11 @@
    71.4 +<and>
    71.5 +  <expr>
    71.6 +    <set name="x">3</set>
    71.7 +    <print><x/></print>
    71.8 +  </expr>
    71.9 +
   71.10 +  <eq>
   71.11 +    <expr/>
   71.12 +    <nil/>
   71.13 +  </eq>
   71.14 +</and>
    72.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    72.2 +++ b/test/spec/spectest17.sh	Wed Oct 10 22:58:21 2012 +0100
    72.3 @@ -0,0 +1,2 @@
    72.4 +#!/bin/sh
    72.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest17.xml
    73.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    73.2 +++ b/test/spec/spectest17.xml	Wed Oct 10 22:58:21 2012 +0100
    73.3 @@ -0,0 +1,48 @@
    73.4 +<expr x="1">
    73.5 +  <define name="foo">
    73.6 +    <return>bar</return>
    73.7 +  </define>
    73.8 +
    73.9 +  <define name="bar">
   73.10 +    <return>1 2</return>
   73.11 +    <set name="x" value="2"/>
   73.12 +  </define>
   73.13 +
   73.14 +  <and>
   73.15 +    <if>
   73.16 +      <eq>
   73.17 +	<foo/>
   73.18 +	<string>bar</string>
   73.19 +      </eq>
   73.20 +      <print newline="true">PASS</print>
   73.21 +      <expr>
   73.22 +	<print newline="true">FAIL</print>
   73.23 +	<false/>
   73.24 +      </expr>
   73.25 +    </if>
   73.26 +
   73.27 +    <if>
   73.28 +      <eq>
   73.29 +	<bar/>
   73.30 +	<integer>2</integer>
   73.31 +      </eq>
   73.32 +      <print newline="true">PASS</print>
   73.33 +      <expr>
   73.34 +	<print newline="true">FAIL</print>
   73.35 +	<false/>
   73.36 +      </expr>
   73.37 +    </if>
   73.38 +
   73.39 +    <if>
   73.40 +      <eq>
   73.41 +	<x/>
   73.42 +	<integer>1</integer>
   73.43 +      </eq>
   73.44 +      <print newline="true">PASS</print>
   73.45 +      <expr>
   73.46 +	<print newline="true">FAIL</print>
   73.47 +	<false/>
   73.48 +      </expr>
   73.49 +    </if>
   73.50 +  </and>
   73.51 +</expr>
    74.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    74.2 +++ b/test/spec/spectest19.sh	Wed Oct 10 22:58:21 2012 +0100
    74.3 @@ -0,0 +1,2 @@
    74.4 +#!/bin/sh
    74.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest19.xml
    75.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    75.2 +++ b/test/spec/spectest19.xml	Wed Oct 10 22:58:21 2012 +0100
    75.3 @@ -0,0 +1,30 @@
    75.4 +<and>
    75.5 +  <if>
    75.6 +    <eq>
    75.7 +      <string>This is #1</string>
    75.8 +      <add>This is #1</add>
    75.9 +    </eq>
   75.10 +    <print newline="true">PASS</print>
   75.11 +    <expr>
   75.12 +      <print newline="true">FAIL</print>
   75.13 +      <false/>
   75.14 +    </expr>
   75.15 +  </if>
   75.16 +
   75.17 +  <if>
   75.18 +    <eq>
   75.19 +      <string>This is the  00  constant.</string>
   75.20 +      <add>
   75.21 +	<string>This is the  </string>
   75.22 +	0
   75.23 +	0
   75.24 +	<string>  constant.</string>
   75.25 +      </add>
   75.26 +    </eq>
   75.27 +    <print newline="true">PASS</print>
   75.28 +    <expr>
   75.29 +      <print newline="true">FAIL</print>
   75.30 +      <false/>
   75.31 +    </expr>
   75.32 +  </if>
   75.33 +</and>
    76.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    76.2 +++ b/test/spec/spectest20.sh	Wed Oct 10 22:58:21 2012 +0100
    76.3 @@ -0,0 +1,2 @@
    76.4 +#!/bin/sh
    76.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest20.xml
    77.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    77.2 +++ b/test/spec/spectest20.xml	Wed Oct 10 22:58:21 2012 +0100
    77.3 @@ -0,0 +1,13 @@
    77.4 +<expr>
    77.5 +  <if>
    77.6 +    <eq>
    77.7 +      <integer>123</integer>
    77.8 +      123
    77.9 +    </eq>
   77.10 +    <print newline="true">PASS</print>
   77.11 +    <expr>
   77.12 +      <print newline="true">FAIL</print>
   77.13 +      <false/>
   77.14 +    </expr>
   77.15 +  </if>
   77.16 +</expr>
    78.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    78.2 +++ b/test/spec/spectest21.sh	Wed Oct 10 22:58:21 2012 +0100
    78.3 @@ -0,0 +1,2 @@
    78.4 +#!/bin/sh
    78.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest21.xml
    79.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    79.2 +++ b/test/spec/spectest21.xml	Wed Oct 10 22:58:21 2012 +0100
    79.3 @@ -0,0 +1,25 @@
    79.4 +<and>
    79.5 +  <if>
    79.6 +    <eq>
    79.7 +      <float>123</float>
    79.8 +      123
    79.9 +    </eq>
   79.10 +    <print newline="true">PASS</print>
   79.11 +    <expr>
   79.12 +      <print newline="true">FAIL</print>
   79.13 +      <false/>
   79.14 +    </expr>
   79.15 +  </if>
   79.16 +
   79.17 +  <if>
   79.18 +    <eq>
   79.19 +      <float>123.143</float>
   79.20 +      123.143
   79.21 +    </eq>
   79.22 +    <print newline="true">PASS</print>
   79.23 +    <expr>
   79.24 +      <print newline="true">FAIL</print>
   79.25 +      <false/>
   79.26 +    </expr>
   79.27 +  </if>
   79.28 +</and>
    80.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.2 +++ b/test/spec/spectest24.sh	Wed Oct 10 22:58:21 2012 +0100
    80.3 @@ -0,0 +1,2 @@
    80.4 +#!/bin/sh
    80.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest24.xml
    81.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    81.2 +++ b/test/spec/spectest24.xml	Wed Oct 10 22:58:21 2012 +0100
    81.3 @@ -0,0 +1,22 @@
    81.4 +<and>
    81.5 +  <if>
    81.6 +    <nil/>
    81.7 +    <expr>
    81.8 +      <print newline="true">FAIL</print>
    81.9 +      <false/>
   81.10 +    </expr>
   81.11 +    <print newline="true">PASS</print>
   81.12 +  </if>
   81.13 +
   81.14 +  <if>
   81.15 +    <eq>
   81.16 +      <nil/>
   81.17 +      <false/>
   81.18 +    </eq>
   81.19 +    <expr>
   81.20 +      <print newline="true">FAIL</print>
   81.21 +      <false/>
   81.22 +    </expr>
   81.23 +    <print newline="true">PASS</print>
   81.24 +  </if>
   81.25 +</and>
    82.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    82.2 +++ b/test/spec/spectest26.sh	Wed Oct 10 22:58:21 2012 +0100
    82.3 @@ -0,0 +1,2 @@
    82.4 +#!/bin/sh
    82.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest26.xml
    83.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    83.2 +++ b/test/spec/spectest26.xml	Wed Oct 10 22:58:21 2012 +0100
    83.3 @@ -0,0 +1,49 @@
    83.4 +<and>
    83.5 +  <if>
    83.6 +    <eq>
    83.7 +      <add>1 2 3</add>
    83.8 +      <integer>6</integer>
    83.9 +    </eq>
   83.10 +    <print newline="true">PASS</print>
   83.11 +    <expr>
   83.12 +      <print newline="true">FAIL</print>
   83.13 +      <false/>
   83.14 +    </expr>
   83.15 +  </if>
   83.16 +
   83.17 +  <if>
   83.18 +    <eq>
   83.19 +      <add>1 2 3.0</add>
   83.20 +      <float>6.0</float>
   83.21 +    </eq>
   83.22 +    <print newline="true">PASS</print>
   83.23 +    <expr>
   83.24 +      <print newline="true">FAIL</print>
   83.25 +      <false/>
   83.26 +    </expr>
   83.27 +  </if>
   83.28 +
   83.29 +  <if>
   83.30 +    <eq>
   83.31 +      <add>Hello World#<add>2 2</add></add>
   83.32 +      <string>Hello World#4</string>
   83.33 +    </eq>
   83.34 +    <print newline="true">PASS</print>
   83.35 +    <expr>
   83.36 +      <print newline="true">FAIL</print>
   83.37 +      <false/>
   83.38 +    </expr>
   83.39 +  </if>
   83.40 +
   83.41 +  <if>
   83.42 +    <eq>
   83.43 +      <add><set>x 3</set>2</add>
   83.44 +      <integer>5</integer>
   83.45 +    </eq>
   83.46 +    <print newline="true">PASS</print>
   83.47 +    <expr>
   83.48 +      <print newline="true">FAIL</print>
   83.49 +      <false/>
   83.50 +    </expr>
   83.51 +  </if>
   83.52 +</and>
    84.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    84.2 +++ b/test/spec/spectest27.sh	Wed Oct 10 22:58:21 2012 +0100
    84.3 @@ -0,0 +1,2 @@
    84.4 +#!/bin/sh
    84.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest27.xml
    85.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    85.2 +++ b/test/spec/spectest27.xml	Wed Oct 10 22:58:21 2012 +0100
    85.3 @@ -0,0 +1,11 @@
    85.4 +<if>
    85.5 +  <eq>
    85.6 +    <subtract>10 2 1</subtract>
    85.7 +    <integer>7</integer>
    85.8 +  </eq>
    85.9 +  <print newline="true">PASS</print>
   85.10 +  <expr>
   85.11 +    <print newline="true">FAIL</print>
   85.12 +    <false/>
   85.13 +  </expr>
   85.14 +</if>
    86.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    86.2 +++ b/test/spec/spectest28.sh	Wed Oct 10 22:58:21 2012 +0100
    86.3 @@ -0,0 +1,2 @@
    86.4 +#!/bin/sh
    86.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest28.xml
    87.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    87.2 +++ b/test/spec/spectest28.xml	Wed Oct 10 22:58:21 2012 +0100
    87.3 @@ -0,0 +1,11 @@
    87.4 +<if>
    87.5 +  <eq>
    87.6 +    <multiply>10 2 1</multiply>
    87.7 +    <integer>20</integer>
    87.8 +  </eq>
    87.9 +  <print newline="true">PASS</print>
   87.10 +  <expr>
   87.11 +    <print newline="true">FAIL</print>
   87.12 +    <false/>
   87.13 +  </expr>
   87.14 +</if>
    88.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    88.2 +++ b/test/spec/spectest29.sh	Wed Oct 10 22:58:21 2012 +0100
    88.3 @@ -0,0 +1,2 @@
    88.4 +#!/bin/sh
    88.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest29.xml
    89.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    89.2 +++ b/test/spec/spectest29.xml	Wed Oct 10 22:58:21 2012 +0100
    89.3 @@ -0,0 +1,11 @@
    89.4 +<if>
    89.5 +  <eq>
    89.6 +    <divide>20 2 2</divide>
    89.7 +    <integer>5</integer>
    89.8 +  </eq>
    89.9 +  <print newline="true">PASS</print>
   89.10 +  <expr>
   89.11 +    <print newline="true">FAIL</print>
   89.12 +    <false/>
   89.13 +  </expr>
   89.14 +</if>
    90.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    90.2 +++ b/test/spec/spectest3.sh	Wed Oct 10 22:58:21 2012 +0100
    90.3 @@ -0,0 +1,8 @@
    90.4 +#!/bin/sh
    90.5 +set -e
    90.6 +$top_builddir/src/xexpr --test-result $srcdir/spectest3.xml > spectest3.out
    90.7 +echo -n "3" > spectest3.ref
    90.8 +cmp spectest3.out spectest3.ref
    90.9 +retval=$?
   90.10 +rm -f spectest3.out spectest3.ref
   90.11 +exit $retval
    91.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    91.2 +++ b/test/spec/spectest3.xml	Wed Oct 10 22:58:21 2012 +0100
    91.3 @@ -0,0 +1,25 @@
    91.4 +<and>
    91.5 +  <expr>
    91.6 +    <define name="email" args="to body">
    91.7 +      <add>
    91.8 +	<string>From user@localhost&#10;</string>
    91.9 +	<string>To: </string>
   91.10 +	<to/>
   91.11 +	<string>&#10;</string>
   91.12 +	<string>&#10;</string>
   91.13 +	<body/>
   91.14 +	<string>&#10;</string>
   91.15 +      </add>
   91.16 +    </define>
   91.17 +
   91.18 +    <eq>
   91.19 +      <email to="authors@ebt.com">hello</email>
   91.20 +      <email>
   91.21 +	<define name="to">authors@ebt.com</define>
   91.22 +	hello
   91.23 +      </email>
   91.24 +    </eq>
   91.25 +  </expr>
   91.26 +
   91.27 +  <print x="2"><define name="x">3</define><x/></print>
   91.28 +</and>
    92.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    92.2 +++ b/test/spec/spectest31.sh	Wed Oct 10 22:58:21 2012 +0100
    92.3 @@ -0,0 +1,2 @@
    92.4 +#!/bin/sh
    92.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest31.xml
    93.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    93.2 +++ b/test/spec/spectest31.xml	Wed Oct 10 22:58:21 2012 +0100
    93.3 @@ -0,0 +1,51 @@
    93.4 +<and>
    93.5 +  <if>
    93.6 +    <eq>
    93.7 +      <string>A</string>
    93.8 +      A
    93.9 +      <set name="x">A</set>
   93.10 +    </eq>
   93.11 +    <print newline="true">PASS</print>
   93.12 +    <expr>
   93.13 +      <print newline="true">FAIL</print>
   93.14 +      <false/>
   93.15 +    </expr>
   93.16 +  </if>
   93.17 +
   93.18 +  <if>
   93.19 +    <eq>
   93.20 +      1 1 1
   93.21 +      <define name="x">1</define>
   93.22 +    </eq>
   93.23 +    <print newline="true">PASS</print>
   93.24 +    <expr>
   93.25 +      <print newline="true">FAIL</print>
   93.26 +      <false/>
   93.27 +    </expr>
   93.28 +  </if>
   93.29 +
   93.30 +  <if>
   93.31 +    <eq>
   93.32 +      <string>A</string>
   93.33 +      A
   93.34 +      <define name="x">B</define>
   93.35 +    </eq>
   93.36 +    <expr>
   93.37 +      <print newline="true">FAIL</print>
   93.38 +      <false/>
   93.39 +    </expr>
   93.40 +    <print newline="true">PASS</print>
   93.41 +  </if>
   93.42 +
   93.43 +  <if>
   93.44 +    <eq>
   93.45 +      1 1 1
   93.46 +      <define name="x">2</define>
   93.47 +    </eq>
   93.48 +    <expr>
   93.49 +      <print newline="true">FAIL</print>
   93.50 +      <false/>
   93.51 +    </expr>
   93.52 +    <print newline="true">PASS</print>
   93.53 +  </if>
   93.54 +</and>
    94.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    94.2 +++ b/test/spec/spectest32.sh	Wed Oct 10 22:58:21 2012 +0100
    94.3 @@ -0,0 +1,2 @@
    94.4 +#!/bin/sh
    94.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest32.xml
    95.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    95.2 +++ b/test/spec/spectest32.xml	Wed Oct 10 22:58:21 2012 +0100
    95.3 @@ -0,0 +1,51 @@
    95.4 +<and>
    95.5 +  <if>
    95.6 +    <neq>
    95.7 +      <string>A</string>
    95.8 +      B
    95.9 +      <set name="x">C</set>
   95.10 +    </neq>
   95.11 +    <print newline="true">PASS</print>
   95.12 +    <expr>
   95.13 +      <print newline="true">FAIL</print>
   95.14 +      <false/>
   95.15 +    </expr>
   95.16 +  </if>
   95.17 +
   95.18 +  <if>
   95.19 +    <neq>
   95.20 +      1 2 3
   95.21 +      <define name="x">4</define>
   95.22 +    </neq>
   95.23 +    <print newline="true">PASS</print>
   95.24 +    <expr>
   95.25 +      <print newline="true">FAIL</print>
   95.26 +      <false/>
   95.27 +    </expr>
   95.28 +  </if>
   95.29 +
   95.30 +  <if>
   95.31 +    <neq>
   95.32 +      <string>A</string>
   95.33 +      B
   95.34 +      <define name="x">B</define>
   95.35 +    </neq>
   95.36 +    <expr>
   95.37 +      <print newline="true">FAIL</print>
   95.38 +      <false/>
   95.39 +    </expr>
   95.40 +    <print newline="true">PASS</print>
   95.41 +  </if>
   95.42 +
   95.43 +  <if>
   95.44 +    <neq>
   95.45 +      1 1 2
   95.46 +      <define name="x">2</define>
   95.47 +    </neq>
   95.48 +    <expr>
   95.49 +      <print newline="true">FAIL</print>
   95.50 +      <false/>
   95.51 +    </expr>
   95.52 +    <print newline="true">PASS</print>
   95.53 +  </if>
   95.54 +</and>
    96.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    96.2 +++ b/test/spec/spectest33.sh	Wed Oct 10 22:58:21 2012 +0100
    96.3 @@ -0,0 +1,2 @@
    96.4 +#!/bin/sh
    96.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest33.xml
    97.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    97.2 +++ b/test/spec/spectest33.xml	Wed Oct 10 22:58:21 2012 +0100
    97.3 @@ -0,0 +1,63 @@
    97.4 +<and>
    97.5 +  <if>
    97.6 +    <leq>
    97.7 +      <define name="x">B</define>
    97.8 +      B
    97.9 +      <string>C</string>
   97.10 +    </leq>
   97.11 +    <print newline="true">PASS</print>
   97.12 +    <expr>
   97.13 +      <print newline="true">FAIL</print>
   97.14 +      <false/>
   97.15 +    </expr>
   97.16 +  </if>
   97.17 +
   97.18 +  <if>
   97.19 +    <leq>
   97.20 +      <define name="x">1</define>
   97.21 +      1 2 3 4
   97.22 +    </leq>
   97.23 +    <print newline="true">PASS</print>
   97.24 +    <expr>
   97.25 +      <print newline="true">FAIL</print>
   97.26 +      <false/>
   97.27 +    </expr>
   97.28 +  </if>
   97.29 +
   97.30 +  <if>
   97.31 +    <leq>
   97.32 +      <define name="x">C</define>
   97.33 +      B
   97.34 +      <string>C</string>
   97.35 +    </leq>
   97.36 +    <expr>
   97.37 +      <print newline="true">FAIL</print>
   97.38 +      <false/>
   97.39 +    </expr>
   97.40 +    <print newline="true">PASS</print>
   97.41 +  </if>
   97.42 +
   97.43 +  <if>
   97.44 +    <leq>
   97.45 +      <define name="x">2</define>
   97.46 +      1 2 3 4
   97.47 +    </leq>
   97.48 +    <expr>
   97.49 +      <print newline="true">FAIL</print>
   97.50 +      <false/>
   97.51 +    </expr>
   97.52 +    <print newline="true">PASS</print>
   97.53 +  </if>
   97.54 +
   97.55 +  <if>
   97.56 +    <leq>
   97.57 +      <string>1</string>
   97.58 +      1 2 3 4
   97.59 +    </leq>
   97.60 +    <expr>
   97.61 +      <print newline="true">FAIL</print>
   97.62 +      <false/>
   97.63 +    </expr>
   97.64 +    <print newline="true">PASS</print>
   97.65 +  </if>
   97.66 +</and>
    98.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    98.2 +++ b/test/spec/spectest34.sh	Wed Oct 10 22:58:21 2012 +0100
    98.3 @@ -0,0 +1,2 @@
    98.4 +#!/bin/sh
    98.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest34.xml
    99.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    99.2 +++ b/test/spec/spectest34.xml	Wed Oct 10 22:58:21 2012 +0100
    99.3 @@ -0,0 +1,63 @@
    99.4 +<and>
    99.5 +  <if>
    99.6 +    <geq>
    99.7 +      <define name="x">B</define>
    99.8 +      B
    99.9 +      <string>A</string>
   99.10 +    </geq>
   99.11 +    <print newline="true">PASS</print>
   99.12 +    <expr>
   99.13 +      <print newline="true">FAIL</print>
   99.14 +      <false/>
   99.15 +    </expr>
   99.16 +  </if>
   99.17 +
   99.18 +  <if>
   99.19 +    <geq>
   99.20 +      <define name="x">3</define>
   99.21 +      3 2 1
   99.22 +    </geq>
   99.23 +    <print newline="true">PASS</print>
   99.24 +    <expr>
   99.25 +      <print newline="true">FAIL</print>
   99.26 +      <false/>
   99.27 +    </expr>
   99.28 +  </if>
   99.29 +
   99.30 +  <if>
   99.31 +    <geq>
   99.32 +      <define name="x">A</define>
   99.33 +      B
   99.34 +      <string>A</string>
   99.35 +    </geq>
   99.36 +    <expr>
   99.37 +      <print newline="true">FAIL</print>
   99.38 +      <false/>
   99.39 +    </expr>
   99.40 +    <print newline="true">PASS</print>
   99.41 +  </if>
   99.42 +
   99.43 +  <if>
   99.44 +    <geq>
   99.45 +      <define name="x">1</define>
   99.46 +      2 1 1
   99.47 +    </geq>
   99.48 +    <expr>
   99.49 +      <print newline="true">FAIL</print>
   99.50 +      <false/>
   99.51 +    </expr>
   99.52 +    <print newline="true">PASS</print>
   99.53 +  </if>
   99.54 +
   99.55 +  <if>
   99.56 +    <geq>
   99.57 +      <string>3</string>
   99.58 +      3 2 1
   99.59 +    </geq>
   99.60 +    <expr>
   99.61 +      <print newline="true">FAIL</print>
   99.62 +      <false/>
   99.63 +    </expr>
   99.64 +    <print newline="true">PASS</print>
   99.65 +  </if>
   99.66 +</and>
   100.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   100.2 +++ b/test/spec/spectest35.sh	Wed Oct 10 22:58:21 2012 +0100
   100.3 @@ -0,0 +1,2 @@
   100.4 +#!/bin/sh
   100.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest35.xml
   101.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   101.2 +++ b/test/spec/spectest35.xml	Wed Oct 10 22:58:21 2012 +0100
   101.3 @@ -0,0 +1,63 @@
   101.4 +<and>
   101.5 +  <if>
   101.6 +    <lt>
   101.7 +      <string>A</string>
   101.8 +      B
   101.9 +      <define name="x">C</define>
  101.10 +    </lt>
  101.11 +    <print newline="true">PASS</print>
  101.12 +    <expr>
  101.13 +      <print newline="true">FAIL</print>
  101.14 +      <false/>
  101.15 +    </expr>
  101.16 +  </if>
  101.17 +
  101.18 +  <if>
  101.19 +    <lt>
  101.20 +      1 2 3
  101.21 +      <define name="x">4</define>
  101.22 +    </lt>
  101.23 +    <print newline="true">PASS</print>
  101.24 +    <expr>
  101.25 +      <print newline="true">FAIL</print>
  101.26 +      <false/>
  101.27 +    </expr>
  101.28 +  </if>
  101.29 +
  101.30 +  <if>
  101.31 +    <lt>
  101.32 +      <string>A</string>
  101.33 +      B
  101.34 +      <define name="x">B</define>
  101.35 +    </lt>
  101.36 +    <expr>
  101.37 +      <print newline="true">FAIL</print>
  101.38 +      <false/>
  101.39 +    </expr>
  101.40 +    <print newline="true">PASS</print>
  101.41 +  </if>
  101.42 +
  101.43 +  <if>
  101.44 +    <lt>
  101.45 +      1 2 3
  101.46 +      <define name="x">3</define>
  101.47 +    </lt>
  101.48 +    <expr>
  101.49 +      <print newline="true">FAIL</print>
  101.50 +      <false/>
  101.51 +    </expr>
  101.52 +    <print newline="true">PASS</print>
  101.53 +  </if>
  101.54 +
  101.55 +  <if>
  101.56 +    <lt>
  101.57 +      1 2 3
  101.58 +      <string>4</string>
  101.59 +    </lt>
  101.60 +    <expr>
  101.61 +      <print newline="true">FAIL</print>
  101.62 +      <false/>
  101.63 +    </expr>
  101.64 +    <print newline="true">PASS</print>
  101.65 +  </if>
  101.66 +</and>
   102.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   102.2 +++ b/test/spec/spectest36.sh	Wed Oct 10 22:58:21 2012 +0100
   102.3 @@ -0,0 +1,2 @@
   102.4 +#!/bin/sh
   102.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest36.xml
   103.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   103.2 +++ b/test/spec/spectest36.xml	Wed Oct 10 22:58:21 2012 +0100
   103.3 @@ -0,0 +1,63 @@
   103.4 +<and>
   103.5 +  <if>
   103.6 +    <gt>
   103.7 +      <string>C</string>
   103.8 +      B
   103.9 +      <define name="x">A</define>
  103.10 +    </gt>
  103.11 +    <print newline="true">PASS</print>
  103.12 +    <expr>
  103.13 +      <print newline="true">FAIL</print>
  103.14 +      <false/>
  103.15 +    </expr>
  103.16 +  </if>
  103.17 +
  103.18 +  <if>
  103.19 +    <gt>
  103.20 +      4 3 2
  103.21 +      <define name="x">1</define>
  103.22 +    </gt>
  103.23 +    <print newline="true">PASS</print>
  103.24 +    <expr>
  103.25 +      <print newline="true">FAIL</print>
  103.26 +      <false/>
  103.27 +    </expr>
  103.28 +  </if>
  103.29 +
  103.30 +  <if>
  103.31 +    <gt>
  103.32 +      <string>C</string>
  103.33 +      B
  103.34 +      <define name="x">C</define>
  103.35 +    </gt>
  103.36 +    <expr>
  103.37 +      <print newline="true">FAIL</print>
  103.38 +      <false/>
  103.39 +    </expr>
  103.40 +    <print newline="true">PASS</print>
  103.41 +  </if>
  103.42 +
  103.43 +  <if>
  103.44 +    <gt>
  103.45 +      4 3 2
  103.46 +      <define name="x">3</define>
  103.47 +    </gt>
  103.48 +    <expr>
  103.49 +      <print newline="true">FAIL</print>
  103.50 +      <false/>
  103.51 +    </expr>
  103.52 +    <print newline="true">PASS</print>
  103.53 +  </if>
  103.54 +
  103.55 +  <if>
  103.56 +    <gt>
  103.57 +      4 3 2
  103.58 +      <string>1</string>
  103.59 +    </gt>
  103.60 +    <expr>
  103.61 +      <print newline="true">FAIL</print>
  103.62 +      <false/>
  103.63 +    </expr>
  103.64 +    <print newline="true">PASS</print>
  103.65 +  </if>
  103.66 +</and>
   104.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   104.2 +++ b/test/spec/spectest38.sh	Wed Oct 10 22:58:21 2012 +0100
   104.3 @@ -0,0 +1,2 @@
   104.4 +#!/bin/sh
   104.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest38.xml
   105.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   105.2 +++ b/test/spec/spectest38.xml	Wed Oct 10 22:58:21 2012 +0100
   105.3 @@ -0,0 +1,43 @@
   105.4 +<and>
   105.5 +  <if>
   105.6 +    <eq>
   105.7 +      <and>
   105.8 +	<true/>
   105.9 +	<define name="x"><true/></define>
  105.10 +      </and>
  105.11 +      <true/>
  105.12 +    </eq>
  105.13 +    <print newline="true">PASS</print>
  105.14 +    <expr>
  105.15 +      <print newline="true">FAIL</print>
  105.16 +      <false/>
  105.17 +    </expr>
  105.18 +  </if>
  105.19 +
  105.20 +  <if>
  105.21 +    <eq>
  105.22 +      <and>
  105.23 +	<true/>
  105.24 +	<define name="x"><false/></define>
  105.25 +      </and>
  105.26 +      <false/>
  105.27 +    </eq>
  105.28 +    <print newline="true">PASS</print>
  105.29 +    <expr>
  105.30 +      <print newline="true">FAIL</print>
  105.31 +      <false/>
  105.32 +    </expr>
  105.33 +  </if>
  105.34 +
  105.35 +  <if>
  105.36 +    <eq>
  105.37 +      <and/>
  105.38 +      <true/>
  105.39 +    </eq>
  105.40 +    <print newline="true">PASS</print>
  105.41 +    <expr>
  105.42 +      <print newline="true">FAIL</print>
  105.43 +      <false/>
  105.44 +    </expr>
  105.45 +  </if>
  105.46 +</and>
   106.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   106.2 +++ b/test/spec/spectest39.sh	Wed Oct 10 22:58:21 2012 +0100
   106.3 @@ -0,0 +1,2 @@
   106.4 +#!/bin/sh
   106.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest39.xml
   107.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   107.2 +++ b/test/spec/spectest39.xml	Wed Oct 10 22:58:21 2012 +0100
   107.3 @@ -0,0 +1,58 @@
   107.4 +<and>
   107.5 +  <if>
   107.6 +    <eq>
   107.7 +      <or>
   107.8 +        <true/>
   107.9 +	<define name="x"><true/></define>
  107.10 +      </or>
  107.11 +      <true/>
  107.12 +    </eq>
  107.13 +    <print newline="true">PASS</print>
  107.14 +    <expr>
  107.15 +      <print newline="true">FAIL</print>
  107.16 +      <false/>
  107.17 +    </expr>
  107.18 +  </if>
  107.19 +
  107.20 +  <if>
  107.21 +    <eq>
  107.22 +      <or>
  107.23 +        <true/>
  107.24 +	<define name="x"><false/></define>
  107.25 +      </or>
  107.26 +      <true/>
  107.27 +    </eq>
  107.28 +    <print newline="true">PASS</print>
  107.29 +    <expr>
  107.30 +      <print newline="true">FAIL</print>
  107.31 +      <false/>
  107.32 +    </expr>
  107.33 +  </if>
  107.34 +
  107.35 +  <if>
  107.36 +    <eq>
  107.37 +      <or>
  107.38 +        <false/>
  107.39 +	<define name="x"><false/></define>
  107.40 +      </or>
  107.41 +      <false/>
  107.42 +    </eq>
  107.43 +    <print newline="true">PASS</print>
  107.44 +    <expr>
  107.45 +      <print newline="true">FAIL</print>
  107.46 +      <false/>
  107.47 +    </expr>
  107.48 +  </if>
  107.49 +
  107.50 +  <if>
  107.51 +    <eq>
  107.52 +      <or/>
  107.53 +      <true/>
  107.54 +    </eq>
  107.55 +    <print newline="true">PASS</print>
  107.56 +    <expr>
  107.57 +      <print newline="true">FAIL</print>
  107.58 +      <false/>
  107.59 +    </expr>
  107.60 +  </if>
  107.61 +</and>
   108.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   108.2 +++ b/test/spec/spectest4.sh	Wed Oct 10 22:58:21 2012 +0100
   108.3 @@ -0,0 +1,2 @@
   108.4 +#!/bin/sh
   108.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest4.xml
   109.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   109.2 +++ b/test/spec/spectest4.xml	Wed Oct 10 22:58:21 2012 +0100
   109.3 @@ -0,0 +1,41 @@
   109.4 +<expr>
   109.5 +  <define name="foo"/>
   109.6 +  <define name="constant"/>
   109.7 +
   109.8 +  <and>
   109.9 +    <if>
  109.10 +      <eq>
  109.11 +	<foo>This is the 0xdeadbeef constant.</foo>
  109.12 +	<foo>
  109.13 +	  <string>This is the</string>
  109.14 +	  <integer>0xdeadbeef</integer>
  109.15 +	  <string>constant.</string>
  109.16 +	</foo>
  109.17 +      </eq>
  109.18 +      <print newline="true">PASS</print>
  109.19 +      <expr>
  109.20 +	<print newline="true">FAIL</print>
  109.21 +	<false/>
  109.22 +      </expr>
  109.23 +    </if>
  109.24 +    
  109.25 +    <if>
  109.26 +      <eq>
  109.27 +	<foo>This is a <constant>constant</constant>.</foo>
  109.28 +	<foo>
  109.29 +	  <string>This is a</string>
  109.30 +	  <constant>
  109.31 +	    <string>constant</string>
  109.32 +	  </constant>
  109.33 +	  <string>.</string>
  109.34 +	</foo>
  109.35 +      </eq>
  109.36 +      <print newline="true">PASS</print>
  109.37 +      <expr>
  109.38 +	<print newline="true">FAIL</print>
  109.39 +	<false/>
  109.40 +      </expr>
  109.41 +    </if>
  109.42 +
  109.43 +  </and>
  109.44 +</expr>
   110.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   110.2 +++ b/test/spec/spectest40.sh	Wed Oct 10 22:58:21 2012 +0100
   110.3 @@ -0,0 +1,2 @@
   110.4 +#!/bin/sh
   110.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest40.xml
   111.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   111.2 +++ b/test/spec/spectest40.xml	Wed Oct 10 22:58:21 2012 +0100
   111.3 @@ -0,0 +1,106 @@
   111.4 +<and>
   111.5 +  <if>
   111.6 +    <eq>
   111.7 +      <not><true/></not>
   111.8 +      <false/>
   111.9 +    </eq>
  111.10 +    <print newline="true">PASS</print>
  111.11 +    <expr>
  111.12 +      <print newline="true">FAIL</print>
  111.13 +      <false/>
  111.14 +    </expr>
  111.15 +  </if>
  111.16 +
  111.17 +  <if>
  111.18 +    <eq>
  111.19 +      <not><false/></not>
  111.20 +      <true/>
  111.21 +    </eq>
  111.22 +    <print newline="true">PASS</print>
  111.23 +    <expr>
  111.24 +      <print newline="true">FAIL</print>
  111.25 +      <false/>
  111.26 +    </expr>
  111.27 +  </if>
  111.28 +
  111.29 +  <if>
  111.30 +    <eq>
  111.31 +      <not><nil/></not>
  111.32 +      <true/>
  111.33 +    </eq>
  111.34 +    <print newline="true">PASS</print>
  111.35 +    <expr>
  111.36 +      <print newline="true">FAIL</print>
  111.37 +      <false/>
  111.38 +    </expr>
  111.39 +  </if>
  111.40 +
  111.41 +  <if>
  111.42 +    <eq>
  111.43 +      <not>1</not>
  111.44 +      <false/>
  111.45 +    </eq>
  111.46 +    <print newline="true">PASS</print>
  111.47 +    <expr>
  111.48 +      <print newline="true">FAIL</print>
  111.49 +      <false/>
  111.50 +    </expr>
  111.51 +  </if>
  111.52 +
  111.53 +  <if>
  111.54 +    <eq>
  111.55 +      <not/>
  111.56 +      <true/>
  111.57 +    </eq>
  111.58 +    <print newline="true">PASS</print>
  111.59 +    <expr>
  111.60 +      <print newline="true">FAIL</print>
  111.61 +      <false/>
  111.62 +    </expr>
  111.63 +  </if>
  111.64 +
  111.65 +  <if>
  111.66 +    <eq>
  111.67 +      <not>
  111.68 +	<true/>
  111.69 +	<true/>
  111.70 +      </not>
  111.71 +      <false/>
  111.72 +    </eq>
  111.73 +    <print newline="true">PASS</print>
  111.74 +    <expr>
  111.75 +      <print newline="true">FAIL</print>
  111.76 +      <false/>
  111.77 +    </expr>
  111.78 +  </if>
  111.79 +
  111.80 +  <if>
  111.81 +    <eq>
  111.82 +      <not>
  111.83 +	<false/>
  111.84 +	<true/>
  111.85 +      </not>
  111.86 +      <true/>
  111.87 +    </eq>
  111.88 +    <print newline="true">PASS</print>
  111.89 +    <expr>
  111.90 +      <print newline="true">FAIL</print>
  111.91 +      <false/>
  111.92 +    </expr>
  111.93 +  </if>
  111.94 +
  111.95 +  <if>
  111.96 +    <eq>
  111.97 +      <not>
  111.98 +	<false/>
  111.99 +	<false/>
 111.100 +      </not>
 111.101 +      <true/>
 111.102 +    </eq>
 111.103 +    <print newline="true">PASS</print>
 111.104 +    <expr>
 111.105 +      <print newline="true">FAIL</print>
 111.106 +      <false/>
 111.107 +    </expr>
 111.108 +  </if>
 111.109 +</and>
   112.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   112.2 +++ b/test/spec/spectest42.sh	Wed Oct 10 22:58:21 2012 +0100
   112.3 @@ -0,0 +1,2 @@
   112.4 +#!/bin/sh
   112.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest42.xml
   113.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   113.2 +++ b/test/spec/spectest42.xml	Wed Oct 10 22:58:21 2012 +0100
   113.3 @@ -0,0 +1,38 @@
   113.4 +<and>
   113.5 +  <if>
   113.6 +    <eq>
   113.7 +      <if>
   113.8 +        <eq>1 2</eq>
   113.9 +	<expr>
  113.10 +	  <string>equal</string>
  113.11 +	</expr>
  113.12 +	<expr>
  113.13 +	  <string>not equal</string>
  113.14 +	</expr>
  113.15 +      </if>
  113.16 +      <string>not equal</string>
  113.17 +    </eq>
  113.18 +    <print newline="true">PASS</print>
  113.19 +    <expr>
  113.20 +      <print newline="true">FAIL</print>
  113.21 +      <false/>
  113.22 +    </expr>
  113.23 +  </if>
  113.24 +
  113.25 +  <if>
  113.26 +    <eq>
  113.27 +      <if>
  113.28 +        <eq>1 2</eq>
  113.29 +	<expr>
  113.30 +	  <string>equal</string>
  113.31 +	</expr>
  113.32 +      </if>
  113.33 +      <nil/>
  113.34 +    </eq>
  113.35 +    <print newline="true">PASS</print>
  113.36 +    <expr>
  113.37 +      <print newline="true">FAIL</print>
  113.38 +      <false/>
  113.39 +    </expr>
  113.40 +  </if>
  113.41 +</and>
   114.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   114.2 +++ b/test/spec/spectest43.sh	Wed Oct 10 22:58:21 2012 +0100
   114.3 @@ -0,0 +1,2 @@
   114.4 +#!/bin/sh
   114.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest43.xml
   115.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   115.2 +++ b/test/spec/spectest43.xml	Wed Oct 10 22:58:21 2012 +0100
   115.3 @@ -0,0 +1,73 @@
   115.4 +<expr>
   115.5 +  <define name="test-one" args="x">
   115.6 +    <switch>
   115.7 +      <case>
   115.8 +	<eq><x/>1</eq>
   115.9 +	1
  115.10 +      </case>
  115.11 +      <case>
  115.12 +	<true/>
  115.13 +	2
  115.14 +      </case>
  115.15 +    </switch>
  115.16 +  </define>
  115.17 +
  115.18 +  <define name="test-two" args="x">
  115.19 +    <switch>
  115.20 +      <case>
  115.21 +	<eq><x/>1</eq>
  115.22 +	1
  115.23 +      </case>
  115.24 +    </switch>
  115.25 +  </define>
  115.26 +
  115.27 +  <and>
  115.28 +    <if>
  115.29 +      <eq>
  115.30 +	<test-one>1</test-one>
  115.31 +	<integer>1</integer>
  115.32 +      </eq>
  115.33 +      <print newline="true">PASS</print>
  115.34 +      <expr>
  115.35 +	<print newline="true">FAIL</print>
  115.36 +	<false/>
  115.37 +      </expr>
  115.38 +    </if>
  115.39 +
  115.40 +    <if>
  115.41 +      <eq>
  115.42 +	<test-one>2</test-one>
  115.43 +	<integer>2</integer>
  115.44 +      </eq>
  115.45 +      <print newline="true">PASS</print>
  115.46 +      <expr>
  115.47 +	<print newline="true">FAIL</print>
  115.48 +	<false/>
  115.49 +      </expr>
  115.50 +    </if>
  115.51 +
  115.52 +    <if>
  115.53 +      <eq>
  115.54 +	<test-two>1</test-two>
  115.55 +	<integer>1</integer>
  115.56 +      </eq>
  115.57 +      <print newline="true">PASS</print>
  115.58 +      <expr>
  115.59 +	<print newline="true">FAIL</print>
  115.60 +	<false/>
  115.61 +      </expr>
  115.62 +    </if>
  115.63 +
  115.64 +    <if>
  115.65 +      <eq>
  115.66 +	<test-two>2</test-two>
  115.67 +	<nil/>
  115.68 +      </eq>
  115.69 +      <print newline="true">PASS</print>
  115.70 +      <expr>
  115.71 +	<print newline="true">FAIL</print>
  115.72 +	<false/>
  115.73 +      </expr>
  115.74 +    </if>
  115.75 +  </and>
  115.76 +</expr>
   116.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   116.2 +++ b/test/spec/spectest45.sh	Wed Oct 10 22:58:21 2012 +0100
   116.3 @@ -0,0 +1,18 @@
   116.4 +#!/bin/sh
   116.5 +$top_builddir/src/xexpr $srcdir/spectest45.xml > spectest45.out
   116.6 +cat <<-EOF > spectest45.ref
   116.7 +10
   116.8 +9
   116.9 +8
  116.10 +7
  116.11 +6
  116.12 +5
  116.13 +4
  116.14 +3
  116.15 +2
  116.16 +1
  116.17 +EOF
  116.18 +cmp spectest45.out spectest45.ref
  116.19 +retval=$?
  116.20 +rm -f spectest45.out spectest45.ref
  116.21 +exit $retval
   117.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   117.2 +++ b/test/spec/spectest45.xml	Wed Oct 10 22:58:21 2012 +0100
   117.3 @@ -0,0 +1,10 @@
   117.4 +<expr>
   117.5 +  <set name="x">10</set>
   117.6 +  <while>
   117.7 +    <gt><x/> 0</gt>
   117.8 +    <expr>
   117.9 +      <print newline="true"><x/></print>
  117.10 +      <subtract><x/> 1</subtract>
  117.11 +    </expr>
  117.12 +  </while>
  117.13 +</expr>
   118.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   118.2 +++ b/test/spec/spectest46.sh	Wed Oct 10 22:58:21 2012 +0100
   118.3 @@ -0,0 +1,18 @@
   118.4 +#!/bin/sh
   118.5 +$top_builddir/src/xexpr $srcdir/spectest46.xml > spectest46.out
   118.6 +cat <<-EOF > spectest46.ref
   118.7 +10
   118.8 +9
   118.9 +8
  118.10 +7
  118.11 +6
  118.12 +5
  118.13 +4
  118.14 +3
  118.15 +2
  118.16 +1
  118.17 +EOF
  118.18 +cmp spectest46.out spectest46.ref
  118.19 +retval=$?
  118.20 +rm -f spectest46.out spectest46.ref
  118.21 +exit $retval
   119.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   119.2 +++ b/test/spec/spectest46.xml	Wed Oct 10 22:58:21 2012 +0100
   119.3 @@ -0,0 +1,10 @@
   119.4 +<expr>
   119.5 +  <set name="x">10</set>
   119.6 +  <do>
   119.7 +    <expr>
   119.8 +      <print newline="true"><x/></print>
   119.9 +      <subtract><x/> 1</subtract>
  119.10 +    </expr>
  119.11 +    <gt><x/> 0</gt>
  119.12 +  </do>
  119.13 +</expr>
   120.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   120.2 +++ b/test/spec/spectest48.sh	Wed Oct 10 22:58:21 2012 +0100
   120.3 @@ -0,0 +1,2 @@
   120.4 +#!/bin/sh
   120.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest48.xml
   121.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   121.2 +++ b/test/spec/spectest48.xml	Wed Oct 10 22:58:21 2012 +0100
   121.3 @@ -0,0 +1,1 @@
   121.4 +<true xmlns:xexpr="http://www.ebt.com/xexpr"/>
   122.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   122.2 +++ b/test/spec/spectest49.sh	Wed Oct 10 22:58:21 2012 +0100
   122.3 @@ -0,0 +1,2 @@
   122.4 +#!/bin/sh
   122.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest49.xml
   123.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   123.2 +++ b/test/spec/spectest49.xml	Wed Oct 10 22:58:21 2012 +0100
   123.3 @@ -0,0 +1,4 @@
   123.4 +<!DOCTYPE xexpr PUBLIC "-//EBT//DTD XML Expression Language//EN" "xexpr.dtd">
   123.5 +<xexpr xmlns="http://www.ebt.com/xexpr">
   123.6 +  <true/>
   123.7 +</xexpr>
   124.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   124.2 +++ b/test/spec/spectest5.sh	Wed Oct 10 22:58:21 2012 +0100
   124.3 @@ -0,0 +1,2 @@
   124.4 +#!/bin/sh
   124.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest5.xml
   125.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   125.2 +++ b/test/spec/spectest5.xml	Wed Oct 10 22:58:21 2012 +0100
   125.3 @@ -0,0 +1,19 @@
   125.4 +<expr>
   125.5 +  <define name="foo"/>
   125.6 +
   125.7 +  <if>
   125.8 +    <eq>
   125.9 +      <foo>
  125.10 +	 This is a test.
  125.11 +      </foo>
  125.12 +      <foo>
  125.13 +	<string>This is a test.</string>
  125.14 +      </foo>
  125.15 +    </eq>
  125.16 +    <print newline="true">PASS</print>
  125.17 +    <expr>
  125.18 +      <print newline="true">FAIL</print>
  125.19 +      <false/>
  125.20 +    </expr>
  125.21 +  </if>
  125.22 +</expr>
   126.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   126.2 +++ b/test/spec/spectest6.sh	Wed Oct 10 22:58:21 2012 +0100
   126.3 @@ -0,0 +1,2 @@
   126.4 +#!/bin/sh
   126.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest6.xml
   127.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   127.2 +++ b/test/spec/spectest6.xml	Wed Oct 10 22:58:21 2012 +0100
   127.3 @@ -0,0 +1,22 @@
   127.4 +<expr>
   127.5 +  <define name="foo"/>
   127.6 +
   127.7 +  <if>
   127.8 +    <eq>
   127.9 +      <foo>
  127.10 +      <string>
  127.11 +          abc
  127.12 +          def
  127.13 +      </string>
  127.14 +      </foo>
  127.15 +      <foo>
  127.16 +	<string>&#10;          abc&#10;          def&#10;      </string>
  127.17 +      </foo>
  127.18 +    </eq>
  127.19 +    <print newline="true">PASS</print>
  127.20 +    <expr>
  127.21 +      <print newline="true">FAIL</print>
  127.22 +      <false/>
  127.23 +    </expr>
  127.24 +  </if>
  127.25 +</expr>
   128.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   128.2 +++ b/test/spec/spectest7.sh	Wed Oct 10 22:58:21 2012 +0100
   128.3 @@ -0,0 +1,2 @@
   128.4 +#!/bin/sh
   128.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest7.xml
   129.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   129.2 +++ b/test/spec/spectest7.xml	Wed Oct 10 22:58:21 2012 +0100
   129.3 @@ -0,0 +1,16 @@
   129.4 +<expr>
   129.5 +  <define name="square" args="x">
   129.6 +    <multiply><x/><x/></multiply>
   129.7 +  </define>
   129.8 +  <if>
   129.9 +    <eq>
  129.10 +      <square>2<define name="x">4</define></square>
  129.11 +      16
  129.12 +    </eq>
  129.13 +    <print newline="true">PASS</print>
  129.14 +    <expr>
  129.15 +      <print newline="true">FAIL</print>
  129.16 +      <false/>
  129.17 +    </expr>
  129.18 +  </if>
  129.19 +</expr>
   130.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   130.2 +++ b/test/spec/spectest8.sh	Wed Oct 10 22:58:21 2012 +0100
   130.3 @@ -0,0 +1,2 @@
   130.4 +#!/bin/sh
   130.5 +$top_builddir/src/xexpr --test-result $srcdir/spectest8.xml
   131.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   131.2 +++ b/test/spec/spectest8.xml	Wed Oct 10 22:58:21 2012 +0100
   131.3 @@ -0,0 +1,54 @@
   131.4 +<and>
   131.5 +  <expr>
   131.6 +    <define name="factorial" args="x">
   131.7 +      <if>
   131.8 +	<lt><x/>2</lt>
   131.9 +	<x/>
  131.10 +	<multiply>
  131.11 +	  <x/>
  131.12 +	  <factorial><subtract><x/>1</subtract></factorial>
  131.13 +	</multiply>
  131.14 +      </if>
  131.15 +    </define>
  131.16 +    <if>
  131.17 +      <eq>
  131.18 +	<factorial>7</factorial>
  131.19 +	5040
  131.20 +      </eq>
  131.21 +      <print newline="true">PASS</print>
  131.22 +      <expr>
  131.23 +	<print newline="true">FAIL</print>
  131.24 +	<false/>
  131.25 +      </expr>
  131.26 +    </if>
  131.27 +  </expr>
  131.28 +  <expr>
  131.29 +    <define name="factorial" args="x">
  131.30 +      <define name="iterator" args="product counter max">
  131.31 +	<if>
  131.32 +	  <gt><counter/><max/></gt>
  131.33 +	  <product/>
  131.34 +	  <iterator>
  131.35 +	    <multiply><counter/><product/></multiply>
  131.36 +	    <add><counter/>1</add>
  131.37 +	    <max/>
  131.38 +	  </iterator>
  131.39 +	</if>
  131.40 +      </define>
  131.41 +
  131.42 +      <iterator>1 1 <x/></iterator>
  131.43 +    </define>
  131.44 +
  131.45 +    <if>
  131.46 +      <eq>
  131.47 +	<factorial>7</factorial>
  131.48 +	5040
  131.49 +      </eq>
  131.50 +      <print newline="true">PASS</print>
  131.51 +      <expr>
  131.52 +	<print newline="true">FAIL</print>
  131.53 +	<false/>
  131.54 +      </expr>
  131.55 +    </if>
  131.56 +  </expr>
  131.57 +</and>