//
// aegis - project change supervisor
// Copyright (C) 1997, 1999, 2002-2008 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include
#include // for assert
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PAIR(a, b) ((a) * rpt_value_type_MAX + (b))
tree_mul::~tree_mul()
{
}
tree_mul::tree_mul(const tree::pointer &a1, const tree::pointer &a2) :
tree_diadic(a1, a2)
{
}
tree::pointer
tree_mul::create(const tree::pointer &a1, const tree::pointer &a2)
{
return pointer(new tree_mul(a1, a2));
}
tree::pointer
tree_mul::create_l(const tree_list &args)
{
function_needs_two("*", args);
return create(args[0], args[1]);
}
rpt_value::pointer
tree_mul::evaluate(string_ty *path_unres, string_ty *path, string_ty *path_res,
struct stat *st) const
{
//
// evaluate the left hand side
//
trace(("tree_mul::evaluate()\n"));
rpt_value::pointer v1 =
get_left()->evaluate(path_unres, path, path_res, st);
if (v1->is_an_error())
{
trace(("}\n"));
return v1;
}
//
// coerce the left hand side to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer v1a = rpt_value::arithmetic(v1);
//
// evaluate the right hand side
//
rpt_value::pointer v2 =
get_right()->evaluate(path_unres, path, path_res, st);
if (v2->is_an_error())
{
trace(("}\n"));
return v2;
}
//
// coerce the right hand side to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer v2a = rpt_value::arithmetic(v2);
//
// the type of the result depends on
// the types of the operands
//
{
rpt_value_integer *v1a_ip =
dynamic_cast(v1a.get());
if (v1a_ip)
{
long v1n = v1a_ip->query();
{
rpt_value_integer *v2a_ip =
dynamic_cast(v2a.get());
if (v2a_ip)
{
long v2n = v2a_ip->query();
return rpt_value_integer::create(v1n * v2n);
}
}
{
rpt_value_real *v2a_rp =
dynamic_cast(v2a.get());
if (v2a_rp)
{
double v2n = v2a_rp->query();
return rpt_value_real::create(v1n * v2n);
}
}
}
}
{
rpt_value_real *v1a_rp = dynamic_cast(v1a.get());
if (v1a_rp)
{
double v1n = v1a_rp->query();
{
rpt_value_integer *v2a_ip =
dynamic_cast(v2a.get());
if (v2a_ip)
{
long v2n = v2a_ip->query();
return rpt_value_real::create(v1n * v2n);
}
}
{
rpt_value_real *v2a_rp =
dynamic_cast(v2a.get());
if (v2a_rp)
{
double v2n = v2a_rp->query();
return rpt_value_real::create(v1n * v2n);
}
}
}
}
sub_context_ty sc;
sc.var_set_charstar("Name1", v1->name());
sc.var_set_charstar("Name2", v2->name());
nstring s(sc.subst_intl(i18n("illegal multiplication ($name1 * $name2)")));
return rpt_value_error::create(s);
}
tree::pointer
tree_mul::optimize()
const
{
tree::pointer tp = create(get_left()->optimize(), get_right()->optimize());
if (tp->constant())
tp = tp->optimize_constant();
return tp;
}
const char *
tree_mul::name()
const
{
return "*";
}
tree_divide::~tree_divide()
{
}
tree_divide::tree_divide(const tree::pointer &a1, const tree::pointer &a2) :
tree_diadic(a1, a2)
{
}
tree::pointer
tree_divide::create(const tree::pointer &a1, const tree::pointer &a2)
{
return pointer(new tree_divide(a1, a2));
}
tree::pointer
tree_divide::create_l(const tree_list &args)
{
function_needs_two("/", args);
return create(args[0], args[1]);
}
static rpt_value::pointer
divide_by_zero_error()
{
sub_context_ty sc;
nstring s(sc.subst_intl(i18n("division by zero")));
return rpt_value_error::create(s);
}
rpt_value::pointer
tree_divide::evaluate(string_ty *path_unres, string_ty *path,
string_ty *path_res, struct stat *st) const
{
//
// evaluate the left hand side
//
trace(("divide::evaluate()\n"));
rpt_value::pointer v1 =
get_left()->evaluate(path_unres, path, path_res, st);
if (v1->is_an_error())
{
trace(("}\n"));
return v1;
}
//
// coerce the left hand side to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer v1a = rpt_value::arithmetic(v1);
//
// evaluate the right hand side
//
rpt_value::pointer v2 =
get_right()->evaluate(path_unres, path, path_res, st);
if (v2->is_an_error())
{
trace(("}\n"));
return v2;
}
//
// coerce the right hand side to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer v2a = rpt_value::arithmetic(v2);
//
// the type of the result depends on
// the types of the operands
//
rpt_value_integer *v1a_ip = dynamic_cast(v1a.get());
if (v1a_ip)
{
long num = v1a_ip->query();
rpt_value_integer *v2a_ip =
dynamic_cast(v2a.get());
if (v2a_ip)
{
long den = v2a_ip->query();
if (den == 0)
return divide_by_zero_error();
return rpt_value_integer::create(num / den);
}
rpt_value_real *v2a_rp = dynamic_cast(v2a.get());
if (v2a_rp)
{
double den = v2a_rp->query();
if (den == 0)
return divide_by_zero_error();
return rpt_value_real::create(num / den);
}
}
rpt_value_real *v1a_rp = dynamic_cast(v1a.get());
if (v1a_rp)
{
double num = v1a_rp->query();
rpt_value_integer *v2a_ip =
dynamic_cast(v2a.get());
if (v2a_ip)
{
long den = v2a_ip->query();
if (den == 0)
return divide_by_zero_error();
return rpt_value_real::create(num / den);
}
rpt_value_real *v2a_rp = dynamic_cast(v2a.get());
if (v2a_rp)
{
double den = v2a_rp->query();
if (den == 0)
return divide_by_zero_error();
return rpt_value_real::create(num / den);
}
}
sub_context_ty sc;
sc.var_set_charstar("Name1", v1a->name());
sc.var_set_charstar("Name2", v2a->name());
nstring s(sc.subst_intl(i18n("illegal division ($name1 / $name2)")));
return rpt_value_error::create(s);
}
tree::pointer
tree_divide::optimize()
const
{
tree::pointer tp = create(get_left()->optimize(), get_right()->optimize());
if (tp->constant())
tp = tp->optimize_constant();
return tp;
}
const char *
tree_divide::name()
const
{
return "/";
}
tree_mod::~tree_mod()
{
}
tree_mod::tree_mod(const tree::pointer &a1, const tree::pointer &a2) :
tree_diadic(a1, a2)
{
}
tree::pointer
tree_mod::create(const tree::pointer &a1, const tree::pointer &a2)
{
return pointer(new tree_mod(a1, a2));
}
tree::pointer
tree_mod::create_l(const tree_list &args)
{
function_needs_two("%", args);
return create(args[0], args[1]);
}
static rpt_value::pointer
modulo_by_zero_error()
{
sub_context_ty sc;
nstring s(sc.subst_intl(i18n("modulo by zero")));
return rpt_value_error::create(s);
}
rpt_value::pointer
tree_mod::evaluate(string_ty *path_unres, string_ty *path,
string_ty *path_res, struct stat *st) const
{
//
// evaluate the left hand side
//
trace(("mod::evaluate()\n"));
rpt_value::pointer v1 =
get_left()->evaluate(path_unres, path, path_res, st);
if (v1->is_an_error())
{
trace(("}\n"));
return v1;
}
//
// coerce the left hand side to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer v1a = rpt_value::arithmetic(v1);
//
// evaluate the right hand side
//
rpt_value::pointer v2 =
get_right()->evaluate(path_unres, path, path_res, st);
if (v2->is_an_error())
{
trace(("}\n"));
return v2;
}
//
// coerce the right hand side to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer v2a = rpt_value::arithmetic(v2);
//
// the type of the result depends on
// the types of the operands
//
rpt_value_integer *v1a_ip = dynamic_cast(v1a.get());
if (v1a_ip)
{
long num = v1a_ip->query();
rpt_value_integer *v2a_ip =
dynamic_cast(v2a.get());
if (v2a_ip)
{
long den = v2a_ip->query();
if (den == 0)
return modulo_by_zero_error();
return rpt_value_integer::create(num % den);
}
rpt_value_real *v2a_rp = dynamic_cast(v2a.get());
if (v2a_rp)
{
double den = v2a_rp->query();
if (den == 0)
return modulo_by_zero_error();
return rpt_value_real::create(fmod(num, den));
}
}
rpt_value_real *v1a_rp = dynamic_cast(v1a.get());
if (v1a_rp)
{
double num = v1a_rp->query();
rpt_value_integer *v2a_ip =
dynamic_cast(v2a.get());
if (v2a_ip)
{
long den = v2a_ip->query();
if (den == 0)
return modulo_by_zero_error();
return rpt_value_real::create(fmod(num, den));
}
rpt_value_real *v2a_rp = dynamic_cast(v2a.get());
if (v2a_rp)
{
double den = v2a_rp->query();
if (den == 0)
return modulo_by_zero_error();
return rpt_value_real::create(fmod(num, den));
}
}
sub_context_ty sc;
sc.var_set_charstar("Name1", v1a->name());
sc.var_set_charstar("Name2", v2a->name());
// xgettext:no-c-format
nstring s(sc.subst_intl(i18n("illegal modulo ($name1 % $name2)")));
return rpt_value_error::create(s);
}
tree::pointer
tree_mod::optimize()
const
{
tree::pointer tp = create(get_left()->optimize(), get_right()->optimize());
if (tp->constant())
tp = tp->optimize_constant();
return tp;
}
const char *
tree_mod::name()
const
{
return "%";
}
tree_neg::~tree_neg()
{
}
tree_neg::tree_neg(const tree::pointer &a_arg) :
tree_monadic(a_arg)
{
}
tree::pointer
tree_neg::create(const tree::pointer &a_arg)
{
return pointer(new tree_neg(a_arg));
}
tree::pointer
tree_neg::create_l(const tree_list &args)
{
function_needs_one("-", args);
return create(args[0]);
}
rpt_value::pointer
tree_neg::evaluate(string_ty *path_unres, string_ty *path, string_ty *path_res,
struct stat *st) const
{
//
// evaluate the argument
//
trace(("neg::evaluate()\n"));
rpt_value::pointer v1 = get_arg()->evaluate(path_unres, path, path_res, st);
if (v1->is_an_error())
{
trace(("}\n"));
return v1;
}
//
// coerce the argument to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer v2 = rpt_value::arithmetic(v1);
//
// the type of the result depends on
// the types of the argument
//
rpt_value_integer *v2_ip = dynamic_cast(v2.get());
if (v2_ip)
{
long n = v2_ip->query();
return rpt_value_integer::create(-n);
}
rpt_value_real *v2_rp = dynamic_cast(v2.get());
if (v2_rp)
{
double n = v2_rp->query();
return rpt_value_real::create(-n);
}
sub_context_ty sc;
sc.var_set_charstar("Name", v2->name());
nstring s(sc.subst_intl(i18n("illegal negative ($name)")));
return rpt_value_error::create(s);
}
tree::pointer
tree_neg::optimize()
const
{
tree::pointer tp = create(get_arg()->optimize());
if (tp->constant())
tp = tp->optimize_constant();
return tp;
}
const char *
tree_neg::name()
const
{
return "-";
}
tree_pos::~tree_pos()
{
}
tree_pos::tree_pos(const tree::pointer &a_arg) :
tree_monadic(a_arg)
{
}
tree::pointer
tree_pos::create(const tree::pointer &a_arg)
{
return pointer(new tree_pos(a_arg));
}
tree::pointer
tree_pos::create_l(const tree_list &args)
{
function_needs_one("+", args);
return create(args[0]);
}
rpt_value::pointer
tree_pos::evaluate(string_ty *path_unres, string_ty *path, string_ty *path_res,
struct stat *st) const
{
//
// evaluate the argument
//
trace(("pos::evaluate()\n"));
rpt_value::pointer v1 = get_arg()->evaluate(path_unres, path, path_res, st);
if (v1->is_an_error())
return v1;
//
// coerce the argument to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer v2 = rpt_value::arithmetic(v1);
//
// the type of the result depends on
// the types of the argument
//
if
(
!dynamic_cast(v2.get())
&&
!dynamic_cast(v2.get())
)
{
sub_context_ty sc;
sc.var_set_charstar("Name", v2->name());
nstring s(sc.subst_intl(i18n("illegal positive ($name)")));
return rpt_value_error::create(s);
}
return v2;
}
tree::pointer
tree_pos::optimize()
const
{
tree::pointer tp = create(get_arg()->optimize());
if (tp->constant())
tp = tp->optimize_constant();
return tp;
}
const char *
tree_pos::name()
const
{
return "+";
}
tree_plus::~tree_plus()
{
}
tree_plus::tree_plus(const tree::pointer &a1, const tree::pointer &a2) :
tree_diadic(a1, a2)
{
}
tree::pointer
tree_plus::create(const tree::pointer &a1, const tree::pointer &a2)
{
return pointer(new tree_plus(a1, a2));
}
tree::pointer
tree_plus::create_l(const tree_list &args)
{
function_needs_two("+", args);
return create(args[0], args[1]);
}
rpt_value::pointer
tree_plus::evaluate(string_ty *path_unres, string_ty *path, string_ty *path_res,
struct stat *st) const
{
//
// evaluate the left hand side
//
trace(("plus::evaluate()\n"));
rpt_value::pointer lv1 =
get_left()->evaluate(path_unres, path, path_res, st);
if (lv1->is_an_error())
return lv1;
//
// coerce the left hand side to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer lv2 = rpt_value::arithmetic(lv1);
//
// evaluate the right hand side
//
rpt_value::pointer rv1 =
get_right()->evaluate(path_unres, path, path_res, st);
if (rv1->is_an_error())
return rv1;
//
// coerce the right hand side to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer rv2 = rpt_value::arithmetic(rv1);
//
// the type of the result depends on
// the types of the operands
//
{
rpt_value_integer *lv2_ip =
dynamic_cast(lv2.get());
if (lv2_ip)
{
long v1n = lv2_ip->query();
{
rpt_value_integer *rv2_ip =
dynamic_cast(rv2.get());
if (rv2_ip)
{
long v2n = rv2_ip->query();
return rpt_value_integer::create(v1n + v2n);
}
}
{
rpt_value_real *rv2_rp =
dynamic_cast(rv2.get());
if (rv2_rp)
{
double v2n = rv2_rp->query();
return rpt_value_real::create(v1n + v2n);
}
}
}
}
{
rpt_value_real *lv2_rp = dynamic_cast(lv2.get());
if (lv2_rp)
{
double v1n = lv2_rp->query();
{
rpt_value_integer *rv2_ip =
dynamic_cast(rv2.get());
if (rv2_ip)
{
long v2n = rv2_ip->query();
return rpt_value_real::create(v1n + v2n);
}
}
{
rpt_value_real *rv2_rp =
dynamic_cast(rv2.get());
if (rv2_rp)
{
double v2n = rv2_rp->query();
return rpt_value_real::create(v1n + v2n);
}
}
}
}
sub_context_ty sc;
sc.var_set_charstar("Name1", lv2->name());
sc.var_set_charstar("Name2", rv2->name());
nstring s(sc.subst_intl(i18n("illegal addition ($name1 + $name2)")));
return rpt_value_error::create(s);
}
tree::pointer
tree_plus::optimize()
const
{
tree::pointer tp = create(get_left()->optimize(), get_right()->optimize());
if (tp->constant())
tp = tp->optimize_constant();
return tp;
}
const char *
tree_plus::name()
const
{
return "+";
}
tree_subtract::~tree_subtract()
{
}
tree_subtract::tree_subtract(const tree::pointer &a1, const tree::pointer &a2) :
tree_diadic(a1, a2)
{
}
tree::pointer
tree_subtract::create(const tree::pointer &a1, const tree::pointer &a2)
{
return pointer(new tree_subtract(a1, a2));
}
tree::pointer
tree_subtract::create_l(const tree_list &args)
{
function_needs_two("-", args);
return create(args[0], args[1]);
}
rpt_value::pointer
tree_subtract::evaluate(string_ty *path_unres, string_ty *path,
string_ty *path_res, struct stat *st) const
{
//
// evaluate the left hand side
//
trace(("subtract::evaluate()\n"));
rpt_value::pointer lv1 =
get_left()->evaluate(path_unres, path, path_res, st);
if (lv1->is_an_error())
return lv1;
//
// coerce the left hand side to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer lv2 = rpt_value::arithmetic(lv1);
//
// evaluate the right hand side
//
rpt_value::pointer rv1 =
get_right()->evaluate(path_unres, path, path_res, st);
if (rv1->is_an_error())
return rv1;
//
// coerce the right hand side to an arithmetic type
// (will not give error if can't, will copy instead)
//
rpt_value::pointer rv2 = rpt_value::arithmetic(rv1);
//
// the type of the result depends on
// the types of the operands
//
{
rpt_value_integer *lv2_ip =
dynamic_cast(lv2.get());
if (lv2_ip)
{
long v1n = lv2_ip->query();
{
rpt_value_integer *rv2_ip =
dynamic_cast(rv2.get());
if (rv2_ip)
{
long v2n = rv2_ip->query();
return rpt_value_integer::create(v1n - v2n);
}
}
{
rpt_value_real *rv2_rp =
dynamic_cast(rv2.get());
if (rv2_rp)
{
double v2n = rv2_rp->query();
return rpt_value_real::create(v1n - v2n);
}
}
}
}
{
rpt_value_real *lv2_rp = dynamic_cast(lv2.get());
if (lv2_rp)
{
double v1n = lv2_rp->query();
{
rpt_value_integer *rv2_ip =
dynamic_cast(rv2.get());
if (rv2_ip)
{
long v2n = rv2_ip->query();
return rpt_value_real::create(v1n - v2n);
}
}
{
rpt_value_real *rv2_rp =
dynamic_cast(rv2.get());
if (rv2_rp)
{
double v2n = rv2_rp->query();
return rpt_value_real::create(v1n - v2n);
}
}
}
}
sub_context_ty sc;
sc.var_set_charstar("Name1", lv2->name());
sc.var_set_charstar("Name2", rv2->name());
nstring s(sc.subst_intl(i18n("illegal subtraction ($name1 - $name2)")));
return rpt_value_error::create(s);
}
tree::pointer
tree_subtract::optimize()
const
{
tree::pointer tp = create(get_left()->optimize(), get_right()->optimize());
if (tp->constant())
tp = tp->optimize_constant();
return tp;
}
const char *
tree_subtract::name()
const
{
return "-";
}
tree_join::~tree_join()
{
}
tree_join::tree_join(const tree::pointer &a1, const tree::pointer &a2) :
tree_diadic(a1, a2)
{
}
tree::pointer
tree_join::create(const tree::pointer &a1, const tree::pointer &a2)
{
return pointer(new tree_join(a1, a2));
}
tree::pointer
tree_join::create_l(const tree_list &args)
{
function_needs_two(":", args);
return create(args[0], args[1]);
}
rpt_value::pointer
tree_join::evaluate(string_ty *path_unres, string_ty *path, string_ty *path_res,
struct stat *st) const
{
//
// evaluate the left hand side
//
trace(("join::evaluate()\n"));
rpt_value::pointer v1 =
get_left()->evaluate(path_unres, path, path_res, st);
if (v1->is_an_error())
{
trace(("}\n"));
return v1;
}
//
// evaluate the right hand side
//
rpt_value::pointer v2 =
get_right()->evaluate(path_unres, path, path_res, st);
if (v2->is_an_error())
{
trace(("}\n"));
return v2;
}
//
// must be a string join
//
rpt_value::pointer v1s = rpt_value::stringize(v1);
rpt_value_string *v1sp = dynamic_cast(v1s.get());
rpt_value::pointer v2s = rpt_value::stringize(v2);
rpt_value_string *v2sp = dynamic_cast(v2s.get());
if (v1sp && v2sp)
{
nstring s = v1sp->query() + v2sp->query();
return rpt_value_string::create(s);
}
sub_context_ty sc;
sc.var_set_charstar("Name1", v1s->name());
sc.var_set_charstar("Name2", v2s->name());
nstring s(sc.subst_intl(i18n("illegal join ($name1 ## $name2)")));
return rpt_value_error::create(s);
}
tree::pointer
tree_join::optimize()
const
{
tree::pointer tp = create(get_left()->optimize(), get_right()->optimize());
if (tp->constant())
tp = tp->optimize_constant();
return tp;
}
const char *
tree_join::name()
const
{
return ":";
}