Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r61391 - in trunk/libs/spirit/example/scheme: example example/scheme example/sexpr input scheme test/scheme
From: joel_at_[hidden]
Date: 2010-04-18 22:31:11


Author: djowel
Date: 2010-04-18 22:31:08 EDT (Sun, 18 Apr 2010)
New Revision: 61391
URL: http://svn.boost.org/trac/boost/changeset/61391

Log:
refining the error checking
Added:
   trunk/libs/spirit/example/scheme/example/scheme/scheme_error_test.cpp (contents, props changed)
   trunk/libs/spirit/example/scheme/test/scheme/scheme_error.scm (contents, props changed)
Text files modified:
   trunk/libs/spirit/example/scheme/example/Jamfile | 1
   trunk/libs/spirit/example/scheme/example/sexpr/out.txt | 2
   trunk/libs/spirit/example/scheme/example/sexpr/sexpr_test.txt | 2
   trunk/libs/spirit/example/scheme/input/parse_sexpr_impl.hpp | 8 +
   trunk/libs/spirit/example/scheme/input/sexpr.hpp | 2
   trunk/libs/spirit/example/scheme/scheme/compiler.hpp | 238 ++++++++++++++++++++++++---------------
   trunk/libs/spirit/example/scheme/scheme/interpreter.hpp | 39 ++++++
   7 files changed, 194 insertions(+), 98 deletions(-)

Modified: trunk/libs/spirit/example/scheme/example/Jamfile
==============================================================================
--- trunk/libs/spirit/example/scheme/example/Jamfile (original)
+++ trunk/libs/spirit/example/scheme/example/Jamfile 2010-04-18 22:31:08 EDT (Sun, 18 Apr 2010)
@@ -31,6 +31,7 @@
 exe factorial1 : scheme/factorial1.cpp ;
 exe factorial2 : scheme/factorial2.cpp ;
 
+exe scheme_error_test : scheme/scheme_error_test.cpp ;
 
 
 

