|
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