// This file is part of fityk program. Copyright (C) 2005 Marcin Wojdyr
// Licence: GNU General Public License version 2
// $Id: cmd.cpp 294 2007-05-16 03:18:25Z wojdyr $
#include <boost/spirit/core.hpp>
#include <boost/spirit/actor/assign_actor.hpp>
#include <boost/spirit/actor/push_back_actor.hpp>
#include <boost/spirit/actor/clear_actor.hpp>
#include <boost/spirit/utility/chset.hpp>
//#include <boost/spirit/utility/chset_operators.hpp>
#include <stdlib.h>
#include <utility>
#include <algorithm>
#include <limits.h>
#include "cmd.h"
#include "cmd2.h"
#include "cmd3.h"
#include "ui.h"
#include "var.h"
#include "sum.h"
#include "func.h"
#include "logic.h"
#include "settings.h"
#include "optional_suffix.h"
using namespace std;
using namespace boost::spirit;
using namespace cmdgram;
namespace {
void do_assign_var(char const* a, char const* b)
{
AL->assign_variable(string(t, 1), string(a,b));
outdated_plot=true; //TODO only if...
}
void do_assign_func(char const*, char const*)
{
t = AL->assign_func(t2, t, vt);
outdated_plot=true; //TODO only if function in @active
}
void do_assign_func_copy(char const*, char const*)
{
t = AL->assign_func_copy(t2, t);
outdated_plot=true; //TODO only if function in @active
}
void do_subst_func_param(char const* a, char const* b)
{
if (t == "F" || t == "Z") {
vector<string> const &names = AL->get_sum(ds_pref)->get_names(t[0]);
for (vector<string>::const_iterator i = names.begin();
i != names.end(); ++i)
AL->substitute_func_param(*i, t2, string(a,b));
}
else
AL->substitute_func_param(t, t2, string(a,b));
outdated_plot=true; //TODO only if...
}
void do_get_func_by_idx(char const* a, char const*)
{
//TODO replace it with ApplicationLogic::find_function_any()
vector<string> const &names = AL->get_sum(ds_pref)->get_names(*a);
int idx = (tmp_int >= 0 ? tmp_int : tmp_int + names.size());
if (!is_index(idx, names))
throw ExecuteError("There is no item with index " + S(tmp_int));
t = names[idx];
}
void do_assign_fz(char const*, char const*)
{
Sum* sum = AL->get_sum(tmp_int2);
assert(t3 == "F" || t3 == "Z");
if (!with_plus)
sum->remove_all_functions_from(t3[0]);
for (vector<string>::const_iterator i = vr.begin(); i != vr.end(); ++i)
sum->add_function_to(*i, t3[0]);
if (!with_plus)
AL->auto_remove_functions();
outdated_plot=true; //TODO only if ds_pref == @active
}
void add_fz_copy(char const* a, char const*)
{
vector<string> const &names = AL->get_sum(ds_pref)->get_names(*a);
for (vector<string>::const_iterator i=names.begin(); i != names.end(); ++i)
vr.push_back(AL->assign_func_copy("", *i));
}
void add_fz_links(char const* a, char const*)
{
vector<string> const &names = AL->get_sum(ds_pref)->get_names(*a);
vr.insert(vr.end(), names.begin(), names.end());
}
void do_remove_from_fz(char const* a, char const*)
{
assert(*a == 'F' || *a == 'Z');
AL->get_sum(ds_pref)->remove_function_from(t, *a);
AL->auto_remove_functions();
outdated_plot=true; //TODO only if ds_pref == @active
}
void do_delete(char const*, char const*)
{
if (!vn.empty()) {
sort(vn.begin(), vn.end());
reverse(vn.begin(), vn.end());
for (vector<int>::const_iterator i = vn.begin(); i != vn.end(); ++i)
AL->remove_ds(*i);
}
AL->delete_funcs_and_vars(vt);
outdated_plot=true; //TODO only if...
}
void do_quit(char const*, char const*) { throw ExitRequestedException(); }
void do_define_func(char const* a, char const* b)
{
string s = string(a,b);
UdfContainer::define(s);
}
void do_undefine_func(char const*, char const*)
{
for (vector<string>::const_iterator i = vt.begin(); i != vt.end(); ++i)
UdfContainer::undefine(*i);
}
void do_replot(char const*, char const*)
{
if (outdated_plot)
AL->get_ui()->draw_plot(2);
outdated_plot=false;
}
void do_temporary_set(char const*, char const*)
{
AL->get_settings()->set_temporary(t2, t);
}
void do_temporary_unset(char const*, char const*)
{
AL->get_settings()->clear_temporary();
}
} //namespace
struct CmdGrammar : public grammar<CmdGrammar>
{
template <typename ScannerT>
struct definition
{
definition(CmdGrammar const& /*self*/)
{
//these static constants for assign_a are workaround for assign_a
//problems, as proposed by Joao Abecasis at Spirit-general ML
//Message-ID: <435FB3DD.8030205@gmail.com>
//Subject: [Spirit-general] Re: weird assign_a(x,y) problem
static const bool true_ = true;
static const bool false_ = false;
static const int minus_one = -1;
static const char *empty = "";
compact_str
= lexeme_d['\'' >> (+~ch_p('\''))[assign_a(t)]
>> '\'']
| lexeme_d[+chset<>(anychar_p - chset<>(" \t\n\r;,"))] [assign_a(t)]
;
assign_var
= VariableLhsG [assign_a(t)]
>> '=' >> no_actions_d[FuncG] [&do_assign_var]
;
type_name
= lexeme_d[(upper_p >> +alnum_p)]
;
function_param
= lexeme_d[alpha_p >> *(alnum_p | '_')]
;
subst_func_param
= ( func_id
| ds_prefix >> (str_p("F")|"Z") [assign_a(t)]
)
>> "." >> function_param [assign_a(t2)]
>> "=" >> no_actions_d[FuncG] [&do_subst_func_param]
;
func_id // stores the function name in `t'
= FunctionLhsG [assign_a(t)]
| ds_prefix >> ((str_p("F[")|"Z[") >> int_p[assign_a(tmp_int)]
>> ch_p(']')) [&do_get_func_by_idx]
;
new_func_rhs //assigns function name to `t'
= type_name [assign_a(t)]
>> str_p("(") [clear_a(vt)]
>> !(
(!(function_param >> "=") >> no_actions_d[FuncG])
[push_back_a(vt)]
% ','
)
>> str_p(")") [&do_assign_func]
| "copy(" >> func_id >> str_p(")") [&do_assign_func_copy]
;
assign_func
= FunctionLhsG [assign_a(t2)] >> '=' >> new_func_rhs
;
assign_fz
= ds_prefix [assign_a(tmp_int2, ds_pref)]
>> (str_p("F")|"Z") [assign_a(t3)]
>> ( str_p("+=") [assign_a(with_plus, true_)]
| str_p("=") [assign_a(with_plus, false_)]
) [clear_a(vr)]
>> (('0' //nothing
| "copy(" >> ds_prefix >> (str_p("F")|"Z") [&add_fz_copy]
>> ")"
| ds_prefix >> (str_p("F")|"Z") [&add_fz_links]
| eps_p [assign_a(t2, empty)]
>> (func_id | new_func_rhs) [push_back_a(vr, t)]
) % '+') [&do_assign_fz]
;
remove_from_fz
= ds_prefix >> ((ch_p('F')|'Z') >> "-=" >> func_id)
[&do_remove_from_fz]
;
ds_prefix
= lexeme_d['@' >> uint_p [assign_a(ds_pref)]
>> '.']
| eps_p [assign_a(ds_pref, minus_one)]
;
define_func
= optional_suffix_p("def","ine")
>> (type_name >> '('
>> ((function_param >> !('=' >> no_actions_d[FuncG])
) % ',')
>> ')' >> '='
>> (((type_name >> '(' // CompoundFunction
>> (no_actions_d[FuncG] % ',')
>> ')'
) % '+')
| no_actions_d[FuncG] //Custom Function
)
) [&do_define_func]
;
temporary_set
= optional_suffix_p("w","ith")
>> ((+(lower_p | '-'))[assign_a(t2)]
>> '=' >> compact_str[&do_temporary_set]
) % ','
;
statement
= !temporary_set
>> ( (optional_suffix_p("del","ete")[clear_a(vt)][clear_a(vn)]
>> ( VariableLhsG [push_back_a(vt)]
| func_id [push_back_a(vt, t)]
| lexeme_d['@' >> uint_p[push_back_a(vn)]]) % ',')
[&do_delete]
| str_p("quit") [&do_quit]
| assign_var
| subst_func_param
| assign_func
| assign_fz
| remove_from_fz
| define_func
| (optional_suffix_p("undef","ine")[clear_a(vt)]
>> type_name[push_back_a(vt)]
% ',')[&do_undefine_func]
| cmd2G
| cmd3G
) [&do_temporary_unset]
;
multi
= (!( (!statement) % ';')
>> !('#' >> *~ch_p('\n'))) [&do_replot]
;
}
rule<ScannerT> assign_var, type_name, func_id, new_func_rhs, assign_func,
function_param, subst_func_param,
assign_fz, remove_from_fz, define_func,
ds_prefix, compact_str, temporary_set, statement, multi;
rule<ScannerT> const& start() const { return multi; }
};
} cmdG;
bool check_command_syntax(string const& str)
{
return parse(str.c_str(), no_actions_d[cmdG], space_p).full;
}
bool parse_and_execute_e(string const& str)
{
parse_info<> result = parse(str.c_str(), no_actions_d[cmdG], space_p);
if (result.full)
parse(str.c_str(), cmdG, space_p);
return result.full;
}
Commands::Status parse_and_execute(string const& str)
{
try {
bool r = parse_and_execute_e(str);
if (r)
return Commands::status_ok;
else {
AL->warn("Syntax error.");
return Commands::status_syntax_error;
}
} catch (ExecuteError &e) {
AL->get_settings()->clear_temporary();
AL->warn(string("Error: ") + e.what());
return Commands::status_execute_error;
}
}
string get_info_string(string const& s, bool full)
{
cmdgram::no_info_output = true;
try {
bool r = parse_and_execute_e((full ? "info+ " : "info ") + s);
if (!r)
throw ExecuteError("Syntax error in info argument");
} catch (ExecuteError &) {
cmdgram::no_info_output = false;
throw;
}
cmdgram::no_info_output = false;
return cmdgram::prepared_info;
}
syntax highlighted by Code2HTML, v. 0.9.1