From 72bbd833136a8a36eab1597c2f32f0890caeade8 Mon Sep 17 00:00:00 2001 From: Gabriel Dos Reis Date: Wed, 23 Dec 2015 12:50:54 -0800 Subject: Arrange the source include director to mirror expected build structure instead of creating links. --- Makefile.in | 20 +- config/open-axiom.m4 | 31 -- configure | 64 +--- configure.ac | 1 - src/include/Charset.H | 49 --- src/include/Constructor.H | 80 ----- src/include/Database.H | 54 --- src/include/FileMapping.H | 66 ---- src/include/Input.H | 108 ------ src/include/InputFragment.h | 90 ----- src/include/Lisp.H | 128 ------- src/include/SourceFile.H | 53 --- src/include/defaults.H | 64 ---- src/include/diagnostics.H | 63 ---- src/include/dialect.H | 47 --- src/include/iterator.H | 83 ----- src/include/open-axiom/Charset | 49 +++ src/include/open-axiom/Constructor | 80 +++++ src/include/open-axiom/Database | 54 +++ src/include/open-axiom/FileMapping | 66 ++++ src/include/open-axiom/Input | 108 ++++++ src/include/open-axiom/InputFragment | 90 +++++ src/include/open-axiom/Lisp | 128 +++++++ src/include/open-axiom/SourceFile | 53 +++ src/include/open-axiom/defaults | 64 ++++ src/include/open-axiom/diagnostics | 63 ++++ src/include/open-axiom/dialect | 47 +++ src/include/open-axiom/hash-table | 85 +++++ src/include/open-axiom/iterator | 83 +++++ src/include/open-axiom/sexpr | 419 ++++++++++++++++++++++ src/include/open-axiom/storage | 299 ++++++++++++++++ src/include/open-axiom/string-pool | 85 +++++ src/include/open-axiom/structure | 75 ++++ src/include/open-axiom/token | 670 +++++++++++++++++++++++++++++++++++ src/include/open-axiom/token-value | 145 ++++++++ src/include/open-axiom/vm | 606 +++++++++++++++++++++++++++++++ src/include/sexpr.H | 419 ---------------------- src/include/storage.H | 299 ---------------- src/include/structure.H | 75 ---- src/include/token-value.def | 145 -------- src/include/token.H | 670 ----------------------------------- src/include/vm.H | 606 ------------------------------- src/utils/Makefile.in | 3 +- src/utils/hash-table.H | 85 ----- src/utils/string-pool.H | 85 ----- 45 files changed, 3272 insertions(+), 3385 deletions(-) delete mode 100644 src/include/Charset.H delete mode 100644 src/include/Constructor.H delete mode 100644 src/include/Database.H delete mode 100644 src/include/FileMapping.H delete mode 100644 src/include/Input.H delete mode 100644 src/include/InputFragment.h delete mode 100644 src/include/Lisp.H delete mode 100644 src/include/SourceFile.H delete mode 100644 src/include/defaults.H delete mode 100644 src/include/diagnostics.H delete mode 100644 src/include/dialect.H delete mode 100644 src/include/iterator.H create mode 100644 src/include/open-axiom/Charset create mode 100644 src/include/open-axiom/Constructor create mode 100644 src/include/open-axiom/Database create mode 100644 src/include/open-axiom/FileMapping create mode 100644 src/include/open-axiom/Input create mode 100644 src/include/open-axiom/InputFragment create mode 100644 src/include/open-axiom/Lisp create mode 100644 src/include/open-axiom/SourceFile create mode 100644 src/include/open-axiom/defaults create mode 100644 src/include/open-axiom/diagnostics create mode 100644 src/include/open-axiom/dialect create mode 100644 src/include/open-axiom/hash-table create mode 100644 src/include/open-axiom/iterator create mode 100644 src/include/open-axiom/sexpr create mode 100644 src/include/open-axiom/storage create mode 100644 src/include/open-axiom/string-pool create mode 100644 src/include/open-axiom/structure create mode 100644 src/include/open-axiom/token create mode 100644 src/include/open-axiom/token-value create mode 100644 src/include/open-axiom/vm delete mode 100644 src/include/sexpr.H delete mode 100644 src/include/storage.H delete mode 100644 src/include/structure.H delete mode 100644 src/include/token-value.def delete mode 100644 src/include/token.H delete mode 100644 src/include/vm.H delete mode 100644 src/utils/hash-table.H delete mode 100644 src/utils/string-pool.H diff --git a/Makefile.in b/Makefile.in index 2f46a05c..f600c853 100644 --- a/Makefile.in +++ b/Makefile.in @@ -233,31 +233,13 @@ am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/compile \ $(top_srcdir)/src/graph/viewman/Makefile.in \ $(top_srcdir)/src/gui/gui.pro.in \ $(top_srcdir)/src/hyper/Makefile.in \ - $(top_srcdir)/src/include/Charset.H \ - $(top_srcdir)/src/include/Constructor.H \ - $(top_srcdir)/src/include/Database.H \ - $(top_srcdir)/src/include/FileMapping.H \ - $(top_srcdir)/src/include/Input.H \ - $(top_srcdir)/src/include/InputFragment.h \ - $(top_srcdir)/src/include/Lisp.H \ - $(top_srcdir)/src/include/SourceFile.H \ - $(top_srcdir)/src/include/defaults.H \ - $(top_srcdir)/src/include/diagnostics.H \ - $(top_srcdir)/src/include/dialect.H \ - $(top_srcdir)/src/include/iterator.H \ - $(top_srcdir)/src/include/sexpr.H \ - $(top_srcdir)/src/include/storage.H \ - $(top_srcdir)/src/include/structure.H \ - $(top_srcdir)/src/include/token-value.def \ - $(top_srcdir)/src/include/token.H \ - $(top_srcdir)/src/include/vm.H \ $(top_srcdir)/src/input/Makefile.in \ $(top_srcdir)/src/interp/Makefile.in \ $(top_srcdir)/src/lib/Makefile.in \ $(top_srcdir)/src/lisp/Makefile.in \ $(top_srcdir)/src/share/Makefile.in \ $(top_srcdir)/src/sman/Makefile.in AUTHORS COPYING ChangeLog \ - INSTALL NEWS README TODO config/compile config/config.guess \ + INSTALL NEWS TODO config/compile config/config.guess \ config/config.sub config/depcomp config/install-sh \ config/ltmain.sh config/missing config/mkinstalldirs DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) diff --git a/config/open-axiom.m4 b/config/open-axiom.m4 index 746c954e..991424c6 100644 --- a/config/open-axiom.m4 +++ b/config/open-axiom.m4 @@ -1197,34 +1197,3 @@ case $oa_cxx_compiler_lineage in ;; esac ]) - - -dnl -------------------------- -dnl -- OPENAXIOM_LINK_FILES -- -dnl -------------------------- -AC_DEFUN([OPENAXIOM_LINK_FILES],[ -oa_incdir=$target/include/open-axiom -AC_CONFIG_LINKS([ - $oa_incdir/hash-table:src/utils/hash-table.H - $oa_incdir/string-pool:src/utils/string-pool.H - $oa_incdir/diagnostics:src/include/diagnostics.H - $oa_incdir/dialect:src/include/dialect.H - $oa_incdir/token-value:src/include/token-value.def - $oa_incdir/token:src/include/token.H - $oa_incdir/defaults:src/include/defaults.H - $oa_incdir/structure:src/include/structure.H - $oa_incdir/iterator:src/include/iterator.H - $oa_incdir/storage:src/include/storage.H - $oa_incdir/Charset:src/include/Charset.H - $oa_incdir/FileMapping:src/include/FileMapping.H - $oa_incdir/SourceFile:src/include/SourceFile.H - $oa_incdir/Input:src/include/Input.H - $oa_incdir/vm:src/include/vm.H - $oa_incdir/sexpr:src/include/sexpr.H - $oa_incdir/Lisp:src/include/Lisp.H - $oa_incdir/InputFragment:src/include/InputFragment.h - $oa_incdir/Constructor:src/include/Constructor.H - $oa_incdir/Database:src/include/Database.H -]) - -]) diff --git a/configure b/configure index 36f8d340..c0983305 100755 --- a/configure +++ b/configure @@ -19435,12 +19435,6 @@ case $oa_cxx_compiler_lineage in esac -oa_incdir=$target/include/open-axiom -ac_config_links="$ac_config_links $oa_incdir/hash-table:src/utils/hash-table.H $oa_incdir/string-pool:src/utils/string-pool.H $oa_incdir/diagnostics:src/include/diagnostics.H $oa_incdir/dialect:src/include/dialect.H $oa_incdir/token-value:src/include/token-value.def $oa_incdir/token:src/include/token.H $oa_incdir/defaults:src/include/defaults.H $oa_incdir/structure:src/include/structure.H $oa_incdir/iterator:src/include/iterator.H $oa_incdir/storage:src/include/storage.H $oa_incdir/Charset:src/include/Charset.H $oa_incdir/FileMapping:src/include/FileMapping.H $oa_incdir/SourceFile:src/include/SourceFile.H $oa_incdir/Input:src/include/Input.H $oa_incdir/vm:src/include/vm.H $oa_incdir/sexpr:src/include/sexpr.H $oa_incdir/Lisp:src/include/Lisp.H $oa_incdir/InputFragment:src/include/InputFragment.h $oa_incdir/Constructor:src/include/Constructor.H $oa_incdir/Database:src/include/Database.H" - - - - ## We are ready to instantiate makefiles. ac_config_files="$ac_config_files Makefile src/Makefile src/utils/Makefile src/rt/Makefile src/boot/Makefile src/algebra/Makefile" @@ -20086,7 +20080,6 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" -config_links="$ac_config_links" config_commands="$ac_config_commands" _ACEOF @@ -20117,9 +20110,6 @@ $config_files Configuration headers: $config_headers -Configuration links: -$config_links - Configuration commands: $config_commands @@ -20641,26 +20631,6 @@ do "config/openaxiom-c-macros.h") CONFIG_HEADERS="$CONFIG_HEADERS config/openaxiom-c-macros.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; - "$oa_incdir/hash-table") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/hash-table:src/utils/hash-table.H" ;; - "$oa_incdir/string-pool") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/string-pool:src/utils/string-pool.H" ;; - "$oa_incdir/diagnostics") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/diagnostics:src/include/diagnostics.H" ;; - "$oa_incdir/dialect") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/dialect:src/include/dialect.H" ;; - "$oa_incdir/token-value") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/token-value:src/include/token-value.def" ;; - "$oa_incdir/token") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/token:src/include/token.H" ;; - "$oa_incdir/defaults") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/defaults:src/include/defaults.H" ;; - "$oa_incdir/structure") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/structure:src/include/structure.H" ;; - "$oa_incdir/iterator") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/iterator:src/include/iterator.H" ;; - "$oa_incdir/storage") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/storage:src/include/storage.H" ;; - "$oa_incdir/Charset") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/Charset:src/include/Charset.H" ;; - "$oa_incdir/FileMapping") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/FileMapping:src/include/FileMapping.H" ;; - "$oa_incdir/SourceFile") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/SourceFile:src/include/SourceFile.H" ;; - "$oa_incdir/Input") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/Input:src/include/Input.H" ;; - "$oa_incdir/vm") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/vm:src/include/vm.H" ;; - "$oa_incdir/sexpr") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/sexpr:src/include/sexpr.H" ;; - "$oa_incdir/Lisp") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/Lisp:src/include/Lisp.H" ;; - "$oa_incdir/InputFragment") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/InputFragment:src/include/InputFragment.h" ;; - "$oa_incdir/Constructor") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/Constructor:src/include/Constructor.H" ;; - "$oa_incdir/Database") CONFIG_LINKS="$CONFIG_LINKS $oa_incdir/Database:src/include/Database.H" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "src/utils/Makefile") CONFIG_FILES="$CONFIG_FILES src/utils/Makefile" ;; @@ -20699,7 +20669,6 @@ done if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers - test "${CONFIG_LINKS+set}" = set || CONFIG_LINKS=$config_links test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi @@ -20997,7 +20966,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_HEADERS" -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :L $CONFIG_LINKS :C $CONFIG_COMMANDS" +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do @@ -21274,38 +21243,7 @@ $as_echo X"$_am_arg" | } s/.*/./; q'`/stamp-h$_am_stamp_count ;; - :L) - # - # CONFIG_LINK - # - if test "$ac_source" = "$ac_file" && test "$srcdir" = '.'; then - : - else - # Prefer the file from the source tree if names are identical. - if test "$ac_source" = "$ac_file" || test ! -r "$ac_source"; then - ac_source=$srcdir/$ac_source - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: linking $ac_source to $ac_file" >&5 -$as_echo "$as_me: linking $ac_source to $ac_file" >&6;} - - if test ! -r "$ac_source"; then - as_fn_error $? "$ac_source: file not found" "$LINENO" 5 - fi - rm -f "$ac_file" - - # Try a relative symlink, then a hard link, then a copy. - case $ac_source in - [\\/$]* | ?:[\\/]* ) ac_rel_source=$ac_source ;; - *) ac_rel_source=$ac_top_build_prefix$ac_source ;; - esac - ln -s "$ac_rel_source" "$ac_file" 2>/dev/null || - ln "$ac_source" "$ac_file" 2>/dev/null || - cp -p "$ac_source" "$ac_file" || - as_fn_error $? "cannot link or copy $ac_source to $ac_file" "$LINENO" 5 - fi - ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; diff --git a/configure.ac b/configure.ac index 60b58d2c..fbbf3ebc 100644 --- a/configure.ac +++ b/configure.ac @@ -115,7 +115,6 @@ OPENAXIOM_FFI_TYPE_TABLE OPENAXIOM_GCL_BUILD_OPTIONS OPENAXIOM_CHECK_MM OPENAXIOM_CHECK_MISC -OPENAXIOM_LINK_FILES ## We are ready to instantiate makefiles. AC_CONFIG_FILES([ diff --git a/src/include/Charset.H b/src/include/Charset.H deleted file mode 100644 index 58fa9ea8..00000000 --- a/src/include/Charset.H +++ /dev/null @@ -1,49 +0,0 @@ -// -*- C++ -*- -// Copyright (C) 2013, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom, nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_CHARSET_included -#define OPENAXIOM_CHARSET_included - -#include - -namespace OpenAxiom { - // Code point value of a UCS member. - using Codepoint = uint32_t; - - // Unicode character type. - enum class Character : Codepoint { - NUL = Codepoint() // The NUL character - }; -} - -#endif // OPENAXIOM_CHARSET_included diff --git a/src/include/Constructor.H b/src/include/Constructor.H deleted file mode 100644 index bfab3940..00000000 --- a/src/include/Constructor.H +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (C) 2013, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom. nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_CONSTRUCTOR_included -#define OPENAXIOM_CONSTRUCTOR_included - -#include - -namespace OpenAxiom { - namespace VM { - // -- identifier - using Identifier = String; - - // -- A constructor kind. - enum class ConstructorKind { category, domain, package }; - - // -- Data structure for a constructor. - struct Constructor { - Identifier name; - Identifier abbrev; - String source_file; - String object_file; - ConstructorKind kind; - }; - } -} - -// -- specialize helper function objects -namespace std { - template<> - struct hash { - using H = hash; - H::result_type operator()(const Constructor& c) const { - return h(c.name); - } - - H h; - }; - - template<> - struct equal_to { - using E = equal_to; - using arg_type = OpenAxiom::VM::Constructor; - bool operator()(const arg_type& x, const arg_type& y) const { - return e(x.name, y.name); - } - E e; - }; -} - -#endif // OPENAXIOM_CONSTRUCTOR_included diff --git a/src/include/Database.H b/src/include/Database.H deleted file mode 100644 index cea082c8..00000000 --- a/src/include/Database.H +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) 2013, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom. nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_DATABASE_included -#define OPENAXIOM_DATABASE_included - -#include -#include -#include - -namespace OpenAxiom { - namespace VM { - struct Database { - explicit Database(const std::string&); - Value find_with(Value, Lisp::Evaluator&); - private: - Memory::FileMapping file; - Sexpr::Reader reader; - Pair toc; - std::map dict; - }; - } -} - -#endif // OPENAXIOM_DATABASE_included diff --git a/src/include/FileMapping.H b/src/include/FileMapping.H deleted file mode 100644 index 0c836efb..00000000 --- a/src/include/FileMapping.H +++ /dev/null @@ -1,66 +0,0 @@ -// -*- C++ -*- -// Copyright (C) 2010-2014, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom. nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// --% Author: Gabriel Dos Reis -// --% Description: -// --% Provide random access read to files through file mapping. - -#ifndef OPENAXIOM_FILEMAPPING_included -#define OPENAXIOM_FILEMAPPING_included - -#include - -namespace OpenAxiom { - namespace Memory { - // ----------------- - // -- FileMapping -- - // ----------------- - struct FileMapping { - explicit FileMapping(std::string); - FileMapping(FileMapping&&); - ~FileMapping(); - const Byte* begin() const { return start; } - const Byte* end() const { return begin() + extent; } - std::size_t size() const { return extent; } - protected: - Byte* start; // address at the mapped storage - size_t extent; // length (in bytes) of the storage - private: - FileMapping(const FileMapping&) = delete; - FileMapping& operator=(const FileMapping&) = delete; - }; - } -} - -#endif // OPENAXIOM_FILEMAPPING_included - diff --git a/src/include/Input.H b/src/include/Input.H deleted file mode 100644 index fa4555b8..00000000 --- a/src/include/Input.H +++ /dev/null @@ -1,108 +0,0 @@ -// -*- C++ -*- -// Copyright (C) 2013, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom, nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_INPUT_included -#define OPENAXIOM_INPUT_included - -#include -#include -#include -#include "open-axiom.h" -#include -#include - -namespace OpenAxiom { - namespace Input { - // -- Input text data - using Text = std::string; - - // -- Type of Thingies that iterate over text values - using TextIterator = Text::const_iterator; - - // -- Position of an input source line. - using LineNumber = Ordinal; - - // -- We keep info only for non-empty input lines. - struct NonEmptyLine : private structure::binary { - NonEmptyLine(LineNumber, const Text&); - LineNumber number() const { return first(); } - const Text& text() const { return second(); } - TextIterator begin() const { return text().begin(); } - TextIterator end() const { return text().end(); } - std::size_t size() const { return text().size(); } - }; - - struct Source; - // -- Index into input source lines -- - using Index = std::size_t; - - // -- Line -- - struct Line : private structure::binary { - using value_type = Text::value_type; - using const_reference = Text::const_reference; - using const_pointer = Text::const_pointer; - using difference_type = Text::difference_type; - using iterator = iterator::basic; - const NonEmptyLine& get() const; - const Text& text() const { return get().text(); } - LineNumber number() const { return get().number(); } - iterator begin() const { return { this, 0 }; } - iterator end() const { return { this, size() }; } - Cardinal size() const { return text().size(); } - const_reference at(Ordinal n) const { return text().at(n); } - private: - constexpr Line(const Source* s, Index i) - : structure::binary(s, i) - { } - const Source* source() const { return first(); } - Index index() const { return second(); } - - friend Source; - }; - - // -- LineIterator -- - using LineIterator = Line::iterator; - - // -- Source -- - struct Source : std::vector { - using iterator = OpenAxiom::iterator::basic; - using Index = Ordinal; // line index - Line line(Index i) const { return { this, i }; } - iterator begin() const { return { this, 0 }; } - iterator end() const { return { this, size() }; } - Line line(LineNumber, const Text&); - }; - } -} - -#endif // OPENAXIOM_INPUT_included diff --git a/src/include/InputFragment.h b/src/include/InputFragment.h deleted file mode 100644 index 7f317973..00000000 --- a/src/include/InputFragment.h +++ /dev/null @@ -1,90 +0,0 @@ -// -*- C++ -*- -// Copyright (C) 2014, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom. nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// --% Author: Gabriel Dos Reis - -#ifndef OPENAXIOM_INPUTFRAGMENT_included -#define OPENAXIOM_INPUTFRAGMENT_included - -#include - -namespace OpenAxiom { - // A physical line is just raw text, coupled with location - // information such as line and indentation column. - struct Line : std::string { - LineNumber number; - ColumnIndex indent; - Line() : number(), indent() { } - - std::string sub_string(ColumnIndex s, ColumnIndex e) const { - return substr(s, e - s); - } - }; - - // A program fragment is a logical line, composed of possibly - // several physical lines subject to the off-side rule. As a - // special case, a line ending with the underbar character - // continues to the next line with disregard to the off-side rule. - struct Fragment : std::vector { - explicit operator bool() const { return not empty(); } - // Holds if the last physical line ends with line continuation marker. - bool line_continuation() const { - return not empty() and back().back() == '_'; - } - // Return the indentation of the last physical line of this fragment. - ColumnIndex last_indent() const { - return empty() ? 0 : back().indent; - } - using std::vector::operator[]; - // Reference a line given by a position into this fragment. - const Line& operator()(const OpenAxiom::FragmentCursor& pos) const { - return (*this)[pos.line]; - } - // Reference a character code unit at the position into this fragment. - uint8_t operator[](const OpenAxiom::FragmentCursor& pos) const { - return (*this)[pos.line][pos.column]; - } - // Advance the cursor position to the next character code unit. - uint8_t advance(OpenAxiom::FragmentCursor& pos) const { - return (*this)[pos.line][pos.column++]; - } - // This predicate holds if this fragment covers the cursor position. - bool covering(const OpenAxiom::FragmentCursor& pos) const { - return pos.column < (*this)[pos.line].size(); - } - }; - - std::ostream& operator<<(std::ostream&, const Fragment&); -} - -#endif // OPENAXIOM_INPUTFRAGMENT_included diff --git a/src/include/Lisp.H b/src/include/Lisp.H deleted file mode 100644 index a189dd38..00000000 --- a/src/include/Lisp.H +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (C) 2013-2014, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// --% Author: Gabriel Dos Reis -// --% Abstract: -// --% Very simple support for some core Lisp-like operations. - -#ifndef OPENAXIOM_LISP_included -#define OPENAXIOM_LISP_included - -#include -#include -#include -#include -#include -#include -#include - -namespace std { - template<> - struct hash { - hash::result_type - operator()(const OpenAxiom::VM::Package& s) const { - return h(s.name); - } - hash h; - }; - - template<> - struct equal_to { - using arg_type = OpenAxiom::VM::Package; - bool operator()(const arg_type& x, const arg_type& y) const { - constexpr equal_to eq { }; - return eq(x.name, y.name); - } - }; -} - -namespace OpenAxiom { - namespace Lisp { - using namespace VM; - - // -- Unimplemented features - struct Unimplemented : Diagnostics::BasicError { - explicit Unimplemented(const std::string&); - }; - - // -- Integer overflow - struct IntegerOverflow : Diagnostics::BasicError { - explicit IntegerOverflow(const std::string&); - }; - - // -- Unbound symbol - struct UnboundSymbol : Diagnostics::BasicError { - explicit UnboundSymbol(const std::string&); - }; - - // -- Unbound functiom symbol - struct UnboundFunctionSymbol : Diagnostics::BasicError { - explicit UnboundFunctionSymbol(const std::string&); - }; - - // -- Anchor maps - using AnchorTable = std::map; - - // -- Evaluator -- - struct Evaluator : VM::BasicContext { - Evaluator(); - Value eval(const Sexpr::Syntax*); - Package* core_package() { return core; } - Package* current_package() { return ns; } - Value toplevel_form(const Sexpr::Syntax*); - Value make_value(const Sexpr::Syntax*); - Value* lexical_binding(String); - Environment* global_environment(); - private: - Package* core; - Package* ns; - Symbol* feature_list; - std::list env_stack; - AnchorTable anchor_map; - }; - - // -- Format a value onto an output stream. - void format(Value, std::ostream&); - std::string show(Value); - - // -- Retracts - Fixnum retract_to_fixnum(Value); - Pair retract_to_pair(Value); - Symbol* retract_to_symbol(Value); - - // -- Alist functions - Value assoc(Value, Pair); - } -} - -#endif // OPENAXIOM_LISP_included - diff --git a/src/include/SourceFile.H b/src/include/SourceFile.H deleted file mode 100644 index 41b085a3..00000000 --- a/src/include/SourceFile.H +++ /dev/null @@ -1,53 +0,0 @@ -// -*- C++ -*- -// Copyright (C) 2013, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom, nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_SOURCEFILE_included -#define OPENAXIOM_SOURCEFILE_included - -#include - -namespace OpenAxiom { - namespace Input { - // -- SourceFile -- - struct SourceFile : Memory::FileMapping { - explicit SourceFile(const std::string&); - const std::string& pathname() const { return path; } - private: - std::string path; - SourceFile(const SourceFile&) = delete; - SourceFile& operator=(const SourceFile&) = delete; - } - } -} - -#endif // OPENAXIOM_SOURCEFILE_included diff --git a/src/include/defaults.H b/src/include/defaults.H deleted file mode 100644 index db399419..00000000 --- a/src/include/defaults.H +++ /dev/null @@ -1,64 +0,0 @@ -// -*- C++ -*- -// Copyright (C) 2013, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom, nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_DEFAULTS_included -#define OPENAXIOM_DEFAULTS_included - -namespace OpenAxiom { - // -- The sole purpose of classes defines in this header is to - // -- provoke the automatic generation of definitions for functions - // -- defined within. These functions are not really friend. The - // -- friendship is such a mechanism to convince the C++ compiler - // -- to do something else. This is standard technique, also - // -- known as `based class parameterized by derived classes', or - // -- `curiously recurring pattern'. - namespace defaults { - // generate definition for != assuming existence of ==. - template - struct neq { - friend bool operator!=(t x, t y) { return not(x == y); } - }; - - // generate definitions for ordering functions assuming <. - template - struct ordering { - friend bool operator<=(t x, t y) { return not(y < x); } - friend bool operator>(t x, t y) { return y < x; } - friend bool operator>=(t x, t y) { return not(x < y); } - }; - } -} - -#endif // OPENAXIOM_DEFAULTS_included - - diff --git a/src/include/diagnostics.H b/src/include/diagnostics.H deleted file mode 100644 index 9cb0fce1..00000000 --- a/src/include/diagnostics.H +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2013, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom. nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_DIAGNOSTICS_included -#define OPENAXIOM_DIAGNOSTICS_included - -#include -#include - -namespace OpenAxiom { - namespace Diagnostics { - struct StandardStream { - StandardStream(std::ostream& = std::cout, std::ostream& = std::cerr); - ~StandardStream(); - - std::ostream& output() const { return *out; } - std::ostream& error() const { return *err; } - std::ostream& set_output(std::ostream&); - std::ostream& set_error(std::ostream&); - private: - std::ostream* out; - std::ostream* err; - }; - - struct BasicError { - explicit BasicError(const std::string& s) : msg(s) { } - const std::string& message() const { return msg; } - protected: - std::string msg; - }; - } -} - -#endif diff --git a/src/include/dialect.H b/src/include/dialect.H deleted file mode 100644 index bcfddd04..00000000 --- a/src/include/dialect.H +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2013-2014, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom. nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_DIALECT_included -#define OPENAXIOM_DIALECT_included - -namespace OpenAxiom { - // Languages for which we have parsers. - enum class Language { - Spad = 0x1, - Boot = 0x2, - Lisp = 0x4, - BootSpad = Spad | Boot, - All = Spad | Boot | Lisp, - }; -} - -#endif // OPENAXIOM_DIALECT_included diff --git a/src/include/iterator.H b/src/include/iterator.H deleted file mode 100644 index 048dc67c..00000000 --- a/src/include/iterator.H +++ /dev/null @@ -1,83 +0,0 @@ -// -*- C++ -*- -// Copyright (C) 2013, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom, nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_ITERATOR_included -#define OPENAXIOM_ITERATOR_included - -#include -#include -#include "open-axiom.h" - -namespace OpenAxiom { - // -- Read-only iterator over a sequence with random access capabilities. - namespace iterator { - template - struct basic - : std::iterator, - defaults::neq>, defaults::ordering> { - using reference = typename Seq::const_reference; - using pointer = typename Seq::const_pointer; - using difference_type = typename Seq::difference_type; - - reference operator*() const { return seq->at(idx); } - pointer operator->() const { return &seq->at(idx); } - reference operator[](Ordinal i) const { return seq->at(idx + i); } - - basic& operator++() { ++idx; return *this; } - basic operator++(int) { auto t = *this; ++idx; return t; } - basic& operator--() { --idx; return *this; } - basic operator--(int) { auto t = *this; --idx; return t; } - - basic& operator+=(Cardinal n) { idx += n; return *this; } - basic& operator-=(Cardinal n) { idx -= n; return *this; } - basic operator+(Cardinal n) const { return { seq, idx + n }; } - basic operator-(Cardinal n) const { return { seq, idx - n }; } - difference_type operator-(basic that) const { return idx - that.idx; } - - - bool operator==(basic that) const { return idx == that.idx; } - bool operator<(basic that) const { return idx < that.idx; } - - private: - friend Seq; - const Seq* seq; - Ordinal idx; - constexpr basic(const Seq* s, Cardinal i) : seq(s), idx(i) { } - }; - } -} - - -#endif // OPENAXIOM_ITERATOR_included - diff --git a/src/include/open-axiom/Charset b/src/include/open-axiom/Charset new file mode 100644 index 00000000..58fa9ea8 --- /dev/null +++ b/src/include/open-axiom/Charset @@ -0,0 +1,49 @@ +// -*- C++ -*- +// Copyright (C) 2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom, nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_CHARSET_included +#define OPENAXIOM_CHARSET_included + +#include + +namespace OpenAxiom { + // Code point value of a UCS member. + using Codepoint = uint32_t; + + // Unicode character type. + enum class Character : Codepoint { + NUL = Codepoint() // The NUL character + }; +} + +#endif // OPENAXIOM_CHARSET_included diff --git a/src/include/open-axiom/Constructor b/src/include/open-axiom/Constructor new file mode 100644 index 00000000..bfab3940 --- /dev/null +++ b/src/include/open-axiom/Constructor @@ -0,0 +1,80 @@ +// Copyright (C) 2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_CONSTRUCTOR_included +#define OPENAXIOM_CONSTRUCTOR_included + +#include + +namespace OpenAxiom { + namespace VM { + // -- identifier + using Identifier = String; + + // -- A constructor kind. + enum class ConstructorKind { category, domain, package }; + + // -- Data structure for a constructor. + struct Constructor { + Identifier name; + Identifier abbrev; + String source_file; + String object_file; + ConstructorKind kind; + }; + } +} + +// -- specialize helper function objects +namespace std { + template<> + struct hash { + using H = hash; + H::result_type operator()(const Constructor& c) const { + return h(c.name); + } + + H h; + }; + + template<> + struct equal_to { + using E = equal_to; + using arg_type = OpenAxiom::VM::Constructor; + bool operator()(const arg_type& x, const arg_type& y) const { + return e(x.name, y.name); + } + E e; + }; +} + +#endif // OPENAXIOM_CONSTRUCTOR_included diff --git a/src/include/open-axiom/Database b/src/include/open-axiom/Database new file mode 100644 index 00000000..cea082c8 --- /dev/null +++ b/src/include/open-axiom/Database @@ -0,0 +1,54 @@ +// Copyright (C) 2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_DATABASE_included +#define OPENAXIOM_DATABASE_included + +#include +#include +#include + +namespace OpenAxiom { + namespace VM { + struct Database { + explicit Database(const std::string&); + Value find_with(Value, Lisp::Evaluator&); + private: + Memory::FileMapping file; + Sexpr::Reader reader; + Pair toc; + std::map dict; + }; + } +} + +#endif // OPENAXIOM_DATABASE_included diff --git a/src/include/open-axiom/FileMapping b/src/include/open-axiom/FileMapping new file mode 100644 index 00000000..0c836efb --- /dev/null +++ b/src/include/open-axiom/FileMapping @@ -0,0 +1,66 @@ +// -*- C++ -*- +// Copyright (C) 2010-2014, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// --% Author: Gabriel Dos Reis +// --% Description: +// --% Provide random access read to files through file mapping. + +#ifndef OPENAXIOM_FILEMAPPING_included +#define OPENAXIOM_FILEMAPPING_included + +#include + +namespace OpenAxiom { + namespace Memory { + // ----------------- + // -- FileMapping -- + // ----------------- + struct FileMapping { + explicit FileMapping(std::string); + FileMapping(FileMapping&&); + ~FileMapping(); + const Byte* begin() const { return start; } + const Byte* end() const { return begin() + extent; } + std::size_t size() const { return extent; } + protected: + Byte* start; // address at the mapped storage + size_t extent; // length (in bytes) of the storage + private: + FileMapping(const FileMapping&) = delete; + FileMapping& operator=(const FileMapping&) = delete; + }; + } +} + +#endif // OPENAXIOM_FILEMAPPING_included + diff --git a/src/include/open-axiom/Input b/src/include/open-axiom/Input new file mode 100644 index 00000000..fa4555b8 --- /dev/null +++ b/src/include/open-axiom/Input @@ -0,0 +1,108 @@ +// -*- C++ -*- +// Copyright (C) 2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom, nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_INPUT_included +#define OPENAXIOM_INPUT_included + +#include +#include +#include +#include "open-axiom.h" +#include +#include + +namespace OpenAxiom { + namespace Input { + // -- Input text data + using Text = std::string; + + // -- Type of Thingies that iterate over text values + using TextIterator = Text::const_iterator; + + // -- Position of an input source line. + using LineNumber = Ordinal; + + // -- We keep info only for non-empty input lines. + struct NonEmptyLine : private structure::binary { + NonEmptyLine(LineNumber, const Text&); + LineNumber number() const { return first(); } + const Text& text() const { return second(); } + TextIterator begin() const { return text().begin(); } + TextIterator end() const { return text().end(); } + std::size_t size() const { return text().size(); } + }; + + struct Source; + // -- Index into input source lines -- + using Index = std::size_t; + + // -- Line -- + struct Line : private structure::binary { + using value_type = Text::value_type; + using const_reference = Text::const_reference; + using const_pointer = Text::const_pointer; + using difference_type = Text::difference_type; + using iterator = iterator::basic; + const NonEmptyLine& get() const; + const Text& text() const { return get().text(); } + LineNumber number() const { return get().number(); } + iterator begin() const { return { this, 0 }; } + iterator end() const { return { this, size() }; } + Cardinal size() const { return text().size(); } + const_reference at(Ordinal n) const { return text().at(n); } + private: + constexpr Line(const Source* s, Index i) + : structure::binary(s, i) + { } + const Source* source() const { return first(); } + Index index() const { return second(); } + + friend Source; + }; + + // -- LineIterator -- + using LineIterator = Line::iterator; + + // -- Source -- + struct Source : std::vector { + using iterator = OpenAxiom::iterator::basic; + using Index = Ordinal; // line index + Line line(Index i) const { return { this, i }; } + iterator begin() const { return { this, 0 }; } + iterator end() const { return { this, size() }; } + Line line(LineNumber, const Text&); + }; + } +} + +#endif // OPENAXIOM_INPUT_included diff --git a/src/include/open-axiom/InputFragment b/src/include/open-axiom/InputFragment new file mode 100644 index 00000000..7f317973 --- /dev/null +++ b/src/include/open-axiom/InputFragment @@ -0,0 +1,90 @@ +// -*- C++ -*- +// Copyright (C) 2014, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// --% Author: Gabriel Dos Reis + +#ifndef OPENAXIOM_INPUTFRAGMENT_included +#define OPENAXIOM_INPUTFRAGMENT_included + +#include + +namespace OpenAxiom { + // A physical line is just raw text, coupled with location + // information such as line and indentation column. + struct Line : std::string { + LineNumber number; + ColumnIndex indent; + Line() : number(), indent() { } + + std::string sub_string(ColumnIndex s, ColumnIndex e) const { + return substr(s, e - s); + } + }; + + // A program fragment is a logical line, composed of possibly + // several physical lines subject to the off-side rule. As a + // special case, a line ending with the underbar character + // continues to the next line with disregard to the off-side rule. + struct Fragment : std::vector { + explicit operator bool() const { return not empty(); } + // Holds if the last physical line ends with line continuation marker. + bool line_continuation() const { + return not empty() and back().back() == '_'; + } + // Return the indentation of the last physical line of this fragment. + ColumnIndex last_indent() const { + return empty() ? 0 : back().indent; + } + using std::vector::operator[]; + // Reference a line given by a position into this fragment. + const Line& operator()(const OpenAxiom::FragmentCursor& pos) const { + return (*this)[pos.line]; + } + // Reference a character code unit at the position into this fragment. + uint8_t operator[](const OpenAxiom::FragmentCursor& pos) const { + return (*this)[pos.line][pos.column]; + } + // Advance the cursor position to the next character code unit. + uint8_t advance(OpenAxiom::FragmentCursor& pos) const { + return (*this)[pos.line][pos.column++]; + } + // This predicate holds if this fragment covers the cursor position. + bool covering(const OpenAxiom::FragmentCursor& pos) const { + return pos.column < (*this)[pos.line].size(); + } + }; + + std::ostream& operator<<(std::ostream&, const Fragment&); +} + +#endif // OPENAXIOM_INPUTFRAGMENT_included diff --git a/src/include/open-axiom/Lisp b/src/include/open-axiom/Lisp new file mode 100644 index 00000000..a189dd38 --- /dev/null +++ b/src/include/open-axiom/Lisp @@ -0,0 +1,128 @@ +// Copyright (C) 2013-2014, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// --% Author: Gabriel Dos Reis +// --% Abstract: +// --% Very simple support for some core Lisp-like operations. + +#ifndef OPENAXIOM_LISP_included +#define OPENAXIOM_LISP_included + +#include +#include +#include +#include +#include +#include +#include + +namespace std { + template<> + struct hash { + hash::result_type + operator()(const OpenAxiom::VM::Package& s) const { + return h(s.name); + } + hash h; + }; + + template<> + struct equal_to { + using arg_type = OpenAxiom::VM::Package; + bool operator()(const arg_type& x, const arg_type& y) const { + constexpr equal_to eq { }; + return eq(x.name, y.name); + } + }; +} + +namespace OpenAxiom { + namespace Lisp { + using namespace VM; + + // -- Unimplemented features + struct Unimplemented : Diagnostics::BasicError { + explicit Unimplemented(const std::string&); + }; + + // -- Integer overflow + struct IntegerOverflow : Diagnostics::BasicError { + explicit IntegerOverflow(const std::string&); + }; + + // -- Unbound symbol + struct UnboundSymbol : Diagnostics::BasicError { + explicit UnboundSymbol(const std::string&); + }; + + // -- Unbound functiom symbol + struct UnboundFunctionSymbol : Diagnostics::BasicError { + explicit UnboundFunctionSymbol(const std::string&); + }; + + // -- Anchor maps + using AnchorTable = std::map; + + // -- Evaluator -- + struct Evaluator : VM::BasicContext { + Evaluator(); + Value eval(const Sexpr::Syntax*); + Package* core_package() { return core; } + Package* current_package() { return ns; } + Value toplevel_form(const Sexpr::Syntax*); + Value make_value(const Sexpr::Syntax*); + Value* lexical_binding(String); + Environment* global_environment(); + private: + Package* core; + Package* ns; + Symbol* feature_list; + std::list env_stack; + AnchorTable anchor_map; + }; + + // -- Format a value onto an output stream. + void format(Value, std::ostream&); + std::string show(Value); + + // -- Retracts + Fixnum retract_to_fixnum(Value); + Pair retract_to_pair(Value); + Symbol* retract_to_symbol(Value); + + // -- Alist functions + Value assoc(Value, Pair); + } +} + +#endif // OPENAXIOM_LISP_included + diff --git a/src/include/open-axiom/SourceFile b/src/include/open-axiom/SourceFile new file mode 100644 index 00000000..41b085a3 --- /dev/null +++ b/src/include/open-axiom/SourceFile @@ -0,0 +1,53 @@ +// -*- C++ -*- +// Copyright (C) 2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom, nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_SOURCEFILE_included +#define OPENAXIOM_SOURCEFILE_included + +#include + +namespace OpenAxiom { + namespace Input { + // -- SourceFile -- + struct SourceFile : Memory::FileMapping { + explicit SourceFile(const std::string&); + const std::string& pathname() const { return path; } + private: + std::string path; + SourceFile(const SourceFile&) = delete; + SourceFile& operator=(const SourceFile&) = delete; + } + } +} + +#endif // OPENAXIOM_SOURCEFILE_included diff --git a/src/include/open-axiom/defaults b/src/include/open-axiom/defaults new file mode 100644 index 00000000..db399419 --- /dev/null +++ b/src/include/open-axiom/defaults @@ -0,0 +1,64 @@ +// -*- C++ -*- +// Copyright (C) 2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom, nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_DEFAULTS_included +#define OPENAXIOM_DEFAULTS_included + +namespace OpenAxiom { + // -- The sole purpose of classes defines in this header is to + // -- provoke the automatic generation of definitions for functions + // -- defined within. These functions are not really friend. The + // -- friendship is such a mechanism to convince the C++ compiler + // -- to do something else. This is standard technique, also + // -- known as `based class parameterized by derived classes', or + // -- `curiously recurring pattern'. + namespace defaults { + // generate definition for != assuming existence of ==. + template + struct neq { + friend bool operator!=(t x, t y) { return not(x == y); } + }; + + // generate definitions for ordering functions assuming <. + template + struct ordering { + friend bool operator<=(t x, t y) { return not(y < x); } + friend bool operator>(t x, t y) { return y < x; } + friend bool operator>=(t x, t y) { return not(x < y); } + }; + } +} + +#endif // OPENAXIOM_DEFAULTS_included + + diff --git a/src/include/open-axiom/diagnostics b/src/include/open-axiom/diagnostics new file mode 100644 index 00000000..9cb0fce1 --- /dev/null +++ b/src/include/open-axiom/diagnostics @@ -0,0 +1,63 @@ +// Copyright (C) 2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_DIAGNOSTICS_included +#define OPENAXIOM_DIAGNOSTICS_included + +#include +#include + +namespace OpenAxiom { + namespace Diagnostics { + struct StandardStream { + StandardStream(std::ostream& = std::cout, std::ostream& = std::cerr); + ~StandardStream(); + + std::ostream& output() const { return *out; } + std::ostream& error() const { return *err; } + std::ostream& set_output(std::ostream&); + std::ostream& set_error(std::ostream&); + private: + std::ostream* out; + std::ostream* err; + }; + + struct BasicError { + explicit BasicError(const std::string& s) : msg(s) { } + const std::string& message() const { return msg; } + protected: + std::string msg; + }; + } +} + +#endif diff --git a/src/include/open-axiom/dialect b/src/include/open-axiom/dialect new file mode 100644 index 00000000..bcfddd04 --- /dev/null +++ b/src/include/open-axiom/dialect @@ -0,0 +1,47 @@ +// Copyright (C) 2013-2014, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_DIALECT_included +#define OPENAXIOM_DIALECT_included + +namespace OpenAxiom { + // Languages for which we have parsers. + enum class Language { + Spad = 0x1, + Boot = 0x2, + Lisp = 0x4, + BootSpad = Spad | Boot, + All = Spad | Boot | Lisp, + }; +} + +#endif // OPENAXIOM_DIALECT_included diff --git a/src/include/open-axiom/hash-table b/src/include/open-axiom/hash-table new file mode 100644 index 00000000..d74c7760 --- /dev/null +++ b/src/include/open-axiom/hash-table @@ -0,0 +1,85 @@ +// Copyright (C) 2010, Gabriel Dos Reis. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of The Numerical Algorithms Group Ltd. nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_HASH_TABLE_INCLUDED +#define OPENAXIOM_HASH_TABLE_INCLUDED + +// --% Author: Gabriel Dos Reis. +// --% Description: +// --% Simple hash table facility. To be replaced by C++0x +// --% hash tables when C++0x compilers become common place. + +#include + +namespace OpenAxiom { + // -------------------- + // -- HashTableEntry -- + // -------------------- + // Datatype for entries in a parameterized hash table. + // The type parameter is required to be a value-construcitble datatype. + // A table bucket entry is required to be at least 8-byte aligned + // so that an instance of it can be used directly as a VM value. + // See for more description. + template + struct alignas(8) HashTableEntry : T { + HashTableEntry* chain; // previous item in the same bucket chain + size_t hash; // hash code of stored data + }; + + // -------------------- + // -- BasicHashTable -- + // -------------------- + // A simple hash table data structure. Ideally, we would like to use + // standard C++ types, but hash tables were only in a C++ 2003 TR, + // officially part of C++0x standard library. We still don't have + // wide-spread C++0x compilers. + template + struct BasicHashTable : private Memory::Arena > { + typedef HashTableEntry EntryType; + explicit BasicHashTable(size_t n) + : Memory::Arena >(n), + buckets(this->allocate(n)), nbuckets(n) { } + + EntryType* hash_chain(size_t h) const { + return buckets + (h % nbuckets); + } + + EntryType* new_bucket() { + return this->allocate(1); + } + + private: + HashTableEntry* const buckets; + const size_t nbuckets; + }; +} + +#endif // OPENAXIOM_HASH_TABLE_INCLUDED diff --git a/src/include/open-axiom/iterator b/src/include/open-axiom/iterator new file mode 100644 index 00000000..048dc67c --- /dev/null +++ b/src/include/open-axiom/iterator @@ -0,0 +1,83 @@ +// -*- C++ -*- +// Copyright (C) 2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom, nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_ITERATOR_included +#define OPENAXIOM_ITERATOR_included + +#include +#include +#include "open-axiom.h" + +namespace OpenAxiom { + // -- Read-only iterator over a sequence with random access capabilities. + namespace iterator { + template + struct basic + : std::iterator, + defaults::neq>, defaults::ordering> { + using reference = typename Seq::const_reference; + using pointer = typename Seq::const_pointer; + using difference_type = typename Seq::difference_type; + + reference operator*() const { return seq->at(idx); } + pointer operator->() const { return &seq->at(idx); } + reference operator[](Ordinal i) const { return seq->at(idx + i); } + + basic& operator++() { ++idx; return *this; } + basic operator++(int) { auto t = *this; ++idx; return t; } + basic& operator--() { --idx; return *this; } + basic operator--(int) { auto t = *this; --idx; return t; } + + basic& operator+=(Cardinal n) { idx += n; return *this; } + basic& operator-=(Cardinal n) { idx -= n; return *this; } + basic operator+(Cardinal n) const { return { seq, idx + n }; } + basic operator-(Cardinal n) const { return { seq, idx - n }; } + difference_type operator-(basic that) const { return idx - that.idx; } + + + bool operator==(basic that) const { return idx == that.idx; } + bool operator<(basic that) const { return idx < that.idx; } + + private: + friend Seq; + const Seq* seq; + Ordinal idx; + constexpr basic(const Seq* s, Cardinal i) : seq(s), idx(i) { } + }; + } +} + + +#endif // OPENAXIOM_ITERATOR_included + diff --git a/src/include/open-axiom/sexpr b/src/include/open-axiom/sexpr new file mode 100644 index 00000000..6920e436 --- /dev/null +++ b/src/include/open-axiom/sexpr @@ -0,0 +1,419 @@ +// Copyright (C) 2010-2014, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of The Numerical Algorithms Group Ltd. nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_SEXPR_included +#define OPENAXIOM_SEXPR_included + +// --% Author: Gabriel Dos Reis. +// --% Description: +// --% A simple support for s-expressions. By design, no ambition +// --% for full-fledged Common Lisp reader capability. Rather, +// --% the aim is a simple data structure for exchanging data +// --% between several components of the OpenAxiom system. +// --% Users interested in fullblown Lisp syntax should seek +// --% to acquire Lisp systems, many of which are freely available. + +#include +#include +#include +#include + +namespace OpenAxiom { + namespace Sexpr { + // ------------ + // -- Lexeme -- + // ------------ + struct Lexeme { + enum Type { + unknown, // unidentified token + semicolon, // ";" for comment + dot, // "." + comma, // "," + open_paren, // "(" + close_paren, // ")" + apostrophe, // "'" + backquote, // "`" + backslash, // "\\" + sharp_open_paren , // "#(" + sharp_apostrophe, // "#'" + sharp_colon, // "#:" + sharp_plus, // "#+" + sharp_minus, // "#-" + sharp_dot, // "#." + comma_at, // ",@" + integer, // integer literal + character, // character literal + string, // string literal + identifier, // plain identifier + sharp_integer_equal, // anchor definition, #n=
+ sharp_integer_sharp // back reference, #n# + }; + + std::pair boundary; + Ordinal line; + const Byte* begin() const { return boundary.first; } + const Byte* end() const { return boundary.second; } + Ordinal size() const { return end() - begin(); } + }; + + // ------------ + // -- Syntax -- + // ------------ + // Base class of syntax object classes. + struct Syntax { + struct Visitor; // base class of syntax visitors + virtual void accept(Visitor&) const = 0; + }; + + // ---------------- + // -- AtomSyntax -- + // ---------------- + // An atom is a syntax object consisting of exatly one token. + // This should not be confused with the notion of atom + // in Lisp languages. + struct AtomSyntax : Syntax { + const Lexeme& lexeme() const { return lex; } + protected: + Lexeme lex; + explicit AtomSyntax(const Lexeme&); + }; + + // ------------------- + // -- IntegerSyntax -- + // ------------------- + // Integer literal syntax objects + struct IntegerSyntax : AtomSyntax { + explicit IntegerSyntax(const Lexeme&); + void accept(Visitor&) const; + }; + + // --------------------- + // -- CharacterSyntax -- + // --------------------- + // Character literal syntax objects. + struct CharacterSyntax : AtomSyntax { + explicit CharacterSyntax(const Lexeme&); + void accept(Visitor&) const; + }; + + // ------------------ + // -- StringSyntax -- + // ------------------ + // Striing literal syntax objjects. + struct StringSyntax : AtomSyntax { + explicit StringSyntax(const Lexeme&); + void accept(Visitor&) const; + }; + + // ------------------ + // -- SymbolSyntax -- + // ------------------ + struct SymbolSyntax : AtomSyntax { + enum Kind { + ordinary = 0x0, // an interned symbol + uninterned = 0x1, // uninterned symbol + absolute = 0x2, // case-sensitive symbol + keyword = 0x4, // a keyword symbol + }; + SymbolSyntax(const Lexeme&, Kind); + Kind kind() const { return sort; } + const Byte* begin() const { return lexeme().begin(); } + const Byte* end() const { return lexeme().end(); } + std::size_t size() const { return lexeme().size(); } + Byte operator[](std::size_t i) const { return begin()[i]; } + void accept(Visitor&) const; + private: + const Kind sort; + }; + + // --------------------- + // -- ReferenceSyntax -- + // --------------------- + // Back reference object to a syntax object. + struct ReferenceSyntax : AtomSyntax { + ReferenceSyntax(const Lexeme&, Ordinal); + size_t tag() const { return pos; } + void accept(Visitor&) const; + private: + Ordinal pos; + }; + + // ------------------ + // -- AnchorSyntax -- + // ------------------ + // Base anchor syntax object. + struct AnchorSyntax : Syntax { + AnchorSyntax(size_t, const Syntax*); + size_t ref() const { return tag; } + const Syntax* value() const { return val; } + void accept(Visitor&) const; + private: + const size_t tag; + const Syntax* const val; + }; + + // -- Abstract over common implementation of unary special operators. + template + struct unary_form : Syntax { + const Syntax* body() const { return form; } + void accept(Visitor&) const; + protected: + unary_form(const Syntax* f) : form(f) { } + private: + const Syntax* const form; + }; + + template + struct binary_form : Syntax { + const Syntax* first() const { return rep.first; } + const Syntax* second() const { return rep.second; } + void accept(Visitor&) const; + protected: + binary_form(const Syntax* f, const Syntax* s) : rep(f, s) { } + private: + std::pair rep; + }; + + // ----------------- + // -- QuoteSyntax -- + // ----------------- + // Quotation syntax object. + struct QuoteSyntax : unary_form { + explicit QuoteSyntax(const Syntax*); + }; + + // --------------------- + // -- AntiquoteSyntax -- + // --------------------- + // Quasi-quotation syntax object. + struct AntiquoteSyntax : unary_form { + explicit AntiquoteSyntax(const Syntax*); + }; + + // ------------ + // -- Expand -- + // ------------ + // Expansion request inside a quasi-quotation. + struct Expand : unary_form { + explicit Expand(const Syntax*); + }; + + // ---------- + // -- Eval -- + // ---------- + // Read-time evaluation request syntax object. + struct Eval : unary_form { + explicit Eval(const Syntax*); + }; + + // ------------ + // -- Splice -- + // ------------ + // Splice request syntax object inside a quasi-quotation. + struct Splice : unary_form { + explicit Splice(const Syntax*); + }; + + // -------------- + // -- Function -- + // -------------- + // Function literal syntax object. + struct Function : unary_form { + explicit Function(const Syntax*); + }; + + // ------------- + // -- Include -- + // ------------- + // Conditional inclusion syntax object + struct Include : binary_form { + Include(const Syntax*, const Syntax*); + }; + + // ------------- + // -- Exclude -- + // ------------- + // Conditional exclusion syntax object + struct Exclude : binary_form { + Exclude(const Syntax*, const Syntax*); + }; + + // ---------------- + // -- ListSyntax -- + // ---------------- + // List syntax objects. + struct ListSyntax : Syntax, private std::vector { + typedef std::vector base; + using base::const_iterator; + using base::begin; + using base::end; + using base::rbegin; + using base::rend; + using base::size; + using base::empty; + using base::front; + + ListSyntax(); + ListSyntax(const base&, bool); + ~ListSyntax(); + void accept(Visitor&) const; + bool dotted() const { return dot; } + private: + bool dot; + }; + + // ------------------ + // -- VectorSyntax -- + // ------------------ + // VectorSyntax syntax objects. + struct VectorSyntax : Syntax, private std::vector { + typedef std::vector base; + using base::const_iterator; + using base::begin; + using base::end; + using base::size; + using base::operator[]; + using base::empty; + + VectorSyntax(); + explicit VectorSyntax(const base&); + ~VectorSyntax(); + void accept(Visitor&) const; + }; + + // --------------------- + // -- Syntax::Visitor -- + // --------------------- + struct Syntax::Visitor { + virtual void visit(const IntegerSyntax&) = 0; + virtual void visit(const CharacterSyntax&) = 0; + virtual void visit(const StringSyntax&) = 0; + virtual void visit(const SymbolSyntax&) = 0; + virtual void visit(const ReferenceSyntax&) = 0; + virtual void visit(const AnchorSyntax&) = 0; + virtual void visit(const QuoteSyntax&) = 0; + virtual void visit(const AntiquoteSyntax&) = 0; + virtual void visit(const Expand&) = 0; + virtual void visit(const Eval&) = 0; + virtual void visit(const Splice&) = 0; + virtual void visit(const Function&) = 0; + virtual void visit(const Include&) = 0; + virtual void visit(const Exclude&) = 0; + virtual void visit(const ListSyntax&) = 0; + virtual void visit(const VectorSyntax&) = 0; + }; + + template + void + unary_form::accept(Visitor& v) const { + v.visit(static_cast(*this)); + } + + template + void + binary_form::accept(Visitor& v) const { + v.visit(static_cast(*this)); + } + + // --------------- + // -- Allocator -- + // --------------- + // Allocator of syntax objects. + struct Allocator { + Allocator(); + ~Allocator(); + + const IntegerSyntax* make_integer(const Lexeme&); + const CharacterSyntax* make_character(const Lexeme&); + const StringSyntax* make_string(const Lexeme&); + const SymbolSyntax* make_symbol(SymbolSyntax::Kind, const Lexeme&); + const ReferenceSyntax* make_reference(size_t, const Lexeme&); + const AnchorSyntax* make_anchor(size_t, const Syntax*); + const QuoteSyntax* make_quote(const Syntax*); + const AntiquoteSyntax* make_antiquote(const Syntax*); + const Expand* make_expand(const Syntax*); + const Eval* make_eval(const Syntax*); + const Splice* make_splice(const Syntax*); + const Function* make_function(const Syntax*); + const Include* make_include(const Syntax*, const Syntax*); + const Exclude* make_exclude(const Syntax*, const Syntax*); + const ListSyntax* make_list(const std::vector&, bool = false); + const VectorSyntax* make_vector(const std::vector&); + + private: + Memory::Factory ints; + Memory::Factory chars; + Memory::Factory strs; + Memory::Factory syms; + Memory::Factory ancs; + Memory::Factory refs; + Memory::Factory quotes; + Memory::Factory antis; + Memory::Factory exps; + Memory::Factory funs; + Memory::Factory incs; + Memory::Factory excs; + Memory::Factory evls; + Memory::Factory spls; + Memory::Factory lists; + Memory::Factory vectors; + ListSyntax empty_list; + VectorSyntax empty_vector; + }; + + // -- Reader -- + struct RawInput { + const Byte* start; + const Byte* end; + Ordinal lineno; + }; + + struct Reader { + struct State { + RawInput bytes; + const Byte* cur; + const Byte* line; + Allocator alloc; + }; + + explicit Reader(const RawInput&); + Reader(const Byte*, const Byte*); + const Byte* position(Ordinal); + bool at_start() const { return st.cur == st.bytes.start; } + const Syntax* read(); + private: + State st; + }; + } +} + +#endif // OPENAXIOM_SEXPR_included diff --git a/src/include/open-axiom/storage b/src/include/open-axiom/storage new file mode 100644 index 00000000..e414dec2 --- /dev/null +++ b/src/include/open-axiom/storage @@ -0,0 +1,299 @@ +// Copyright (C) 2010-2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// --% Author: Gabriel Dos Reis +// --% Description: +// --% Memory management facility. Acquire raw memory directly +// --% from the host OS. Provide random access read to +// --% files through file mapping. + +#ifndef OPENAXIOM_STORAGE_included +#define OPENAXIOM_STORAGE_included + +#include +#include +#include +#include +#include + +namespace OpenAxiom { + // Datatype for the unit of storage. + using Byte = unsigned char; + + // ----------------- + // -- SystemError -- + // ----------------- + // Objects of (type derived from) this type are used to report + // error orignating from the OpenAxiom core system. + struct SystemError { + explicit SystemError(const std::string&); + virtual ~SystemError(); + // Return the text of the diagnostic message. + virtual const std::string& message() const; + protected: + const std::string text; + }; + + // Report a file system error + void filesystem_error(const std::string&); + + namespace Memory { + // Datatype for pointers to data. + using Pointer = void*; + + // Precision of the host OS storage page unit in byte count + size_t page_size(); + + // Acquire raw memory from the host OS. + Pointer os_acquire_raw_memory(size_t); + + // Release raw storage to the hosting OS. The first operand must + // be a pointer value previously returned by `os_acquire_raw_memory'. + // Otherwise, the result is undefined. + void os_release_raw_memory(Pointer, size_t); + + // Acquire `n' pages of memory storage from the host OS. + inline Pointer + acquire_raw_pages(size_t n) { + return os_acquire_raw_memory(n * page_size()); + } + + // Release `n' pages of storage starting the location `p'. + inline void + release_raw_pages(Pointer p, size_t n) { + os_release_raw_memory(p, n * page_size()); + } + + // ------------- + // -- Storage -- + // ------------- + // This class provides low-level abstractions intented for use + // to implement higher level storage abstractions. + struct Storage { + // Objects of this abstract datatype hold storage objects. + struct Handle; + + // Return the storage pointed to by the operand. It + // must be a pointer value previously returned by `acquire'. + // Otherwise, the result is undefined. + static void release(Handle*); + + // Return the start address of storage area. Clients would + // want to add padding bytes necessary to accomodate alignment + // requirements. + // Note: this should not be confused with the address of + // the handle object. + static Pointer begin(Handle*); + + // Courtesy conversion function from pointer to byte address. + static Byte* byte_address(Pointer h) { + return static_cast(h); + } + + // Round up `n' to a multiple of `a', a power of 2. + static size_t + round_up(size_t n, size_t a) { + return (n + a - 1) & ~(a - 1); + } + }; + + // ------------------------- + // -- SinglyLinkedStorage -- + // ------------------------- + // This class implements a simple single-linked list of storage + // objects. Each storage object in the link is created with + // a specific starting alignment requirements. + struct SinglyLinkedStorage : Storage { + // Return the previous handle in the link chain. + static Handle*& previous(Handle*); + }; + + // ------------------------- + // -- DoublyLinkedStorage -- + // ------------------------- + // Like SinglyLinkedStorage, except that the chain of storage + // object supports bidirectional travervsal. + struct DoublyLinkedStorage : Storage { + // Same as Storage::acquire, except that begin(h) returns an + // address that satisfies the alignment requirement `a'. + static Handle* acquire(size_t n, size_t a); + + // Return the previous handle in the link chain. + static Handle*& previous(Handle*); + + // Return the next handle in the link chain. + static Handle*& next(Handle*); + }; + + // ------------------ + // -- BlockStorage -- + // ------------------ + // This class implements a simple single-linked list of block storage. + // Each block maintains information about the next allocatable + // address within that block. + struct BlockStorage : SinglyLinkedStorage { + // Same as SinglyLinkedStorage::acquire(); initialize internal + // bookkeepking machinery. + static Handle* acquire(size_t n, size_t a); + + // Return the next allocatable address within the given block. + static Pointer next_address(Handle*); + + // Return the amount of allocatable byte in the given block. + static size_t room(Handle*); + + // Set `n' bytes aside with the given storage block. + static Pointer book(Handle*, size_t); + }; + + // ----------- + // -- Arena -- + // ----------- + // Extensible storage holding objects of a given type. + // The totality of all objects held in such a storage does not + // necessarily constitute a contiguous block. However, + // it is guaranteed that objects allocated in a single call + // to `allocate()' occupy a contiguous block of storage. + template + struct Arena : protected BlockStorage { + // Acquire storage capable of holding `n' objects of type `T'. + explicit Arena(size_t); + // Release all storage acquired by this object, upon end of life. + ~Arena(); + // allocate storage for `n' more objects of type `T'. + T* allocate(size_t); + // Number of objects of type `T' allocated in this storage. + size_t population() const; + + protected: + // Address of the first object of type `T' in a storage. + static T* first_object(Handle* h) { + return static_cast(BlockStorage::begin(h)); + } + + // Address of one-past-the-end object of type `T' in this storage. + static T* last_object(Handle* h) { + return static_cast(BlockStorage::next_address(h)); + } + + // Number of objects allocated in a storage. + static size_t object_count(Handle* h) { + return last_object(h) - first_object(h); + } + + BlockStorage::Handle* store; // active storage to allocate from + }; + + template + size_t + Arena::population() const { + size_t n = 0; + for (Handle* h = store; h != nullptr; h = previous(h)) + n += object_count(h); + return n; + } + + template + T* + Arena::allocate(size_t n) { + const size_t sz = n * sizeof(T); + if (BlockStorage::room(store) < sz) { + // Not enough room left. Make sure we allocate storage + // at least as big as the current. + Handle* h = acquire(std::max(n, object_count(store)), alignof(T)); + previous(h) = store; + store = h; + } + return static_cast(BlockStorage::book(store, sz)); + } + + template + Arena::Arena(size_t n) + : store(BlockStorage::acquire(n * sizeof (T), alignof (T))) + { } + + template + Arena::~Arena() { + // Release storage in the reverse order of their + // their allocation. + while (store != nullptr) { + Handle* current = store; + store = BlockStorage::previous(store); + BlockStorage::release(current); + } + } + + // ------------- + // -- Factory -- + // ------------- + template + struct Factory : Arena { + using Handler = typename Arena::Handle; + + Factory() : Arena(nominal_population()) { } + ~Factory(); + + // Allocate storage and value-construct an object of type `T'. + T* make() { + return new(this->allocate(1)) T{ }; + } + + // Allocate storage and construct an object of type `T'. + template + T* make(const Args&... args) { + return new(this->allocate(1)) T{args...}; + } + + private: + // Return 1 or the number of objects that can fit in a page unit. + static size_t nominal_population() { + const size_t psz = page_size(); + if (sizeof (T) > psz) + return 1; + return psz / sizeof(T); + } + }; + + // Destroy objects in the reverse order of their construction. + template + Factory::~Factory() { + for (auto s = this->store; s != nullptr; s = Arena::previous(s)) { + T* last = Arena::last_object(s); + for (--last; last >= Arena::first_object(s); --last) + last->~T(); + } + } + } +} + +#endif // OPENAXIOM_STORAGE_included + diff --git a/src/include/open-axiom/string-pool b/src/include/open-axiom/string-pool new file mode 100644 index 00000000..1f746e6d --- /dev/null +++ b/src/include/open-axiom/string-pool @@ -0,0 +1,85 @@ +// Copyright (C) 2010-2015, Gabriel Dos Reis. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of The Numerical Algorithms Group Ltd. nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_STRING_POOL_INCLUDED +#define OPENAXIOM_STRING_POOL_INCLUDED + +#include + +// --% Author: Gabriel Dos Reis. +// --% Description: +// --% Basic persistent string facility. +// --% A stringpool for allocating long-living string objects. + +namespace OpenAxiom { + struct StringPool; + + // ---------------- + // -- StringItem -- + // ---------------- + // String data allocated from a stringpool. + struct StringItem { + const Byte* begin() const { return text; } + const Byte* end() const { return text + length; } + size_t size() const { return length; } + bool equal(const Byte*, size_t) const; + protected: + const Byte* text; // pointer to the byte sequence + size_t length; // number of bytes in this string + friend StringPool; + StringItem() : text(), length() { } + }; + + // ---------------- + // -- StringPool -- + // ---------------- + // A string-pool object is a repository of long-living string objects. + // It contains no duplicates, therefore allows fast equality + // comparison of string objects. + struct StringPool : private BasicHashTable { + using BasicHashTable::EntryType; + + StringPool(); + // Intern a NUL-terminated sequence of characters. + EntryType* intern(const char*); + + // Intern a sequence of characters given by its start and length. + EntryType* intern(const Byte*, size_t); + private: + Memory::Arena strings; // character blub + // Allocate a string from the internal arena. + const Byte* make_copy(const Byte*, size_t); + }; + + typedef const StringPool::EntryType* InternedString; +} + +#endif // OPENAXIOM_STRING_POOL_INCLUDED diff --git a/src/include/open-axiom/structure b/src/include/open-axiom/structure new file mode 100644 index 00000000..33c084f2 --- /dev/null +++ b/src/include/open-axiom/structure @@ -0,0 +1,75 @@ +// Copyright (C) 2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom, nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_STRUCTURE_included +#define OPENAXIOM_STRUCTURE_included + +namespace OpenAxiom { + // -- helper classes for structural abstractions -- + namespace structure { + // unary structures + template + struct unary { + explicit constexpr unary(const T& t) : arg(t) { }; + constexpr const T& operand() const { return arg; } + private: + const T arg; + }; + + // binary structures + template + struct binary { + constexpr binary(const T& t, const U& u) : arg0(t), arg1(u) { }; + constexpr const T& first() const { return arg0; } + constexpr const U& second() const { return arg1; } + private: + const T arg0; + const U arg1; + }; + + // ternary structures + template + struct ternary { + constexpr ternary(const T& t, const U& u, const V& v) + : arg0(t), arg1(u), arg2(v) { } + constexpr const T& first() const { return arg0; } + constexpr const U& second() const { return arg1; } + constexpr const V& third() const { return arg2; } + private: + const T arg0; + const U arg1; + const V arg2; + }; + } +} + +#endif // OPENAXIOM_STRUCTURE_included diff --git a/src/include/open-axiom/token b/src/include/open-axiom/token new file mode 100644 index 00000000..b57b69d6 --- /dev/null +++ b/src/include/open-axiom/token @@ -0,0 +1,670 @@ +// Copyright (C) 2013-2014, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_TOKEN_included +#define OPENAXIOM_TOKEN_included + +#include +#include +#include +#include +#include + +namespace OpenAxiom { + // Categorization of Boot and Spad tokens. + enum class TokenCategory : uint8_t { + Unclassified, // token of unknown class + Whitespace, // sequence of white-space characters + Comment, // a description of an ignorable comment + Punctuator, // a punctuator character + Operator, // an operator both symbolic and alphabetic + Integer, // an integer literal + FloatingPoint, // a floating-point literal + String, // a string literal + Keyword, // a reserved word both symbolic and alphabetic + Identifier, // an identifier + Formatting, // a layout formatting token + Junk, // invalid/malformed token + EOS // end-of-token-stream indicator + }; + + std::ostream& operator<<(std::ostream&, TokenCategory); + + // The abstract value associated with a token. + enum class TokenValue : uint8_t { +#undef OPENAXIOM_DEFINE_TOKEN +#define OPENAXIOM_DEFINE_TOKEN(T, ...) T, +#include +#undef OPENAXIOM_DEFINE_TOKEN + Artificial, // Tokens after this are artificial + Indent, // new line indentation, greater than previous + Unindent, // new line indentation, less than previous + Justify, // align indentation with preceding line. + + EndOfStream // end of token stream + }; + + std::ostream& operator<<(std::ostream&, TokenValue); + + // Datatypes for locating lines and columns. + using LineNumber = std::size_t; + using ColumnIndex = std::size_t; + + struct Locus { + LineNumber line; + ColumnIndex column; + }; + + std::ostream& operator<<(std::ostream&, const Locus&); + + // Program text region + struct Region { + Locus start; + Locus end; + }; + + // Given a symbolic or alphabetic token, retrieve its category + // and associated abstract value. + struct TokenClassification { + TokenCategory category; + TokenValue value; + + explicit operator bool() const { + return category != TokenCategory::Unclassified; + } + }; + + TokenClassification classify(const std::string&); + + // Token data structure: a region of text with a classification. + struct Token : TokenClassification, Region { + using Location = Locus; + }; + + // Cursor into a fragment. + struct FragmentCursor { + std::size_t line; // index of a line in a fragment + std::size_t column; // column number at line. + + inline FragmentCursor& operator++() { + ++column; + return *this; + } + + inline FragmentCursor operator++(int) { + auto tmp = *this; + ++*this; + return tmp; + } + + inline FragmentCursor& operator--() { + --column; + return *this; + } + + inline FragmentCursor operator--(int) { + auto tmp = *this; + --*this; + return tmp; + } + }; + + // -- Exception types + struct EndOfStringUnseen { + LineNumber line; + ColumnIndex column; + }; + + struct MissingExponent { + LineNumber line; + ColumnIndex column; + }; + + // Object of this datatype decompose a program fragment into a + // token stream. The tokens are of type indicated by Tok. + template + struct Tokenizer { + Tokenizer(Frag& f) + : frag(f), + pos{ 0, frag.front().indent } + { + indents.push(pos.column); + } + + bool eos() const { + return pos.line >= frag.size() + or (pos.line + 1 == frag.size() and pos.column >= frag.back().size()); + } + + Tok get(Language = Language::Spad); + private: + Frag& frag; + FragmentCursor pos; + std::stack indents; + + std::size_t line_length() const { return frag(pos).size(); } + LineNumber next_line_number() const { + return pos.line + 1 < frag.size() + ? frag[pos.line + 1].number + : frag.back().number + 1; + } + ColumnIndex next_indentation() const { + return pos.line + 1 < frag.size() ? frag[pos.line + 1].indent : 0; + } + + LineNumber line_number() const { + return pos.line < frag.size() + ? frag(pos).number + : frag.back().number + 1; + } + + ColumnIndex column_number() const { + return pos.line < frag.size() ? pos.column : 0; + } + + using Locus = typename Tok::Location; + Locus current_locus() { + return { line_number(), column_number() }; + } + }; + + bool separator_or_punctuator(uint8_t); + + template + inline void comment_token(T& t, TokenValue v) { + t.category = TokenCategory::Comment; + t.value = v; + } + + template + inline void operator_token(T& t, TokenValue v) { + t.category = TokenCategory::Operator; + t.value = v; + } + + template + inline void punctuator_token(T& t, TokenValue v) { + t.category = TokenCategory::Punctuator; + t.value = v; + } + + template + static void junk(L& line, ColumnIndex& idx, T& t) { + while (idx < line.size() and not separator_or_punctuator(line[idx])) + ++idx; + t.category = TokenCategory::Junk; + } + + template + inline void + skip_whitespace(L& line, ColumnIndex& idx) { + while (idx < line.size() and isspace(line[idx])) + ++idx; + } + + template + void string_literal(Frag& frag, FragmentCursor& pos, Tok& t) { + bool done = false; + bool escape = false; + while (frag.covering(pos) && not done) { + switch (frag(pos)[pos.column++]) { + case '"': done = !escape; + // fallthrough + default: escape = false; break; + case '_': + if (pos.column == frag(pos).size() + and pos.line < frag.size() - 1) { + ++pos.line; + pos.column = 0; + } + else + escape = !escape; + break; + } + } + if (not done) + throw EndOfStringUnseen{ frag(pos).number, pos.column }; + t.category = TokenCategory::String; + } + + template + void skip_to_end_of_integer(L& line, ColumnIndex& idx) { + while (idx < line.size() and isdigit(line[idx])) + ++idx; + } + + template + void integer(L& line, ColumnIndex& idx, T& t) { + skip_to_end_of_integer(line, idx); + t.category = TokenCategory::Integer; + } + + template + T& number(L& line, ColumnIndex& idx, T& t) { + integer(line, idx, t); + if (idx >= line.size() or line[idx] != '.') + return t; + if (++idx >= line.size() or not isdigit(line[idx])) { + --idx; + return t; + } + + t.category = TokenCategory::FloatingPoint; + skip_to_end_of_integer(line, idx); + if (idx >= line.size() or (line[idx] != 'e' and line[idx] != 'E')) + return t; + if (++idx < line.size() and (line[idx] == '+' or line[idx] == '-')) + ++idx; + if (idx >= line.size() or not isdigit(line[idx])) + throw MissingExponent{ line.number, idx }; + skip_to_end_of_integer(line, idx); + return t; + } + + inline bool + identifier_head(uint8_t c) { + return isalpha(c) or c == '%' or c == '_'; + } + + inline bool + identifier_part(uint8_t c) { + return identifier_head(c) or isdigit(c); + } + + inline bool + identifier_suffix(uint8_t c) { + return c == '!' or c == '?'; + } + + inline bool internal_prefix(uint8_t c) { + return c == '%' or c == '$'; + } + + template + inline void + skip_prefix(L& line, ColumnIndex& idx, uint8_t c) { + while (idx < line.size() and line[idx] == c) + ++idx; + } + + template + T& identifier(L& line, ColumnIndex& idx, T& t, Language dialect) { + t.category = TokenCategory::Identifier; + + ColumnIndex start = --idx; // idx was ahead by 1. + if (dialect == Language::Boot and internal_prefix(line[idx])) + skip_prefix(line, idx, line[idx]); + bool saw_escape = false; + while (idx < line.size()) { + if (not identifier_part(line[idx]) and line[idx - 1] != '_') + break; + else if (line[idx] == '_') + saw_escape = true; + ++idx; + } + while (idx < line.size() and identifier_suffix(line[idx])) + ++idx; + + if (saw_escape) + t.category = TokenCategory::Identifier; + else if (auto info = classify(line.sub_string(start, idx))) { + t.category = info.category; + t.value = info.value; + } + return t; + } + + template + static void + left_paren_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + punctuator_token(t, TokenValue::OpenParen); + if (frag.covering(pos) and frag[pos] == '|') { + ++pos; + t.value = TokenValue::OpenMetaParen; + } + } + + template + static void + left_brace_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + punctuator_token(t, TokenValue::OpenBrace); + if (frag.covering(pos) and frag[pos] == '|') { + ++pos; + t.value = TokenValue::OpenMetaBrace; + } + } + + template + static void + left_bracket_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + punctuator_token(t, TokenValue::OpenBracket); + if (frag.covering(pos) and frag[pos] == '|') { + ++pos; + t.value = TokenValue::OpenMetaBracket; + } + } + + template + static void + colon_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + operator_token(t, TokenValue::Colon); + if (frag.covering(pos)) + switch (frag[pos]) { + case ':': t.value = TokenValue::ColonColon; ++pos; break; + case '=': t.value = TokenValue::ColonEq; ++pos; break; + case '-': t.value = TokenValue::ColonDash; ++pos; break; + default: break; + } + } + + template + static void + star_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + operator_token(t, TokenValue::Star); + if (frag.covering(pos) and frag[pos] == '*') { + t.value = TokenValue::StarStar; + ++pos; + } + } + + template + static void + slash_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + operator_token(t, TokenValue::Slash); + if (frag.covering(pos)) + switch (frag[pos]) { + case '/': t.value = TokenValue::SlashSlash; ++pos; break; + case '\\': t.value = TokenValue::SlashBackslash; ++pos; break; + default: break; + } + } + + template + static void + backslash_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + operator_token(t, TokenValue::Backslash); + if (frag.covering(pos)) + switch (frag[pos]) { + case '\\': t.value = TokenValue::BackslashBackslash; ++pos; break; + case '/': t.value = TokenValue::BackslashSlash; ++pos; break; + default: break; + } + } + + template + static void + less_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + operator_token(t, TokenValue::Less); + if (frag.covering(pos)) + switch (frag[pos]) { + case '-': t.value = TokenValue::LeftArrow; ++pos; break; + case '<': t.value = TokenValue::OpenChevron; ++pos; break; + case '=': + t.value = TokenValue::LessEq; + if (frag.covering(++pos) and frag[pos] == '>') { + t.value = TokenValue::Equiv; + ++pos; + } + break; + default: break; + } + } + + template + static void + equal_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + operator_token(t, TokenValue::Eq); + if (frag.covering(pos)) + switch (frag[pos]) { + case '>': t.value = TokenValue::Implies; ++pos; break; + case '=': + t.value = TokenValue::EqEq; + if (frag.covering(++pos) and frag[pos] == '>') { + t.value = TokenValue::FatArrow; + ++pos; + } + break; + default: break; + } + } + + template + static void + tilde_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + operator_token(t, TokenValue::Tilde); + if (frag.covering(pos) and frag[pos] == '=') { + t.value = TokenValue::TildeEq; + ++pos; + } + } + + template + static void + greater_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + operator_token(t, TokenValue::Greater); + if (frag.covering(pos)) + switch (frag[pos]) { + case '=': t.value = TokenValue::GreaterEq; ++pos; break; + case '>': t.value = TokenValue::CloseChevron; ++pos; break; + } + } + + template + static void + bar_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + punctuator_token(t, TokenValue::Bar); + if (frag.covering(pos)) + switch (frag[pos]) { + case ']': t.value = TokenValue::CloseMetaBracket; ++pos; break; + case '}': t.value = TokenValue::CloseMetaBrace; ++pos; break; + case ')': t.value = TokenValue::CloseMetaParen; ++pos; break; + default: break; + } + } + + template + static void + minus_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + operator_token(t, TokenValue::Minus); + if (frag.covering(pos)) + switch (frag[pos]) { + case '>': t.value = TokenValue::RightArrow; ++pos; break; + case '-': + comment_token(t, TokenValue::Wisecrack); + pos.column = frag(pos).size(); + break; + } + } + + + template + static void + plus_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + operator_token(t, TokenValue::Plus); + if (frag.covering(pos)) + switch (frag[pos]) { + case '+': + comment_token(t, TokenValue::Commentary); + pos.column = frag(pos).size(); + break; + case '-': + if (pos.column + 1 < frag(pos).size() + and frag(pos)[pos.column + 1] == '>') { + t.value = TokenValue::MapsTo; + pos.column += 2; + } + break; + default: break; + } + } + + template + static void + dot_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { + operator_token(t, TokenValue::Dot); + if (frag.covering(pos) and frag[pos] == '.') { + t.value = TokenValue::DotDot; + ++pos; + } + } + + template + static void + dollar_et_al(Frag& frag, FragmentCursor& pos, Tok& t, Language dialect) { + if (dialect != Language::Boot or not frag.covering(pos) + or separator_or_punctuator(frag[pos])) + operator_token(t, TokenValue::Dollar); + else + identifier(frag(pos), pos.column, t, dialect); + } + + template + static void + sharp_et_al(Frag& frag, FragmentCursor& pos, Tok& t, Language dialect) { + if (dialect != Language::Lisp) + operator_token(t, TokenValue::Sharp); + else if (frag.covering(pos)) + switch (frag[pos++]) { + case '(': punctuator_token(t, TokenValue::SharpLeftParen); break; + case '\'': operator_token(t, TokenValue::SharpApostrophe); break; + case ':': operator_token(t, TokenValue::SharpColon); break; + case '+': punctuator_token(t, TokenValue::SharpPlus); break; + case '-': punctuator_token(t, TokenValue::SharpMinus); break; + case '.': operator_token(t, TokenValue::SharpDot); break; + default: --pos; break; + } + } + + + template + Tok Tokenizer::get(Language dialect) { + Tok t { }; + t.start = current_locus(); + + if (eos()) { + t.category = TokenCategory::EOS; + t.end = current_locus(); + return t; + } + else if (isspace(frag[pos])) { + skip_whitespace(frag(pos), pos.column); + t.category = TokenCategory::Whitespace; + t.end = current_locus(); + return t; + } + else if (pos.column == line_length() - 1 and frag(pos).back() == '_') { + ++pos.line; + pos.column = frag(pos).indent; + } + else if (pos.column == line_length()) { + auto indent = indents.top(); + auto next_indent = next_indentation(); + t.start = t.end = { next_line_number(), next_indent }; + if (indent < next_indent) { + indents.push(next_indent); + ++pos.line; + pos.column = next_indent; + t.category = TokenCategory::Formatting; + t.value = TokenValue::Indent; + } + else if (indent > next_indent) { + indents.pop(); + t.category = TokenCategory::Formatting; + t.value = TokenValue::Unindent; + } + else { + ++pos.line; + pos.column = next_indent; + t.category = TokenCategory::Formatting; + t.value = TokenValue::Justify; + } + return t; + } + + switch (auto c = frag.advance(pos)) { + case '#': sharp_et_al(frag, pos, t, dialect); break; + case '@': operator_token(t, TokenValue::At); break; + case '^': operator_token(t, TokenValue::Caret); break; + case '&': punctuator_token(t, TokenValue::Ampersand); break; + case '!': punctuator_token(t, TokenValue::Exclamation); break; + case '\'': punctuator_token(t, TokenValue::Apostrophe); break; + case ',': punctuator_token(t, TokenValue::Comma); break; + case ';': punctuator_token(t, TokenValue::Semicolon); break; + case '`': punctuator_token(t, TokenValue::Backquote); break; + case '(': left_paren_et_al(frag, pos, t); break; + case ')': punctuator_token(t, TokenValue::CloseParen); break; + case '{': left_brace_et_al(frag, pos, t); break; + case '}': punctuator_token(t, TokenValue::CloseBrace); break; + case '[': left_bracket_et_al(frag, pos, t); break; + case ']': punctuator_token(t, TokenValue::CloseBracket); break; + case ':': colon_et_al(frag, pos, t); break; + case '*': star_et_al(frag, pos, t); break; + case '/': slash_et_al(frag, pos, t); break; + case '\\': backslash_et_al(frag, pos, t); break; + case '<': less_et_al(frag, pos, t); break; + case '=': equal_et_al(frag, pos, t); break; + case '~': tilde_et_al(frag, pos, t); break; + case '>': greater_et_al(frag, pos, t); break; + case '|': bar_et_al(frag, pos, t); break; + case '-': minus_et_al(frag, pos, t); break; + case '+': plus_et_al(frag, pos, t); break; + case '.': dot_et_al(frag, pos, t); break; + case '"': string_literal(frag, pos, t); break; + case '$': dollar_et_al(frag, pos, t, dialect); break; + + default: + if (isdigit(c)) + number(frag(pos), pos.column, t); + else if (identifier_head(c)) + identifier(frag(pos), pos.column, t, dialect); + else + junk(frag(pos), pos.column, t); + break; + } + + t.end = { frag(pos).number, pos.column }; + return t; + } + + // -- Token streams. + template + struct TokenStream : std::vector { + template + explicit TokenStream(Frag& f, Language dialect = Language::Spad) { + Tokenizer lex { f }; + while (auto t = lex.get(dialect)) + this->push_back(t); + } + }; +} + +#endif // OPENAXIOM_TOKEN_included diff --git a/src/include/open-axiom/token-value b/src/include/open-axiom/token-value new file mode 100644 index 00000000..9a949b86 --- /dev/null +++ b/src/include/open-axiom/token-value @@ -0,0 +1,145 @@ +// Copyright (C) 2014, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +OPENAXIOM_DEFINE_TOKEN(Unknown, "", Unclassified, Language::All) +OPENAXIOM_DEFINE_TOKEN(Apostrophe, "'", Punctuator, Language::All) +OPENAXIOM_DEFINE_TOKEN(Backquote, "`", Punctuator, Language::All) +OPENAXIOM_DEFINE_TOKEN(Bar, "|", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Dot, ".", Punctuator, Language::All) +OPENAXIOM_DEFINE_TOKEN(DotDot, "..", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Colon, ":", Punctuator, Language::All) +OPENAXIOM_DEFINE_TOKEN(ColonColon, "::", Operator, Language::All) +OPENAXIOM_DEFINE_TOKEN(ColonDash, ":-", Operator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(ColonEq, ":=", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(At, "@", Operator, Language::All) +OPENAXIOM_DEFINE_TOKEN(Exclamation, "!", Punctuator, Language::Boot) +OPENAXIOM_DEFINE_TOKEN(Comma, ",", Punctuator, Language::All) +OPENAXIOM_DEFINE_TOKEN(CommaAt, ",@", Operator, Language::Lisp) +OPENAXIOM_DEFINE_TOKEN(Semicolon, ";", Punctuator, Language::All) +OPENAXIOM_DEFINE_TOKEN(Star, "*", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(StarStar, "**", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Plus, "+", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Minus, "-", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Slash, "/", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(SlashSlash, "//", Operator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(SlashBackslash, "/\\", Operator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(Backslash, "\\", Operator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(BackslashSlash, "\\/", Operator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(BackslashBackslash, "\\\\", Operator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(Less, "<", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(LessEq, "<=", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Greater, ">", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(GreaterEq, ">=", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Eq, "=", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(EqEq, "==", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Tilde, "~", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(TildeEq, "~=", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Caret, "^", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Sharp, "#", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(SharpLeftParen, "#(", Punctuator, Language::Lisp) +OPENAXIOM_DEFINE_TOKEN(SharpApostrophe, "#'", Operator, Language::Lisp) +OPENAXIOM_DEFINE_TOKEN(SharpColon, "#:", Operator, Language::Lisp) +OPENAXIOM_DEFINE_TOKEN(SharpPlus, "#+", Punctuator, Language::Lisp) +OPENAXIOM_DEFINE_TOKEN(SharpMinus, "#-", Punctuator, Language::Lisp) +OPENAXIOM_DEFINE_TOKEN(SharpDot, "#.", Operator, Language::Lisp) +OPENAXIOM_DEFINE_TOKEN(Dollar, "$", Operator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(Ampersand, "&", Operator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(RightArrow, "->", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(LeftArrow, "<-", Operator, Language::Boot) +OPENAXIOM_DEFINE_TOKEN(Implies, "=>", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Equiv, "<=>", Keyword, Language::Boot) +OPENAXIOM_DEFINE_TOKEN(MapsTo, "+->", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(FatArrow, "==>", Keyword, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(OpenParen, "(", Punctuator, Language::All) +OPENAXIOM_DEFINE_TOKEN(CloseParen, ")", Punctuator, Language::All) +OPENAXIOM_DEFINE_TOKEN(OpenMetaParen, "(|", Punctuator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(CloseMetaParen, "|)", Punctuator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(OpenBracket, "[", Punctuator, Language::All) +OPENAXIOM_DEFINE_TOKEN(CloseBracket, "]", Punctuator, Language::All) +OPENAXIOM_DEFINE_TOKEN(OpenMetaBracket, "[|", Punctuator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(CloseMetaBracket, "|]", Punctuator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(OpenBrace, "{", Punctuator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(CloseBrace, "}", Punctuator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(OpenMetaBrace, "{|", Punctuator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(CloseMetaBrace, "|}", Punctuator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(OpenChevron, "<<", Operator, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(CloseChevron, ">>", Operator, Language::Spad) + +OPENAXIOM_DEFINE_TOKEN(Wisecrack, "--", Comment, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Commentary, "++", Comment, Language::BootSpad) + +OPENAXIOM_DEFINE_TOKEN(Add, "add", Keyword, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(And, "and", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Assume, "assume", Keyword, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(Break, "break", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(By, "by", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Case, "case", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Catch, "catch", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Cross, "cross", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Do, "do", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Else, "else", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Exists, "exists", Keyword, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(Finally, "finally", Keyword, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(For, "for", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Forall, "forall", Keyword, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(From, "from", Keyword, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(Function, "function", Keyword, Language::Boot) +OPENAXIOM_DEFINE_TOKEN(Has, "has", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(If, "if", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Import, "import", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(In, "in", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Inline, "inline", Keyword, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(Is, "is", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Isnt, "isnt", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Iterate, "iterate", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Leave, "leave", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Macro, "macro", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Mod, "mod", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Namespace, "namespace", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Of, "of", Keyword, Language::Boot) +OPENAXIOM_DEFINE_TOKEN(Or, "or", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Pretend, "pretend", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Quo, "quo", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Rem, "rem", Operator, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Repeat, "repeat", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Return, "return", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Rule, "rule", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Structure, "structure", Keyword, Language::Boot) +OPENAXIOM_DEFINE_TOKEN(Then, "then", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(Throw, "throw", Keyword, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(Try, "try", Keyword, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(Until, "until", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(With, "with", Keyword, Language::Spad) +OPENAXIOM_DEFINE_TOKEN(Where, "where", Keyword, Language::BootSpad) +OPENAXIOM_DEFINE_TOKEN(While, "while", Keyword, Language::BootSpad) diff --git a/src/include/open-axiom/vm b/src/include/open-axiom/vm new file mode 100644 index 00000000..3bb62250 --- /dev/null +++ b/src/include/open-axiom/vm @@ -0,0 +1,606 @@ +// Copyright (C) 2011-2014, Gabriel Dos Reis. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// --% Author: Gabriel Dos Reis +// --% Description: +// --% Interface and implementation of basic services of the +// --% OpenAxiom Virtual Machine. + +#ifndef OPENAXIOM_VM_included +#define OPENAXIOM_VM_included + +#include +#include +#include +#include +#include +#include +#include + +#define internal_type struct alignas(16) +#define internal_data alignas(16) + +namespace OpenAxiom { + namespace VM { + // --% + // --% Value representation + // --% + // A far reaching design decision is that of providing a uniform + // representation for values. That is all values, irrespective + // of type have fit in a fixed format, i.e. a scalar register. + // This means that values that are more complicated than a scalar, + // i.e. the vast majority and most interesting values, have to + // be stored in allocated objects and addresses of their container + // objects used in place of the actual values. This is folklore + // in the communities of garbage collected languages. + // + // An unfortunate but widely held belief is that AXIOM-based + // systems (and computer algebra systems in general) are + // Lisp-based systems. Nothing could be further from the truth + // for OpenAxiom. The type system is believed to support + // erasure semantics, at least for values. + // + // However the current implementation, being Lisp-based, + // unwittingly makes use of some Lisp features that are not + // strictly necessary. It would take a certain amount of effort + // to get rid of them. Consequently, we must cope -- at least + // for now -- with the notion of uniform value representation and + // use runtime predicates to descriminate between values. + // On the other hand, we do not want to carry an unduly expensive + // abstraction penalty for perfectly well behaved and well + // disciplined programs. So, here are a few constraints: + // 1. Small integers should represent themselves -- not allocated. + // Furthermore, the maximum range should be sought where possible. + // 2. Since we have to deal with characters, they should be + // directly represented -- not allocated. + // 3. List values and list manipulation should be efficient. + // Ideally, a pair should occupy no more than what it + // takes to store two values in a type-erasure semantics. + // 4. Idealy, pointers to foreign objects (at least) should be + // left unmolested. + // 5. Ideally, we want efficient access to string literals + // + // * Assumptions: + // (a) the host machine has sizeof(Value) quo 4 = 0. + // (b) allocated objects can be aligned on sizeof(Value) boundary. + // (c) the host machine has 2's complement arithmetic. + // + // If: + // -- we use a dedicated allocation pool for cons cells + // -- we allocate the first cell in each cons-storage arena + // on a 8-byte boundary + // -- we use exactly 2 * sizeof(Value) to store a cons cell + // therefore realizing constraint (3) + // then: + // every pointer to a cons cell will have its last 3 bits cleared. + // + // Therefore, we can use the last 3 bits to tag a cons value, instead + // of storing the tag inside the cons cell. We can't leave those + // bits cleared for we would not be able to easily and cheaply + // distinguish a pointer to a cons cell from a pointer to other + // objects, in particular foreign objects. + // + // To meet constraint (1), we must logically use at least one bit + // to distinguish a small integer from a pointer to a cons cell. + // The good news is that we need no more than that if pointers + // to foreign pointers do not have the last bit set. Which is + // the case with assumption (a). Furthermore, if we align all + // other internal data on 16 byte boundary, then we have 4 spare bits + // for use to categorize values. + // Therefore we arrive at the first design: + // I. the value representation of a small integer always has the + // the least significant bit set. All other bits are + // significant. In other words, the last four bits of a small + // integer are 0bxxx1 + // + // As a consequence, the last bit of all other values must be cleared. + // + // Next, + // II. All foreign pointers that are aligned on 8-boundary are + // directly represented. Any foreign pointer not meeting + // this condition is stored in an internal object. As a + // consequence, the last four bits of all foreign addresses + // directly represented follow the pattern 0bx000. + // + // III. Cons cells are represented by their addresses with the + // last 4 bits matching the pattern 0bx010. + // + // IV. All internal objects are allocated on 16-byte boundary. + // Their last 4 bits are set to the pattern 0b0110. + // + // V. String literals are represented by their addressed with + // the last four bits following the pattern 0bx100.. + // + // Finally: + // IV. The representation of a character shall have the last four + // bits set to 0b1110. + // + // Note: These choices do not fully satisfy constraint 4. This is + // because we restrict foreign pointers to address aligned + // to 8-byte boundaries. A modest constraint. + // + // Special Constants: + // NIL 0x00 + // T 0x10 + + + // ----------- + // -- Value -- + // ----------- + // All VM values fit in a universal value datatype. + using ValueBits = uintptr_t; + using ValueMask = ValueBits; + enum class Value : ValueBits { + nil = 0x00, // distinguished NIL value + t = 0x10, // distinguished T value + }; + + // -- Testing for nil value. + constexpr Value null(Value v) { + return v == Value::nil ? Value::t : Value::nil; + } + + // -- Convert VM Boolean value to C++ view + constexpr bool to_bool(Value v) { return v != Value::nil; } + + // -- Convert a C++ Boolean value to VM view. + constexpr Value to_value(bool b) { + return b ? Value::t : Value::nil; + } + + // -- Identity equality. + constexpr Value eq(Value x, Value y) { return to_value(x == y); } + + template + struct ValueTrait { + }; + + // Return the tag of an abstract value, when viewed as a potential + // T-value. + template + constexpr ValueBits tag(Value v) { + return ValueBits(v) & ValueTrait::tag_mask; + } + + // Return true if the abstract value is, in fact, a T-value. + template + constexpr bool is(Value v) { + return tag(v) == ValueTrait::tag; + } + + // Return the pristine bits of an abstract value without its tag. + template + constexpr ValueBits native(Value v) { + return ValueBits(v) & ~ValueTrait::tag_mask; + } + + // -- Arity: number of arguments or forms taken by a function + // or a special operator. + enum class Arity : intptr_t { + variable = -1, // Any number of arguments. + zero = 0, // Exactly no argument. + one = 1, // Exactly one argument. + two = 2, // Exactly two arguments. + three = 3, // Exactly three arguments. + }; + + // ------------- + // -- Dynamic -- + // ------------- + // Any internal value is of a class derived from this. + internal_type Dynamic { + struct Visitor; + virtual ~Dynamic(); + virtual void accept(Visitor&) const = 0; + }; + + // Provide an S-view of a T-typed expression, assuming the type T + // derives from S. + template + inline const S& as(const T& t) { return t; } + + template<> + struct ValueTrait { + enum Tag : ValueBits { tag = 0x6 }; + enum Mask : ValueBits { tag_mask = 0xF }; + }; + + inline Dynamic* to_dynamic(Value v) { + return reinterpret_cast(native(v)); + } + + inline Dynamic* to_dynamic_if_can(Value v) { + return is(v) ? to_dynamic(v) : nullptr; + } + + template + using IfDynamic = typename + std::enable_if::value, Value>::type; + + template + inline IfDynamic to_value(const T* o) { + return Value(ValueBits(o) | ValueTrait::tag); + } + + // -- Callable -- + struct Callable : Dynamic { + }; + + // ------------- + // -- Fixnum --- + // ------------- + // VM integers are divided into classes: small numbers, + // and large numbers. A small number fits entirely in a register. + // A large number is allocated and represented by its address. + using FixnumBits = intptr_t; + enum class Fixnum : FixnumBits { + minimum = FixnumBits(~(~ValueBits() >> 2)), + zero = FixnumBits(0), + one = FixnumBits(1), + maximum = FixnumBits(~ValueBits() >> 2), + }; + + template<> + struct ValueTrait { + enum Tag : ValueBits { tag = 0x1 }; + enum Mask : ValueBits { tag_mask = 0x1 }; + }; + + constexpr Fixnum to_fixnum(Value v) { + return Fixnum(FixnumBits(v) >> 1); + } + + constexpr Value from_fixnum(Fixnum i) { + return Value((ValueBits(i) << 1 ) | ValueTrait::tag); + } + + // ------------ + // -- String -- + // ------------ + using String = InternedString; + + template<> + struct ValueTrait { + enum Tag : ValueBits { tag = 0x4 }; + enum Mask : ValueBits { tag_mask = 0x7 }; + }; + + inline InternedString to_string(Value v) { + return reinterpret_cast(native(v)); + } + + inline Value from_string(InternedString s) { + return Value(ValueBits(s) | ValueTrait::tag); + } + + inline InternedString to_string_if_can(Value v) { + return is(v) ? to_string(v) : nullptr; + } + + // ------------- + // -- Pointer -- + // ------------- + // Allocated objects are represented by their addresses. + using Memory::Pointer; + + template<> + struct ValueTrait { + enum Tag : ValueBits { tag = 0x0 }; + enum Mask : ValueBits { tag_mask = 0x7 }; + }; + + inline Pointer to_pointer(Value v) { + return Pointer(ValueBits(v)); + } + + inline Value from_pointer(Pointer p) { + return Value(ValueBits(p) | ValueTrait::tag); + } + + // ---------- + // -- Pair -- + // ---------- + struct alignas(8) ConsCell { + Value head; + Value tail; + }; + + using Pair = ConsCell*; + + template<> + struct ValueTrait { + enum Tag : ValueBits { tag = 0x2 }; + enum Mask : ValueBits { tag_mask = 0x7 }; + }; + + inline Pair to_pair(Value v) { + return reinterpret_cast(native(v)); + } + + inline Value from_pair(Pair p) { + return Value(ValueBits(p) | ValueTrait::tag); + } + + // Return true if argument designates a pair. + constexpr Value consp(Value v) { + return to_value(v != Value::nil and v != Value::t and is(v)); + } + + inline Value atom(Value v) { + return null(consp(v)); + } + + // If `v' designates a pair, return a pointer to its + // concrete representation. + inline Pair to_pair_if_can(Value v) { + return consp(v) == Value::t ? to_pair(v) : nullptr; + } + + Fixnum count_nodes(Pair); + inline Fixnum count_nodes(Value v) { + if (auto p = to_pair_if_can(v)) + return count_nodes(p); + return Fixnum::zero; + } + + // --------------- + // -- Character -- + // --------------- + // This datatype is prepared for Uncode characters even if + // we do not handle UCN characters at the moment. + enum class Character : ValueBits { }; + + template<> + struct ValueTrait { + enum Tag : ValueBits { tag = 0xE }; + enum Mask : ValueBits { tag_mask = 0xF }; + }; + + constexpr Character to_character(Value v) { + return Character(ValueBits(v) >> 4); + } + + constexpr Value from_character(Character c) { + return Value((ValueBits(c) << 4) | ValueTrait::tag); + } + + // -- Object -- + // An object is a typed value. + struct Type; + struct Object { + Value value; + const Type* type; + }; + + struct Package; + + enum class SymbolAttribute : ValueBits { + None = 0x0, // No particular attribute. + Constant = 0x1, // Symbol defined constant. + Special = 0x2, // Symbol declared special. + Keyword = 0x4, // A keyword symbol. + SpecialConstant = Constant | Special, + }; + + constexpr SymbolAttribute + operator&(SymbolAttribute x, SymbolAttribute y) { + return SymbolAttribute(ValueBits(x) & ValueBits(y)); + } + + // ------------ + // -- Symbol -- + // ------------ + struct Symbol : Dynamic { + const InternedString name; + Value value; + const Callable* function; + Pair properties; + Package* package; + SymbolAttribute attributes; + explicit Symbol(InternedString); + void accept(Visitor&) const override; + bool has(SymbolAttribute x) const { return (attributes & x) == x; } + }; + + inline Symbol* to_symbol_if_can(Value v) { + return dynamic_cast(to_dynamic_if_can(v)); + } + + inline bool is_symbol(Value v) { + return to_symbol_if_can(v) != nullptr; + } + + // -- Test if a value is a symbol. + inline Value symbolp(Value v) { + return to_value(v == Value::nil or v == Value::t or is_symbol(v)); + } + + // -- Test if a value is a keyword symbol. + inline Value keywordp(Value v) { + if (auto sym = to_symbol_if_can(v)) + return to_value(sym->has(SymbolAttribute::Keyword)); + return Value::nil; + } + + struct CmpByName { + template + bool operator()(const T& x, const T& y) const { + return std::less()(x.name, y.name); + } + }; + + template + inline const T* setf_symbol_function(Symbol* sym, const T* fun) { + sym->function = fun; + return fun; + } + + // -- Argument binding as value. + // Binding a parameter to a value in a call. + struct Binding : Dynamic { + Symbol* symbol; + Value value; + void accept(Visitor&) const override; + }; + + // -- Environments. + struct Environment { + struct Binding { + Symbol* symbol; + Value value; + }; + + Environment(); + ~Environment(); + + void bind(Symbol*, Value); + Binding* lookup(InternedString); + private: + std::vector lexical; + std::vector dynamic; + }; + + // ------------- + // -- Package -- + // ------------- + struct Package : Dynamic { + const InternedString name; + std::set symbols; + + explicit Package(InternedString); + void accept(Visitor&) const override; + Symbol* make_symbol(InternedString); + Symbol* find_symbol(InternedString); + }; + + // -------------- + // -- Function -- + // -------------- + struct FunctionBase : Callable { + const Symbol* name; + Value type; + FunctionBase(const Symbol* n, Value t = Value::nil) + : name(n), type(t) { } + void accept(Visitor&) const override; + }; + + // ------------------------ + // -- Builtin Operations -- + // ------------------------ + // Types for native implementation of builtin operators. + struct BasicContext; + + template + using RuntimeOperation = Value(*)(BasicContext*, Ts...); + using NullaryCode = RuntimeOperation<>; + using UnaryCode = RuntimeOperation; + using BinaryCode = RuntimeOperation; + using TernaryCode = RuntimeOperation; + + template + struct BuiltinFunction : FunctionBase { + Code code; + BuiltinFunction(const Symbol* n, Code c) + : FunctionBase(n), code(c) + { } + void accept(Visitor&) const override; + }; + + using NullaryOperator = BuiltinFunction; + using UnaryOperator = BuiltinFunction; + using BinaryOperator = BuiltinFunction; + using TernaryOperator = BuiltinFunction; + + // -- Operand stack. + struct OperandStack : private std::vector { + using super = std::vector; + using iterator = std::reverse_iterator; + using super::size; + using super::empty; + iterator begin() { return rbegin(); } + iterator end() { return rend(); } + Value top() { return back(); } + void push(Value v) { push_back(v); } + Value pop() { auto v = back(); pop_back(); return v; } + void operator-=(std::size_t i) { resize(size() - i); } + Value operator[](std::size_t i) { + return super::operator[](size() - i - 1); + } + }; + + // -- Dynamic::Visitor -- + struct Dynamic::Visitor { + virtual void visit(const Symbol&) = 0; + virtual void visit(const Binding&) = 0; + virtual void visit(const Package&) = 0; + virtual void visit(const FunctionBase&) = 0; + virtual void visit(const NullaryOperator&); + virtual void visit(const UnaryOperator&); + virtual void visit(const BinaryOperator&); + }; + + template + void BuiltinFunction::accept(Visitor& v) const { v.visit(*this); } + + // ------------------ + // -- BasicContext -- + // ------------------ + // Provides basic evaluation services. + struct BasicContext : StringPool { + BasicContext(); + ~BasicContext(); + + Package* make_package(InternedString); + Symbol* make_keyword(InternedString); + Pair make_pair(Value, Value); + const NullaryOperator* make_operator(Symbol*, NullaryCode); + const UnaryOperator* make_operator(Symbol*, UnaryCode); + const BinaryOperator* make_operator(Symbol*, BinaryCode); + const TernaryOperator* make_operator(Symbol*, TernaryCode); + + Package* keyword_package() const { return keywords; } + Package* homeless_package() const { return homeless; } + + protected: + std::set packages; + Memory::Factory conses; + Memory::Factory nullaries; + Memory::Factory unaries; + Memory::Factory binaries; + Memory::Factory ternaries; + Package* keywords; + Package* homeless; + }; + }; +} + +#endif // OPENAXIOM_VM_INCLUDED + diff --git a/src/include/sexpr.H b/src/include/sexpr.H deleted file mode 100644 index 6920e436..00000000 --- a/src/include/sexpr.H +++ /dev/null @@ -1,419 +0,0 @@ -// Copyright (C) 2010-2014, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of The Numerical Algorithms Group Ltd. nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_SEXPR_included -#define OPENAXIOM_SEXPR_included - -// --% Author: Gabriel Dos Reis. -// --% Description: -// --% A simple support for s-expressions. By design, no ambition -// --% for full-fledged Common Lisp reader capability. Rather, -// --% the aim is a simple data structure for exchanging data -// --% between several components of the OpenAxiom system. -// --% Users interested in fullblown Lisp syntax should seek -// --% to acquire Lisp systems, many of which are freely available. - -#include -#include -#include -#include - -namespace OpenAxiom { - namespace Sexpr { - // ------------ - // -- Lexeme -- - // ------------ - struct Lexeme { - enum Type { - unknown, // unidentified token - semicolon, // ";" for comment - dot, // "." - comma, // "," - open_paren, // "(" - close_paren, // ")" - apostrophe, // "'" - backquote, // "`" - backslash, // "\\" - sharp_open_paren , // "#(" - sharp_apostrophe, // "#'" - sharp_colon, // "#:" - sharp_plus, // "#+" - sharp_minus, // "#-" - sharp_dot, // "#." - comma_at, // ",@" - integer, // integer literal - character, // character literal - string, // string literal - identifier, // plain identifier - sharp_integer_equal, // anchor definition, #n= - sharp_integer_sharp // back reference, #n# - }; - - std::pair boundary; - Ordinal line; - const Byte* begin() const { return boundary.first; } - const Byte* end() const { return boundary.second; } - Ordinal size() const { return end() - begin(); } - }; - - // ------------ - // -- Syntax -- - // ------------ - // Base class of syntax object classes. - struct Syntax { - struct Visitor; // base class of syntax visitors - virtual void accept(Visitor&) const = 0; - }; - - // ---------------- - // -- AtomSyntax -- - // ---------------- - // An atom is a syntax object consisting of exatly one token. - // This should not be confused with the notion of atom - // in Lisp languages. - struct AtomSyntax : Syntax { - const Lexeme& lexeme() const { return lex; } - protected: - Lexeme lex; - explicit AtomSyntax(const Lexeme&); - }; - - // ------------------- - // -- IntegerSyntax -- - // ------------------- - // Integer literal syntax objects - struct IntegerSyntax : AtomSyntax { - explicit IntegerSyntax(const Lexeme&); - void accept(Visitor&) const; - }; - - // --------------------- - // -- CharacterSyntax -- - // --------------------- - // Character literal syntax objects. - struct CharacterSyntax : AtomSyntax { - explicit CharacterSyntax(const Lexeme&); - void accept(Visitor&) const; - }; - - // ------------------ - // -- StringSyntax -- - // ------------------ - // Striing literal syntax objjects. - struct StringSyntax : AtomSyntax { - explicit StringSyntax(const Lexeme&); - void accept(Visitor&) const; - }; - - // ------------------ - // -- SymbolSyntax -- - // ------------------ - struct SymbolSyntax : AtomSyntax { - enum Kind { - ordinary = 0x0, // an interned symbol - uninterned = 0x1, // uninterned symbol - absolute = 0x2, // case-sensitive symbol - keyword = 0x4, // a keyword symbol - }; - SymbolSyntax(const Lexeme&, Kind); - Kind kind() const { return sort; } - const Byte* begin() const { return lexeme().begin(); } - const Byte* end() const { return lexeme().end(); } - std::size_t size() const { return lexeme().size(); } - Byte operator[](std::size_t i) const { return begin()[i]; } - void accept(Visitor&) const; - private: - const Kind sort; - }; - - // --------------------- - // -- ReferenceSyntax -- - // --------------------- - // Back reference object to a syntax object. - struct ReferenceSyntax : AtomSyntax { - ReferenceSyntax(const Lexeme&, Ordinal); - size_t tag() const { return pos; } - void accept(Visitor&) const; - private: - Ordinal pos; - }; - - // ------------------ - // -- AnchorSyntax -- - // ------------------ - // Base anchor syntax object. - struct AnchorSyntax : Syntax { - AnchorSyntax(size_t, const Syntax*); - size_t ref() const { return tag; } - const Syntax* value() const { return val; } - void accept(Visitor&) const; - private: - const size_t tag; - const Syntax* const val; - }; - - // -- Abstract over common implementation of unary special operators. - template - struct unary_form : Syntax { - const Syntax* body() const { return form; } - void accept(Visitor&) const; - protected: - unary_form(const Syntax* f) : form(f) { } - private: - const Syntax* const form; - }; - - template - struct binary_form : Syntax { - const Syntax* first() const { return rep.first; } - const Syntax* second() const { return rep.second; } - void accept(Visitor&) const; - protected: - binary_form(const Syntax* f, const Syntax* s) : rep(f, s) { } - private: - std::pair rep; - }; - - // ----------------- - // -- QuoteSyntax -- - // ----------------- - // Quotation syntax object. - struct QuoteSyntax : unary_form { - explicit QuoteSyntax(const Syntax*); - }; - - // --------------------- - // -- AntiquoteSyntax -- - // --------------------- - // Quasi-quotation syntax object. - struct AntiquoteSyntax : unary_form { - explicit AntiquoteSyntax(const Syntax*); - }; - - // ------------ - // -- Expand -- - // ------------ - // Expansion request inside a quasi-quotation. - struct Expand : unary_form { - explicit Expand(const Syntax*); - }; - - // ---------- - // -- Eval -- - // ---------- - // Read-time evaluation request syntax object. - struct Eval : unary_form { - explicit Eval(const Syntax*); - }; - - // ------------ - // -- Splice -- - // ------------ - // Splice request syntax object inside a quasi-quotation. - struct Splice : unary_form { - explicit Splice(const Syntax*); - }; - - // -------------- - // -- Function -- - // -------------- - // Function literal syntax object. - struct Function : unary_form { - explicit Function(const Syntax*); - }; - - // ------------- - // -- Include -- - // ------------- - // Conditional inclusion syntax object - struct Include : binary_form { - Include(const Syntax*, const Syntax*); - }; - - // ------------- - // -- Exclude -- - // ------------- - // Conditional exclusion syntax object - struct Exclude : binary_form { - Exclude(const Syntax*, const Syntax*); - }; - - // ---------------- - // -- ListSyntax -- - // ---------------- - // List syntax objects. - struct ListSyntax : Syntax, private std::vector { - typedef std::vector base; - using base::const_iterator; - using base::begin; - using base::end; - using base::rbegin; - using base::rend; - using base::size; - using base::empty; - using base::front; - - ListSyntax(); - ListSyntax(const base&, bool); - ~ListSyntax(); - void accept(Visitor&) const; - bool dotted() const { return dot; } - private: - bool dot; - }; - - // ------------------ - // -- VectorSyntax -- - // ------------------ - // VectorSyntax syntax objects. - struct VectorSyntax : Syntax, private std::vector { - typedef std::vector base; - using base::const_iterator; - using base::begin; - using base::end; - using base::size; - using base::operator[]; - using base::empty; - - VectorSyntax(); - explicit VectorSyntax(const base&); - ~VectorSyntax(); - void accept(Visitor&) const; - }; - - // --------------------- - // -- Syntax::Visitor -- - // --------------------- - struct Syntax::Visitor { - virtual void visit(const IntegerSyntax&) = 0; - virtual void visit(const CharacterSyntax&) = 0; - virtual void visit(const StringSyntax&) = 0; - virtual void visit(const SymbolSyntax&) = 0; - virtual void visit(const ReferenceSyntax&) = 0; - virtual void visit(const AnchorSyntax&) = 0; - virtual void visit(const QuoteSyntax&) = 0; - virtual void visit(const AntiquoteSyntax&) = 0; - virtual void visit(const Expand&) = 0; - virtual void visit(const Eval&) = 0; - virtual void visit(const Splice&) = 0; - virtual void visit(const Function&) = 0; - virtual void visit(const Include&) = 0; - virtual void visit(const Exclude&) = 0; - virtual void visit(const ListSyntax&) = 0; - virtual void visit(const VectorSyntax&) = 0; - }; - - template - void - unary_form::accept(Visitor& v) const { - v.visit(static_cast(*this)); - } - - template - void - binary_form::accept(Visitor& v) const { - v.visit(static_cast(*this)); - } - - // --------------- - // -- Allocator -- - // --------------- - // Allocator of syntax objects. - struct Allocator { - Allocator(); - ~Allocator(); - - const IntegerSyntax* make_integer(const Lexeme&); - const CharacterSyntax* make_character(const Lexeme&); - const StringSyntax* make_string(const Lexeme&); - const SymbolSyntax* make_symbol(SymbolSyntax::Kind, const Lexeme&); - const ReferenceSyntax* make_reference(size_t, const Lexeme&); - const AnchorSyntax* make_anchor(size_t, const Syntax*); - const QuoteSyntax* make_quote(const Syntax*); - const AntiquoteSyntax* make_antiquote(const Syntax*); - const Expand* make_expand(const Syntax*); - const Eval* make_eval(const Syntax*); - const Splice* make_splice(const Syntax*); - const Function* make_function(const Syntax*); - const Include* make_include(const Syntax*, const Syntax*); - const Exclude* make_exclude(const Syntax*, const Syntax*); - const ListSyntax* make_list(const std::vector&, bool = false); - const VectorSyntax* make_vector(const std::vector&); - - private: - Memory::Factory ints; - Memory::Factory chars; - Memory::Factory strs; - Memory::Factory syms; - Memory::Factory ancs; - Memory::Factory refs; - Memory::Factory quotes; - Memory::Factory antis; - Memory::Factory exps; - Memory::Factory funs; - Memory::Factory incs; - Memory::Factory excs; - Memory::Factory evls; - Memory::Factory spls; - Memory::Factory lists; - Memory::Factory vectors; - ListSyntax empty_list; - VectorSyntax empty_vector; - }; - - // -- Reader -- - struct RawInput { - const Byte* start; - const Byte* end; - Ordinal lineno; - }; - - struct Reader { - struct State { - RawInput bytes; - const Byte* cur; - const Byte* line; - Allocator alloc; - }; - - explicit Reader(const RawInput&); - Reader(const Byte*, const Byte*); - const Byte* position(Ordinal); - bool at_start() const { return st.cur == st.bytes.start; } - const Syntax* read(); - private: - State st; - }; - } -} - -#endif // OPENAXIOM_SEXPR_included diff --git a/src/include/storage.H b/src/include/storage.H deleted file mode 100644 index e414dec2..00000000 --- a/src/include/storage.H +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright (C) 2010-2013, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom. nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// --% Author: Gabriel Dos Reis -// --% Description: -// --% Memory management facility. Acquire raw memory directly -// --% from the host OS. Provide random access read to -// --% files through file mapping. - -#ifndef OPENAXIOM_STORAGE_included -#define OPENAXIOM_STORAGE_included - -#include -#include -#include -#include -#include - -namespace OpenAxiom { - // Datatype for the unit of storage. - using Byte = unsigned char; - - // ----------------- - // -- SystemError -- - // ----------------- - // Objects of (type derived from) this type are used to report - // error orignating from the OpenAxiom core system. - struct SystemError { - explicit SystemError(const std::string&); - virtual ~SystemError(); - // Return the text of the diagnostic message. - virtual const std::string& message() const; - protected: - const std::string text; - }; - - // Report a file system error - void filesystem_error(const std::string&); - - namespace Memory { - // Datatype for pointers to data. - using Pointer = void*; - - // Precision of the host OS storage page unit in byte count - size_t page_size(); - - // Acquire raw memory from the host OS. - Pointer os_acquire_raw_memory(size_t); - - // Release raw storage to the hosting OS. The first operand must - // be a pointer value previously returned by `os_acquire_raw_memory'. - // Otherwise, the result is undefined. - void os_release_raw_memory(Pointer, size_t); - - // Acquire `n' pages of memory storage from the host OS. - inline Pointer - acquire_raw_pages(size_t n) { - return os_acquire_raw_memory(n * page_size()); - } - - // Release `n' pages of storage starting the location `p'. - inline void - release_raw_pages(Pointer p, size_t n) { - os_release_raw_memory(p, n * page_size()); - } - - // ------------- - // -- Storage -- - // ------------- - // This class provides low-level abstractions intented for use - // to implement higher level storage abstractions. - struct Storage { - // Objects of this abstract datatype hold storage objects. - struct Handle; - - // Return the storage pointed to by the operand. It - // must be a pointer value previously returned by `acquire'. - // Otherwise, the result is undefined. - static void release(Handle*); - - // Return the start address of storage area. Clients would - // want to add padding bytes necessary to accomodate alignment - // requirements. - // Note: this should not be confused with the address of - // the handle object. - static Pointer begin(Handle*); - - // Courtesy conversion function from pointer to byte address. - static Byte* byte_address(Pointer h) { - return static_cast(h); - } - - // Round up `n' to a multiple of `a', a power of 2. - static size_t - round_up(size_t n, size_t a) { - return (n + a - 1) & ~(a - 1); - } - }; - - // ------------------------- - // -- SinglyLinkedStorage -- - // ------------------------- - // This class implements a simple single-linked list of storage - // objects. Each storage object in the link is created with - // a specific starting alignment requirements. - struct SinglyLinkedStorage : Storage { - // Return the previous handle in the link chain. - static Handle*& previous(Handle*); - }; - - // ------------------------- - // -- DoublyLinkedStorage -- - // ------------------------- - // Like SinglyLinkedStorage, except that the chain of storage - // object supports bidirectional travervsal. - struct DoublyLinkedStorage : Storage { - // Same as Storage::acquire, except that begin(h) returns an - // address that satisfies the alignment requirement `a'. - static Handle* acquire(size_t n, size_t a); - - // Return the previous handle in the link chain. - static Handle*& previous(Handle*); - - // Return the next handle in the link chain. - static Handle*& next(Handle*); - }; - - // ------------------ - // -- BlockStorage -- - // ------------------ - // This class implements a simple single-linked list of block storage. - // Each block maintains information about the next allocatable - // address within that block. - struct BlockStorage : SinglyLinkedStorage { - // Same as SinglyLinkedStorage::acquire(); initialize internal - // bookkeepking machinery. - static Handle* acquire(size_t n, size_t a); - - // Return the next allocatable address within the given block. - static Pointer next_address(Handle*); - - // Return the amount of allocatable byte in the given block. - static size_t room(Handle*); - - // Set `n' bytes aside with the given storage block. - static Pointer book(Handle*, size_t); - }; - - // ----------- - // -- Arena -- - // ----------- - // Extensible storage holding objects of a given type. - // The totality of all objects held in such a storage does not - // necessarily constitute a contiguous block. However, - // it is guaranteed that objects allocated in a single call - // to `allocate()' occupy a contiguous block of storage. - template - struct Arena : protected BlockStorage { - // Acquire storage capable of holding `n' objects of type `T'. - explicit Arena(size_t); - // Release all storage acquired by this object, upon end of life. - ~Arena(); - // allocate storage for `n' more objects of type `T'. - T* allocate(size_t); - // Number of objects of type `T' allocated in this storage. - size_t population() const; - - protected: - // Address of the first object of type `T' in a storage. - static T* first_object(Handle* h) { - return static_cast(BlockStorage::begin(h)); - } - - // Address of one-past-the-end object of type `T' in this storage. - static T* last_object(Handle* h) { - return static_cast(BlockStorage::next_address(h)); - } - - // Number of objects allocated in a storage. - static size_t object_count(Handle* h) { - return last_object(h) - first_object(h); - } - - BlockStorage::Handle* store; // active storage to allocate from - }; - - template - size_t - Arena::population() const { - size_t n = 0; - for (Handle* h = store; h != nullptr; h = previous(h)) - n += object_count(h); - return n; - } - - template - T* - Arena::allocate(size_t n) { - const size_t sz = n * sizeof(T); - if (BlockStorage::room(store) < sz) { - // Not enough room left. Make sure we allocate storage - // at least as big as the current. - Handle* h = acquire(std::max(n, object_count(store)), alignof(T)); - previous(h) = store; - store = h; - } - return static_cast(BlockStorage::book(store, sz)); - } - - template - Arena::Arena(size_t n) - : store(BlockStorage::acquire(n * sizeof (T), alignof (T))) - { } - - template - Arena::~Arena() { - // Release storage in the reverse order of their - // their allocation. - while (store != nullptr) { - Handle* current = store; - store = BlockStorage::previous(store); - BlockStorage::release(current); - } - } - - // ------------- - // -- Factory -- - // ------------- - template - struct Factory : Arena { - using Handler = typename Arena::Handle; - - Factory() : Arena(nominal_population()) { } - ~Factory(); - - // Allocate storage and value-construct an object of type `T'. - T* make() { - return new(this->allocate(1)) T{ }; - } - - // Allocate storage and construct an object of type `T'. - template - T* make(const Args&... args) { - return new(this->allocate(1)) T{args...}; - } - - private: - // Return 1 or the number of objects that can fit in a page unit. - static size_t nominal_population() { - const size_t psz = page_size(); - if (sizeof (T) > psz) - return 1; - return psz / sizeof(T); - } - }; - - // Destroy objects in the reverse order of their construction. - template - Factory::~Factory() { - for (auto s = this->store; s != nullptr; s = Arena::previous(s)) { - T* last = Arena::last_object(s); - for (--last; last >= Arena::first_object(s); --last) - last->~T(); - } - } - } -} - -#endif // OPENAXIOM_STORAGE_included - diff --git a/src/include/structure.H b/src/include/structure.H deleted file mode 100644 index 33c084f2..00000000 --- a/src/include/structure.H +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2013, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom, nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_STRUCTURE_included -#define OPENAXIOM_STRUCTURE_included - -namespace OpenAxiom { - // -- helper classes for structural abstractions -- - namespace structure { - // unary structures - template - struct unary { - explicit constexpr unary(const T& t) : arg(t) { }; - constexpr const T& operand() const { return arg; } - private: - const T arg; - }; - - // binary structures - template - struct binary { - constexpr binary(const T& t, const U& u) : arg0(t), arg1(u) { }; - constexpr const T& first() const { return arg0; } - constexpr const U& second() const { return arg1; } - private: - const T arg0; - const U arg1; - }; - - // ternary structures - template - struct ternary { - constexpr ternary(const T& t, const U& u, const V& v) - : arg0(t), arg1(u), arg2(v) { } - constexpr const T& first() const { return arg0; } - constexpr const U& second() const { return arg1; } - constexpr const V& third() const { return arg2; } - private: - const T arg0; - const U arg1; - const V arg2; - }; - } -} - -#endif // OPENAXIOM_STRUCTURE_included diff --git a/src/include/token-value.def b/src/include/token-value.def deleted file mode 100644 index 9a949b86..00000000 --- a/src/include/token-value.def +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (C) 2014, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom. nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -OPENAXIOM_DEFINE_TOKEN(Unknown, "", Unclassified, Language::All) -OPENAXIOM_DEFINE_TOKEN(Apostrophe, "'", Punctuator, Language::All) -OPENAXIOM_DEFINE_TOKEN(Backquote, "`", Punctuator, Language::All) -OPENAXIOM_DEFINE_TOKEN(Bar, "|", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Dot, ".", Punctuator, Language::All) -OPENAXIOM_DEFINE_TOKEN(DotDot, "..", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Colon, ":", Punctuator, Language::All) -OPENAXIOM_DEFINE_TOKEN(ColonColon, "::", Operator, Language::All) -OPENAXIOM_DEFINE_TOKEN(ColonDash, ":-", Operator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(ColonEq, ":=", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(At, "@", Operator, Language::All) -OPENAXIOM_DEFINE_TOKEN(Exclamation, "!", Punctuator, Language::Boot) -OPENAXIOM_DEFINE_TOKEN(Comma, ",", Punctuator, Language::All) -OPENAXIOM_DEFINE_TOKEN(CommaAt, ",@", Operator, Language::Lisp) -OPENAXIOM_DEFINE_TOKEN(Semicolon, ";", Punctuator, Language::All) -OPENAXIOM_DEFINE_TOKEN(Star, "*", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(StarStar, "**", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Plus, "+", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Minus, "-", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Slash, "/", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(SlashSlash, "//", Operator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(SlashBackslash, "/\\", Operator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(Backslash, "\\", Operator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(BackslashSlash, "\\/", Operator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(BackslashBackslash, "\\\\", Operator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(Less, "<", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(LessEq, "<=", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Greater, ">", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(GreaterEq, ">=", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Eq, "=", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(EqEq, "==", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Tilde, "~", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(TildeEq, "~=", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Caret, "^", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Sharp, "#", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(SharpLeftParen, "#(", Punctuator, Language::Lisp) -OPENAXIOM_DEFINE_TOKEN(SharpApostrophe, "#'", Operator, Language::Lisp) -OPENAXIOM_DEFINE_TOKEN(SharpColon, "#:", Operator, Language::Lisp) -OPENAXIOM_DEFINE_TOKEN(SharpPlus, "#+", Punctuator, Language::Lisp) -OPENAXIOM_DEFINE_TOKEN(SharpMinus, "#-", Punctuator, Language::Lisp) -OPENAXIOM_DEFINE_TOKEN(SharpDot, "#.", Operator, Language::Lisp) -OPENAXIOM_DEFINE_TOKEN(Dollar, "$", Operator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(Ampersand, "&", Operator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(RightArrow, "->", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(LeftArrow, "<-", Operator, Language::Boot) -OPENAXIOM_DEFINE_TOKEN(Implies, "=>", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Equiv, "<=>", Keyword, Language::Boot) -OPENAXIOM_DEFINE_TOKEN(MapsTo, "+->", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(FatArrow, "==>", Keyword, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(OpenParen, "(", Punctuator, Language::All) -OPENAXIOM_DEFINE_TOKEN(CloseParen, ")", Punctuator, Language::All) -OPENAXIOM_DEFINE_TOKEN(OpenMetaParen, "(|", Punctuator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(CloseMetaParen, "|)", Punctuator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(OpenBracket, "[", Punctuator, Language::All) -OPENAXIOM_DEFINE_TOKEN(CloseBracket, "]", Punctuator, Language::All) -OPENAXIOM_DEFINE_TOKEN(OpenMetaBracket, "[|", Punctuator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(CloseMetaBracket, "|]", Punctuator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(OpenBrace, "{", Punctuator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(CloseBrace, "}", Punctuator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(OpenMetaBrace, "{|", Punctuator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(CloseMetaBrace, "|}", Punctuator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(OpenChevron, "<<", Operator, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(CloseChevron, ">>", Operator, Language::Spad) - -OPENAXIOM_DEFINE_TOKEN(Wisecrack, "--", Comment, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Commentary, "++", Comment, Language::BootSpad) - -OPENAXIOM_DEFINE_TOKEN(Add, "add", Keyword, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(And, "and", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Assume, "assume", Keyword, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(Break, "break", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(By, "by", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Case, "case", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Catch, "catch", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Cross, "cross", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Do, "do", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Else, "else", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Exists, "exists", Keyword, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(Finally, "finally", Keyword, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(For, "for", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Forall, "forall", Keyword, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(From, "from", Keyword, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(Function, "function", Keyword, Language::Boot) -OPENAXIOM_DEFINE_TOKEN(Has, "has", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(If, "if", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Import, "import", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(In, "in", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Inline, "inline", Keyword, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(Is, "is", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Isnt, "isnt", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Iterate, "iterate", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Leave, "leave", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Macro, "macro", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Mod, "mod", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Namespace, "namespace", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Of, "of", Keyword, Language::Boot) -OPENAXIOM_DEFINE_TOKEN(Or, "or", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Pretend, "pretend", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Quo, "quo", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Rem, "rem", Operator, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Repeat, "repeat", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Return, "return", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Rule, "rule", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Structure, "structure", Keyword, Language::Boot) -OPENAXIOM_DEFINE_TOKEN(Then, "then", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(Throw, "throw", Keyword, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(Try, "try", Keyword, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(Until, "until", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(With, "with", Keyword, Language::Spad) -OPENAXIOM_DEFINE_TOKEN(Where, "where", Keyword, Language::BootSpad) -OPENAXIOM_DEFINE_TOKEN(While, "while", Keyword, Language::BootSpad) diff --git a/src/include/token.H b/src/include/token.H deleted file mode 100644 index b57b69d6..00000000 --- a/src/include/token.H +++ /dev/null @@ -1,670 +0,0 @@ -// Copyright (C) 2013-2014, Gabriel Dos Reis. -// All rights reserved. -// Written by Gabriel Dos Reis. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom. nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_TOKEN_included -#define OPENAXIOM_TOKEN_included - -#include -#include -#include -#include -#include - -namespace OpenAxiom { - // Categorization of Boot and Spad tokens. - enum class TokenCategory : uint8_t { - Unclassified, // token of unknown class - Whitespace, // sequence of white-space characters - Comment, // a description of an ignorable comment - Punctuator, // a punctuator character - Operator, // an operator both symbolic and alphabetic - Integer, // an integer literal - FloatingPoint, // a floating-point literal - String, // a string literal - Keyword, // a reserved word both symbolic and alphabetic - Identifier, // an identifier - Formatting, // a layout formatting token - Junk, // invalid/malformed token - EOS // end-of-token-stream indicator - }; - - std::ostream& operator<<(std::ostream&, TokenCategory); - - // The abstract value associated with a token. - enum class TokenValue : uint8_t { -#undef OPENAXIOM_DEFINE_TOKEN -#define OPENAXIOM_DEFINE_TOKEN(T, ...) T, -#include -#undef OPENAXIOM_DEFINE_TOKEN - Artificial, // Tokens after this are artificial - Indent, // new line indentation, greater than previous - Unindent, // new line indentation, less than previous - Justify, // align indentation with preceding line. - - EndOfStream // end of token stream - }; - - std::ostream& operator<<(std::ostream&, TokenValue); - - // Datatypes for locating lines and columns. - using LineNumber = std::size_t; - using ColumnIndex = std::size_t; - - struct Locus { - LineNumber line; - ColumnIndex column; - }; - - std::ostream& operator<<(std::ostream&, const Locus&); - - // Program text region - struct Region { - Locus start; - Locus end; - }; - - // Given a symbolic or alphabetic token, retrieve its category - // and associated abstract value. - struct TokenClassification { - TokenCategory category; - TokenValue value; - - explicit operator bool() const { - return category != TokenCategory::Unclassified; - } - }; - - TokenClassification classify(const std::string&); - - // Token data structure: a region of text with a classification. - struct Token : TokenClassification, Region { - using Location = Locus; - }; - - // Cursor into a fragment. - struct FragmentCursor { - std::size_t line; // index of a line in a fragment - std::size_t column; // column number at line. - - inline FragmentCursor& operator++() { - ++column; - return *this; - } - - inline FragmentCursor operator++(int) { - auto tmp = *this; - ++*this; - return tmp; - } - - inline FragmentCursor& operator--() { - --column; - return *this; - } - - inline FragmentCursor operator--(int) { - auto tmp = *this; - --*this; - return tmp; - } - }; - - // -- Exception types - struct EndOfStringUnseen { - LineNumber line; - ColumnIndex column; - }; - - struct MissingExponent { - LineNumber line; - ColumnIndex column; - }; - - // Object of this datatype decompose a program fragment into a - // token stream. The tokens are of type indicated by Tok. - template - struct Tokenizer { - Tokenizer(Frag& f) - : frag(f), - pos{ 0, frag.front().indent } - { - indents.push(pos.column); - } - - bool eos() const { - return pos.line >= frag.size() - or (pos.line + 1 == frag.size() and pos.column >= frag.back().size()); - } - - Tok get(Language = Language::Spad); - private: - Frag& frag; - FragmentCursor pos; - std::stack indents; - - std::size_t line_length() const { return frag(pos).size(); } - LineNumber next_line_number() const { - return pos.line + 1 < frag.size() - ? frag[pos.line + 1].number - : frag.back().number + 1; - } - ColumnIndex next_indentation() const { - return pos.line + 1 < frag.size() ? frag[pos.line + 1].indent : 0; - } - - LineNumber line_number() const { - return pos.line < frag.size() - ? frag(pos).number - : frag.back().number + 1; - } - - ColumnIndex column_number() const { - return pos.line < frag.size() ? pos.column : 0; - } - - using Locus = typename Tok::Location; - Locus current_locus() { - return { line_number(), column_number() }; - } - }; - - bool separator_or_punctuator(uint8_t); - - template - inline void comment_token(T& t, TokenValue v) { - t.category = TokenCategory::Comment; - t.value = v; - } - - template - inline void operator_token(T& t, TokenValue v) { - t.category = TokenCategory::Operator; - t.value = v; - } - - template - inline void punctuator_token(T& t, TokenValue v) { - t.category = TokenCategory::Punctuator; - t.value = v; - } - - template - static void junk(L& line, ColumnIndex& idx, T& t) { - while (idx < line.size() and not separator_or_punctuator(line[idx])) - ++idx; - t.category = TokenCategory::Junk; - } - - template - inline void - skip_whitespace(L& line, ColumnIndex& idx) { - while (idx < line.size() and isspace(line[idx])) - ++idx; - } - - template - void string_literal(Frag& frag, FragmentCursor& pos, Tok& t) { - bool done = false; - bool escape = false; - while (frag.covering(pos) && not done) { - switch (frag(pos)[pos.column++]) { - case '"': done = !escape; - // fallthrough - default: escape = false; break; - case '_': - if (pos.column == frag(pos).size() - and pos.line < frag.size() - 1) { - ++pos.line; - pos.column = 0; - } - else - escape = !escape; - break; - } - } - if (not done) - throw EndOfStringUnseen{ frag(pos).number, pos.column }; - t.category = TokenCategory::String; - } - - template - void skip_to_end_of_integer(L& line, ColumnIndex& idx) { - while (idx < line.size() and isdigit(line[idx])) - ++idx; - } - - template - void integer(L& line, ColumnIndex& idx, T& t) { - skip_to_end_of_integer(line, idx); - t.category = TokenCategory::Integer; - } - - template - T& number(L& line, ColumnIndex& idx, T& t) { - integer(line, idx, t); - if (idx >= line.size() or line[idx] != '.') - return t; - if (++idx >= line.size() or not isdigit(line[idx])) { - --idx; - return t; - } - - t.category = TokenCategory::FloatingPoint; - skip_to_end_of_integer(line, idx); - if (idx >= line.size() or (line[idx] != 'e' and line[idx] != 'E')) - return t; - if (++idx < line.size() and (line[idx] == '+' or line[idx] == '-')) - ++idx; - if (idx >= line.size() or not isdigit(line[idx])) - throw MissingExponent{ line.number, idx }; - skip_to_end_of_integer(line, idx); - return t; - } - - inline bool - identifier_head(uint8_t c) { - return isalpha(c) or c == '%' or c == '_'; - } - - inline bool - identifier_part(uint8_t c) { - return identifier_head(c) or isdigit(c); - } - - inline bool - identifier_suffix(uint8_t c) { - return c == '!' or c == '?'; - } - - inline bool internal_prefix(uint8_t c) { - return c == '%' or c == '$'; - } - - template - inline void - skip_prefix(L& line, ColumnIndex& idx, uint8_t c) { - while (idx < line.size() and line[idx] == c) - ++idx; - } - - template - T& identifier(L& line, ColumnIndex& idx, T& t, Language dialect) { - t.category = TokenCategory::Identifier; - - ColumnIndex start = --idx; // idx was ahead by 1. - if (dialect == Language::Boot and internal_prefix(line[idx])) - skip_prefix(line, idx, line[idx]); - bool saw_escape = false; - while (idx < line.size()) { - if (not identifier_part(line[idx]) and line[idx - 1] != '_') - break; - else if (line[idx] == '_') - saw_escape = true; - ++idx; - } - while (idx < line.size() and identifier_suffix(line[idx])) - ++idx; - - if (saw_escape) - t.category = TokenCategory::Identifier; - else if (auto info = classify(line.sub_string(start, idx))) { - t.category = info.category; - t.value = info.value; - } - return t; - } - - template - static void - left_paren_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - punctuator_token(t, TokenValue::OpenParen); - if (frag.covering(pos) and frag[pos] == '|') { - ++pos; - t.value = TokenValue::OpenMetaParen; - } - } - - template - static void - left_brace_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - punctuator_token(t, TokenValue::OpenBrace); - if (frag.covering(pos) and frag[pos] == '|') { - ++pos; - t.value = TokenValue::OpenMetaBrace; - } - } - - template - static void - left_bracket_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - punctuator_token(t, TokenValue::OpenBracket); - if (frag.covering(pos) and frag[pos] == '|') { - ++pos; - t.value = TokenValue::OpenMetaBracket; - } - } - - template - static void - colon_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - operator_token(t, TokenValue::Colon); - if (frag.covering(pos)) - switch (frag[pos]) { - case ':': t.value = TokenValue::ColonColon; ++pos; break; - case '=': t.value = TokenValue::ColonEq; ++pos; break; - case '-': t.value = TokenValue::ColonDash; ++pos; break; - default: break; - } - } - - template - static void - star_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - operator_token(t, TokenValue::Star); - if (frag.covering(pos) and frag[pos] == '*') { - t.value = TokenValue::StarStar; - ++pos; - } - } - - template - static void - slash_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - operator_token(t, TokenValue::Slash); - if (frag.covering(pos)) - switch (frag[pos]) { - case '/': t.value = TokenValue::SlashSlash; ++pos; break; - case '\\': t.value = TokenValue::SlashBackslash; ++pos; break; - default: break; - } - } - - template - static void - backslash_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - operator_token(t, TokenValue::Backslash); - if (frag.covering(pos)) - switch (frag[pos]) { - case '\\': t.value = TokenValue::BackslashBackslash; ++pos; break; - case '/': t.value = TokenValue::BackslashSlash; ++pos; break; - default: break; - } - } - - template - static void - less_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - operator_token(t, TokenValue::Less); - if (frag.covering(pos)) - switch (frag[pos]) { - case '-': t.value = TokenValue::LeftArrow; ++pos; break; - case '<': t.value = TokenValue::OpenChevron; ++pos; break; - case '=': - t.value = TokenValue::LessEq; - if (frag.covering(++pos) and frag[pos] == '>') { - t.value = TokenValue::Equiv; - ++pos; - } - break; - default: break; - } - } - - template - static void - equal_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - operator_token(t, TokenValue::Eq); - if (frag.covering(pos)) - switch (frag[pos]) { - case '>': t.value = TokenValue::Implies; ++pos; break; - case '=': - t.value = TokenValue::EqEq; - if (frag.covering(++pos) and frag[pos] == '>') { - t.value = TokenValue::FatArrow; - ++pos; - } - break; - default: break; - } - } - - template - static void - tilde_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - operator_token(t, TokenValue::Tilde); - if (frag.covering(pos) and frag[pos] == '=') { - t.value = TokenValue::TildeEq; - ++pos; - } - } - - template - static void - greater_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - operator_token(t, TokenValue::Greater); - if (frag.covering(pos)) - switch (frag[pos]) { - case '=': t.value = TokenValue::GreaterEq; ++pos; break; - case '>': t.value = TokenValue::CloseChevron; ++pos; break; - } - } - - template - static void - bar_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - punctuator_token(t, TokenValue::Bar); - if (frag.covering(pos)) - switch (frag[pos]) { - case ']': t.value = TokenValue::CloseMetaBracket; ++pos; break; - case '}': t.value = TokenValue::CloseMetaBrace; ++pos; break; - case ')': t.value = TokenValue::CloseMetaParen; ++pos; break; - default: break; - } - } - - template - static void - minus_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - operator_token(t, TokenValue::Minus); - if (frag.covering(pos)) - switch (frag[pos]) { - case '>': t.value = TokenValue::RightArrow; ++pos; break; - case '-': - comment_token(t, TokenValue::Wisecrack); - pos.column = frag(pos).size(); - break; - } - } - - - template - static void - plus_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - operator_token(t, TokenValue::Plus); - if (frag.covering(pos)) - switch (frag[pos]) { - case '+': - comment_token(t, TokenValue::Commentary); - pos.column = frag(pos).size(); - break; - case '-': - if (pos.column + 1 < frag(pos).size() - and frag(pos)[pos.column + 1] == '>') { - t.value = TokenValue::MapsTo; - pos.column += 2; - } - break; - default: break; - } - } - - template - static void - dot_et_al(Frag& frag, FragmentCursor& pos, Tok& t) { - operator_token(t, TokenValue::Dot); - if (frag.covering(pos) and frag[pos] == '.') { - t.value = TokenValue::DotDot; - ++pos; - } - } - - template - static void - dollar_et_al(Frag& frag, FragmentCursor& pos, Tok& t, Language dialect) { - if (dialect != Language::Boot or not frag.covering(pos) - or separator_or_punctuator(frag[pos])) - operator_token(t, TokenValue::Dollar); - else - identifier(frag(pos), pos.column, t, dialect); - } - - template - static void - sharp_et_al(Frag& frag, FragmentCursor& pos, Tok& t, Language dialect) { - if (dialect != Language::Lisp) - operator_token(t, TokenValue::Sharp); - else if (frag.covering(pos)) - switch (frag[pos++]) { - case '(': punctuator_token(t, TokenValue::SharpLeftParen); break; - case '\'': operator_token(t, TokenValue::SharpApostrophe); break; - case ':': operator_token(t, TokenValue::SharpColon); break; - case '+': punctuator_token(t, TokenValue::SharpPlus); break; - case '-': punctuator_token(t, TokenValue::SharpMinus); break; - case '.': operator_token(t, TokenValue::SharpDot); break; - default: --pos; break; - } - } - - - template - Tok Tokenizer::get(Language dialect) { - Tok t { }; - t.start = current_locus(); - - if (eos()) { - t.category = TokenCategory::EOS; - t.end = current_locus(); - return t; - } - else if (isspace(frag[pos])) { - skip_whitespace(frag(pos), pos.column); - t.category = TokenCategory::Whitespace; - t.end = current_locus(); - return t; - } - else if (pos.column == line_length() - 1 and frag(pos).back() == '_') { - ++pos.line; - pos.column = frag(pos).indent; - } - else if (pos.column == line_length()) { - auto indent = indents.top(); - auto next_indent = next_indentation(); - t.start = t.end = { next_line_number(), next_indent }; - if (indent < next_indent) { - indents.push(next_indent); - ++pos.line; - pos.column = next_indent; - t.category = TokenCategory::Formatting; - t.value = TokenValue::Indent; - } - else if (indent > next_indent) { - indents.pop(); - t.category = TokenCategory::Formatting; - t.value = TokenValue::Unindent; - } - else { - ++pos.line; - pos.column = next_indent; - t.category = TokenCategory::Formatting; - t.value = TokenValue::Justify; - } - return t; - } - - switch (auto c = frag.advance(pos)) { - case '#': sharp_et_al(frag, pos, t, dialect); break; - case '@': operator_token(t, TokenValue::At); break; - case '^': operator_token(t, TokenValue::Caret); break; - case '&': punctuator_token(t, TokenValue::Ampersand); break; - case '!': punctuator_token(t, TokenValue::Exclamation); break; - case '\'': punctuator_token(t, TokenValue::Apostrophe); break; - case ',': punctuator_token(t, TokenValue::Comma); break; - case ';': punctuator_token(t, TokenValue::Semicolon); break; - case '`': punctuator_token(t, TokenValue::Backquote); break; - case '(': left_paren_et_al(frag, pos, t); break; - case ')': punctuator_token(t, TokenValue::CloseParen); break; - case '{': left_brace_et_al(frag, pos, t); break; - case '}': punctuator_token(t, TokenValue::CloseBrace); break; - case '[': left_bracket_et_al(frag, pos, t); break; - case ']': punctuator_token(t, TokenValue::CloseBracket); break; - case ':': colon_et_al(frag, pos, t); break; - case '*': star_et_al(frag, pos, t); break; - case '/': slash_et_al(frag, pos, t); break; - case '\\': backslash_et_al(frag, pos, t); break; - case '<': less_et_al(frag, pos, t); break; - case '=': equal_et_al(frag, pos, t); break; - case '~': tilde_et_al(frag, pos, t); break; - case '>': greater_et_al(frag, pos, t); break; - case '|': bar_et_al(frag, pos, t); break; - case '-': minus_et_al(frag, pos, t); break; - case '+': plus_et_al(frag, pos, t); break; - case '.': dot_et_al(frag, pos, t); break; - case '"': string_literal(frag, pos, t); break; - case '$': dollar_et_al(frag, pos, t, dialect); break; - - default: - if (isdigit(c)) - number(frag(pos), pos.column, t); - else if (identifier_head(c)) - identifier(frag(pos), pos.column, t, dialect); - else - junk(frag(pos), pos.column, t); - break; - } - - t.end = { frag(pos).number, pos.column }; - return t; - } - - // -- Token streams. - template - struct TokenStream : std::vector { - template - explicit TokenStream(Frag& f, Language dialect = Language::Spad) { - Tokenizer lex { f }; - while (auto t = lex.get(dialect)) - this->push_back(t); - } - }; -} - -#endif // OPENAXIOM_TOKEN_included diff --git a/src/include/vm.H b/src/include/vm.H deleted file mode 100644 index 3bb62250..00000000 --- a/src/include/vm.H +++ /dev/null @@ -1,606 +0,0 @@ -// Copyright (C) 2011-2014, Gabriel Dos Reis. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of OpenAxiom nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// --% Author: Gabriel Dos Reis -// --% Description: -// --% Interface and implementation of basic services of the -// --% OpenAxiom Virtual Machine. - -#ifndef OPENAXIOM_VM_included -#define OPENAXIOM_VM_included - -#include -#include -#include -#include -#include -#include -#include - -#define internal_type struct alignas(16) -#define internal_data alignas(16) - -namespace OpenAxiom { - namespace VM { - // --% - // --% Value representation - // --% - // A far reaching design decision is that of providing a uniform - // representation for values. That is all values, irrespective - // of type have fit in a fixed format, i.e. a scalar register. - // This means that values that are more complicated than a scalar, - // i.e. the vast majority and most interesting values, have to - // be stored in allocated objects and addresses of their container - // objects used in place of the actual values. This is folklore - // in the communities of garbage collected languages. - // - // An unfortunate but widely held belief is that AXIOM-based - // systems (and computer algebra systems in general) are - // Lisp-based systems. Nothing could be further from the truth - // for OpenAxiom. The type system is believed to support - // erasure semantics, at least for values. - // - // However the current implementation, being Lisp-based, - // unwittingly makes use of some Lisp features that are not - // strictly necessary. It would take a certain amount of effort - // to get rid of them. Consequently, we must cope -- at least - // for now -- with the notion of uniform value representation and - // use runtime predicates to descriminate between values. - // On the other hand, we do not want to carry an unduly expensive - // abstraction penalty for perfectly well behaved and well - // disciplined programs. So, here are a few constraints: - // 1. Small integers should represent themselves -- not allocated. - // Furthermore, the maximum range should be sought where possible. - // 2. Since we have to deal with characters, they should be - // directly represented -- not allocated. - // 3. List values and list manipulation should be efficient. - // Ideally, a pair should occupy no more than what it - // takes to store two values in a type-erasure semantics. - // 4. Idealy, pointers to foreign objects (at least) should be - // left unmolested. - // 5. Ideally, we want efficient access to string literals - // - // * Assumptions: - // (a) the host machine has sizeof(Value) quo 4 = 0. - // (b) allocated objects can be aligned on sizeof(Value) boundary. - // (c) the host machine has 2's complement arithmetic. - // - // If: - // -- we use a dedicated allocation pool for cons cells - // -- we allocate the first cell in each cons-storage arena - // on a 8-byte boundary - // -- we use exactly 2 * sizeof(Value) to store a cons cell - // therefore realizing constraint (3) - // then: - // every pointer to a cons cell will have its last 3 bits cleared. - // - // Therefore, we can use the last 3 bits to tag a cons value, instead - // of storing the tag inside the cons cell. We can't leave those - // bits cleared for we would not be able to easily and cheaply - // distinguish a pointer to a cons cell from a pointer to other - // objects, in particular foreign objects. - // - // To meet constraint (1), we must logically use at least one bit - // to distinguish a small integer from a pointer to a cons cell. - // The good news is that we need no more than that if pointers - // to foreign pointers do not have the last bit set. Which is - // the case with assumption (a). Furthermore, if we align all - // other internal data on 16 byte boundary, then we have 4 spare bits - // for use to categorize values. - // Therefore we arrive at the first design: - // I. the value representation of a small integer always has the - // the least significant bit set. All other bits are - // significant. In other words, the last four bits of a small - // integer are 0bxxx1 - // - // As a consequence, the last bit of all other values must be cleared. - // - // Next, - // II. All foreign pointers that are aligned on 8-boundary are - // directly represented. Any foreign pointer not meeting - // this condition is stored in an internal object. As a - // consequence, the last four bits of all foreign addresses - // directly represented follow the pattern 0bx000. - // - // III. Cons cells are represented by their addresses with the - // last 4 bits matching the pattern 0bx010. - // - // IV. All internal objects are allocated on 16-byte boundary. - // Their last 4 bits are set to the pattern 0b0110. - // - // V. String literals are represented by their addressed with - // the last four bits following the pattern 0bx100.. - // - // Finally: - // IV. The representation of a character shall have the last four - // bits set to 0b1110. - // - // Note: These choices do not fully satisfy constraint 4. This is - // because we restrict foreign pointers to address aligned - // to 8-byte boundaries. A modest constraint. - // - // Special Constants: - // NIL 0x00 - // T 0x10 - - - // ----------- - // -- Value -- - // ----------- - // All VM values fit in a universal value datatype. - using ValueBits = uintptr_t; - using ValueMask = ValueBits; - enum class Value : ValueBits { - nil = 0x00, // distinguished NIL value - t = 0x10, // distinguished T value - }; - - // -- Testing for nil value. - constexpr Value null(Value v) { - return v == Value::nil ? Value::t : Value::nil; - } - - // -- Convert VM Boolean value to C++ view - constexpr bool to_bool(Value v) { return v != Value::nil; } - - // -- Convert a C++ Boolean value to VM view. - constexpr Value to_value(bool b) { - return b ? Value::t : Value::nil; - } - - // -- Identity equality. - constexpr Value eq(Value x, Value y) { return to_value(x == y); } - - template - struct ValueTrait { - }; - - // Return the tag of an abstract value, when viewed as a potential - // T-value. - template - constexpr ValueBits tag(Value v) { - return ValueBits(v) & ValueTrait::tag_mask; - } - - // Return true if the abstract value is, in fact, a T-value. - template - constexpr bool is(Value v) { - return tag(v) == ValueTrait::tag; - } - - // Return the pristine bits of an abstract value without its tag. - template - constexpr ValueBits native(Value v) { - return ValueBits(v) & ~ValueTrait::tag_mask; - } - - // -- Arity: number of arguments or forms taken by a function - // or a special operator. - enum class Arity : intptr_t { - variable = -1, // Any number of arguments. - zero = 0, // Exactly no argument. - one = 1, // Exactly one argument. - two = 2, // Exactly two arguments. - three = 3, // Exactly three arguments. - }; - - // ------------- - // -- Dynamic -- - // ------------- - // Any internal value is of a class derived from this. - internal_type Dynamic { - struct Visitor; - virtual ~Dynamic(); - virtual void accept(Visitor&) const = 0; - }; - - // Provide an S-view of a T-typed expression, assuming the type T - // derives from S. - template - inline const S& as(const T& t) { return t; } - - template<> - struct ValueTrait { - enum Tag : ValueBits { tag = 0x6 }; - enum Mask : ValueBits { tag_mask = 0xF }; - }; - - inline Dynamic* to_dynamic(Value v) { - return reinterpret_cast(native(v)); - } - - inline Dynamic* to_dynamic_if_can(Value v) { - return is(v) ? to_dynamic(v) : nullptr; - } - - template - using IfDynamic = typename - std::enable_if::value, Value>::type; - - template - inline IfDynamic to_value(const T* o) { - return Value(ValueBits(o) | ValueTrait::tag); - } - - // -- Callable -- - struct Callable : Dynamic { - }; - - // ------------- - // -- Fixnum --- - // ------------- - // VM integers are divided into classes: small numbers, - // and large numbers. A small number fits entirely in a register. - // A large number is allocated and represented by its address. - using FixnumBits = intptr_t; - enum class Fixnum : FixnumBits { - minimum = FixnumBits(~(~ValueBits() >> 2)), - zero = FixnumBits(0), - one = FixnumBits(1), - maximum = FixnumBits(~ValueBits() >> 2), - }; - - template<> - struct ValueTrait { - enum Tag : ValueBits { tag = 0x1 }; - enum Mask : ValueBits { tag_mask = 0x1 }; - }; - - constexpr Fixnum to_fixnum(Value v) { - return Fixnum(FixnumBits(v) >> 1); - } - - constexpr Value from_fixnum(Fixnum i) { - return Value((ValueBits(i) << 1 ) | ValueTrait::tag); - } - - // ------------ - // -- String -- - // ------------ - using String = InternedString; - - template<> - struct ValueTrait { - enum Tag : ValueBits { tag = 0x4 }; - enum Mask : ValueBits { tag_mask = 0x7 }; - }; - - inline InternedString to_string(Value v) { - return reinterpret_cast(native(v)); - } - - inline Value from_string(InternedString s) { - return Value(ValueBits(s) | ValueTrait::tag); - } - - inline InternedString to_string_if_can(Value v) { - return is(v) ? to_string(v) : nullptr; - } - - // ------------- - // -- Pointer -- - // ------------- - // Allocated objects are represented by their addresses. - using Memory::Pointer; - - template<> - struct ValueTrait { - enum Tag : ValueBits { tag = 0x0 }; - enum Mask : ValueBits { tag_mask = 0x7 }; - }; - - inline Pointer to_pointer(Value v) { - return Pointer(ValueBits(v)); - } - - inline Value from_pointer(Pointer p) { - return Value(ValueBits(p) | ValueTrait::tag); - } - - // ---------- - // -- Pair -- - // ---------- - struct alignas(8) ConsCell { - Value head; - Value tail; - }; - - using Pair = ConsCell*; - - template<> - struct ValueTrait { - enum Tag : ValueBits { tag = 0x2 }; - enum Mask : ValueBits { tag_mask = 0x7 }; - }; - - inline Pair to_pair(Value v) { - return reinterpret_cast(native(v)); - } - - inline Value from_pair(Pair p) { - return Value(ValueBits(p) | ValueTrait::tag); - } - - // Return true if argument designates a pair. - constexpr Value consp(Value v) { - return to_value(v != Value::nil and v != Value::t and is(v)); - } - - inline Value atom(Value v) { - return null(consp(v)); - } - - // If `v' designates a pair, return a pointer to its - // concrete representation. - inline Pair to_pair_if_can(Value v) { - return consp(v) == Value::t ? to_pair(v) : nullptr; - } - - Fixnum count_nodes(Pair); - inline Fixnum count_nodes(Value v) { - if (auto p = to_pair_if_can(v)) - return count_nodes(p); - return Fixnum::zero; - } - - // --------------- - // -- Character -- - // --------------- - // This datatype is prepared for Uncode characters even if - // we do not handle UCN characters at the moment. - enum class Character : ValueBits { }; - - template<> - struct ValueTrait { - enum Tag : ValueBits { tag = 0xE }; - enum Mask : ValueBits { tag_mask = 0xF }; - }; - - constexpr Character to_character(Value v) { - return Character(ValueBits(v) >> 4); - } - - constexpr Value from_character(Character c) { - return Value((ValueBits(c) << 4) | ValueTrait::tag); - } - - // -- Object -- - // An object is a typed value. - struct Type; - struct Object { - Value value; - const Type* type; - }; - - struct Package; - - enum class SymbolAttribute : ValueBits { - None = 0x0, // No particular attribute. - Constant = 0x1, // Symbol defined constant. - Special = 0x2, // Symbol declared special. - Keyword = 0x4, // A keyword symbol. - SpecialConstant = Constant | Special, - }; - - constexpr SymbolAttribute - operator&(SymbolAttribute x, SymbolAttribute y) { - return SymbolAttribute(ValueBits(x) & ValueBits(y)); - } - - // ------------ - // -- Symbol -- - // ------------ - struct Symbol : Dynamic { - const InternedString name; - Value value; - const Callable* function; - Pair properties; - Package* package; - SymbolAttribute attributes; - explicit Symbol(InternedString); - void accept(Visitor&) const override; - bool has(SymbolAttribute x) const { return (attributes & x) == x; } - }; - - inline Symbol* to_symbol_if_can(Value v) { - return dynamic_cast(to_dynamic_if_can(v)); - } - - inline bool is_symbol(Value v) { - return to_symbol_if_can(v) != nullptr; - } - - // -- Test if a value is a symbol. - inline Value symbolp(Value v) { - return to_value(v == Value::nil or v == Value::t or is_symbol(v)); - } - - // -- Test if a value is a keyword symbol. - inline Value keywordp(Value v) { - if (auto sym = to_symbol_if_can(v)) - return to_value(sym->has(SymbolAttribute::Keyword)); - return Value::nil; - } - - struct CmpByName { - template - bool operator()(const T& x, const T& y) const { - return std::less()(x.name, y.name); - } - }; - - template - inline const T* setf_symbol_function(Symbol* sym, const T* fun) { - sym->function = fun; - return fun; - } - - // -- Argument binding as value. - // Binding a parameter to a value in a call. - struct Binding : Dynamic { - Symbol* symbol; - Value value; - void accept(Visitor&) const override; - }; - - // -- Environments. - struct Environment { - struct Binding { - Symbol* symbol; - Value value; - }; - - Environment(); - ~Environment(); - - void bind(Symbol*, Value); - Binding* lookup(InternedString); - private: - std::vector lexical; - std::vector dynamic; - }; - - // ------------- - // -- Package -- - // ------------- - struct Package : Dynamic { - const InternedString name; - std::set symbols; - - explicit Package(InternedString); - void accept(Visitor&) const override; - Symbol* make_symbol(InternedString); - Symbol* find_symbol(InternedString); - }; - - // -------------- - // -- Function -- - // -------------- - struct FunctionBase : Callable { - const Symbol* name; - Value type; - FunctionBase(const Symbol* n, Value t = Value::nil) - : name(n), type(t) { } - void accept(Visitor&) const override; - }; - - // ------------------------ - // -- Builtin Operations -- - // ------------------------ - // Types for native implementation of builtin operators. - struct BasicContext; - - template - using RuntimeOperation = Value(*)(BasicContext*, Ts...); - using NullaryCode = RuntimeOperation<>; - using UnaryCode = RuntimeOperation; - using BinaryCode = RuntimeOperation; - using TernaryCode = RuntimeOperation; - - template - struct BuiltinFunction : FunctionBase { - Code code; - BuiltinFunction(const Symbol* n, Code c) - : FunctionBase(n), code(c) - { } - void accept(Visitor&) const override; - }; - - using NullaryOperator = BuiltinFunction; - using UnaryOperator = BuiltinFunction; - using BinaryOperator = BuiltinFunction; - using TernaryOperator = BuiltinFunction; - - // -- Operand stack. - struct OperandStack : private std::vector { - using super = std::vector; - using iterator = std::reverse_iterator; - using super::size; - using super::empty; - iterator begin() { return rbegin(); } - iterator end() { return rend(); } - Value top() { return back(); } - void push(Value v) { push_back(v); } - Value pop() { auto v = back(); pop_back(); return v; } - void operator-=(std::size_t i) { resize(size() - i); } - Value operator[](std::size_t i) { - return super::operator[](size() - i - 1); - } - }; - - // -- Dynamic::Visitor -- - struct Dynamic::Visitor { - virtual void visit(const Symbol&) = 0; - virtual void visit(const Binding&) = 0; - virtual void visit(const Package&) = 0; - virtual void visit(const FunctionBase&) = 0; - virtual void visit(const NullaryOperator&); - virtual void visit(const UnaryOperator&); - virtual void visit(const BinaryOperator&); - }; - - template - void BuiltinFunction::accept(Visitor& v) const { v.visit(*this); } - - // ------------------ - // -- BasicContext -- - // ------------------ - // Provides basic evaluation services. - struct BasicContext : StringPool { - BasicContext(); - ~BasicContext(); - - Package* make_package(InternedString); - Symbol* make_keyword(InternedString); - Pair make_pair(Value, Value); - const NullaryOperator* make_operator(Symbol*, NullaryCode); - const UnaryOperator* make_operator(Symbol*, UnaryCode); - const BinaryOperator* make_operator(Symbol*, BinaryCode); - const TernaryOperator* make_operator(Symbol*, TernaryCode); - - Package* keyword_package() const { return keywords; } - Package* homeless_package() const { return homeless; } - - protected: - std::set packages; - Memory::Factory conses; - Memory::Factory nullaries; - Memory::Factory unaries; - Memory::Factory binaries; - Memory::Factory ternaries; - Package* keywords; - Package* homeless; - }; - }; -} - -#endif // OPENAXIOM_VM_INCLUDED - diff --git a/src/utils/Makefile.in b/src/utils/Makefile.in index 18806e1d..cde398ed 100644 --- a/src/utils/Makefile.in +++ b/src/utils/Makefile.in @@ -220,8 +220,7 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags -am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/hash-table.H \ - $(srcdir)/string-pool.H $(top_srcdir)/config/depcomp \ +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp \ $(top_srcdir)/config/mkinstalldirs DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ diff --git a/src/utils/hash-table.H b/src/utils/hash-table.H deleted file mode 100644 index d74c7760..00000000 --- a/src/utils/hash-table.H +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) 2010, Gabriel Dos Reis. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of The Numerical Algorithms Group Ltd. nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_HASH_TABLE_INCLUDED -#define OPENAXIOM_HASH_TABLE_INCLUDED - -// --% Author: Gabriel Dos Reis. -// --% Description: -// --% Simple hash table facility. To be replaced by C++0x -// --% hash tables when C++0x compilers become common place. - -#include - -namespace OpenAxiom { - // -------------------- - // -- HashTableEntry -- - // -------------------- - // Datatype for entries in a parameterized hash table. - // The type parameter is required to be a value-construcitble datatype. - // A table bucket entry is required to be at least 8-byte aligned - // so that an instance of it can be used directly as a VM value. - // See for more description. - template - struct alignas(8) HashTableEntry : T { - HashTableEntry* chain; // previous item in the same bucket chain - size_t hash; // hash code of stored data - }; - - // -------------------- - // -- BasicHashTable -- - // -------------------- - // A simple hash table data structure. Ideally, we would like to use - // standard C++ types, but hash tables were only in a C++ 2003 TR, - // officially part of C++0x standard library. We still don't have - // wide-spread C++0x compilers. - template - struct BasicHashTable : private Memory::Arena > { - typedef HashTableEntry EntryType; - explicit BasicHashTable(size_t n) - : Memory::Arena >(n), - buckets(this->allocate(n)), nbuckets(n) { } - - EntryType* hash_chain(size_t h) const { - return buckets + (h % nbuckets); - } - - EntryType* new_bucket() { - return this->allocate(1); - } - - private: - HashTableEntry* const buckets; - const size_t nbuckets; - }; -} - -#endif // OPENAXIOM_HASH_TABLE_INCLUDED diff --git a/src/utils/string-pool.H b/src/utils/string-pool.H deleted file mode 100644 index 1f746e6d..00000000 --- a/src/utils/string-pool.H +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) 2010-2015, Gabriel Dos Reis. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// - Neither the name of The Numerical Algorithms Group Ltd. nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef OPENAXIOM_STRING_POOL_INCLUDED -#define OPENAXIOM_STRING_POOL_INCLUDED - -#include - -// --% Author: Gabriel Dos Reis. -// --% Description: -// --% Basic persistent string facility. -// --% A stringpool for allocating long-living string objects. - -namespace OpenAxiom { - struct StringPool; - - // ---------------- - // -- StringItem -- - // ---------------- - // String data allocated from a stringpool. - struct StringItem { - const Byte* begin() const { return text; } - const Byte* end() const { return text + length; } - size_t size() const { return length; } - bool equal(const Byte*, size_t) const; - protected: - const Byte* text; // pointer to the byte sequence - size_t length; // number of bytes in this string - friend StringPool; - StringItem() : text(), length() { } - }; - - // ---------------- - // -- StringPool -- - // ---------------- - // A string-pool object is a repository of long-living string objects. - // It contains no duplicates, therefore allows fast equality - // comparison of string objects. - struct StringPool : private BasicHashTable { - using BasicHashTable::EntryType; - - StringPool(); - // Intern a NUL-terminated sequence of characters. - EntryType* intern(const char*); - - // Intern a sequence of characters given by its start and length. - EntryType* intern(const Byte*, size_t); - private: - Memory::Arena strings; // character blub - // Allocate a string from the internal arena. - const Byte* make_copy(const Byte*, size_t); - }; - - typedef const StringPool::EntryType* InternedString; -} - -#endif // OPENAXIOM_STRING_POOL_INCLUDED -- cgit v1.2.3