Added: trunk/libs/spirit/example/scheme/example/scheme/scheme_error_test.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/example/scheme/example/scheme/scheme_error_test.cpp 2010-04-18 22:31:08 EDT (Sun, 18 Apr 2010)
@@ -0,0 +1,47 @@
+/*=============================================================================
+ Copyright (c) 2001-2010 Joel de Guzman
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#include <boost/config/warning_disable.hpp>
+
+#include <input/sexpr.hpp>
+#include <input/parse_sexpr_impl.hpp>
+#include <scheme/compiler.hpp>
+#include <utree/io.hpp>
+#include <fstream>
+
+///////////////////////////////////////////////////////////////////////////////
+// Main program
+///////////////////////////////////////////////////////////////////////////////
+int main(int argc, char **argv)
+{
+ char const* filename = filename = argv[1];
+ std::ifstream in(filename, std::ios_base::in);
+
+ if (!in)
+ {
+ std::cerr << "scheme_error.scm not found" << std::endl;
+ return -1;
+ }
+
+ // Ignore the BOM marking the beginning of a UTF-8 file in Windows
+ char c = in.peek();
+ if (c == '\xef')
+ {
+ char s[3];
+ in >> s[0] >> s[1] >> s[2];
+ s[3] = '\0';
+ if (s != std::string("\xef\xbb\xbf"))
+ {
+ std::cerr << "unexpected characters in file" << std::endl;
+ return -1;
+ }
+ }
+
+ scheme::interpreter factorial(in, filename);
+ return 0;
+}
+
+

Modified: trunk/libs/spirit/example/scheme/example/sexpr/out.txt
==============================================================================
--- trunk/libs/spirit/example/scheme/example/sexpr/out.txt (original)
+++ trunk/libs/spirit/example/scheme/example/sexpr/out.txt 2010-04-18 22:31:08 EDT (Sun, 18 Apr 2010)
@@ -1,2 +1,2 @@
-success: (123.45 true false 255 63 "this is a € string" "Τη γλώσσα μου έδωσαν ελληνική" b0123456789abcdef123456789abcdef (92 ("another string" apple Sîne)))
+success: (123.45 true false 255 63 "this is a € string" "Τη γλώσσα μου έδωσαν ελληνική" #0123456789abcdef123456789abcdef# (92 ("another string" apple Sîne)))
 

Modified: trunk/libs/spirit/example/scheme/example/sexpr/sexpr_test.txt
==============================================================================
--- trunk/libs/spirit/example/scheme/example/sexpr/sexpr_test.txt (original)
+++ trunk/libs/spirit/example/scheme/example/sexpr/sexpr_test.txt 2010-04-18 22:31:08 EDT (Sun, 18 Apr 2010)
@@ -6,7 +6,7 @@
     077
     "this is a \u20AC string" ; A UTF-8 string
     "Τη γλώσσα μου έδωσαν ελληνική" ; Another UTF-8 string
- b0123456789ABCDEF0123456789abcdef ; A binary stream
+ #0123456789ABCDEF0123456789abcdef# ; A binary stream
     (
         92 ("another string" apple Sîne)
     )

Modified: trunk/libs/spirit/example/scheme/input/parse_sexpr_impl.hpp
==============================================================================
--- trunk/libs/spirit/example/scheme/input/parse_sexpr_impl.hpp (original)
+++ trunk/libs/spirit/example/scheme/input/parse_sexpr_impl.hpp 2010-04-18 22:31:08 EDT (Sun, 18 Apr 2010)
@@ -69,7 +69,9 @@
         scheme::input::sexpr_white_space<iterator_type> ws;
 
         using boost::spirit::qi::phrase_parse;
- return phrase_parse(first, last, +p, ws, result);
+ bool ok = phrase_parse(first, last, +p, ws, result);
+ result.tag(1); // line
+ return ok;
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -112,7 +114,9 @@
         iterator_type last(rng.end());
 
         using boost::spirit::qi::phrase_parse;
- return phrase_parse(first, last, +p, ws, result);
+ bool ok = phrase_parse(first, last, +p, ws, result);
+ result.tag(1); // line
+ return ok;
     }
 
     ///////////////////////////////////////////////////////////////////////////

Modified: trunk/libs/spirit/example/scheme/input/sexpr.hpp
==============================================================================
--- trunk/libs/spirit/example/scheme/input/sexpr.hpp (original)
+++ trunk/libs/spirit/example/scheme/input/sexpr.hpp 2010-04-18 22:31:08 EDT (Sun, 18 Apr 2010)
@@ -119,7 +119,7 @@
                     | int_
                     ;
 
- byte_str = lexeme[no_case['b'] > +hex2];
+ byte_str = lexeme['#' > +hex2 > '#'];
 
             start.name("sexpr");
             start.name("sexpr");

Modified: trunk/libs/spirit/example/scheme/scheme/compiler.hpp
==============================================================================
--- trunk/libs/spirit/example/scheme/scheme/compiler.hpp (original)
+++ trunk/libs/spirit/example/scheme/scheme/compiler.hpp 2010-04-18 22:31:08 EDT (Sun, 18 Apr 2010)
@@ -23,27 +23,43 @@
 ///////////////////////////////////////////////////////////////////////////////
     struct scheme_exception : std::exception {};
 
- struct identifier_not_found : scheme_exception
+ struct compilation_error : std::exception
     {
         virtual const char* what() const throw()
         {
- return "scheme: Identifier not found";
+ return "scheme: Compilation error";
         }
     };
 
- struct duplicate_identifier : scheme_exception
+ struct identifier_expected : scheme_exception
     {
         virtual const char* what() const throw()
         {
- return "scheme: Duplicate identifier";
+ return "scheme: Identifier expected";
+ }
+ };
+
+ struct identifier_not_found : scheme_exception
+ {
+ std::string msg;
+ identifier_not_found(std::string const& id)
+ : msg("scheme: Identifier (" + id + ") not found") {}
+
+ virtual const char* what() const throw()
+ {
+ return msg.c_str();;
         }
     };
 
- struct unknown_expression : scheme_exception
+ struct duplicate_identifier : scheme_exception
     {
+ std::string msg;
+ duplicate_identifier(std::string const& id)
+ : msg("scheme: Duplicate identifier (" + id + ')') {}
+
         virtual const char* what() const throw()
         {
- return "scheme: Unknown_expression";
+ return "scheme: Duplicate identifier";
         }
     };
 
@@ -71,7 +87,7 @@
         void define(std::string const& name, Function const& f, int arity)
         {
             if (definitions.find(name) != definitions.end())
- throw duplicate_identifier();
+ throw duplicate_identifier(name);
             definitions[name] = std::make_pair(compiled_function(f), arity);
         }
 
@@ -87,6 +103,16 @@
             return std::make_pair((compiled_function*)0, 0);
         }
 
+ void undefine(std::string const& name)
+ {
+ definitions.erase(name);
+ }
+
+ bool defined(std::string const& name)
+ {
+ return definitions.find(name) != definitions.end();
+ }
+
         environment* parent() const { return outer; }
 
     private:
@@ -160,7 +186,7 @@
                 actor_list flist;
                 return (*r.first)(flist);
             }
- throw identifier_not_found();
+ throw identifier_not_found(name);
             return function();
         }
 
@@ -179,109 +205,111 @@
             std::vector<std::string> const& args,
             utree const& body) const
         {
- fragments.push_back(function());
- function& f = fragments.back();
- env.define(name, external_function(f), args.size());
- f = make_lambda(args, body);
- return f;
+ try
+ {
+ if (env.defined(name))
+ throw duplicate_identifier(name);
+ fragments.push_back(function());
+ function& f = fragments.back();
+ env.define(name, external_function(f), args.size());
+ f = make_lambda(args, body);
+ return f;
+ }
+ catch (compilation_error const&)
+ {
+ env.undefine(name);
+ throw;
+ }
         }
 
         template <typename Iterator>
         function operator()(boost::iterator_range<Iterator> const& range) const
         {
- try
- {
- std::string name(get_symbol(*range.begin()));
+ std::string name(get_symbol(*range.begin()));
 
- if (name == "define")
- {
- std::string fname;
- std::vector<std::string> args;
-
- Iterator i = range.begin(); ++i;
- if (i->which() == utree_type::list_type)
- {
- // (define (f x) ...body...)
- utree const& decl = *i++;
- Iterator di = decl.begin();
- fname = get_symbol(*di++);
- while (di != decl.end())
- args.push_back(get_symbol(*di++));
- }
- else
- {
- // (define f ...body...)
- fname = get_symbol(*i++);
-
- // (define f (lambda (x) ...body...))
- if (i->which() == utree_type::list_type
- && get_symbol((*i)[0]) == "lambda")
- {
- utree const& arg_names = (*i)[1];
- Iterator ai = arg_names.begin();
- while (ai != arg_names.end())
- args.push_back(get_symbol(*ai++));
- }
- }
-
- return define_function(fname, args, *i);
- }
+ if (name == "define")
+ {
+ std::string fname;
+ std::vector<std::string> args;
 
- if (name == "lambda")
+ Iterator i = range.begin(); ++i;
+ if (i->which() == utree_type::list_type)
                 {
- // (lambda (x) ...body...)
- Iterator i = range.begin(); ++i;
- utree const& arg_names = *i++;
- Iterator ai = arg_names.begin();
- std::vector<std::string> args;
- while (ai != arg_names.end())
- args.push_back(get_symbol(*ai++));
- return make_lambda(args, *i);
+ // (define (f x) ...body...)
+ utree const& decl = *i++;
+ Iterator di = decl.begin();
+ fname = get_symbol(*di++);
+ while (di != decl.end())
+ args.push_back(get_symbol(*di++));
                 }
-
- // (f x)
- std::pair<compiled_function*, int> r = env.find(name);
- if (r.first)
+ else
                 {
- actor_list flist;
- Iterator i = range.begin(); ++i;
- for (; i != range.end(); ++i)
- flist.push_back(
- compile(*i, env, fragments, line, source_file));
+ // (define f ...body...)
+ fname = get_symbol(*i++);
 
- // Arity check
- if (r.second < 0) // non-fixed arity
+ // (define f (lambda (x) ...body...))
+ if (i->which() == utree_type::list_type
+ && get_symbol((*i)[0]) == "lambda")
                     {
- if (int(flist.size()) < -r.second)
- throw incorrect_arity();
+ utree const& arg_names = (*i)[1];
+ Iterator ai = arg_names.begin();
+ while (ai != arg_names.end())
+ args.push_back(get_symbol(*ai++));
                     }
- else // fixed arity
- {
- if (int(flist.size()) != r.second)
- throw incorrect_arity();
- }
- return (*r.first)(flist);
                 }
 
- throw unknown_expression();
+ return define_function(fname, args, *i);
             }
 
- catch (scheme_exception const& x)
+ if (name == "lambda")
             {
- if (source_file != "")
- std::cerr << source_file;
+ // (lambda (x) ...body...)
+ Iterator i = range.begin(); ++i;
+ utree const& arg_names = *i++;
+ Iterator ai = arg_names.begin();
+ std::vector<std::string> args;
+ while (ai != arg_names.end())
+ args.push_back(get_symbol(*ai++));
+ return make_lambda(args, *i);
+ }
 
- if (line != -1)
- std::cerr << '(' << line << ')';
+ // (f x)
+ std::pair<compiled_function*, int> r = env.find(name);
+ if (r.first)
+ {
+ actor_list flist;
+ Iterator i = range.begin(); ++i;
+ for (; i != range.end(); ++i)
+ flist.push_back(
+ compile(*i, env, fragments, line, source_file));
 
- std::cerr << " : Error! " << x.what() << std::endl;
+ // Arity check
+ if (r.second < 0) // non-fixed arity
+ {
+ if (int(flist.size()) < -r.second)
+ throw incorrect_arity();
+ }
+ else // fixed arity
+ {
+ if (int(flist.size()) != r.second)
+ throw incorrect_arity();
+ }
+ return (*r.first)(flist);
+ }
+ else
+ {
+ throw identifier_not_found(name);
             }
 
+ // Just return the list $$$ TODO $$$ how do we disambiguate lists
+ // and function calls?
             return function();
         }
 
         static std::string get_symbol(utree const& s)
         {
+ if (s.which() != utree_type::symbol_type)
+ throw identifier_expected();
             utf8_symbol_range symbol = s.as<utf8_symbol_range>();
             return std::string(symbol.begin(), symbol.end());
         }
@@ -296,8 +324,25 @@
     {
         int line = (ast.which() == utree_type::list_type)
             ? ast.tag() : parent_line;
- return utree::visit(ast,
- compiler(env, fragments, line, source_file));
+
+ try
+ {
+ return utree::visit(ast,
+ compiler(env, fragments, line, source_file));
+ }
+ catch (scheme_exception const& x)
+ {
+ if (source_file != "")
+ std::cerr << source_file;
+
+ if (line != -1)
+ std::cerr << '(' << line << ')';
+
+ std::cerr << " : Error! " << x.what() << std::endl;
+ throw compilation_error();
+ }
+
+ return function();
     }
 
     void compile_all(
@@ -311,8 +356,15 @@
             ? ast.tag() : 1;
         BOOST_FOREACH(utree const& program, ast)
         {
- scheme::function
+ scheme::function f;
+ try
+ {
                 f = compile(program, env, fragments, line, source_file);
+ }
+ catch (compilation_error const& x)
+ {
+ continue; // try the next expression
+ }
             results.push_back(f);
         }
     }
@@ -341,15 +393,10 @@
             if (outer == 0)
                 build_basic_environment(env);
 
- if (input::parse_sexpr_list(in, program))
+ if (input::parse_sexpr_list(in, program, source_file))
             {
                 compile_all(program, env, flist, fragments, source_file);
             }
- else
- {
- // $$$ Use exceptions $$$
- BOOST_ASSERT(false);
- }
         }
 
         interpreter(utree const& program, environment* outer = 0)
@@ -364,6 +411,11 @@
             return flist.back()(args);
         }
 
+ bool empty() const
+ {
+ return flist.empty() || flist.back().empty();
+ }
+
         environment env;
         utree program;
         actor_list fragments;

Modified: trunk/libs/spirit/example/scheme/scheme/interpreter.hpp
==============================================================================
--- trunk/libs/spirit/example/scheme/scheme/interpreter.hpp (original)
+++ trunk/libs/spirit/example/scheme/scheme/interpreter.hpp 2010-04-18 22:31:08 EDT (Sun, 18 Apr 2010)
@@ -171,6 +171,45 @@
     function const _10 = arg(10);
 
     ///////////////////////////////////////////////////////////////////////////
+ // variable arguments.
+ // Collects the arguments from n to last in a utree list.
+ ///////////////////////////////////////////////////////////////////////////
+ struct vararg_function : actor<vararg_function>
+ {
+ std::size_t n;
+ vararg_function(std::size_t n) : n(n) {}
+
+ utree eval(args_type args) const
+ {
+ utree result;
+ for (std::size_t i = n; i < args.size(); ++i)
+ result.push_back(boost::ref(args[i]));
+ return result;
+ }
+ };
+
+ struct vararg
+ {
+ typedef function result_type;
+ function operator()(std::size_t n) const
+ {
+ return function(vararg_function(n));
+ }
+ };
+
+ vararg const varg = {};
+ function const _1_ = varg(0);
+ function const _2_ = varg(1);
+ function const _3_ = varg(2);
+ function const _4_ = varg(3);
+ function const _5_ = varg(4);
+ function const _6_ = varg(5);
+ function const _7_ = varg(6);
+ function const _8_ = varg(7);
+ function const _9_ = varg(8);
+ function const _10_ = varg(10);
+
+ ///////////////////////////////////////////////////////////////////////////
     // composite
     ///////////////////////////////////////////////////////////////////////////
     template <typename Derived>

Added: trunk/libs/spirit/example/scheme/test/scheme/scheme_error.scm
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/example/scheme/test/scheme/scheme_error.scm 2010-04-18 22:31:08 EDT (Sun, 18 Apr 2010)
@@ -0,0 +1,21 @@
+blah ; blah not found
+
+(define
+ (foo x)
+ (+ x 456))
+
+(define
+ (bar x)
+ (+ x y)) ; y not found
+
+(foo 123)
+(foo z) ; z not found
+
+(define foo 123) ; redefinition
+
+(foo 123 456) ; incorrect arity
+
+(bar 999) ; bar should not be found
+
+
+


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk