# HG changeset patch # User ali # Date 1349906301 -3600 # Node ID bc8c9a11cbfc99c50112c09b0f4f391ca4ec4e12 Initial version diff -r 000000000000 -r bc8c9a11cbfc .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,28 @@ +.*\.o$ +.*\.lo$ +.*\.la$ +.*\.pc$ +/Makefile$ +/Makefile.in$ +^Makefile$ +^Makefile.in$ +^src/xexpr$ +/\.libs/ +/\.deps/ +^configure$ +^config\. +^config/ +^libtool$ +^gtk-doc\.make$ +^autom4te\.cache/ +^aclocal\.m4$ +^stamp-h1$ +^m4/ +^docs/.*\.sgml$ +^docs/.*\.stamp$ +^docs/reference/html/ +^docs/reference/xml/ +^docs/reference/tmpl/ +^docs/reference/version.xml +^docs/reference/libxexpr-*.txt +^docs/reference/libxexpr.* diff -r 000000000000 -r bc8c9a11cbfc COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/COPYING Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,515 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. +^L + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. +^L + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. +^L + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. +^L + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. +^L + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. +^L + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. +^L + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS +^L + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper +mail. + +You should also get your employer (if you work as a programmer) or +your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James +Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff -r 000000000000 -r bc8c9a11cbfc Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile.am Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,5 @@ +ACLOCAL_AMFLAGS=-I m4 + +SUBDIRS=libxexpr src test docs/reference + +DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc diff -r 000000000000 -r bc8c9a11cbfc bootstrap.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bootstrap.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,9 @@ +#!/bin/sh +set -e +mkdir -p config +gtkdocize +autoheader +aclocal +libtoolize +automake --foreign --add-missing +autoconf diff -r 000000000000 -r bc8c9a11cbfc configure.ac --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/configure.ac Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,80 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_INIT([libxexpr],[1.0],[ali@juiblex.co.uk]) +AC_PREREQ(2.59) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([config]) +AC_CONFIG_SRCDIR([libxexpr/xexpr.h]) +AC_CONFIG_HEADER([config.h]) +AC_CONFIG_FILES([Makefile +libxexpr/Makefile +libxexpr/libxexpr.pc +src/Makefile +test/Makefile +test/spec/Makefile +test/idb/Makefile +test/libxexpr/Makefile +docs/reference/Makefile +docs/reference/version.xml +]) +AM_INIT_AUTOMAKE(no-define) +AC_CANONICAL_HOST +AC_SUBST(HOST_OS,$host_os) +AC_SUBST(HOST_CPU,$host_cpu) + +# libtool versioning for libxexpr. For a release one of the following +# must apply: +# +# - If interfaces have been changed or added, but binary compatibility has +# been preserved, increment CURRENT and AGE and set REVISION to 0. +# - If binary compatibility has been broken (eg removed or changed interfaces), +# increment CURRENT and set AGE and REVISION to 0. +# - If the interface is the same as the previous version, increment REVISION. +# +lt_current=0 +lt_revision=0 +lt_age=0 +LIBXEXPR_LT_VERSION_INFO="$lt_current:$lt_revision:$lt_age" +AC_SUBST(LIBXEXPR_LT_VERSION_INFO) + +################################################## +# Checks for programs. +################################################## +AC_PROG_CC +AC_LIBTOOL_WIN32_DLL +AC_PROG_LIBTOOL +PKG_PROG_PKG_CONFIG +GTK_DOC_CHECK([1.11],[--flavour no-tmpl]) + +################################################## +# Checks for header files. +################################################## +AC_HEADER_STDC + +################################################## +# Checks for typedefs, structures, and compiler characteristics. +################################################## + +################################################## +# Checks for libraries. +################################################## +PKG_CHECK_MODULES(GLIB,[glib-2.0]) +PKG_CHECK_MODULES(LIBXML,[libxml-2.0]) +LIBXEXPR_CFLAGS="$LIBXML_CFLAGS $GLIB_CFLAGS" +LIBXEXPR_LIBS="$LIBXML_LIBS $GLIB_LIBS" +AC_SUBST(LIBXEXPR_CFLAGS) +AC_SUBST(LIBXEXPR_LIBS) + +################################################## +# Checks for library functions. +################################################## + +################################################## +# Checks for processor independent files. +################################################## + +################################################## +# Generate the various configured files +################################################## +AC_OUTPUT diff -r 000000000000 -r bc8c9a11cbfc docs/reference/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/reference/Makefile.am Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,95 @@ +## Process this file with automake to produce Makefile.in + +# We require automake 1.6 at least. +AUTOMAKE_OPTIONS=1.6 + +# This is a blank Makefile.am for using gtk-doc. +# Copy this to your project's API docs directory and modify the variables to +# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples +# of using the various options. + +# The name of the module, e.g. 'glib'. +DOC_MODULE=libxexpr + +# Uncomment for versioned docs and specify the version of the module, e.g. '2'. +#DOC_MODULE_VERSION=2 + + +# The top-level SGML file. You can change this if you want to. +DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml + +# The directory containing the source code. Relative to $(srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting the functions and macros. +# e.g. DOC_SOURCE_DIR=../../../gtk +DOC_SOURCE_DIR=../../libxexpr + +# Extra options to pass to gtkdoc-scangobj. Not normally needed. +SCANGOBJ_OPTIONS= + +# Extra options to supply to gtkdoc-scan. +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +SCAN_OPTIONS=--rebuild-types --rebuild-sections + +# Extra options to supply to gtkdoc-mkdb. +# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml +MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space=xexpr + +# Extra options to supply to gtkdoc-mktmpl +# e.g. MKTMPL_OPTIONS=--only-section-tmpl +MKTMPL_OPTIONS= + +# Extra options to supply to gtkdoc-mkhtml +MKHTML_OPTIONS= + +# Extra options to supply to gtkdoc-fixref. Not normally needed. +# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html +FIXXREF_OPTIONS= + +# Used for dependencies. The docs will be rebuilt if any of these change. +# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h +# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c +HFILE_GLOB=$(top_srcdir)/libxexpr/*.h +CFILE_GLOB=$(top_srcdir)/libxexpr/*.c + +# Header files to ignore when scanning. +# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h +IGNORE_HFILES=xexpr.h xexprprivate.h + +# Images to copy into HTML directory. +# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png +HTML_IMAGES= + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +# e.g. content_files=running.sgml building.sgml changes-2.0.sgml +content_files=version.xml implementation_defined_behaviour.xml \ + language_extensions.xml xexpr.xml + +# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded +# These files must be listed here *and* in content_files +# e.g. expand_content_files=running.sgml +expand_content_files= + +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. +# Only needed if you are using gtkdoc-scangobj to dynamically query widget +# signals and properties. +# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) +# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) +GTKDOC_CFLAGS= +GTKDOC_LIBS= + +# This includes the standard gtk-doc make rules, copied by gtkdocize. +include $(top_srcdir)/gtk-doc.make + +# Other files to distribute +# e.g. EXTRA_DIST += version.xml.in +EXTRA_DIST+=version.xml.in + +# Files not to distribute +# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types +# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt +DISTCLEANFILES=$(DOC_MODULE).types $(DOC_MODULE)-sections.txt + +# Comment this out if you want your docs-status tested during 'make check' +TESTS_ENVIRONMENT=cd $(srcdir) && +TESTS=$(GTKDOC_CHECK) diff -r 000000000000 -r bc8c9a11cbfc docs/reference/implementation_defined_behaviour.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/reference/implementation_defined_behaviour.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,415 @@ + + + + Implementation Defined Behaviour + + + The specification of the XEXPR language is laid out in a W3C note of + 21 November + 2000. However, the specification leaves quite a bit of + information to be deduced from the examples and leaves other parts of + the language loosly specified. This chapter documents the way that + libxexpr implements the language and gives the rationale for each + decision taken. + + + + Numbers + + + Numbers are defined in pseudo-BNF as: + +number : whitespace sign simple-number whitespace + ; + +whitespace : [ \t\n]* + ; + +sign : [+-]? + ; + +simple-number : 0x[0-9A-Fa-f]+ + | [0-9]+ + | [0-9]+\.[0-9]+ + | [0-9]+\.[0-9]+[eE][+-][0-9]+ + ; + that is: they have an optional leading sign and may be surrounded with + whitespace. + + + + Rationale + + + While negative numbers can be created using <subtract> without + the need for any signs, this seems overly cumbersome. + + + + The examples in the specification make it clear that where two numbers + are seperated by a space, this should be parsed as just two numbers + and not two numbers plus an interveening string which a strict reading + of the specification would imply. + + + + + + Bindings + + + Bindings are parsed as integers, floats or strings in that order (ie., + the first type that matches will be used). Thus the following pairs + of expressions are equivalent: + +<func x="+01 "/> + +<func> + <define name="x"><integer>1</integer></define> +</func> + +<func x=" 14.0e-1"/> + +<func> + <define name="x"><float>1.4</float></define> +</func> + +<func x="Hello "/> + +<func> + <define name="x"><string>Hello </string></define> +</func> + + + Rationale + + + This seems to satisfy the doctrine of least-surpise. + + + + + + Parsing of PCDATA + + + When numbers and strings are mixed in PCDATA, any whitespace surrounding + the numbers is taken to be part of the numbers rather than the strings. + Thus the following two expressions are equivalent: + +<foo>This is the 0xdeadbeef constant.</foo> + +<foo> + <string>This is the</string> + <integer>0xdeadbeef</integer> + <string>constant.</string> +</foo> + + + + Rationale + + + This seems more consistent with spaces between numbers not being + parsed as strings than the alternative. + + + + + + The <define> Function + + + The <define> function creates a new function in the environment in + which it is invoked. This is different than the <set> function + which will modify the definition of an existing function if such exists. + Only if no such function is defined in any of the active environments will + <set> create a new function (and then in the outermost, or global, + environment). + + + + Rationale + + + We know from the examples in the specification (eg., in + section 45) + that <subtract> changes the definition of its first argument + in at least the grandfather environment. It makes sense that <set> + should do the same. When we come to <define>, however, we + know from section + 3 that it is equivalent to an attribute on the parent element + and so it makes sense that it should create a variable in the parent + environment. + + + + + + The <get> Function + + + The following two expressions are equivalent: + +<get name="x"/> +<get>x</get> + The expression <x/> has the same effect except in the case of + <add> and <subtract> where these two expressions are + different: + +<add><x/>1</add> +<add><get>x</get>1</add> + The first changes the definition of <x>, the second does not. + + + + Note that IDs are allowed to start with the dot (.) and hyphen (-) + characters which are not valid as the first character in XML tags. + Thus get must be used in the following: + +<expr> + <define name=".net">4.5.50709</define> + <print><get>.net</get></print> +</expr> + + + + Since <get> returns a function definition (just like + <define>), it is possible to define functions of this type that + take arguments and even invoke them in a somewhat circuitous manner: + +<expr> + <define name=".product" args="a b c d"> + <add> + <multiply> + <a/> + <b/> + </multiply> + <multiply> + <c/> + <d/> + </multiply> + </add> + </define> + + <expr> + <define name="closure"/> + <set name="closure"> + <get>.product</get> + </set> + <closure>1 2 3 4</closure> + </expr> +</expr> + + + + Rationale + + + Section 14 + tells us that <get>x</get> and <x/> have the same + effect in most cases (and thus presumably not all cases) and it + would seem surprising if <get> were not to insulate a + function in this manner. + + + + + + Arithmetic Operators + + + The empty arithmetic operators (<add/>, <subtract/>, + <multiply/> and <divide/>) all evaluate to <nil/>. + + + + The <add> and <subtract> operators change their first + argument in some circumstances as in this example from the specification: + +<while> + <gt><x/> 0</gt> + <expr> + <print newline="true"><x/><print> + <subtract><x/> 1</subtract> + </expr> +</while> + + + + In general, the first agument will be modified if it is a function + invocation that has no bindings and no arguments. Thus the following + will print 9: + +<define name="x"><multiply>2 3</multiply></define> +<add><x/>3</add> +<print><x/></print> + whereas this will print 6: + +<define name="x"><multiply>2 3</multiply></define> +<add><x unused=""/>3</add> +<print><x/></print> + + + + Where arguments are modified, this occurs as the arguments are being + evaluated. Thus this expression: + +<add><x/><x/><x/></add> + will multiply <x> by 4 rather than by 3. + + + + Rationale + + + The examples in the specification imply that <add> and + <subtract> modify their first argument when it is a + variable. The iterative example in + section 8 + wouldn't work if <multiply> worked the same way (and the + definition of <2pi> in section 7 would + not be expected to modify the definition of <pi> each time + it is called). Note that this example is erroneous: IDs can't contain + numbers. + + + + It seems undesirable to modify functions that take arguments. + Making the decision based on the invocation rather than the + function definition makes expressions much easier to read. + + + + + + Comparison Functions + + + The empty comparison functions (<eq/>, <neq/>, <leq/>, + <geq/>, <lt/> and <gt/>) and comparison functions with + exactly one argument all evaluate to <true/>. + + + + The ordered comparison functions (<leq>, <geq>, <lt> + and <gt>) act as if the equivalent mathematical operator was + inserted between their arguments. Thus: + +<lt> + 1 2 3 +</lt> + is equivalent to the mathematical expression: + 1 < 2 < 3 + and: + +<leq> + 1 2 3 +</leq> + is equivalent to the mathematical expression: + 1 ≤ 2 ≤ 3 + + + + When comparing objects of different types: + + + Numbers will be implicitly cast between <float> and + <integer> where that involves no loss of precision + + + Strings will be compared byte-by-byte as UTF8 encoded strings + + + Functions will always be completely evaluated + + + Invocations of the constant functions are ordered as <false/> + < <nil/> < <true/> + + + + + + Rationale + + + The empty comparison functions equaluate to <true> by analogy + with the comparison functions. + + + + The ordering of the comparison functions is confused in the + specification with the examples for <lt> and <gt> agreeing + with libxexpr's behaviour and the examples for <leq> and + <geq> doing the opposite. The choice was arbitary. + + + + + + Redefining Builtin Functions + + + Attempting to redefine a builtin function results in an error. + + + + Rationale + + + While this could be implemented, there is no mention of it in the + specification and it would complicate the implementation with no + obvious benefit. + + + + + + Namespaces + + + libxexpr considers an element's namespace to be part of its name + and thus elements in a namespace other than the XEXPR namespace as + are always distinct from functions defined by XEXPR. In addition, + functions defined using <define> are defined in the + XEXPR namespace. + + + + libxexpr provides hooks for extending the XEXPR language by allowing + handlers to be installed for other namespaces. + + + + Elements which are in no namespace are treated as if they were in the + XEXPR namespace. + + + + Rationale + + + Being able to extend the XEXPR language is vital for it to be useful + and namespaces are the obvious way to do this. + + + + diff -r 000000000000 -r bc8c9a11cbfc docs/reference/language_extensions.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/reference/language_extensions.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,277 @@ + + + + Language Extensions + + + These language extensions are provided in the following namespace URI: + +http://www.juiblex.co.uk/ns/libxexpr + + People using this namespace are encouraged to use the libxexpr namespace + prefix. + + + + Function <pi> + + + Synopsis + + <pi> returns the value of π. + + + + + Arguments + + <pi> takes no arguments. + + + + + Return Values + + <pi> returns the value of π. + + + + + +<libxexpr:pi/> ≅ <float>3.14</float> + + + + + Function <sin> + + + Synopsis + + <sin> computes the sine function. + + + + + Arguments + + <sin> takes one argument: x. If no argument is given, an error + occurs. + + + + + Return Values + + <sin> returns the sine of its argument, given in radians. + If the argument does not evaluate to a finite number, + <sin> returns an indeterminate result. + + + + + +<libxexpr:sin> + <divide> + <libxexpr:pi/> + 2 + </divide> +</libxexpr:sin> --> <float>1</float> + + + + + Function <atan> + + + Synopsis + + <atan> computes the arc tangent function. + + + + + Arguments + + <atan> takes two arguments: x and y. The y argument defaults to + 1. If the x argument is missing, an error occurs. + + + + + Return Values + + <atan> returns the principal value of the arc tangent of its + argument(s) in radians. If either argument is indeterminate, + the result is also indeterminate. + + + + If two arguments are given, <atan> returns the arc tangent of + y/x, using the signs of the two arguments to determine the quadrant + of the result which will be in the range [-π, π]. If both arguments + are 0, the result will also be 0. + + + + If only one argument is given, <atan> returns the arc tangent of + its argument. The result will be in the range [-π/2, π/2]. + + + + + +<libxexpr:atan>1 0</libxexpr:atan> --> <float>0</float> + + + + + Function <exp> + + + Synopsis + + <exp> computes the base-e exponential function. + + + + + Arguments + + <exp> takes zero or one argument: x. + + + + + Return Values + + <exp> returns the value of e (the base of natural logarithms) + raised to the power of its argument (or just e if no argument is + supplied). If the argument does not evaluate to a finite number, + <exp> returns an indeterminate result. + + + + + +<libxexpr:exp>2</libxexpr:exp> ≅ <float>7.389</float> + + + + + Function <log> + + + Synopsis + + <log> computes the natural logarithmic function. + + + + + Arguments + + <log> takes one argument: x. If no argument is given, an error + occurs. + + + + + Return Values + + <log> returns the natural logarithm of its argument. + If the argument does not evaluate to a positive finite number, + <log> returns an indeterminate result. + + + + + +<libxexpr:log> + <libxexpr:exp>2</libxexpr:exp> +</libxexpr:log> --> <float>2</float> + + + + + Function <pow> + + + Synopsis + + <pow> computes the value of its first argument raised to the + power of its second argument. + + + + + Arguments + + <pow> takes two arguments: x and y. If fewer arguments are + given, an error occurs. + + + + + Return Values + + <pow> returns the value of x (its first argument) raised to the + power of y (its second argument). + + + + If x is a finite value less than 0, and y is a finite non-integer, + <pow> returns an indeterminate result. + + + + If the result overflows, <pow> returns an indeterminate result. + + + + If result underflows, and is not representable, 0 is returned. + + + + Except as specified below, if either argument is indeterminate, + the result is also indeterminate. + + + + If x is 1, the result is 1 (even if y is indeterminate). + + + + If y is 0, the result is 1 (even if x is indeterminate). + + + + If x is 0, and y is an odd integer greater than 0, the result is 0. + + + + If x is 0, and y greater than 0 and not an odd integer, the result + is 0. + + + + If x is 0, and y is less than 0, + <pow> returns an indeterminate result. + + + + + + <libxexpr:pow>10 2</libxexpr:pow> --> <float>100</float> + + + diff -r 000000000000 -r bc8c9a11cbfc docs/reference/libxexpr-docs.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/reference/libxexpr-docs.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,41 @@ + + + +]> + + + libxexpr Reference Manual + + for libxexpr &version; + The latest version of this documentation can be found on-line at + http://www.juiblex.co.uk/libxexpr/docs/reference/. + + + + + Tools + + + + + API Reference + + + + + + + + + + + + API Index + + + + + diff -r 000000000000 -r bc8c9a11cbfc docs/reference/version.xml.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/reference/version.xml.in Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,1 @@ +@VERSION@ diff -r 000000000000 -r bc8c9a11cbfc docs/reference/xexpr.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/reference/xexpr.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,97 @@ + + + +xexpr +1 +User Commands + + + +xexpr +XEXPR Interpreter + + + + +xexpr +OPTION +script + + + +Description +xexpr is an XEXPR interpreter. It loads and executes +XEXPR programs. + + + +Options + + + +, + +print help and exit + + + + +, + +Instead of executing the XEXPR program, dump the parsed tree after loading + + + + +, + +After executing the XEXPR program, dump the result + + + + +, + +After executing the XEXPR program, test the result and exit 0 if it evaluates +to <true/> and non-zero if it evaluates to <false/> + + + + +, + +Adds id to the set of symbols to trace. + +When variables with the name of a traced symbol are created or changed, +xexpr will output a suitable tracing message and a stack +dump + + + + + + +Do XInclude processing + + + + + + +Set a global XEXPR variable of the given name with a +numeric value of number. A float or integer type +will be selected automatically. + + + + + + +Set a global XEXPR variable of the given name with a +string value of value. + + + + + + diff -r 000000000000 -r bc8c9a11cbfc libxexpr/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/Makefile.am Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,14 @@ +AM_CFLAGS=-g $(LIBXEXPR_CFLAGS) +LIBS=$(LIBXEXPR_LIBS) +INCLUDES=-I$(top_srcdir) +AM_LDFLAGS=-no-undefined -version-info $(LIBXEXPR_LT_VERSION_INFO) + +pkginclude_HEADERS=xexprdump.h xexpreval.h xexprparse.h xexprtypes.h \ + xexpr.h + +lib_LTLIBRARIES=libxexpr.la +libxexpr_la_SOURCES=xexprdump.c xexpreval.c xexprparse.c xexprtypes.c \ + extension.c xexprprivate.h $(pkginclude_HEADERS) + +pkgconfigdir=$(libdir)/pkgconfig +pkgconfig_DATA=libxexpr.pc diff -r 000000000000 -r bc8c9a11cbfc libxexpr/extension.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/extension.c Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,209 @@ +#include +#include +#include +#include +#include "xexprprivate.h" + +static XexprConstant *xexpr_do_pi(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + return xexpr_new_number(M_PI); +} + +static XexprConstant *xexpr_do_sin(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *x; + x=xexpr_bindings_get(bindings,"x"); + if (!x) + { + if (args) + { + x=args->data; + args=args->next; + } + else + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Missing \"x\" argument to \"libxexpr:sin\""); + return NULL; + } + } + if (!xexpr_constant_cast(x,XEXPR_TYPE_NUMBER)) + return xexpr_new_number(0.0/0.0); + if (!isfinite(x->u.number)) + return xexpr_new_number(0.0/0.0); + else + return xexpr_new_number(sin(x->u.number)); +} + +static XexprConstant *xexpr_do_atan(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *x,*y; + x=xexpr_bindings_get(bindings,"x"); + if (!x) + { + if (args) + { + x=args->data; + args=args->next; + } + else + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Missing \"x\" argument to \"libxexpr:atan\""); + return NULL; + } + } + if (!xexpr_constant_cast(x,XEXPR_TYPE_NUMBER)) + return xexpr_new_number(0.0/0.0); + y=xexpr_bindings_get(bindings,"y"); + if (!y && args) + { + y=args->data; + args=args->next; + } + if (y && !xexpr_constant_cast(y,XEXPR_TYPE_NUMBER)) + return xexpr_new_number(0.0/0.0); + if (!isfinite(x->u.number) || y && !isfinite(y->u.number)) + return xexpr_new_number(0.0/0.0); + else if (y) + return xexpr_new_number(atan2(y->u.number,x->u.number)); + else + return xexpr_new_number(atan(x->u.number)); +} + +static XexprConstant *xexpr_do_exp(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *x; + x=xexpr_bindings_get(bindings,"x"); + if (!x && args) + { + x=args->data; + args=args->next; + } + if (x && !xexpr_constant_cast(x,XEXPR_TYPE_NUMBER)) + return xexpr_new_number(0.0/0.0); + if (x && !isfinite(x->u.number)) + return xexpr_new_number(0.0/0.0); + else + return xexpr_new_number(x?exp(x->u.number):exp(1.0)); +} + +static XexprConstant *xexpr_do_log(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *x; + x=xexpr_bindings_get(bindings,"x"); + if (!x) + { + if (args) + { + x=args->data; + args=args->next; + } + else + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Missing \"x\" argument to \"libxexpr:log\""); + return NULL; + } + } + if (!xexpr_constant_cast(x,XEXPR_TYPE_NUMBER)) + return xexpr_new_number(0.0/0.0); + if (!isfinite(x->u.number)) + return xexpr_new_number(0.0/0.0); + else + return xexpr_new_number(log(x->u.number)); +} + +static XexprConstant *xexpr_do_pow(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *x,*y; + x=xexpr_bindings_get(bindings,"x"); + if (!x) + { + if (args) + { + x=args->data; + args=args->next; + } + else + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Missing \"x\" argument to \"libxexpr:atan\""); + return NULL; + } + } + if (!xexpr_constant_cast(x,XEXPR_TYPE_NUMBER)) + return xexpr_new_number(0.0/0.0); + y=xexpr_bindings_get(bindings,"y"); + if (!y) + { + if (args) + { + y=args->data; + args=args->next; + } + else + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Missing \"y\" argument to \"libxexpr:pow\""); + return NULL; + } + } + if (!xexpr_constant_cast(y,XEXPR_TYPE_NUMBER)) + return xexpr_new_number(0.0/0.0); + if (x->u.number==1 || y->u.number==0) + return xexpr_new_number(1.0); + else if (!isfinite(x->u.number) || !isfinite(y->u.number)) + return xexpr_new_number(0.0/0.0); + else + return xexpr_new_number(pow(x->u.number,y->u.number)); +} + +static struct libxexpr_function { + char *id; + XexprConstant *(*func)(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err); +} libxexpr_functions[]={ + { "pi", xexpr_do_pi }, + { "sin", xexpr_do_sin }, + { "atan", xexpr_do_atan }, + { "exp", xexpr_do_exp }, + { "log", xexpr_do_log }, + { "pow", xexpr_do_pow }, +}; + +XexprConstant *_xexpr_libxexpr_function_evaluate(Xexpr *xexpr,const char *ns, + const char *id,GSList *bindings,GSList *args,GError **err) +{ + int func; + XexprConstant *value,*result; + GSList *evaluated_args=NULL; + for(func=0;funcdata,err); + if (!value) + return NULL; + evaluated_args=g_slist_prepend(evaluated_args,value); + args=args->next; + } + evaluated_args=g_slist_reverse(evaluated_args); + result=libxexpr_functions[func].func(xexpr,bindings,evaluated_args,err); + g_slist_foreach(evaluated_args,(GFunc)xexpr_constant_free,NULL); + g_slist_free(evaluated_args); + return result; +} diff -r 000000000000 -r bc8c9a11cbfc libxexpr/libxexpr.pc.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/libxexpr.pc.in Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libxexpr +Description: An implementation of XEXPR - http://www.w3.org/TR/xexpr +Version: @VERSION@ +Requires: libxml-2.0 glib-2.0 +Libs: -L${libdir} -lxexpr +Cflags: -I${includedir} diff -r 000000000000 -r bc8c9a11cbfc libxexpr/xexpr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/xexpr.h Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,11 @@ +#ifndef __XEXPER_H__ +#define __XEXPER_H__ + +#define XEXPR_NS "http://www.ebt.com/xexpr" +#define LIBXEXPR_NS "http://www.juiblex.co.uk/ns/libxexpr" + +#include +#include +#include + +#endif /* __XEXPER_H__ */ diff -r 000000000000 -r bc8c9a11cbfc libxexpr/xexprdump.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/xexprdump.c Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,299 @@ +#include +#include +#include +#include + +/** + * SECTION:xexprdump + * @short_description: Functions to dump XEXPR objects + * @stability: Stable + * @include: libxexpr/xexpr.h + * + * A set of functions to dump + * XEXPR + * objects. + */ + +static void xexpr_attribute_dump_string(XexprConstant *constant,GString *str) +{ + const char *s; + gunichar c; + switch(constant->type) + { + default: + return xexpr_constant_dump_string(constant,str); + break; + case XEXPR_TYPE_STRING: + if (strchr(constant->u.string,'"')) + { + if (strchr(constant->u.string,'\'')) + { + g_string_append_c(str,'"'); + for(s=constant->u.string;s;s=g_utf8_next_char(s)) + { + c=g_utf8_get_char(s); + if (c=='"') + g_string_append_c(str,'\\'); + g_string_append_unichar(str,c); + } + g_string_append_c(str,'"'); + } + else + { + g_string_append_c(str,'\''); + g_string_append(str,constant->u.string); + g_string_append_c(str,'\''); + } + } + else + { + g_string_append_c(str,'"'); + g_string_append(str,constant->u.string); + g_string_append_c(str,'"'); + } + break; + case XEXPR_TYPE_INTEGER: + g_string_append_printf(str,"\"%lld\"",constant->u.integer); + break; + case XEXPR_TYPE_NUMBER: + g_string_append_printf(str,"\"%lg\"",constant->u.number); + break; + } +} + +/** + * xexpr_constant_dump_string: + * @constant: an #XexprConstant to dump + * @str: the string to dump to + * + * Dumps @constant to the given @str in XML format. For invocation, string + * and numeric types, XEXPR itself is used as the dump format (with explicit + * type tags). Function definitions cannot be expressed in XEXPR (which + * requires that functions be given a name), so we get as close as we can + * and use a <define> element without the required name attribute. + */ +void xexpr_constant_dump_string(XexprConstant *constant,GString *str) +{ + int i; + gchar *s; + XexprBinding *binding; + GSList *lnk; + GQuark prefix; + switch(constant->type) + { + case XEXPR_TYPE_FUNCTION: + g_string_append(str,"u.function->args) + { + g_string_append(str," args=\""); + for(lnk=constant->u.function->args;lnk;lnk=lnk->next) + { + g_string_append(str,lnk->data); + if (lnk->next) + g_string_append_c(str,' '); + } + g_string_append_c(str,'"'); + } + g_string_append_c(str,'>'); + for(lnk=constant->u.function->constants;lnk;lnk=lnk->next) + xexpr_constant_dump_string(lnk->data,str); + g_string_append(str,""); + break; + case XEXPR_TYPE_INVOCATION: + g_string_append_c(str,'<'); + if (!constant->u.invocation->ns) + prefix=0; + else if (!strcmp(constant->u.invocation->ns,LIBXEXPR_NS)) + prefix=g_quark_from_static_string("libxexpr"); + else + { + for(i=0;;i++) + { + s=g_strdup_printf("x%d",i); + if (!g_quark_try_string(s)) + { + prefix=g_quark_from_string(s); + g_free(s); + break; + } + g_free(s); + } + } + if (prefix) + { + g_string_append(str,g_quark_to_string(prefix)); + g_string_append_c(str,':'); + } + g_string_append(str,constant->u.invocation->function); + if (prefix && prefix!=g_quark_from_static_string("libxexpr")) + { + g_string_append(str," xmlns:"); + g_string_append(str,g_quark_to_string(prefix)); + g_string_append(str,"=\""); + g_string_append(str,constant->u.invocation->ns); + g_string_append_c(str,'"'); + } + for(lnk=constant->u.invocation->bindings;lnk;lnk=lnk->next) + { + binding=lnk->data; + g_string_append_c(str,' '); + g_string_append(str,binding->id); + g_string_append_c(str,'='); + xexpr_attribute_dump_string(binding->value,str); + } + if (constant->u.invocation->constants) + { + g_string_append_c(str,'>'); + xexpr_constants_dump_string(constant->u.invocation->constants, + str); + g_string_append(str,"u.invocation->function); + g_string_append_c(str,'>'); + } + else + g_string_append(str,"/>"); + break; + case XEXPR_TYPE_STRING: + g_string_append(str,""); + g_string_append(str,constant->u.string); + g_string_append(str,""); + break; + case XEXPR_TYPE_INTEGER: + g_string_append_printf(str,"%lld", + constant->u.integer); + break; + case XEXPR_TYPE_NUMBER: + g_string_append_printf(str,"%lg",constant->u.number); + break; + } +} + +/** + * xexpr_constants_dump_string: + * @constants: (transfer none) (element-type XexprConstant): a list of + * #XexprConstant constants to dump + * @str: the string to dump to + * + * Dumps @constants to the given @str in XML format one after the other, + * thus forming an XML fragment. + * + * See xexpr_constant_dump_string() for details of the XML format used. + */ +void xexpr_constants_dump_string(GSList *constants,GString *str) +{ + XexprConstant *constant; + GSList *lnk; + for(lnk=constants;lnk;lnk=lnk->next) + { + constant=lnk->data; + xexpr_constant_dump_string(constant,str); + } +} + +/** + * xexpr_dump_string: + * @xexpr: an #Xexpr to dump + * @str: the string to dump to + * + * Dumps @xexpr to the given @str in XML format. If @xexpr contains multiple + * constants, this will result in an XML fragment. + * + * See xexpr_constant_dump_string() for details of the XML format used. + */ +void xexpr_dump_string(Xexpr *xexpr,GString *str) +{ + xexpr_constants_dump_string(xexpr->constants,str); +} + +/** + * xexpr_constant_dump: + * @constant: an #XexprConstant to dump + * @fp: the FILE to dump to + * + * Dumps @constant to the given @fp in XML format. + * + * See xexpr_constant_dump_string() for details of the XML format used. + */ +void xexpr_constant_dump(XexprConstant *constant,FILE *fp) +{ + GString *str=g_string_new(NULL); + xexpr_constant_dump_string(constant,str); + fputs(str->str,fp); + g_string_free(str,TRUE); +} + +/** + * xexpr_constants_dump: + * @constants: (transfer none) (element-type XexprConstant): a list of + * #XexprConstant constants to dump + * @fp: the FILE to dump to + * + * Dumps @constants to the given @fp in XML format one after the other, + * thus forming an XML fragment. + * + * See xexpr_constant_dump_string() for details of the XML format used. + */ +void xexpr_constants_dump(GSList *constants,FILE *fp) +{ + GString *str=g_string_new(NULL); + xexpr_constants_dump_string(constants,str); + fputs(str->str,fp); + g_string_free(str,TRUE); +} + +/** + * xexpr_dump: + * @xexpr: an #Xexpr to dump + * @fp: the FILE to dump to + * + * Dumps @xexpr to the given @fp in XML format. If @xexpr contains multiple + * constants, this will result in an XML fragment. + * + * See xexpr_constant_dump_string() for details of the XML format used. + */ +void xexpr_dump(Xexpr *xexpr,FILE *fp) +{ + xexpr_constants_dump(xexpr->constants,fp); +} + +/** + * xexpr_stack_dump: + * @xexpr: an #Xexpr whose stack you wish to dump + * @fp: the FILE to dump to + * + * Dumps the current stack of @xexpr to the given @fp in human readable format. + * The environments of the various invoked functions will be given in order + * starting with the innermost (\#0). For each environment, the variables + * defined there will be given along with their current values. Global + * variables are contained in the outermost environment. + */ +void xexpr_stack_dump(Xexpr *xexpr,FILE *fp) +{ + int i; + GSList *lnk; + XexprBinding *binding; + XexprEnvironment *environment=xexpr_get_environment(xexpr); + for(i=0;environment;environment=environment->outer,i++) + { + fprintf(fp,"#%-2d ",i); + if (environment->function) + fprintf(fp,"%s",environment->function); + else + fprintf(fp,"%p",environment); + fprintf(fp," ("); + for(lnk=environment->bindings;lnk;lnk=lnk->next) + { + binding=lnk->data; + fprintf(fp,"%s = ",binding->id); + xexpr_constant_dump(binding->value,fp); + if (lnk->next) + fprintf(fp,", "); + } + fprintf(fp,")\n"); + } +} diff -r 000000000000 -r bc8c9a11cbfc libxexpr/xexprdump.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/xexprdump.h Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,19 @@ +#ifndef __XEXPER_DUMP_H__ +#define __XEXPER_DUMP_H__ + +#include +#include "xexprtypes.h" + +G_BEGIN_DECLS + +void xexpr_constant_dump_string(XexprConstant *constant,GString *str); +void xexpr_constants_dump_string(GSList *constants,GString *str); +void xexpr_dump_string(Xexpr *xexpr,GString *str); +void xexpr_constant_dump(XexprConstant *constant,FILE *fp); +void xexpr_constants_dump(GSList *constants,FILE *fp); +void xexpr_dump(Xexpr *xexpr,FILE *fp); +void xexpr_stack_dump(Xexpr *xexpr,FILE *fp); + +G_END_DECLS + +#endif /* __XEXPER_DUMP_H__ */ diff -r 000000000000 -r bc8c9a11cbfc libxexpr/xexpreval.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/xexpreval.c Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,1621 @@ +#include +#include +#include +#include +#include "xexprprivate.h" + +/** + * SECTION:xexpreval + * @short_description: An evaluator for the XEXPR language + * @stability: Stable + * @include: libxexpr/xexpr.h + * + * An evaluator for the + * XEXPR + * language. + */ + +GSList *xexpr_extensions=NULL; + +static XexprExtension libxexpr_extension={ + LIBXEXPR_NS,_xexpr_libxexpr_function_evaluate +}; + +static XexprConstant *xexpr_do_string(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err); +static gboolean xexpr_defineable_id(const char *id,GError **err); + +/** + * xexpr_eval_error_quark: + * + * Registers an error quark for the libxexpr evaluator if necessary. + * + * Return value: The error quark used for libxexpr evaluator errors. + */ +GQuark xexpr_eval_error_quark(void) +{ + static GQuark quark; + if (!quark) + quark=g_quark_from_static_string("xexpr_eval_error"); + return quark; +} + +/** + * xexpr_register_extension: + * @extension: (transfer none): an #XexprExtension + * + * Registers an extension to handle the evaluation of functions and retrieval + * of variables in a new namespace. + * + * Return value: %TRUE if the extension was successfully registered + */ +gboolean xexpr_register_extension(XexprExtension *extension) +{ + GSList *lnk; + XexprExtension *ext; + static GStaticMutex mutex=G_STATIC_MUTEX_INIT; + g_static_mutex_lock(&mutex); + if (!xexpr_extensions) + xexpr_extensions=g_slist_prepend(xexpr_extensions,&libxexpr_extension); + if (!extension || !extension->ns || !*extension->ns || + !strcmp(extension->ns,XEXPR_NS)) + { + g_static_mutex_unlock(&mutex); + return FALSE; + } + for(lnk=xexpr_extensions;lnk;lnk=lnk->next) + { + ext=lnk->data; + if (!strcmp(ext->ns,extension->ns)) + { + g_static_mutex_unlock(&mutex); + return FALSE; + } + } + extension=g_memdup(extension,sizeof(*extension)); + extension->ns=g_strdup(extension->ns); + xexpr_extensions=g_slist_prepend(xexpr_extensions,extension); + g_static_mutex_unlock(&mutex); + return TRUE; +} + +/* + * Returned constant should be freed iff evaluate is TRUE + */ +static XexprConstant *xexpr_get_argument(Xexpr *xexpr,GSList *bindings, + GSList **args,const char *func,const char *id,gboolean evaluate,GError **err) +{ + XexprConstant *arg; + arg=xexpr_bindings_get(bindings,id); + if (!arg) + { + if (*args) + { + arg=(*args)->data; + *args=(*args)->next; + } + else + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Missing \"%s\" argument to \"%s\"",id,func); + return NULL; + } + } + if (arg && evaluate) + arg=xexpr_constant_evaluate(xexpr,arg,err); + return arg; +} + +static XexprConstant *xexpr_do_define(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + int i; + gchar **vector=NULL; + GSList *parameters=NULL; + XexprConstant *name,*params,*value,*arg; + XexprEnvironment *frame; + name=xexpr_get_argument(xexpr,bindings,&args,"define","name",TRUE,err); + if (!name) + return NULL; + if (name->type!=XEXPR_TYPE_STRING) + { + args=g_slist_prepend(NULL,name); + arg=xexpr_do_string(xexpr,NULL,args,NULL); + g_slist_free(args); + if (arg) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Attempt to define a function with a non-string name \"%s\"", + arg->u.string); + xexpr_constant_free(arg); + } + else + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Attempt to define a function with a non-string name"); + xexpr_constant_free(name); + return NULL; + } + else if (!_xexpr_validate_id(name->u.string,err) || + !xexpr_defineable_id(name->u.string,err)) + { + xexpr_constant_free(name); + return NULL; + } + params=xexpr_bindings_get(bindings,"args"); + if (params) + { + params=xexpr_constant_evaluate(xexpr,params,err); + if (params->type!=XEXPR_TYPE_STRING) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Attempt to define a function with non-string argument names"); + xexpr_constant_free(params); + xexpr_constant_free(name); + return NULL; + } + vector=g_strsplit_set(params->u.string," \t\n\r",-1); + for(i=0;vector[i];i++) + { + if (vector[i][0]>='0' && vector[i][0]<='9' || + (vector[i][0]=='+' || vector[i][0]=='-') && + vector[i][1]>='0' && vector[i][1]<='9') + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Attempt to define a function with non-string argument names"); + xexpr_constant_free(params); + xexpr_constant_free(name); + g_strfreev(vector); + g_slist_free(parameters); + return NULL; + } + parameters=g_slist_prepend(parameters,vector[i]); + } + parameters=g_slist_reverse(parameters); + } + value=xexpr_new_function(parameters,args); + g_slist_free(parameters); + if (vector) + g_strfreev(vector); + frame=xexpr->environment; + xexpr->environment=frame->outer; + xexpr_var_new(xexpr,name->u.string,value); + xexpr->environment=frame; + xexpr_constant_free(name); + return value; +} + +static XexprConstant *xexpr_do_print(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + gboolean newline=FALSE; + GSList *lnk; + XexprConstant *arg; + arg=xexpr_bindings_get(bindings,"newline"); + if (arg && arg->type==XEXPR_TYPE_STRING && !strcmp(arg->u.string,"true")) + newline=TRUE; + for(lnk=args;lnk;lnk=lnk->next) + { + arg=lnk->data; + switch(arg->type) + { + case XEXPR_TYPE_FUNCTION: + /* + * http://www.w3.org/TR/xexpr/#id-0003 implies that + * function objects are ignored in . + */ + break; + case XEXPR_TYPE_INVOCATION: + printf("<%s/>",arg->u.invocation->function); + break; + case XEXPR_TYPE_STRING: + fputs(arg->u.string,stdout); + break; + case XEXPR_TYPE_INTEGER: + printf("%lld",arg->u.integer); + break; + case XEXPR_TYPE_NUMBER: + printf("%lg",arg->u.number); + break; + } + } + if (newline) + putchar('\n'); + return xexpr_new_invocation(NULL,"true",NULL,NULL); +} + +static XexprConstant *xexpr_do_println(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + putchar('\n'); + return xexpr_new_invocation(NULL,"true",NULL,NULL); +} + +static XexprConstant *xexpr_do_get(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + XexprConstant *name,*value; + name=xexpr_get_argument(xexpr,bindings,&args,"get","name",FALSE,err); + if (!name) + return NULL; + if (name->type==XEXPR_TYPE_STRING) + value=xexpr_var_get(xexpr,name->u.string); + else + value=NULL; + if (value) + value=xexpr_constant_dup(value); + else + value=xexpr_new_invocation(NULL,"nil",NULL,NULL); + return value; +} + +static XexprConstant *xexpr_do_set(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + XexprConstant *name,*value; + name=xexpr_get_argument(xexpr,bindings,&args,"set","name",FALSE,err); + if (!name) + return NULL; + if (name->type!=XEXPR_TYPE_STRING) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Attempt to bind a value a non-string name"); + xexpr_constant_free(name); + return NULL; + } + else if (!_xexpr_validate_id(name->u.string,err) || + !xexpr_defineable_id(name->u.string,err)) + { + xexpr_constant_free(name); + return NULL; + } + value=xexpr_get_argument(xexpr,bindings,&args,"set","value",FALSE,err); + if (!value) + return NULL; + xexpr_var_set(xexpr,name->u.string,value); + return xexpr_constant_dup(value); +} + +static XexprConstant *xexpr_do_expr(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + if (!args) + return xexpr_new_invocation(NULL,"nil",NULL,NULL); + while(args->next) + args=args->next; + return xexpr_constant_dup(args->data); +} + +static XexprConstant *xexpr_do_return(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + XexprConstant *retval; + if (!args) + retval=xexpr_new_invocation(NULL,"nil",NULL,NULL); + while(args->next) + args=args->next; + retval=xexpr_constant_dup(args->data); + return xexpr_new_invocation_take_ownership(NULL,g_strdup("return"),NULL, + g_slist_prepend(NULL,retval)); +} + +static XexprConstant *xexpr_do_string(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + XexprConstant *arg; + GString *str=g_string_new(NULL); + while(args) + { + arg=args->data; + switch(arg->type) + { + case XEXPR_TYPE_FUNCTION: + g_warn_if_reached(); + break; + case XEXPR_TYPE_INVOCATION: + g_string_append_printf(str,"<%s/>",arg->u.invocation->function); + break; + case XEXPR_TYPE_STRING: + g_string_append(str,arg->u.string); + break; + case XEXPR_TYPE_INTEGER: + g_string_append_printf(str,"%lld",arg->u.integer); + break; + case XEXPR_TYPE_NUMBER: + g_string_append_printf(str,"%lg",arg->u.number); + break; + } + args=args->next; + } + return xexpr_new_string_take_ownership(g_string_free(str,FALSE)); +} + +static XexprConstant *xexpr_do_integer(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + XexprConstant *arg; + double d; + long long int value=0; + while(args) + { + arg=args->data; + switch(arg->type) + { + case XEXPR_TYPE_FUNCTION: + g_warn_if_reached(); + break; + case XEXPR_TYPE_INVOCATION: + g_warn_if_reached(); + break; + case XEXPR_TYPE_STRING: + value=g_ascii_strtoll(arg->u.string,NULL,0); + if (value==LLONG_MIN || value==LLONG_MAX) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Integer overflow on %s",arg->u.string); + return NULL; + } + break; + case XEXPR_TYPE_INTEGER: + value=arg->u.integer; + break; + case XEXPR_TYPE_NUMBER: + if (!isfinite(arg->u.number)) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "%lg is not finite",arg->u.number); + return NULL; + } + d=nearbyint(arg->u.number); + if (d<=LLONG_MIN || d>=LLONG_MAX) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Integer overflow on %lg",arg->u.number); + return NULL; + } + value=(long long int)d; + break; + } + args=args->next; + } + return xexpr_new_integer(value); +} + +static XexprConstant *xexpr_do_float(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + XexprConstant *arg; + double value=0.0/0.0; + while(args) + { + arg=args->data; + switch(arg->type) + { + case XEXPR_TYPE_FUNCTION: + g_warn_if_reached(); + break; + case XEXPR_TYPE_INVOCATION: + g_warn_if_reached(); + break; + case XEXPR_TYPE_STRING: + value=g_ascii_strtod(arg->u.string,NULL); + if (value==HUGE_VAL || value==-HUGE_VAL) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Numeric overflow on %s",arg->u.string); + return NULL; + } + break; + case XEXPR_TYPE_INTEGER: + if (arg->u.integer<-DBL_MAX || arg->u.integer>DBL_MAX) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Numeric overflow on %lld",arg->u.integer); + return NULL; + } + value=(double)arg->u.integer; + break; + case XEXPR_TYPE_NUMBER: + value=arg->u.number; + break; + } + args=args->next; + } + return xexpr_new_number(value); +} + +static XexprConstant *xexpr_do_true(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + return xexpr_new_invocation(NULL,"true",NULL,NULL); +} + +static XexprConstant *xexpr_do_false(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + return xexpr_new_invocation(NULL,"false",NULL,NULL); +} + +static XexprConstant *xexpr_do_nil(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + return xexpr_new_invocation(NULL,"nil",NULL,NULL); +} + +typedef struct xexpr_accumulator { + gboolean first; + Xexpr *xexpr; + GSList *args; + const char *result_binding; + XexprConstant *arg,*result; +} XexprAccumulator; + +static gboolean xexpr_accumulator_init(XexprAccumulator *accumulator, + Xexpr *xexpr,GSList *args,gboolean bind_result,GError **err) +{ + XexprConstant *arg; + accumulator->xexpr=xexpr; + accumulator->args=args; + accumulator->arg=NULL; + accumulator->first=TRUE; + if (!accumulator->args) + { + accumulator->result_binding=NULL; + accumulator->result=xexpr_new_invocation(NULL,"nil",NULL,NULL); + return TRUE; + } + arg=accumulator->args->data; + /* + * If arg invokes a function with no bindings and no arguments + * then the result is accumulated in the function itself. + * This allows constructs such as: + * 1 + * as a shorthand for: + * 1 + * This is implied by http://www.w3.org/TR/xexpr/#id-0045 + * + * Note that since the value accumulates: + * + * results in 4 rather than 3. + */ + if (bind_result && arg->type==XEXPR_TYPE_INVOCATION && + !arg->u.invocation->bindings && !arg->u.invocation->constants) + accumulator->result_binding=arg->u.invocation->function; + else + accumulator->result_binding=NULL; + accumulator->result=xexpr_constant_evaluate(xexpr,arg,err); + while(accumulator->result && accumulator->result->type==XEXPR_TYPE_FUNCTION) + { + arg=xexpr_constant_evaluate(xexpr,accumulator->result,err); + xexpr_constant_free(accumulator->result); + accumulator->result=arg; + } + return !!accumulator->result; +} + +static gboolean xexpr_accumulator_next(XexprAccumulator *accumulator) +{ + if (accumulator->result_binding && !accumulator->first) + { + xexpr_var_set(accumulator->xexpr,accumulator->result_binding, + accumulator->result); + if (xexpr_is_tracing(accumulator->xexpr,accumulator->result_binding)) + { + printf("\nChanged variable %s\n",accumulator->result_binding); + xexpr_stack_dump(accumulator->xexpr,stdout); + } + } + accumulator->args=accumulator->args->next; + accumulator->first=FALSE; + return !!accumulator->args; +} + +static XexprConstant *xexpr_accumulator_get(XexprAccumulator *accumulator, + GError **err) +{ + if (accumulator->arg) + xexpr_constant_free(accumulator->arg); + accumulator->arg=xexpr_constant_evaluate(accumulator->xexpr, + accumulator->args->data,err); + return accumulator->arg; +} + +static XexprConstant *xexpr_accumulator_finish(XexprAccumulator *accumulator) +{ + if (accumulator->arg) + xexpr_constant_free(accumulator->arg); + return accumulator->result; +} + +static void xexpr_accumulator_abort(XexprAccumulator *accumulator) +{ + xexpr_constant_free(xexpr_accumulator_finish(accumulator)); +} + +static XexprConstant *xexpr_do_add(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *arg; + gchar *str; + XexprAccumulator accumulator; + if (!xexpr_accumulator_init(&accumulator,xexpr,args,TRUE,err)) + return NULL; + while(xexpr_accumulator_next(&accumulator)) + { + arg=xexpr_accumulator_get(&accumulator,err); + if (!arg) + { + xexpr_accumulator_abort(&accumulator); + return NULL; + } + switch(accumulator.result->type) + { + case XEXPR_TYPE_INVOCATION: + case XEXPR_TYPE_FUNCTION: + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Attempt to perform arithmetic op on a function"); + xexpr_accumulator_abort(&accumulator); + return NULL; + break; + case XEXPR_TYPE_STRING: + switch(arg->type) + { + case XEXPR_TYPE_FUNCTION: + case XEXPR_TYPE_INVOCATION: + g_set_error(err,XEXPR_EVAL_ERROR, + XEXPR_EVAL_ERROR_FAILED, + "Attempt to perform arithmetic op on a function"); + xexpr_accumulator_abort(&accumulator); + return NULL; + case XEXPR_TYPE_STRING: + str=g_strconcat(accumulator.result->u.string, + arg->u.string,NULL); + g_free(accumulator.result->u.string); + accumulator.result->u.string=str; + break; + case XEXPR_TYPE_INTEGER: + str=g_strdup_printf("%s%lld", + accumulator.result->u.string,arg->u.integer); + g_free(accumulator.result->u.string); + accumulator.result->u.string=str; + break; + case XEXPR_TYPE_NUMBER: + str=g_strdup_printf("%s%lg", + accumulator.result->u.string,arg->u.number); + g_free(accumulator.result->u.string); + accumulator.result->u.string=str; + break; + } + break; + case XEXPR_TYPE_INTEGER: + if (arg->type==XEXPR_TYPE_INTEGER) + { + accumulator.result->u.integer+=arg->u.integer; + break; + } + else if (arg->type==XEXPR_TYPE_NUMBER) + { + accumulator.result->type=XEXPR_TYPE_NUMBER; + accumulator.result->u.number=accumulator.result->u.integer; + } + /* Fall through */ + case XEXPR_TYPE_NUMBER: + if (arg->type==XEXPR_TYPE_INTEGER) + accumulator.result->u.number+=arg->u.integer; + else if (arg->type==XEXPR_TYPE_NUMBER) + accumulator.result->u.number+=arg->u.number; + else + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Attempt to add non-numeric to numeric quantity"); + xexpr_accumulator_abort(&accumulator); + return NULL; + } + break; + } + } + return xexpr_accumulator_finish(&accumulator); +} + +static XexprConstant *xexpr_do_subtract(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + XexprConstant *arg; + XexprAccumulator accumulator; + if (!xexpr_accumulator_init(&accumulator,xexpr,args,TRUE,err)) + return NULL; + while(xexpr_accumulator_next(&accumulator)) + { + arg=xexpr_accumulator_get(&accumulator,err); + if (!arg) + { + xexpr_accumulator_abort(&accumulator); + return NULL; + } + if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER) + { +invalid_args: + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Attempt to perform subtraction on a non-numeric quantity"); + xexpr_accumulator_abort(&accumulator); + return NULL; + } + switch(accumulator.result->type) + { + case XEXPR_TYPE_INTEGER: + if (arg->type==XEXPR_TYPE_INTEGER) + { + accumulator.result->u.integer-=arg->u.integer; + break; + } + else + { + accumulator.result->type=XEXPR_TYPE_NUMBER; + accumulator.result->u.number=accumulator.result->u.integer; + } + /* Fall through */ + case XEXPR_TYPE_NUMBER: + if (accumulator.arg->type==XEXPR_TYPE_INTEGER) + accumulator.result->u.number-=arg->u.integer; + else + accumulator.result->u.number-=arg->u.number; + break; + default: + goto invalid_args; + } + } + return xexpr_accumulator_finish(&accumulator); +} + +static XexprConstant *xexpr_do_multiply(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + XexprConstant *arg; + XexprAccumulator accumulator; + if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err)) + return NULL; + while(xexpr_accumulator_next(&accumulator)) + { + arg=xexpr_accumulator_get(&accumulator,err); + if (!arg) + { + xexpr_accumulator_abort(&accumulator); + return NULL; + } + if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER) + { + GString *str=g_string_new(NULL); +invalid_args: + xexpr_constant_dump_string(arg,str); + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Attempt to perform multiply on a non-numeric quantity: %s", + str->str); + g_string_free(str,TRUE); + xexpr_accumulator_abort(&accumulator); + return NULL; + } + switch(accumulator.result->type) + { + case XEXPR_TYPE_INTEGER: + if (arg->type==XEXPR_TYPE_INTEGER) + { + accumulator.result->u.integer*=arg->u.integer; + break; + } + else + { + accumulator.result->type=XEXPR_TYPE_NUMBER; + accumulator.result->u.number=accumulator.result->u.integer; + } + /* Fall through */ + case XEXPR_TYPE_NUMBER: + if (arg->type==XEXPR_TYPE_INTEGER) + accumulator.result->u.number*=arg->u.integer; + else + accumulator.result->u.number*=arg->u.number; + break; + default: + goto invalid_args; + } + } + return xexpr_accumulator_finish(&accumulator); +} + +static XexprConstant *xexpr_do_divide(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + XexprConstant *arg; + long long int r; + XexprAccumulator accumulator; + if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err)) + return NULL; + while(xexpr_accumulator_next(&accumulator)) + { + arg=xexpr_accumulator_get(&accumulator,err); + if (!arg) + { + xexpr_accumulator_abort(&accumulator); + return NULL; + } + if (arg->type!=XEXPR_TYPE_INTEGER && arg->type!=XEXPR_TYPE_NUMBER) + { +invalid_args: + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Attempt to perform divide on a non-numeric quantity"); + xexpr_accumulator_abort(&accumulator); + return NULL; + } + switch(accumulator.result->type) + { + case XEXPR_TYPE_INTEGER: + if (arg->type==XEXPR_TYPE_INTEGER) + { + r=accumulator.result->u.integer/arg->u.integer; + if (r*arg->u.integer==accumulator.result->u.integer) + { + accumulator.result->u.integer=r; + break; + } + } + accumulator.result->type=XEXPR_TYPE_NUMBER; + accumulator.result->u.number=accumulator.result->u.integer; + /* Fall through */ + case XEXPR_TYPE_NUMBER: + if (arg->type==XEXPR_TYPE_INTEGER) + accumulator.result->u.number/=arg->u.integer; + else + accumulator.result->u.number/=arg->u.number; + break; + default: + goto invalid_args; + } + } + return xexpr_accumulator_finish(&accumulator); +} + +/** + * xexpr_constant_cast: + * @constant: an #XexprConstant to cast + * @to: type to cast @constant to + * + * Attempt to perform an implicit cast of @constant to the given type @to. + * Implicit casting can only be performed between the two numeric types + * and then only where the quantity can be represented without loss of + * precision. + * + * Return value: %TRUE if @constant is now of type @to. + */ +gboolean xexpr_constant_cast(XexprConstant *constant,XexprType to) +{ + double dummy; + if (constant->type==to) + return TRUE; + if (constant->type==XEXPR_TYPE_NUMBER && to==XEXPR_TYPE_INTEGER && + constant->u.number>=LLONG_MIN && constant->u.number<=LLONG_MAX && + !modf(constant->u.number,&dummy)) + { + constant->type=XEXPR_TYPE_INTEGER; + constant->u.integer=constant->u.number; + return TRUE; + } + else if (constant->type==XEXPR_TYPE_INTEGER && to==XEXPR_TYPE_NUMBER && + constant->u.integer+1.0!=(double)constant->u.integer && + constant->u.integer-1.0!=(double)constant->u.integer) + { + constant->type=XEXPR_TYPE_NUMBER; + constant->u.number=constant->u.integer; + return TRUE; + } + else + return FALSE; +} + +static gboolean xexpr_constant_boolean(Xexpr *xexpr,XexprConstant *constant, + GError **err) +{ + gboolean retval; + XexprConstant *result; + switch (constant->type) + { + case XEXPR_TYPE_NUMBER: + return !(constant->u.number==0); + case XEXPR_TYPE_INTEGER: + return !!constant->u.integer; + case XEXPR_TYPE_STRING: + return !!*constant->u.string; + case XEXPR_TYPE_INVOCATION: + return strcmp(constant->u.invocation->function,"false") && + strcmp(constant->u.invocation->function,"nil"); + case XEXPR_TYPE_FUNCTION: + /* + * See http://www.w3.org/TR/xexpr/#id-0038 + */ + result=xexpr_constant_evaluate(xexpr,constant,err); + if (!result) + return FALSE; + retval=xexpr_constant_boolean(xexpr,result,err); + xexpr_constant_free(result); + return retval; + } + return FALSE; +} + +/* + * Returns: 0 if equal, <0 if value1 < value2, >0 if value1 > value2, + * NaN if value1 is not comparible with value2. + */ +static double xexpr_constant_compare(Xexpr *xexpr,XexprConstant *v1, + XexprConstant *v2) +{ + double retval=0.0/0.0; + XexprConstant *value1,*value2; + value1=xexpr_constant_evaluate(xexpr,v1,NULL); + if (!value1) + value1=xexpr_constant_dup(v1); + while(value1->type==XEXPR_TYPE_FUNCTION) + { + v1=xexpr_constant_evaluate(xexpr,value1,NULL); + if (v1) + { + xexpr_constant_free(value1); + value1=v1; + } + else + break; + } + value2=xexpr_constant_evaluate(xexpr,v2,NULL); + if (!value2) + value2=xexpr_constant_dup(v2); + while(value2->type==XEXPR_TYPE_FUNCTION) + { + v2=xexpr_constant_evaluate(xexpr,value2,NULL); + if (v2) + { + xexpr_constant_free(value2); + value2=v2; + } + else + break; + } + if (value1->type!=value2->type) + { + if (!xexpr_constant_cast(value1,value2->type) && + !xexpr_constant_cast(value2,value1->type)) + { + xexpr_constant_free(value1); + xexpr_constant_free(value2); + return 0.0/0.0; + } + } + switch(value1->type) + { + case XEXPR_TYPE_FUNCTION: + g_warn_if_reached(); + break; + case XEXPR_TYPE_INVOCATION: + g_warn_if_fail(value1->u.invocation->bindings==NULL); + g_warn_if_fail(value2->u.invocation->bindings==NULL); + g_warn_if_fail(value1->u.invocation->constants==NULL); + g_warn_if_fail(value2->u.invocation->constants==NULL); + retval=strcmp(value1->u.invocation->function, + value2->u.invocation->function); + break; + case XEXPR_TYPE_STRING: + retval=strcmp(value1->u.string,value2->u.string); + break; + case XEXPR_TYPE_INTEGER: + retval=value1->u.integer-value2->u.integer; + break; + case XEXPR_TYPE_NUMBER: + retval=value1->u.number-value2->u.number; + break; + } + xexpr_constant_free(value1); + xexpr_constant_free(value2); + return retval; +} + +static XexprConstant *xexpr_do_eq(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *arg,*standard=NULL; + while(args) + { + arg=args->data; + if (!standard) + standard=arg; + else if (xexpr_constant_compare(xexpr,standard,arg)) + return xexpr_new_invocation(NULL,"false",NULL,NULL); + args=args->next; + } + return xexpr_new_invocation(NULL,"true",NULL,NULL); +} + +static XexprConstant *xexpr_do_neq(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *arg; + GSList *lnk; + while(args) + { + arg=args->data; + for(lnk=args->next;lnk;lnk=lnk->next) + if (!xexpr_constant_compare(xexpr,arg,lnk->data)) + return xexpr_new_invocation(NULL,"false",NULL,NULL); + args=args->next; + } + return xexpr_new_invocation(NULL,"true",NULL,NULL); +} + +static XexprConstant *xexpr_do_leq(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *arg,*standard=NULL; + while(args) + { + arg=args->data; + if (standard && !(xexpr_constant_compare(xexpr,standard,arg)<=0)) + return xexpr_new_invocation(NULL,"false",NULL,NULL); + standard=arg; + args=args->next; + } + return xexpr_new_invocation(NULL,"true",NULL,NULL); +} + +static XexprConstant *xexpr_do_geq(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *arg,*standard=NULL; + while(args) + { + arg=args->data; + if (standard && !(xexpr_constant_compare(xexpr,standard,arg)>=0)) + return xexpr_new_invocation(NULL,"false",NULL,NULL); + standard=arg; + args=args->next; + } + return xexpr_new_invocation(NULL,"true",NULL,NULL); +} + +static XexprConstant *xexpr_do_lt(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *arg,*standard=NULL; + while(args) + { + arg=args->data; + if (standard && !(xexpr_constant_compare(xexpr,standard,arg)<0)) + return xexpr_new_invocation(NULL,"false",NULL,NULL); + standard=arg; + args=args->next; + } + return xexpr_new_invocation(NULL,"true",NULL,NULL); +} + +static XexprConstant *xexpr_do_gt(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + XexprConstant *arg,*standard=NULL; + while(args) + { + arg=args->data; + if (standard && !(xexpr_constant_compare(xexpr,standard,arg)>0)) + return xexpr_new_invocation(NULL,"false",NULL,NULL); + standard=arg; + args=args->next; + } + return xexpr_new_invocation(NULL,"true",NULL,NULL); +} + +static XexprConstant *xexpr_do_and(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + GError *tmp_err=NULL; + XexprConstant *arg; + XexprAccumulator accumulator; + if (!args) + return xexpr_new_invocation(NULL,"true",NULL,NULL); + if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err)) + return NULL; + if (!xexpr_constant_boolean(xexpr,accumulator.result,&tmp_err)) + { + xexpr_accumulator_abort(&accumulator); + if (tmp_err) + { + g_propagate_error(err,tmp_err); + return NULL; + } + else + return xexpr_new_invocation(NULL,"false",NULL,NULL); + } + while(xexpr_accumulator_next(&accumulator)) + { + arg=xexpr_accumulator_get(&accumulator,err); + if (!arg) + { + xexpr_accumulator_abort(&accumulator); + return NULL; + } + if (!xexpr_constant_boolean(xexpr,arg,&tmp_err)) + { + xexpr_accumulator_abort(&accumulator); + if (tmp_err) + { + g_propagate_error(err,tmp_err); + return NULL; + } + else + return xexpr_new_invocation(NULL,"false",NULL,NULL); + } + } + xexpr_accumulator_abort(&accumulator); + return xexpr_new_invocation(NULL,"true",NULL,NULL); +} + +static XexprConstant *xexpr_do_or(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + GError *tmp_err=NULL; + XexprConstant *arg; + XexprAccumulator accumulator; + if (!args) + return xexpr_new_invocation(NULL,"true",NULL,NULL); + if (!xexpr_accumulator_init(&accumulator,xexpr,args,FALSE,err)) + return NULL; + if (xexpr_constant_boolean(xexpr,accumulator.result,&tmp_err)) + { + xexpr_accumulator_abort(&accumulator); + return xexpr_new_invocation(NULL,"true",NULL,NULL); + } + else if (tmp_err) + { + xexpr_accumulator_abort(&accumulator); + g_propagate_error(err,tmp_err); + return NULL; + } + while(xexpr_accumulator_next(&accumulator)) + { + arg=xexpr_accumulator_get(&accumulator,err); + if (!arg) + { + xexpr_accumulator_abort(&accumulator); + return NULL; + } + if (xexpr_constant_boolean(xexpr,arg,&tmp_err)) + { + xexpr_accumulator_abort(&accumulator); + return xexpr_new_invocation(NULL,"true",NULL,NULL); + } + else if (tmp_err) + { + xexpr_accumulator_abort(&accumulator); + g_propagate_error(err,tmp_err); + return NULL; + } + } + xexpr_accumulator_abort(&accumulator); + return xexpr_new_invocation(NULL,"false",NULL,NULL); +} + +/* + * is a misnomer, http://www.w3.org/TR/xexpr/#id-0040 + * makes it clear that, except in the trivial case of no arguments, + * is simply the negation of . + */ +static XexprConstant *xexpr_do_not(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + gboolean test; + XexprConstant *result; + if (!args) + return xexpr_new_invocation(NULL,"true",NULL,NULL); + result=xexpr_do_and(xexpr,bindings,args,err); + if (!result) + return NULL; + test=xexpr_constant_boolean(xexpr,result,NULL); + xexpr_constant_free(result); + return xexpr_new_invocation(NULL,test?"false":"true",NULL,NULL); +} + +static XexprConstant *xexpr_do_if(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + GError *tmp_err=NULL; + gboolean test; + XexprConstant *arg; + if (g_slist_length(args)<2) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + " requires at least 2 arguments to be passed"); + return NULL; + } + arg=xexpr_constant_evaluate(xexpr,args->data,err); + if (!arg) + return NULL; + test=xexpr_constant_boolean(xexpr,arg,&tmp_err); + if (tmp_err) + { + g_propagate_error(err,tmp_err); + return NULL; + } + xexpr_constant_free(arg); + if (test) + return xexpr_constant_evaluate(xexpr,args->next->data,err); + else if (args->next->next) + return xexpr_constant_evaluate(xexpr,args->next->next->data,err); + else + return xexpr_new_invocation(NULL,"nil",NULL,NULL); +} + +static XexprConstant *xexpr_do_switch(Xexpr *xexpr,GSList *bindings, + GSList *args,GError **err) +{ + GError *tmp_err=NULL; + gboolean test; + XexprConstant *case_arg,*arg; + GSList *lnk; + while(args) + { + case_arg=args->data; + if (case_arg->type!=XEXPR_TYPE_INVOCATION || + strcmp(case_arg->u.invocation->function,"case")) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + " requires a list of expressions"); + return NULL; + } + lnk=case_arg->u.invocation->constants; + if (!lnk) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + " requires a test expression"); + return NULL; + } + arg=xexpr_constant_evaluate(xexpr,lnk->data,err); + if (!arg) + return NULL; + test=xexpr_constant_boolean(xexpr,arg,&tmp_err); + if (tmp_err) + { + g_propagate_error(err,tmp_err); + return NULL; + } + xexpr_constant_free(arg); + if (test) + { + arg=NULL; + while(lnk) + { + if (arg) + xexpr_constant_free(arg); + arg=xexpr_constant_evaluate(xexpr,lnk->data,err); + if (!arg) + return NULL; + lnk=lnk->next; + } + if (!arg) + arg=xexpr_new_invocation(NULL,"nil",NULL,NULL); + return arg; + } + args=args->next; + } + return xexpr_new_invocation(NULL,"nil",NULL,NULL); +} + +static XexprConstant *xexpr_do_while(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + GError *tmp_err=NULL; + gboolean test; + XexprConstant *arg,*result; + if (g_slist_length(args)!=2) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + " takes 2 arguments"); + return NULL; + } + result=xexpr_new_invocation(NULL,"nil",NULL,NULL); + do + { + arg=xexpr_constant_evaluate(xexpr,args->data,err); + if (!arg) + { + xexpr_constant_free(result); + return NULL; + } + test=xexpr_constant_boolean(xexpr,arg,&tmp_err); + if (tmp_err) + { + g_propagate_error(err,tmp_err); + return NULL; + } + xexpr_constant_free(arg); + if (test) + { + xexpr_constant_free(result); + result=xexpr_constant_evaluate(xexpr,args->next->data,err); + if (!result) + return NULL; + } + } while(test); + return result; +} + +static XexprConstant *xexpr_do_do(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err) +{ + GError *tmp_err=NULL; + gboolean test; + XexprConstant *arg,*result; + if (g_slist_length(args)!=2) + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + " takes 2 arguments"); + return NULL; + } + result=NULL; + do + { + if (result) + xexpr_constant_free(result); + result=xexpr_constant_evaluate(xexpr,args->data,err); + if (!result) + return NULL; + arg=xexpr_constant_evaluate(xexpr,args->next->data,err); + if (!arg) + { + xexpr_constant_free(result); + return NULL; + } + test=xexpr_constant_boolean(xexpr,arg,&tmp_err); + if (tmp_err) + { + g_propagate_error(err,tmp_err); + return NULL; + } + xexpr_constant_free(arg); + } while(test); + return result; +} + +static struct xexpr_builtin { + char *id; + gboolean evaluate_args; + XexprConstant *(*func)(Xexpr *xexpr,GSList *bindings,GSList *args, + GError **err); +} xexpr_builtins[]={ + { "define", FALSE, xexpr_do_define }, + { "print", TRUE, xexpr_do_print }, + { "println", TRUE, xexpr_do_println }, + { "get", TRUE, xexpr_do_get }, + { "set", TRUE, xexpr_do_set }, + { "expr", TRUE, xexpr_do_expr }, + { "xexpr", TRUE, xexpr_do_expr }, + { "return", TRUE, xexpr_do_return }, + { "string", TRUE, xexpr_do_string }, + { "integer", TRUE, xexpr_do_integer }, + { "float", TRUE, xexpr_do_float }, + { "true", TRUE, xexpr_do_true }, + { "false", TRUE, xexpr_do_false }, + { "nil", TRUE, xexpr_do_nil }, + { "add", FALSE, xexpr_do_add }, + { "subtract", FALSE, xexpr_do_subtract }, + { "multiply", FALSE, xexpr_do_multiply }, + { "divide", FALSE, xexpr_do_divide }, + { "eq", TRUE, xexpr_do_eq }, + { "neq", TRUE, xexpr_do_neq }, + { "leq", TRUE, xexpr_do_leq }, + { "geq", TRUE, xexpr_do_geq }, + { "lt", TRUE, xexpr_do_lt }, + { "gt", TRUE, xexpr_do_gt }, + { "and", FALSE, xexpr_do_and }, + { "or", FALSE, xexpr_do_or }, + { "not", FALSE, xexpr_do_not }, + { "if", FALSE, xexpr_do_if }, + { "switch", FALSE, xexpr_do_switch }, + { "while", FALSE, xexpr_do_while }, + { "do", FALSE, xexpr_do_do }, +}; + +static gboolean xexpr_defineable_id(const char *id,GError **err) +{ + int i; + for(i=0;itype==XEXPR_TYPE_FUNCTION,NULL); + result=NULL; + for(lnk=constant->u.function->constants;lnk;lnk=lnk->next) + { + if (result) + xexpr_constant_free(result); + result=xexpr_constant_evaluate(xexpr,lnk->data,err); + if (!result) + return NULL; + if (result->type==XEXPR_TYPE_INVOCATION && + !strcmp(result->u.invocation->function,"return")) + { + lnk=g_slist_last(result->u.invocation->constants); + tmp=xexpr_constant_dup(lnk->data); + xexpr_constant_free(result); + result=tmp; + break; + } + } + if (!result) + result=xexpr_new_invocation(NULL,"nil",NULL,NULL); + return result; +} + +static XexprConstant *xexpr_function_evaluate(Xexpr *xexpr,const char *ns, + const char *id,GSList *bindings,GSList *args,GError **err) +{ + int builtin; + gboolean evaluate_args; + XexprBinding *binding; + XexprExtension *ext; + XexprConstant *value,*function_def,*result; + const char *unbound_parameter; + GSList *unbound_args=args,*lnk,*actual,*unbound_parameters; + if (ns) + { + for(lnk=xexpr_extensions;lnk;lnk=lnk->next) + { + ext=lnk->data; + if (!strcmp(ext->ns,ns)) + return ext->function_evaluate(xexpr,ns,id,bindings,args,err); + } + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "Unknown namespace \"%s\"",ns); + return NULL; + } + for(builtin=0;builtintype!=XEXPR_TYPE_FUNCTION) + return xexpr_constant_evaluate(xexpr,function_def,err); + unbound_parameters=g_slist_copy(function_def->u.function->args); + evaluate_args=TRUE; + } + else + { + function_def=NULL; + unbound_parameters=NULL; + } + for(lnk=bindings;lnk;lnk=lnk->next) + { + binding=lnk->data; + actual=g_slist_find_custom(unbound_parameters,binding->id, + (GCompareFunc)strcmp); + if (actual) + unbound_parameters=g_slist_delete_link(unbound_parameters,actual); + xexpr_var_new(xexpr,binding->id,binding->value); + } + if (evaluate_args) + { + for(lnk=unbound_parameters;lnk;lnk=lnk->next) + { + unbound_parameter=lnk->data; + value=xexpr_var_get(xexpr,unbound_parameter); + if (value) + xexpr_var_new(xexpr,unbound_parameter,value); + else + { + value=xexpr_new_invocation(NULL,"nil",NULL,NULL); + xexpr_var_new(xexpr,unbound_parameter,value); + xexpr_constant_free(value); + } + } + } + while(unbound_parameters) + { + unbound_parameter=unbound_parameters->data; + if (unbound_args) + { + if (evaluate_args) + { + value=xexpr_constant_evaluate(xexpr,unbound_args->data,err); + if (!value) + { + g_slist_free(unbound_parameters); + return NULL; + } + xexpr_var_set(xexpr,unbound_parameter,value); + xexpr_constant_free(value); + } + else + { + value=unbound_args->data; + xexpr_var_new(xexpr,unbound_parameter,value); + } + unbound_args=unbound_args->next; + unbound_parameters= + g_slist_delete_link(unbound_parameters,unbound_parameters); + } + else + { + g_set_error(err,XEXPR_EVAL_ERROR,XEXPR_EVAL_ERROR_FAILED, + "No actual value to bind to parameter %s of function %s", + unbound_parameter,id); + g_slist_free(unbound_parameters); + return NULL; + } + } + if (evaluate_args) + { + args=NULL; + while(unbound_args) + { + value=xexpr_constant_evaluate(xexpr,unbound_args->data,err); + if (!value) + return NULL; + args=g_slist_prepend(args,value); + unbound_args=unbound_args->next; + } + args=g_slist_reverse(args); + } + if (function_def) + result=xexpr_closure(xexpr,function_def,err); + else + result=xexpr_builtins[builtin].func(xexpr,bindings,args,err); + if (evaluate_args) + { + g_slist_foreach(args,(GFunc)xexpr_constant_free,NULL); + g_slist_free(args); + } + return result; +} + +/** + * xexpr_constant_evaluate: + * @xexpr: an #Xexpr + * @constant: the #XexprConstant to evaluate + * @err: (allow-none): location to store error, or %NULL + * + * Evaluate an XEXPR expression. Typically, an expression will evaluate to + * one of the basic types: string, integer or float. However, the XEXPR + * language specification states that <define> returns a function + * object (ie., an #XexprConstant with type %XEXPR_TYPE_FUNCTION). + * If such a function object is passed to xexpr_constant_evaluate(), then + * the function definition will be evaluated. If the function takes + * arguments, then these will be taken as <nil>. + * + * The returned expresion should be freed with xexpr_constant_free() + * when no longer needed. + * + * Return value: (transfer full): The evaluated result, or %NULL on error + */ +XexprConstant *xexpr_constant_evaluate(Xexpr *xexpr,XexprConstant *constant, + GError **err) +{ + GSList *lnk; + XexprConstant *result,*tmp; + switch(constant->type) + { + case XEXPR_TYPE_FUNCTION: + /* + * It's not clear how function objects should be evaluated. + * We choose to invoke them with all arguments as . + * Note that this means that x will not error + * out if x is defined as taking arguments whereas + * will. http://www.w3.org/TR/xexpr/#id-0014 states that + * these have the same effect in _most_ cases which implies + * that there are differences in some cases. + */ + _xexpr_push_environment(xexpr,NULL); + tmp=xexpr_new_invocation(NULL,"nil",NULL,NULL); + for(lnk=constant->u.function->args;lnk;lnk=lnk->next) + xexpr_var_new(xexpr,lnk->data,tmp); + xexpr_constant_free(tmp); + result=xexpr_closure(xexpr,constant,err); + _xexpr_pop_environment(xexpr); + return result; + break; + case XEXPR_TYPE_INVOCATION: + _xexpr_push_environment(xexpr,constant->u.invocation->function); + result=xexpr_function_evaluate(xexpr, + constant->u.invocation->ns, + constant->u.invocation->function, + constant->u.invocation->bindings, + constant->u.invocation->constants,err); + _xexpr_pop_environment(xexpr); + return result; + break; + case XEXPR_TYPE_STRING: + return xexpr_new_string(constant->u.string,-1); + break; + case XEXPR_TYPE_INTEGER: + return xexpr_new_integer(constant->u.integer); + break; + case XEXPR_TYPE_NUMBER: + return xexpr_new_number(constant->u.number); + break; + } + return NULL; +} + +/** + * xexpr_evaluate: + * @xexpr: an #Xexpr to evaluate + * @err: (allow-none): location to store error, or %NULL + * + * Evaluate an XEXPR expression. Typically, an expression will evaluate to + * one of the basic types: string, integer or float. However, the XEXPR + * language specification states that <define> returns a function + * object (ie., an #XexprConstant with type %XEXPR_TYPE_FUNCTION). + * If such a function object is passed to xexpr_evaluate(), then + * the function definition will be evaluated. If the function takes + * arguments, then these will be taken as <nil>. + * + * The returned expresion should be freed with xexpr_free() + * when no longer needed. + * + * Return value: (transfer full): The evaluated result, or %NULL on error + */ +Xexpr *xexpr_evaluate(Xexpr *xexpr,GError **err) +{ + Xexpr *results; + XexprConstant *constant,*result; + GSList *lnk; + results=xexpr_sub(xexpr); + for(lnk=xexpr->constants;lnk;lnk=lnk->next) + { + constant=lnk->data; + result=xexpr_constant_evaluate(xexpr,constant,err); + if (!result) + { + xexpr_free(results); + return NULL; + } + else + results->constants=g_slist_prepend(results->constants,result); + } + results->constants=g_slist_reverse(results->constants); + return results; +} + +/** + * xexpr_test: + * @xexpr: an #Xexpr to test + * @err: (allow-none): location to store error, or %NULL + * + * Test an expression by looking at the last constant in the expression. + * Numerical constants are treated as <true> if they are non-zero, + * string constants are treated as <true> if they are non-empty, + * function invocations are treated as <true> unless they are + * <false> or <nil>, function definitions are recursively + * evaluated before they are tested. + * + * Return value: %TRUE if the expression is equivalent to <true>. + */ +gboolean xexpr_test(Xexpr *xexpr,GError **err) +{ + GSList *lnk; + XexprConstant *constant; + lnk=g_slist_last(xexpr->constants); + constant=lnk->data; + return xexpr_constant_boolean(xexpr,constant,err); +} diff -r 000000000000 -r bc8c9a11cbfc libxexpr/xexpreval.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/xexpreval.h Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,37 @@ +#ifndef __XEXPER_EVAL_H__ +#define __XEXPER_EVAL_H__ + +#include +#include "xexprtypes.h" + +G_BEGIN_DECLS + +/** + * XEXPR_EVAL_ERROR: + * + * Used to get the #GError quark for libxexpr evaluator errors. + */ +#define XEXPR_EVAL_ERROR xexpr_eval_error_quark() + +/** + * XexprEvalError: + * @XEXPR_EVAL_ERROR_FAILED: Indicates a generic failure. + * + * Enum values for evaluator errors. + */ +typedef enum +{ + XEXPR_EVAL_ERROR_FAILED +} XexprEvalError; + +GQuark xexpr_eval_error_quark(void); +gboolean xexpr_register_extension(XexprExtension *extension); +XexprConstant *xexpr_constant_evaluate(Xexpr *xexpr,XexprConstant *constant, + GError **err); +Xexpr *xexpr_evaluate(Xexpr *xexpr,GError **err); +gboolean xexpr_constant_cast(XexprConstant *constant,XexprType to); +gboolean xexpr_test(Xexpr *xexpr,GError **err); + +G_END_DECLS + +#endif /* __XEXPER_EVAL_H__ */ diff -r 000000000000 -r bc8c9a11cbfc libxexpr/xexprparse.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/xexprparse.c Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,320 @@ +#include +#include +#include +#include "xexprparse.h" + +/** + * SECTION:xexprparse + * @short_description: A parser for the XEXPR language + * @stability: Stable + * @include: libxexpr/xexpr.h + * + * A parser for the + * XEXPR + * language. + */ + +/** + * xexpr_parse_error_quark: + * + * Registers an error quark for the libxexpr parser if necessary. + * + * Return value: The error quark used for libxexpr parser errors. + */ +GQuark xexpr_parse_error_quark(void) +{ + static GQuark quark; + if (!quark) + quark=g_quark_from_static_string("xexpr_parse_error"); + return quark; +} + +gboolean _xexpr_validate_id(const char *id,GError **err) +{ + int i; + for(i=0;id[i];i++) + if (!g_ascii_isalpha(id[i]) && id[i]!='-' && id[i]!='.') + { + g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED, + "Invalid XEXPR ID: \"%s\"",id); + return FALSE; + } + return TRUE; +} + +static gboolean xexpr_parse_pcdata(Xexpr *xexpr,xmlNode *node,xmlChar *pcdata, + GError **err) +{ + int n; + const char *s,*t; + xmlChar *text; + gchar *str; + gboolean is_integer; + long long int integer; + double number; + s=(const char *)pcdata; + if (node->type==XML_TEXT_NODE && + (!node->prev || node->prev->type!=XML_TEXT_NODE)) + while(g_ascii_isspace(*s)) + s++; + while(*s) + { + t=strpbrk(s,"+-0123456789"); + /* All numbers start with [+-]?[0-9] (possibly with leading WS) */ + if (t && (t[0]!='+' && t[0]!='-' || t[1]!='+' && t[1]!='-')) + { + while(t>s && g_ascii_isspace(t[-1])) + t--; + if (t>s) + xexpr->constants=g_slist_prepend(xexpr->constants, + xexpr_new_string(s,t-s)); + s=t; + while(g_ascii_isspace(*s)) + s++; + if (*s=='+' || *s=='-') + s++; + if (s[0]=='0' && s[1]=='x' && + (n=strspn(s+2,"0123456789ABCDEFabcdef"))>0) + { + s+=2+n; + is_integer=TRUE; + } + else + { + s+=strspn(s,"0123456789"); + if (*s=='.' && (n=strspn(s+1,"0123456789"))>0) + { + s+=1+n; + if ((s[0]=='e' || s[0]=='E') && (s[1]=='+' || s[1]=='-') && + (n=strspn(s+2,"0123456789"))>0) + s+=2+n; + is_integer=FALSE; + } + else + is_integer=TRUE; + } + while(g_ascii_isspace(*s)) + s++; + str=g_strndup(t,s-t); + if (is_integer) + { + integer=g_ascii_strtoll(str,NULL,0); + if (integer==LLONG_MIN || integer==LLONG_MAX) + { + text=xmlGetNodePath(node); + g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED, + "Integer overflow on %s at %s",str,(const char *)text); + xmlFree(text); + g_free(str); + return FALSE; + } + else + xexpr->constants=g_slist_prepend(xexpr->constants, + xexpr_new_integer(integer)); + } + else + { + number=g_ascii_strtod(str,NULL); + if (number==HUGE_VAL || number==-HUGE_VAL) + { + text=xmlGetNodePath(node); + g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED, + "Numeric overflow on %s at %s",str,(const char *)text); + xmlFree(text); + g_free(str); + return FALSE; + } + else + xexpr->constants=g_slist_prepend(xexpr->constants, + xexpr_new_number(number)); + } + g_free(str); + } + else + { + n=strlen(s); + if (node->type==XML_TEXT_NODE && + (!node->next || node->next->type!=XML_TEXT_NODE)) + while(n && g_ascii_isspace(s[n-1])) + n--; + xexpr->constants=g_slist_prepend(xexpr->constants, + xexpr_new_string(s,n)); + break; + } + } + return TRUE; +} + +static gboolean xexpr_parse_string(Xexpr *xexpr,xmlNode *xml,GError **err) +{ + xmlNode *node; + xmlChar *text; + GString *str=g_string_new(NULL); + for(node=xml;node;node=node->next) + { + if (node->type==XML_ELEMENT_NODE) + { + text=xmlGetNodePath(node); + g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED, + "No markup can occur within at %s",(const char *)text); + xmlFree(text); + return FALSE; + } + else if (node->type==XML_TEXT_NODE) + g_string_append(str,(const char *)node->content); + else if (node->type!=XML_COMMENT_NODE) + { + text=xmlGetNodePath(node); + g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED, + "Unexpected node type %d at %s",node->type,(const char *)text); + xmlFree(text); + return FALSE; + } + } + xexpr->constants=g_slist_append(xexpr->constants, + xexpr_new_string_take_ownership(g_string_free(str,FALSE))); + return TRUE; +} + +/** + * xexpr_parse_node: + * @xexpr: an #Xexpr + * @node: the #xmlNode to parse + * @err: (allow-none): location to store error, or %NULL. + * + * Parse an XEXPR expression whose root is @node. + * + * Typical usage of this function might be: + * |[ + * doc=xmlReadFile(filename,NULL,0); + * if (doc && !xexpr_parse_node(xexpr,xmlDocGetRootElement(doc),&err)) + * { + * fprintf(stderr,"%s: %s\n",filename,err->message); + * exit(1); + * } + * ]| + * + * Return value: %TRUE if @node was successfully parsed. + */ +gboolean xexpr_parse_node(Xexpr *xexpr,xmlNode *node,GError **err) +{ + XexprConstant *constant; + XexprBinding *binding; + Xexpr *sub,*binding_xexpr; + xmlAttr *attr; + xmlChar *prop; + GSList *bindings; + char *ns; + sub=xexpr_sub(xexpr); + if (!strcmp((const char *)node->name,"string")) + { + if (!xexpr_parse_string(sub,node->children,err)) + { + xexpr_free(sub); + return FALSE; + } + } + else if (!_xexpr_validate_id((const char *)node->name,err) || + !xexpr_parse_fragment(sub,node->children,err)) + { + xexpr_free(sub); + return FALSE; + } + bindings=NULL; + for(attr=node->properties;attr;attr=attr->next) + { + if (!_xexpr_validate_id((const char *)attr->name,err)) + { + g_slist_foreach(bindings,(GFunc)xexpr_binding_free,NULL); + g_slist_free(bindings); + xexpr_free(sub); + return FALSE; + } + prop=xmlGetProp(node,attr->name); + binding_xexpr=xexpr_sub(xexpr); + if (!xexpr_parse_pcdata(binding_xexpr,(xmlNode *)attr,prop,err)) + { + xmlFree(prop); + g_slist_foreach(bindings,(GFunc)xexpr_binding_free,NULL); + g_slist_free(bindings); + xexpr_free(binding_xexpr); + xexpr_free(sub); + return FALSE; + } + binding=g_slice_new(XexprBinding); + binding->id=g_strdup((const char *)attr->name); + if (!binding_xexpr->constants || binding_xexpr->constants->next) + binding->value=xexpr_new_string((const char *)prop,-1); + else + { + binding->value=binding_xexpr->constants->data; + g_slist_free(binding_xexpr->constants); + binding_xexpr->constants=NULL; + } + xexpr_free(binding_xexpr); + xmlFree(prop); + bindings=g_slist_prepend(bindings,binding); + } + bindings=g_slist_reverse(bindings); + if (node->ns) + ns=g_strdup((const char *)node->ns->href); + else + ns=NULL; + constant=xexpr_new_invocation_take_ownership(ns, + g_strdup((const char *)node->name),bindings,sub->constants); + sub->constants=NULL; + xexpr_free(sub); + xexpr->constants=g_slist_prepend(xexpr->constants,constant); + return TRUE; +} + +/** + * xexpr_parse_fragment: + * @xexpr: an #Xexpr + * @xml: the first #xmlNode to parse + * @err: (allow-none): location to store error, or %NULL. + * + * Parse an XEXPR expression consisting of @xml and its siblings. + * + * Typical usage of this function might be: + * |[ + * xpathObj=xmlXPathEvalExpression(BAD_CAST "//params/setting",xpathCtx); + * xml=xpathObj?xpathObj->nodesetval->nodeTab[0]:NULL; + * if (xml && !xexpr_parse_fragment(xexpr,xml->children,&err)) + * { + * fprintf(stderr,"%s: %s\n",filename,err->message); + * exit(1); + * } + * ]| + * + * Return value: %TRUE if @xml was successfully parsed. + */ +gboolean xexpr_parse_fragment(Xexpr *xexpr,xmlNode *xml,GError **err) +{ + xmlNode *node; + xmlChar *text; + xexpr->constants=g_slist_reverse(xexpr->constants); + for(node=xml;node;node=node->next) + { + if (node->type==XML_ELEMENT_NODE) + { + if (!xexpr_parse_node(xexpr,node,err)) + return FALSE; + } + else if (node->type==XML_TEXT_NODE) + { + if (!xexpr_parse_pcdata(xexpr,node,node->content,err)) + return FALSE; + } + else if (node->type!=XML_COMMENT_NODE) + { + text=xmlGetNodePath(node); + g_set_error(err,XEXPR_PARSE_ERROR,XEXPR_PARSE_ERROR_FAILED, + "Unexpected node type %d at %s",node->type,(const char *)text); + xmlFree(text); + return FALSE; + } + } + xexpr->constants=g_slist_reverse(xexpr->constants); + return TRUE; +} diff -r 000000000000 -r bc8c9a11cbfc libxexpr/xexprparse.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/xexprparse.h Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,34 @@ +#ifndef __XEXPER_PARSE_H__ +#define __XEXPER_PARSE_H__ + +#include +#include +#include "xexprtypes.h" + +G_BEGIN_DECLS + +/** + * XEXPR_PARSE_ERROR: + * + * Used to get the #GError quark for libxexpr parser errors. + */ +#define XEXPR_PARSE_ERROR xexpr_parse_error_quark() + +/** + * XexprParseError: + * @XEXPR_PARSE_ERROR_FAILED: Indicates a generic failure. + * + * Enum values for parser errors. + */ +typedef enum +{ + XEXPR_PARSE_ERROR_FAILED +} XexprParseError; + +GQuark xexpr_parse_error_quark(void); +gboolean xexpr_parse_fragment(Xexpr *xexpr,xmlNode *xml,GError **err); +gboolean xexpr_parse_node(Xexpr *xexpr,xmlNode *node,GError **err); + +G_END_DECLS + +#endif /* __XEXPER_PARSE_H__ */ diff -r 000000000000 -r bc8c9a11cbfc libxexpr/xexprprivate.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/xexprprivate.h Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,5 @@ +gboolean _xexpr_validate_id(const char *id,GError **err); +void _xexpr_push_environment(Xexpr *xexpr,const char *id); +void _xexpr_pop_environment(Xexpr *xexpr); +XexprConstant *_xexpr_libxexpr_function_evaluate(Xexpr *xexpr,const char *ns, + const char *id,GSList *bindings,GSList *args,GError **err); diff -r 000000000000 -r bc8c9a11cbfc libxexpr/xexprtypes.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/xexprtypes.c Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,705 @@ +#include +#include +#include +#include +#include "xexprprivate.h" + +/** + * SECTION:xexprtypes + * @short_description: Types defined in libxexpr + * @stability: Stable + * @include: libxexpr/xexpr.h + * + * The various types defined in libxexpr and the functions that support them. + */ + +static XexprEnvironment *xexpr_environment_new(const char *function, + XexprEnvironment *outer); + +/** + * xexpr_binding_free: + * @binding: an #XexprBinding + * + * Frees the memory allocated for the #XexprBinding. + */ +void xexpr_binding_free(XexprBinding *binding) +{ + g_free(binding->id); + xexpr_constant_free(binding->value); + g_slice_free(XexprBinding,binding); +} + +/** + * xexpr_environment_free: + * @environment: an #XexprEnvironment + * + * Frees the memory allocated for the #XexprEnvironment. + */ +static void xexpr_environment_free(XexprEnvironment *environment) +{ + g_warn_if_fail(environment->refcount==1); + if (environment->outer) + environment->outer->refcount--; + g_free(environment->function); + g_slist_foreach(environment->bindings,(GFunc)xexpr_binding_free,NULL); + g_slist_free(environment->bindings); + g_slice_free(XexprEnvironment,environment); +} + +/* + * xexpr_invocation_free: + * @invocation: an #XexprInvocation + * + * Frees the memory allocated for the #XexprInvocation. + */ +static void xexpr_invocation_free(XexprInvocation *invocation) +{ + g_free(invocation->function); + g_slist_foreach(invocation->bindings,(GFunc)xexpr_binding_free,NULL); + g_slist_free(invocation->bindings); + g_slist_foreach(invocation->constants,(GFunc)xexpr_constant_free,NULL); + g_slist_free(invocation->constants); + g_slice_free(XexprInvocation,invocation); +} + +/* + * xexpr_function_free: + * @function: an #XexprFunction + * + * Frees the memory allocated for the #XexprFunction. + */ +static void xexpr_function_free(XexprFunction *function) +{ + g_slist_foreach(function->args,(GFunc)g_free,NULL); + g_slist_free(function->args); + g_slist_foreach(function->constants,(GFunc)xexpr_constant_free,NULL); + g_slist_free(function->constants); + g_slice_free(XexprFunction,function); +} + +/** + * xexpr_constant_free: + * @constant: an #XexprConstant + * + * Frees the memory allocated for the #XexprConstant. + */ +void xexpr_constant_free(XexprConstant *constant) +{ + switch(constant->type) + { + case XEXPR_TYPE_INVOCATION: + xexpr_invocation_free(constant->u.invocation); + break; + case XEXPR_TYPE_FUNCTION: + xexpr_function_free(constant->u.function); + break; + case XEXPR_TYPE_STRING: + g_free(constant->u.string); + break; + case XEXPR_TYPE_INTEGER: + case XEXPR_TYPE_NUMBER: + break; + } + g_slice_free(XexprConstant,constant); +} + +/** + * xexpr_free: + * @xexpr: an #Xexpr + * + * Frees the memory allocated for the #Xexpr. + */ +void xexpr_free(Xexpr *xexpr) +{ + g_slist_foreach(xexpr->tracing,(GFunc)g_free,NULL); + g_slist_free(xexpr->tracing); + g_slist_foreach(xexpr->constants,(GFunc)xexpr_constant_free,NULL); + g_slist_free(xexpr->constants); + g_slice_free(Xexpr,xexpr); +} + +/** + * xexpr_new: + * + * Creates a new #Xexpr. + * + * Returns: the new #Xexpr + */ +Xexpr *xexpr_new(void) +{ + xexpr_register_extension(NULL); + return g_slice_new0(Xexpr); +} + +/** + * xexpr_sub: + * @xexpr: an #Xexpr to copy the initial options from + * + * Creates a new #Xexpr, copying options from @xexpr. + * + * Returns: the new #Xexpr + */ +Xexpr *xexpr_sub(Xexpr *xexpr) +{ + GSList *lnk; + Xexpr *sub=xexpr_new(); + sub->tracing=g_slist_copy(xexpr->tracing); + for(lnk=sub->tracing;lnk;lnk=lnk->next) + lnk->data=g_strdup(lnk->data); + return sub; +} + +/** + * xexpr_is_tracing: + * @xexpr: an #Xexpr + * @id: the symbol to test for + * + * Checks if a symbol is currently being traced, returning %TRUE if it is. + * + * Returns: %TRUE if @id is being traced + */ +gboolean xexpr_is_tracing(Xexpr *xexpr,const char *id) +{ + return !!g_slist_find_custom(xexpr->tracing,id,(GCompareFunc)g_strcmp0); +} + +/** + * xexpr_start_tracing: + * @xexpr: an #Xexpr + * @id: the symbol to trace + * + * Adds @id to the set of symbols to trace. + * + * When variables with the name of a traced symbol are created or changed, + * the evaluator will output a suitable tracing message and a stack dump. + * + * + * Example Tracing Output + * + * Created new variable x in frame \#0 + * \#0 test1 (x = <nil/>) + * \#1 eq () + * \#2 if () + * \#3 and () + * \#4 expr () + * + * Set variable x + * \#0 test1 (x = <integer>1</integer>) + * \#1 eq () + * \#2 if () + * \#3 and () + * \#4 expr () + * + * + */ +void xexpr_start_tracing(Xexpr *xexpr,const char *id) +{ + if (!xexpr_is_tracing(xexpr,id)) + xexpr->tracing=g_slist_prepend(xexpr->tracing,g_strdup(id)); +} + +/** + * xexpr_get_environment: + * @xexpr: an #Xexpr + * + * Gets the #XexprEnvironment of the given #Xexpr. + * + * Returns: (transfer none): the innermost environment + */ +XexprEnvironment *xexpr_get_environment(Xexpr *xexpr) +{ + if (!xexpr->environment) + xexpr->environment=xexpr_environment_new(NULL,NULL); + return xexpr->environment; +} + +/** + * xexpr_set_constants_take_ownership: + * @xexpr: an #Xexpr + * @constants: (transfer full) (element-type XexprConstant): A list of + * constants to use, replacing any existing constants + * + * Sets the list of constants which make up the expression. + */ +void xexpr_set_constants_take_ownership(Xexpr *xexpr,GSList *constants) +{ + g_slist_foreach(xexpr->constants,(GFunc)xexpr_constant_free,NULL); + g_slist_free(xexpr->constants); + xexpr->constants=constants; +} + +/** + * xexpr_set_constants: + * @xexpr: an #Xexpr + * @constants: (transfer none) (element-type XexprConstant): A list of + * constants to use, replacing any existing constants + * + * Sets the list of constants which make up the expression. + */ +void xexpr_set_constants(Xexpr *xexpr,GSList *constants) +{ + GSList *lnk,*copy=NULL; + for(lnk=constants;lnk;lnk=lnk->next) + copy=g_slist_prepend(copy,xexpr_constant_dup(lnk->data)); + copy=g_slist_reverse(copy); + xexpr_set_constants_take_ownership(xexpr,copy); +} + +void _xexpr_push_environment(Xexpr *xexpr,const char *id) +{ + xexpr->environment=xexpr_environment_new(id,xexpr_get_environment(xexpr)); +} + +void _xexpr_pop_environment(Xexpr *xexpr) +{ + XexprEnvironment *outer=xexpr->environment->outer; + if (outer) + { + xexpr_environment_free(xexpr->environment); + xexpr->environment=outer; + } +} + +/** + * xexpr_new_invocation_take_ownership: + * @ns: (transfer full): the namespace to which @function belongs, or %NULL + * @function: (transfer full): the name of the function to be invoked + * @bindings: (transfer full) (element-type XexprBinding): the pre-bound + * arguments + * @constants: (transfer full) (element-type XexprConstant): the other + * arguments + * + * Create a new #XexprConstant that invokes @function with pre-bound arguments + * @bindings and with @constants as further arguments. Functions with named + * parameters will use the pre-bound arguments first if present, otherwise + * the other arguments will be bound to the unbound parameters as needed. + * + * @ns should be %NULL, the empty string or %XEXPR_NS for XEXPR functions. + * + * Returns: (transfer full): the new #XexprConstant + */ +XexprConstant *xexpr_new_invocation_take_ownership(char *ns,char *function, + GSList *bindings,GSList *constants) +{ + XexprConstant *constant; + constant=g_slice_new(XexprConstant); + constant->type=XEXPR_TYPE_INVOCATION; + constant->u.invocation=g_slice_new(XexprInvocation); + if (ns && (!*ns || !strcmp(ns,XEXPR_NS))) + { + g_free(ns); + ns=NULL; + } + constant->u.invocation->ns=ns; + constant->u.invocation->function=function; + constant->u.invocation->bindings=bindings; + constant->u.invocation->constants=constants; + return constant; +} + +/** + * xexpr_new_invocation: + * @ns: (transfer none): the namespace to which @function belongs, or %NULL + * @function: (transfer none): the name of the function to be invoked + * @bindings: (transfer none) (element-type XexprBinding): the pre-bound + * arguments + * @constants: (transfer none) (element-type XexprConstant): the other + * arguments + * + * Create a new #XexprConstant that invokes @function with pre-bound arguments + * @bindings and with @constants as further arguments. Functions with named + * parameters will use the pre-bound arguments first if present, otherwise + * the other arguments will be bound to the unbound parameters as needed. + * + * @ns should be %NULL, the empty string or %XEXPR_NS for XEXPR functions. + * + * Returns: (transfer full): the new #XexprConstant + */ +XexprConstant *xexpr_new_invocation(const char *ns,const char *function, + GSList *bindings,GSList *constants) +{ + GSList *list,*lnk; + list=g_slist_copy(constants); + for(lnk=list;lnk;lnk=lnk->next) + lnk->data=xexpr_constant_dup(lnk->data); + if (ns && (!*ns || !strcmp(ns,XEXPR_NS))) + ns=NULL; + return xexpr_new_invocation_take_ownership(g_strdup(ns),g_strdup(function), + xexpr_bindings_dup(bindings),list); +} + +/** + * xexpr_new_function_take_ownership: + * @args: (transfer full) (element-type utf8): the parameter names + * @constants: (transfer full) (element-type XexprConstant): the constants + * which will be evaluated when the function is invoked + * + * Create a new #XexprConstant that defines an unnamed function. Creating a + * function definition is the first step in defining a function. The second + * step is to bind the definition to a name, eg., using xexpr_var_new(). + * + * Returns: (transfer full): the new #XexprConstant + */ +XexprConstant *xexpr_new_function_take_ownership(GSList *args,GSList *constants) +{ + XexprConstant *constant; + constant=g_slice_new(XexprConstant); + constant->type=XEXPR_TYPE_FUNCTION; + constant->u.function=g_slice_new(XexprFunction); + constant->u.function->args=args; + constant->u.function->constants=constants; + return constant; +} + +/** + * xexpr_new_function: + * @args: (transfer none) (element-type utf8): the parameter names + * @constants: (transfer none) (element-type XexprConstant): the constants + * which will be evaluated when the function is invoked + * + * Create a new #XexprConstant that defines an unnamed function. Creating a + * function definition is the first step in defining a function. The second + * step is to bind the definition to a name, eg., using xexpr_var_new(). + * + * Returns: (transfer full): the new #XexprConstant + */ +XexprConstant *xexpr_new_function(GSList *args,GSList *constants) +{ + GSList *lnk; + args=g_slist_copy(args); + for(lnk=args;lnk;lnk=lnk->next) + lnk->data=g_strdup(lnk->data); + constants=g_slist_copy(constants); + for(lnk=constants;lnk;lnk=lnk->next) + lnk->data=xexpr_constant_dup(lnk->data); + return xexpr_new_function_take_ownership(args,constants); +} + +/** + * xexpr_new_string_take_ownership: + * @s: (transfer full): the string + * + * Create a new #XexprConstant that consists of the given string. + * + * Returns: (transfer full): the new #XexprConstant + */ +XexprConstant *xexpr_new_string_take_ownership(char *s) +{ + XexprConstant *constant; + constant=g_slice_new(XexprConstant); + constant->type=XEXPR_TYPE_STRING; + constant->u.string=s; + return constant; +} + +/** + * xexpr_new_string: + * @s: (transfer none): the string + * @len: length of @s to use, or -1 to treat @s as nul-terminated + * + * Create a new #XexprConstant that consists of the given string. + * + * Returns: (transfer full): the new #XexprConstant + */ +XexprConstant *xexpr_new_string(const char *s,gssize len) +{ + if (len<0) + len=strlen(s); + return xexpr_new_string_take_ownership(g_strndup(s,len)); +} + +/** + * xexpr_new_integer: + * @integer: the integer + * + * Create a new #XexprConstant that consists of the given integer. + * + * Returns: (transfer full): the new #XexprConstant + */ +XexprConstant *xexpr_new_integer(long long int integer) +{ + XexprConstant *constant; + constant=g_slice_new(XexprConstant); + constant->type=XEXPR_TYPE_INTEGER; + constant->u.integer=integer; + return constant; +} + +/** + * xexpr_new_number: + * @number: the number + * + * Create a new #XexprConstant that consists of the given floating-point number. + * + * Returns: (transfer full): the new #XexprConstant + */ +XexprConstant *xexpr_new_number(double number) +{ + XexprConstant *constant; + constant=g_slice_new(XexprConstant); + constant->type=XEXPR_TYPE_NUMBER; + constant->u.number=number; + return constant; +} + +static XexprEnvironment *xexpr_environment_new(const char *function, + XexprEnvironment *outer) +{ + XexprEnvironment *environment=g_slice_new0(XexprEnvironment); + environment->function=g_strdup(function); + environment->refcount=1; + environment->outer=outer; + if (outer) + outer->refcount++; + return environment; +} + +/** + * xexpr_environment_foreach: + * @environment: an #XexprEnvironment + * @func: the function to call with each active variable + * @user_data: user data to pass to the function + * + * Calls a function for each active variable in an #XexprEnvironment. + */ +void xexpr_environment_foreach(XexprEnvironment *environment,GTraverseFunc func, + gpointer user_data) +{ + GSList *lnk; + GSList *environments=NULL; + GTree *active; + XexprBinding *binding; + while(environment) + { + environments=g_slist_prepend(environments,environment); + environment=environment->outer; + } + active=g_tree_new((GCompareFunc)strcmp); + while(environments) + { + environment=environments->data; + environments=g_slist_delete_link(environments,environments); + for(lnk=environment->bindings;lnk;lnk=lnk->next) + { + binding=lnk->data; + g_tree_insert(active,binding->id,binding->value); + } + } + g_tree_foreach(active,func,user_data); + g_tree_destroy(active); +} + +/** + * xexpr_bindings_get: + * @bindings: (transfer none) (element-type XexprBinding): the bindings to + * search + * @id: the symbol to search for + * + * Look for a binding of symbol @id in @bindings and return the value if + * found. + * + * Returns: (transfer none): the found #XexprConstant or %NULL + */ +XexprConstant *xexpr_bindings_get(GSList *bindings,const char *id) +{ + GSList *lnk; + XexprBinding *binding; + for(lnk=bindings;lnk;lnk=lnk->next) + { + binding=lnk->data; + if (!strcmp(binding->id,id)) + return binding->value; + } + return NULL; +} + +/** + * xexpr_bindings_set: + * @bindings: (transfer none) (element-type XexprBinding): the bindings to + * update + * @id: an existing symbol to set + * @value: (transfer none): the new value + * + * Update an existing binding of symbol @id in @bindings with the new value + * @value. If no existing binding is found, return %FALSE. + * + * Returns: %TRUE if @id was found and updated + */ +gboolean xexpr_bindings_set(GSList *bindings,const char *id, + XexprConstant *value) +{ + GSList *lnk; + XexprBinding *binding; + for(lnk=bindings;lnk;lnk=lnk->next) + { + binding=lnk->data; + if (!strcmp(binding->id,id)) + { + xexpr_constant_free(binding->value); + binding->value=xexpr_constant_dup(value); + return TRUE; + } + } + return FALSE; +} + +/** + * xexpr_bindings_new: + * @bindings: (transfer full) (element-type XexprBinding): the bindings to + * modify + * @id: a symbol to set or create + * @value: (transfer none): the new value + * + * Update an existing binding of symbol @id or create a new one in @bindings + * with the new value @value. + * + * Returns: (transfer full) (element-type XexprBinding): the new bindings list + */ +GSList *xexpr_bindings_new(GSList *bindings,const char *id,XexprConstant *value) +{ + XexprBinding *binding; + if (!xexpr_bindings_set(bindings,id,value)) + { + binding=g_slice_new(XexprBinding); + binding->id=g_strdup(id); + binding->value=xexpr_constant_dup(value); + bindings=g_slist_prepend(bindings,binding); + } + return bindings; +} + +/** + * xexpr_var_get: + * @xexpr: an #Xexpr + * @id: a symbol to look up + * + * Look for a definition of symbol @id in @xexpr and return its value. If + * no definition exists, return %NULL. + * + * Returns: (transfer none): the bound value, or %NULL if not found. + */ +XexprConstant *xexpr_var_get(Xexpr *xexpr,const char *id) +{ + XexprConstant *value=NULL; + XexprEnvironment *environment=xexpr_get_environment(xexpr); + while(environment && !value) + { + value=xexpr_bindings_get(environment->bindings,id); + environment=environment->outer; + } + return value; +} + +/** + * xexpr_var_new: + * @xexpr: an #Xexpr + * @id: a symbol to set or create + * @value: (transfer none): the new value + * + * Update an existing binding of symbol @id in the innermost environment of + * @xexpr or create a new one with the new value @value. + */ +void xexpr_var_new(Xexpr *xexpr,const char *id,XexprConstant *value) +{ + XexprEnvironment *environment=xexpr_get_environment(xexpr); + environment->bindings=xexpr_bindings_new(environment->bindings,id,value); + if (xexpr_is_tracing(xexpr,id)) + { + printf("\nCreated new variable %s in frame #0\n",id); + xexpr_stack_dump(xexpr,stdout); + } +} + +/** + * xexpr_var_set: + * @xexpr: an #Xexpr + * @id: a symbol to set or create + * @value: (transfer none): the new value + * + * Update the active binding of symbol @id in @xexpr if such exists or create + * create a new one in the outermost environment with the new value @value. + */ +void xexpr_var_set(Xexpr *xexpr,const char *id,XexprConstant *value) +{ + XexprEnvironment *environment=xexpr_get_environment(xexpr); + while(environment) + { + if (xexpr_bindings_set(environment->bindings,id,value)) + { + if (xexpr_is_tracing(xexpr,id)) + { + printf("\nSet variable %s\n",id); + xexpr_stack_dump(xexpr,stdout); + } + return; + } + if (environment->outer) + environment=environment->outer; + else + break; + } + environment->bindings=xexpr_bindings_new(environment->bindings,id,value); + if (xexpr_is_tracing(xexpr,id)) + { + printf("\nCreated new global variable %s\n",id); + xexpr_stack_dump(xexpr,stdout); + } +} + +/** + * xexpr_constant_dup: + * @constant: an #XexprConstant to duplicate + * + * Duplicate @constant. + * + * Returns: (transfer full): the new #XexprConstant + */ +XexprConstant *xexpr_constant_dup(XexprConstant *constant) +{ + switch(constant->type) + { + case XEXPR_TYPE_INVOCATION: + return xexpr_new_invocation(constant->u.invocation->ns, + constant->u.invocation->function,constant->u.invocation->bindings, + constant->u.invocation->constants); + break; + case XEXPR_TYPE_FUNCTION: + return xexpr_new_function(constant->u.function->args, + constant->u.function->constants); + break; + case XEXPR_TYPE_STRING: + return xexpr_new_string(constant->u.string,-1); + break; + case XEXPR_TYPE_INTEGER: + return xexpr_new_integer(constant->u.integer); + break; + case XEXPR_TYPE_NUMBER: + return xexpr_new_number(constant->u.number); + break; + } + return NULL; +} + +/** + * xexpr_bindings_dup: + * @bindings: (transfer none) (element-type XexprBinding): a list of bindings + * to duplicate + * + * Duplicate @bindings. + * + * Returns: (transfer full) (element-type XexprBinging): the new bindings list + */ +GSList *xexpr_bindings_dup(GSList *bindings) +{ + GSList *lnk,*list=NULL; + XexprBinding *binding,*dup; + for(lnk=bindings;lnk;lnk=lnk->next) + { + binding=lnk->data; + dup=g_slice_new(XexprBinding); + dup->id=g_strdup(binding->id); + dup->value=xexpr_constant_dup(binding->value); + list=g_slist_prepend(list,dup); + } + return g_slist_reverse(list); +} diff -r 000000000000 -r bc8c9a11cbfc libxexpr/xexprtypes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxexpr/xexprtypes.h Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,176 @@ +#ifndef __XEXPER_TYPES_H__ +#define __XEXPER_TYPES_H__ + +#include +#include + +G_BEGIN_DECLS + +/** + * XexprInvocation: + * @ns: the namespace to which @function belongs, or %NULL + * @function: the function to be invoked + * @bindings: (element-type XexprBinding): the pre-bound arguments + * @constants: (element-type XexprConstant): the other arguments + * + * A structure describing the invocation of a function. + */ +typedef struct xexpr_invocation { + char *ns; + char *function; + GSList *bindings; + GSList *constants; +} XexprInvocation; + +/** + * XexprFunction: + * @args: (element-type utf8): the parameter names + * @constants: (element-type XexprConstant): the constants + * which will be evaluated when the function is invoked + * + * A structure describing the definition of a function. + */ +typedef struct xexpr_function { + GSList *args; + GSList *constants; +} XexprFunction; + +typedef struct xexpr_constant XexprConstant; + +/** + * XexprBinding: + * @id: the bound name + * @value: the expresion bound to @id + * + * A structure describing the binding of a value to a name. + */ +typedef struct xexpr_binding { + char *id; + XexprConstant *value; +} XexprBinding; + +/** + * XexprType: + * @XEXPR_TYPE_INVOCATION: a function invocation + * @XEXPR_TYPE_FUNCTION: a function definition + * @XEXPR_TYPE_STRING: a string + * @XEXPR_TYPE_INTEGER: an integer + * @XEXPR_TYPE_NUMBER: a floating-point number + * + * Enum values for the type, to specify the type of expression. + */ +typedef enum { + XEXPR_TYPE_INVOCATION=1, + XEXPR_TYPE_FUNCTION, + XEXPR_TYPE_STRING, + XEXPR_TYPE_INTEGER, + XEXPR_TYPE_NUMBER +} XexprType; + +/** + * XexprConstant: + * @type: the type of expression + * @u: type-specific parameters + * + * A structure describing an XEXPR expression + */ +struct xexpr_constant { + XexprType type; + union { + XexprInvocation *invocation; + XexprFunction *function; + char *string; + long long int integer; + double number; + } u; +}; + +/** + * XexprEnvironment: + * @function: the name of the function to which the environment belongs, + * or %NULL if this is the outermost environment + * @outer: the next environment in the chain from innermost to outermost, + * or %NULL if this is the outermost environment + * @bindings: (element-type XexprBinding): the variables set in this environment + * + * A structure describing an XEXPR environment + */ +typedef struct xexpr_environment { + /*< private >*/ + int refcount; + /*< public >*/ + char *function; + struct xexpr_environment *outer; + GSList *bindings; +} XexprEnvironment; + +/** + * Xexpr: + * @constants: (element-type XexprConstant): the constants that make up this + * expression + * @environment: the innermost environment + * + * A structure describing an XEXPR expression + */ +typedef struct xexpr { + /*< private >*/ + GSList *tracing; + /*< public >*/ + GSList *constants; + XexprEnvironment *environment; +} Xexpr; + +/** + * XexprExtension: + * @ns: the namespace of the extension + * @function_evaluate: evaluates functions defined in the extension + * + * A structure describing an XEXPR extension + */ +typedef struct xexpr_extension { + char *ns; + XexprConstant *(*function_evaluate)(Xexpr *xexpr,const char *ns, + const char *id,GSList *bindings,GSList *args,GError **err); +} XexprExtension; + +XexprConstant *xexpr_new_string(const char *s,gssize len); +XexprConstant *xexpr_new_string_take_ownership(char *s); +XexprConstant *xexpr_new_integer(long long int integer); +XexprConstant *xexpr_new_number(double number); +XexprConstant *xexpr_new_invocation(const char *ns,const char *function, + GSList *bindings,GSList *constants); +XexprConstant *xexpr_new_invocation_take_ownership(char *ns,char *function, + GSList *bindings,GSList *constants); +XexprConstant *xexpr_new_function_take_ownership(GSList *args, + GSList *constants); +XexprConstant *xexpr_new_function(GSList *args,GSList *constants); +XexprConstant *xexpr_constant_dup(XexprConstant *constant); +void xexpr_constant_free(XexprConstant *constant); + +void xexpr_binding_free(XexprBinding *binding); + +XexprConstant *xexpr_bindings_get(GSList *bindings,const char *id); +gboolean xexpr_bindings_set(GSList *bindings,const char *id, + XexprConstant *value); +GSList *xexpr_bindings_new(GSList *bindings,const char *id, + XexprConstant *value); +GSList *xexpr_bindings_dup(GSList *bindings); + +Xexpr *xexpr_new(void); +Xexpr *xexpr_sub(Xexpr *xexpr); +void xexpr_var_new(Xexpr *xexpr,const char *id,XexprConstant *value); +void xexpr_var_set(Xexpr *xexpr,const char *id,XexprConstant *value); +XexprConstant *xexpr_var_get(Xexpr *xexpr,const char *id); +void xexpr_start_tracing(Xexpr *xexpr,const char *id); +gboolean xexpr_is_tracing(Xexpr *xexpr,const char *id); +void xexpr_free(Xexpr *xexpr); +XexprEnvironment *xexpr_get_environment(Xexpr *xexpr); +void xexpr_set_constants(Xexpr *xexpr,GSList *constants); +void xexpr_set_constants_take_ownership(Xexpr *xexpr,GSList *constants); + +void xexpr_environment_foreach(XexprEnvironment *environment,GTraverseFunc func, + gpointer user_data); + +G_END_DECLS + +#endif /* __XEXPER_TYPES_H__ */ diff -r 000000000000 -r bc8c9a11cbfc src/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Makefile.am Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,4 @@ +AM_CFLAGS=$(LIBXEXPR_CFLAGS) -g -I$(top_srcdir) +LDADD=../libxexpr/libxexpr.la $(LIBXEXPR_LIBS) + +bin_PROGRAMS=xexpr diff -r 000000000000 -r bc8c9a11cbfc src/xexpr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/xexpr.c Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,193 @@ +#include +#include +#include +#include +#include +#include + +gboolean dump_tree,dump_result,test_result,do_xinclude; +gchar **files; + +gboolean trace_symbol(const gchar *option_name,const gchar *value,gpointer data, + GError **err) +{ + Xexpr *xexpr=data; + xexpr_start_tracing(xexpr,value); + return TRUE; +} + +gboolean set_param(const gchar *option_name,const gchar *value,gpointer data, + GError **err) +{ + const char *s; + char *endptr; + double d,integer; + gchar *name; + XexprConstant *arg; + Xexpr *xexpr=data; + s=strchr(value,','); + if (!s) + { + g_set_error(err,G_OPTION_ERROR,G_OPTION_ERROR_BAD_VALUE, + "No comma found in --param argument \"%s\"",value); + return FALSE; + } + name=g_strndup(value,s-value); + d=strtod(s+1,&endptr); + if (!d || *endptr) + { + g_set_error(err,G_OPTION_ERROR,G_OPTION_ERROR_BAD_VALUE, + "Invalid number in --param argument: \"%s\"",s); + return FALSE; + } + if (!modf(d,&integer)) + arg=xexpr_new_integer(integer); + else + arg=xexpr_new_number(d); + xexpr_var_set(xexpr,name,arg); + xexpr_constant_free(arg); + return TRUE; +} + +gboolean set_string_param(const gchar *option_name,const gchar *value, + gpointer data,GError **err) +{ + const char *s; + char *endptr; + double d,integer; + gchar *name; + XexprConstant *arg; + Xexpr *xexpr=data; + s=strchr(value,','); + if (!s) + { + g_set_error(err,G_OPTION_ERROR,G_OPTION_ERROR_BAD_VALUE, + "No comma found in --stringparam argument \"%s\"",value); + return FALSE; + } + name=g_strndup(value,s-value); + arg=xexpr_new_string(s+1,-1); + xexpr_var_set(xexpr,name,arg); + xexpr_constant_free(arg); + return TRUE; +} + +static GOptionEntry entries[]={ + { "dump-tree",'d',0,G_OPTION_ARG_NONE,&dump_tree,"Dump parsed file",NULL }, + { "dump-result",'D',0,G_OPTION_ARG_NONE,&dump_result,"Dump result",NULL }, + { "test-result",'t',0,G_OPTION_ARG_NONE,&test_result,"Test result",NULL }, + { "trace",'T',0,G_OPTION_ARG_CALLBACK,trace_symbol,"Trace symbol",NULL }, + { G_OPTION_REMAINING,0,0,G_OPTION_ARG_FILENAME_ARRAY,&files,NULL, + "[]" }, + { "xinclude",0,0,G_OPTION_ARG_NONE,&do_xinclude,"Do XInclude processing", + NULL }, + { "param",0,0,G_OPTION_ARG_CALLBACK,set_param, + "Pass a (parameter,number) pair",NULL }, + { "stringparam",0,0,G_OPTION_ARG_CALLBACK,set_string_param, + "Pass a (parameter,string) pair",NULL }, + { NULL } +}; + +gboolean set_variable(gpointer key,gpointer value,gpointer data) +{ + xexpr_var_set(data,key,value); + return FALSE; +} + +gboolean run_xexpr(Xexpr *xexpr,xmlDocPtr doc,const char *filename) +{ + gboolean retval=TRUE; + GError *err=NULL; + Xexpr *sub,*result; + sub=xexpr_sub(xexpr); + xexpr_environment_foreach(xexpr_get_environment(xexpr),set_variable,sub); + if (!xexpr_parse_node(sub,xmlDocGetRootElement(doc),&err)) + { + fprintf(stderr,"%s: %s\n",filename,err->message); + exit(1); + } + if (dump_tree) + { + xexpr_dump(sub,stdout); + putchar('\n'); + } + else + { + result=xexpr_evaluate(sub,&err); + if (err) + { + fprintf(stderr,"%s: %s\n",filename,err->message); + g_clear_error(&err); + xexpr_free(sub); + return FALSE; + } + if (dump_result) + { + printf("\nResult: "); + xexpr_dump(result,stdout); + putchar('\n'); + } + if (test_result) + retval=xexpr_test(result,NULL); + xexpr_free(result); + } + xexpr_free(sub); + return retval; +} + +int main(int argc,char **argv) +{ + int i; + xmlDocPtr doc; + int xml_options=XML_PARSE_NOENT; + gboolean result=TRUE; + GError *err=NULL; + GOptionGroup *group; + GOptionContext *context; + Xexpr *xexpr; + xexpr=xexpr_new(); + context=g_option_context_new("- XEXPR interpreter"); + group=g_option_group_new(NULL,NULL,NULL,xexpr,NULL); + g_option_group_add_entries(group,entries); + g_option_context_set_main_group(context,group); + if (!g_option_context_parse(context,&argc,&argv,&err)) + { + fprintf(stderr,"%s\n",err->message); + exit(1); + } + if (do_xinclude) + xml_options|=XML_PARSE_XINCLUDE|XML_PARSE_NOXINCNODE; + if (files && files[0]) + { + for(i=0;files[i];i++) + { + doc=xmlReadFile(files[i],NULL,xml_options); + if (!doc) + result=FALSE; + else + { + if (do_xinclude && xmlXIncludeProcessFlags(doc,xml_options)<0) + result=FALSE; + else if (!run_xexpr(xexpr,doc,files[i])) + result=FALSE; + xmlFreeDoc(doc); + } + } + } + else + { + doc=xmlReadFd(0,NULL,NULL,xml_options); + if (!doc) + result=FALSE; + else + { + if (do_xinclude && xmlXIncludeProcessFlags(doc,xml_options)<0) + result=FALSE; + else if (!run_xexpr(xexpr,doc,"stdin")) + result=FALSE; + xmlFreeDoc(doc); + } + } + xexpr_free(xexpr); + exit(result?0:1); +} diff -r 000000000000 -r bc8c9a11cbfc test/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/Makefile.am Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,1 @@ +SUBDIRS=spec idb libxexpr diff -r 000000000000 -r bc8c9a11cbfc test/idb/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/Makefile.am Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,11 @@ +TESTS_ENVIRONMENT=top_builddir="$(top_builddir)" +check_SCRIPTS=numbers bindings pcdata define get arithmetic comparison \ + builtin namespaces +TESTS=$(check_SCRIPTS) + +%: %.sh + cp $(srcdir)/$*.sh $@ + chmod +x $@ + +EXTRA_DIST=$(check_SCRIPTS:%=%.sh) $(check_SCRIPTS:%=%.xml) +CLEANFILES=$(check_SCRIPTS) diff -r 000000000000 -r bc8c9a11cbfc test/idb/arithmetic.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/arithmetic.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,11 @@ +#!/bin/sh +$top_builddir/src/xexpr $srcdir/arithmetic.xml > arithmetic.out +cat <<-EOF > arithmetic.ref +9 +6 +20 +EOF +cmp arithmetic.out arithmetic.ref +retval=$? +rm -f arithmetic.out arithmetic.ref +exit $retval diff -r 000000000000 -r bc8c9a11cbfc test/idb/arithmetic.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/arithmetic.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,15 @@ + + 2 3 + 3 + + + + 2 3 + 3 + + + + 5 + + + diff -r 000000000000 -r bc8c9a11cbfc test/idb/bindings.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/bindings.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/bindings.xml diff -r 000000000000 -r bc8c9a11cbfc test/idb/bindings.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/bindings.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,47 @@ + + + + + + + + + 1 + + + PASS + + FAIL + + + + + + + + + 1.4 + + + PASS + + FAIL + + + + + + + + + Hello + + + PASS + + FAIL + + + + + diff -r 000000000000 -r bc8c9a11cbfc test/idb/builtin.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/builtin.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,3 @@ +#!/bin/sh +$top_builddir/src/xexpr $srcdir/builtin.xml >& /dev/null && exit 1 +exit 0 diff -r 000000000000 -r bc8c9a11cbfc test/idb/builtin.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/builtin.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,4 @@ + + + + diff -r 000000000000 -r bc8c9a11cbfc test/idb/comparison.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/comparison.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/comparison.xml diff -r 000000000000 -r bc8c9a11cbfc test/idb/comparison.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/comparison.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,224 @@ + + + + + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + + + + Hello + + + PASS + + FAIL + + + + + + + 27.2 + + + PASS + + FAIL + + + + + + + 0 + + + PASS + + FAIL + + + + + + + 3 + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + + + + 1 2 3 + + + PASS + + FAIL + + + + + + + 1 2 3 + + + PASS + + FAIL + + + + + + + 3535 + + + PASS + + FAIL + + + + + + + œæ + + + PASS + + FAIL + + + + + + + + 2 + 3 + + + + PASS + + FAIL + + + + + + + + + + + + + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/idb/define.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/define.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/define.xml diff -r 000000000000 -r bc8c9a11cbfc test/idb/define.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/define.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,35 @@ + + 1 + + + + + + 2 + + + + + + FAIL + + + PASS + + + + + + 2 + + + + + PASS + + FAIL + + + + + diff -r 000000000000 -r bc8c9a11cbfc test/idb/get.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/get.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/get.xml diff -r 000000000000 -r bc8c9a11cbfc test/idb/get.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/get.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,80 @@ + + 1 + + + + + + + + + + + + + + + + + + x + + PASS + + FAIL + + + + + + + + 1 + 1 + + + + 1 + x1 + + + + + FAIL + + + PASS + + + + + 4.5.50709 + .net + + PASS + + FAIL + + + + + + + + + + .product + + 1 2 3 4 + + 14 + + PASS + + FAIL + + + + + + diff -r 000000000000 -r bc8c9a11cbfc test/idb/namespaces.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/namespaces.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/namespaces.xml diff -r 000000000000 -r bc8c9a11cbfc test/idb/namespaces.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/namespaces.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,10 @@ + + + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/idb/numbers.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/numbers.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/numbers.xml diff -r 000000000000 -r bc8c9a11cbfc test/idb/numbers.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/numbers.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,25 @@ + + + + -1 + 0 1 + + PASS + + FAIL + + + + + + + +1.7 + 1.7 + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/idb/pcdata.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/pcdata.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/pcdata.xml diff -r 000000000000 -r bc8c9a11cbfc test/idb/pcdata.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/idb/pcdata.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,19 @@ + + + + + + This is the 0xdeadbeef constant. + + This is the + 0xdeadbeef + constant. + + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/Makefile.am Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,10 @@ +TESTS_ENVIRONMENT=top_builddir="$(top_builddir)" +check_SCRIPTS=pi sin atan exp log +TESTS=$(check_SCRIPTS) + +%: %.sh + cp $(srcdir)/$*.sh $@ + chmod +x $@ + +EXTRA_DIST=$(check_SCRIPTS:%=%.sh) $(check_SCRIPTS:%=%.xml) +CLEANFILES=$(check_SCRIPTS) diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/atan.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/atan.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/atan.xml diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/atan.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/atan.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,26 @@ + + + + 1 0 + 0 + + PASS + + FAIL + + + + + + + + 0 + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/exp.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/exp.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/exp.xml diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/exp.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/exp.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,15 @@ + + + + 7.389 + 2 + 7.390 + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/log.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/log.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/log.xml diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/log.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/log.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,16 @@ + + + + + 2 + + 2 + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/pi.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/pi.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/pi.xml diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/pi.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/pi.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,17 @@ + + + + + + 1 + 4 + + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/pow.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/pow.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,14 @@ + + + + 10 2 + 100 + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/sin.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/sin.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/sin.xml diff -r 000000000000 -r bc8c9a11cbfc test/libxexpr/sin.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/libxexpr/sin.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,19 @@ + + + + + + + 2 + + + 1 + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/Makefile.am Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,15 @@ +TESTS_ENVIRONMENT=top_builddir="$(top_builddir)" +check_SCRIPTS=spectest3 spectest4 spectest5 spectest6 spectest7 spectest8 \ + spectest11 spectest12 spectest13 spectest14 spectest15 spectest16 \ + spectest17 spectest19 spectest20 spectest21 spectest24 spectest26 \ + spectest27 spectest28 spectest29 spectest31 spectest32 spectest33 \ + spectest34 spectest35 spectest36 spectest38 spectest39 spectest40 \ + spectest42 spectest43 spectest45 spectest46 spectest48 spectest49 +TESTS=$(check_SCRIPTS) + +%: %.sh + cp $(srcdir)/$*.sh $@ + chmod +x $@ + +EXTRA_DIST=$(check_SCRIPTS:%=%.sh) $(check_SCRIPTS:%=%.xml) +CLEANFILES=$(check_SCRIPTS) diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest11.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest11.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest11.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest11.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest11.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,71 @@ + + 3.14 + + + 2 + + + + + + + 3.14 + + PASS + + FAIL + + + + + + + 10 + 20 + + PASS + + FAIL + + + + + + + + 2 + 4 + + 8 + + PASS + + FAIL + + + + + + Times two returns: + + 2 + 5 + + + + + + + 2 + 5 + + 10 + + PASS + + FAIL + + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest12.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest12.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,8 @@ +#!/bin/sh +set -e +$top_builddir/src/xexpr --test-result $srcdir/spectest12.xml > spectest12.out +echo "4Hello World" > spectest12.ref +cmp spectest12.out spectest12.ref +retval=$? +rm -f spectest12.out spectest12.ref +exit $retval diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest12.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest12.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,5 @@ + + 2 2 + Hello World + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest13.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest13.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,8 @@ +#!/bin/sh +set -e +$top_builddir/src/xexpr --test-result $srcdir/spectest13.xml > spectest13.out +echo "" > spectest13.ref +cmp spectest13.out spectest13.ref +retval=$? +rm -f spectest13.out spectest13.ref +exit $retval diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest13.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest13.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,1 @@ + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest14.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest14.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest14.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest14.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest14.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,31 @@ + + 1 + + + + + + x + + + PASS + + FAIL + + + + + + + + y + + + PASS + + FAIL + + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest15.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest15.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest15.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest15.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest15.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,37 @@ + + + + + hello + + PASS + + FAIL + + + + + + + hello + hello + + PASS + + FAIL + + + + + + + hello 123 + 123 + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest16.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest16.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,8 @@ +#!/bin/sh +set -e +$top_builddir/src/xexpr --test-result $srcdir/spectest16.xml > spectest16.out +echo -n "3" > spectest16.ref +cmp spectest16.out spectest16.ref +retval=$? +rm -f spectest16.out spectest16.ref +exit $retval diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest16.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest16.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,11 @@ + + + 3 + + + + + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest17.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest17.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest17.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest17.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest17.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,48 @@ + + + bar + + + + 1 2 + + + + + + + + bar + + PASS + + FAIL + + + + + + + + 2 + + PASS + + FAIL + + + + + + + + 1 + + PASS + + FAIL + + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest19.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest19.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest19.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest19.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest19.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,30 @@ + + + + This is #1 + This is #1 + + PASS + + FAIL + + + + + + + This is the 00 constant. + + This is the + 0 + 0 + constant. + + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest20.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest20.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest20.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest20.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest20.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,13 @@ + + + + 123 + 123 + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest21.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest21.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest21.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest21.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest21.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,25 @@ + + + + 123 + 123 + + PASS + + FAIL + + + + + + + 123.143 + 123.143 + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest24.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest24.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest24.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest24.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest24.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,22 @@ + + + + + FAIL + + + PASS + + + + + + + + + FAIL + + + PASS + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest26.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest26.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest26.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest26.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest26.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,49 @@ + + + + 1 2 3 + 6 + + PASS + + FAIL + + + + + + + 1 2 3.0 + 6.0 + + PASS + + FAIL + + + + + + + Hello World#2 2 + Hello World#4 + + PASS + + FAIL + + + + + + + x 32 + 5 + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest27.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest27.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest27.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest27.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest27.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,11 @@ + + + 10 2 1 + 7 + + PASS + + FAIL + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest28.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest28.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest28.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest28.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest28.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,11 @@ + + + 10 2 1 + 20 + + PASS + + FAIL + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest29.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest29.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest29.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest29.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest29.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,11 @@ + + + 20 2 2 + 5 + + PASS + + FAIL + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest3.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest3.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,8 @@ +#!/bin/sh +set -e +$top_builddir/src/xexpr --test-result $srcdir/spectest3.xml > spectest3.out +echo -n "3" > spectest3.ref +cmp spectest3.out spectest3.ref +retval=$? +rm -f spectest3.out spectest3.ref +exit $retval diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest3.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest3.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,25 @@ + + + + + From user@localhost + To: + + + + + + + + + + hello + + authors@ebt.com + hello + + + + + 3 + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest31.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest31.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest31.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest31.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest31.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,51 @@ + + + + A + A + A + + PASS + + FAIL + + + + + + + 1 1 1 + 1 + + PASS + + FAIL + + + + + + + A + A + B + + + FAIL + + + PASS + + + + + 1 1 1 + 2 + + + FAIL + + + PASS + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest32.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest32.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest32.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest32.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest32.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,51 @@ + + + + A + B + C + + PASS + + FAIL + + + + + + + 1 2 3 + 4 + + PASS + + FAIL + + + + + + + A + B + B + + + FAIL + + + PASS + + + + + 1 1 2 + 2 + + + FAIL + + + PASS + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest33.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest33.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest33.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest33.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest33.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,63 @@ + + + + B + B + C + + PASS + + FAIL + + + + + + + 1 + 1 2 3 4 + + PASS + + FAIL + + + + + + + C + B + C + + + FAIL + + + PASS + + + + + 2 + 1 2 3 4 + + + FAIL + + + PASS + + + + + 1 + 1 2 3 4 + + + FAIL + + + PASS + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest34.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest34.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest34.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest34.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest34.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,63 @@ + + + + B + B + A + + PASS + + FAIL + + + + + + + 3 + 3 2 1 + + PASS + + FAIL + + + + + + + A + B + A + + + FAIL + + + PASS + + + + + 1 + 2 1 1 + + + FAIL + + + PASS + + + + + 3 + 3 2 1 + + + FAIL + + + PASS + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest35.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest35.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest35.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest35.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest35.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,63 @@ + + + + A + B + C + + PASS + + FAIL + + + + + + + 1 2 3 + 4 + + PASS + + FAIL + + + + + + + A + B + B + + + FAIL + + + PASS + + + + + 1 2 3 + 3 + + + FAIL + + + PASS + + + + + 1 2 3 + 4 + + + FAIL + + + PASS + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest36.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest36.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest36.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest36.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest36.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,63 @@ + + + + C + B + A + + PASS + + FAIL + + + + + + + 4 3 2 + 1 + + PASS + + FAIL + + + + + + + C + B + C + + + FAIL + + + PASS + + + + + 4 3 2 + 3 + + + FAIL + + + PASS + + + + + 4 3 2 + 1 + + + FAIL + + + PASS + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest38.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest38.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest38.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest38.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest38.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,43 @@ + + + + + + + + + + PASS + + FAIL + + + + + + + + + + + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest39.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest39.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest39.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest39.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest39.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,58 @@ + + + + + + + + + + PASS + + FAIL + + + + + + + + + + + + + PASS + + FAIL + + + + + + + + + + + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest4.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest4.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest4.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest4.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest4.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,41 @@ + + + + + + + + This is the 0xdeadbeef constant. + + This is the + 0xdeadbeef + constant. + + + PASS + + FAIL + + + + + + + This is a constant. + + This is a + + constant + + . + + + PASS + + FAIL + + + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest40.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest40.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest40.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest40.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest40.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,106 @@ + + + + + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + + + + 1 + + + PASS + + FAIL + + + + + + + + + + PASS + + FAIL + + + + + + + + + + + + + PASS + + FAIL + + + + + + + + + + + + + PASS + + FAIL + + + + + + + + + + + + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest42.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest42.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest42.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest42.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest42.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,38 @@ + + + + + 1 2 + + equal + + + not equal + + + not equal + + PASS + + FAIL + + + + + + + + 1 2 + + equal + + + + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest43.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest43.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest43.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest43.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest43.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,73 @@ + + + + + 1 + 1 + + + + 2 + + + + + + + + 1 + 1 + + + + + + + + 1 + 1 + + PASS + + FAIL + + + + + + + 2 + 2 + + PASS + + FAIL + + + + + + + 1 + 1 + + PASS + + FAIL + + + + + + + 2 + + + PASS + + FAIL + + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest45.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest45.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,18 @@ +#!/bin/sh +$top_builddir/src/xexpr $srcdir/spectest45.xml > spectest45.out +cat <<-EOF > spectest45.ref +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +EOF +cmp spectest45.out spectest45.ref +retval=$? +rm -f spectest45.out spectest45.ref +exit $retval diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest45.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest45.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,10 @@ + + 10 + + 0 + + + 1 + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest46.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest46.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,18 @@ +#!/bin/sh +$top_builddir/src/xexpr $srcdir/spectest46.xml > spectest46.out +cat <<-EOF > spectest46.ref +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +EOF +cmp spectest46.out spectest46.ref +retval=$? +rm -f spectest46.out spectest46.ref +exit $retval diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest46.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest46.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,10 @@ + + 10 + + + + 1 + + 0 + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest48.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest48.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest48.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest48.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest48.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,1 @@ + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest49.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest49.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest49.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest49.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest49.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,4 @@ + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest5.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest5.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest5.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest5.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest5.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,19 @@ + + + + + + + This is a test. + + + This is a test. + + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest6.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest6.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest6.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest6.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest6.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,22 @@ + + + + + + + + abc + def + + + + abc def + + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest7.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest7.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest7.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest7.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest7.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,16 @@ + + + + + + + 24 + 16 + + PASS + + FAIL + + + + diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest8.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest8.sh Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,2 @@ +#!/bin/sh +$top_builddir/src/xexpr --test-result $srcdir/spectest8.xml diff -r 000000000000 -r bc8c9a11cbfc test/spec/spectest8.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/spec/spectest8.xml Wed Oct 10 22:58:21 2012 +0100 @@ -0,0 +1,54 @@ + + + + + 2 + + + + 1 + + + + + + 7 + 5040 + + PASS + + FAIL + + + + + + + + + + + + + 1 + + + + + + 1 1 + + + + + 7 + 5040 + + PASS + + FAIL + + + + +