1 /*
2  * Copyright (c) 2003-2018, John Wiegley.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  *
15  * - Neither the name of New Artisans LLC nor the names of its
16  *   contributors may be used to endorse or promote products derived from
17  *   this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /**
33  * @addtogroup expr
34  */
35 
36 /**
37  * @file   expr.h
38  * @author John Wiegley
39  *
40  * @ingroup expr
41  */
42 #ifndef _EXPR_H
43 #define _EXPR_H
44 
45 #include "exprbase.h"
46 #include "value.h"
47 
48 namespace ledger {
49 
50 class expr_t : public expr_base_t<value_t>
51 {
52   class parser_t;
53   typedef expr_base_t<value_t> base_type;
54 
55 public:
56   struct token_t;
57   class op_t;
58   typedef intrusive_ptr<op_t>       ptr_op_t;
59   typedef intrusive_ptr<const op_t> const_ptr_op_t;
60 
61   enum check_expr_kind_t {
62     EXPR_GENERAL,
63     EXPR_ASSERTION,
64     EXPR_CHECK
65   };
66 
67   typedef std::pair<expr_t, check_expr_kind_t> check_expr_pair;
68   typedef std::list<check_expr_pair>           check_expr_list;
69 
70 protected:
71   ptr_op_t ptr;
72 
73 public:
74   expr_t();
75   expr_t(const expr_t& other);
76   expr_t(ptr_op_t _ptr, scope_t * _context = NULL);
77 
78   expr_t(const string& _str, const parse_flags_t& flags = PARSE_DEFAULT);
79   expr_t(std::istream& in, const parse_flags_t& flags = PARSE_DEFAULT);
80 
81   virtual ~expr_t();
82 
83   expr_t& operator=(const expr_t& _expr);
84 
85   virtual operator bool() const throw();
86 
87   ptr_op_t get_op() throw();
88 
89   void parse(const string& str, const parse_flags_t& flags = PARSE_DEFAULT) {
90     std::istringstream stream(str);
91     return parse(stream, flags, str);
92   }
93 
94   virtual void    parse(std::istream&           in,
95                         const parse_flags_t&    flags           = PARSE_DEFAULT,
96                         const optional<string>& original_string = none);
97   virtual void    compile(scope_t& scope);
98   virtual value_t real_calc(scope_t& scope);
99 
100   bool            is_constant() const;
101   value_t&        constant_value();
102   const value_t&  constant_value() const;
103   bool            is_function() const;
104   func_t&         get_function();
105 
106   virtual string  context_to_str() const;
107   virtual void    print(std::ostream& out) const;
108   virtual void    dump(std::ostream& out) const;
109 };
110 
111 /**
112  * Dealing with expr pointers tucked into value objects.
113  */
is_expr(const value_t & val)114 inline bool is_expr(const value_t& val) {
115   return val.is_any() && val.as_any().type() == typeid(expr_t::ptr_op_t);
116 }
117 
118 expr_t::ptr_op_t as_expr(const value_t& val);
119 void             set_expr(value_t& val, expr_t::ptr_op_t op);
120 value_t          expr_value(expr_t::ptr_op_t op);
121 
122 // A merged expression allows one to set an expression term, "foo", and
123 // a base expression, "bar", and then merge in later expressions that
124 // utilize foo.  For example:
125 //
126 //    foo: bar
127 //  merge: foo * 10
128 //  merge: foo + 20
129 //
130 // When this expression is finally compiled, the base and merged
131 // elements are written into this:
132 //
133 //   __tmp=(foo=bar; foo=foo*10; foo=foo+20);__tmp
134 //
135 // This allows users to select flags like -O, -B or -I at any time, and
136 // also combine flags such as -V and -A.
137 
138 class merged_expr_t : public expr_t
139 {
140 public:
141   string term;
142   string base_expr;
143   string merge_operator;
144 
145   std::list<string> exprs;
146 
147   merged_expr_t(const string& _term, const string& expr,
148                 const string& merge_op = ";")
expr_t()149     : expr_t(), term(_term), base_expr(expr), merge_operator(merge_op) {
150     TRACE_CTOR(merged_expr_t, "string, string, string");
151   }
~merged_expr_t()152   virtual ~merged_expr_t() {
153     TRACE_DTOR(merged_expr_t);
154   }
155 
set_term(const string & _term)156   void set_term(const string& _term) {
157     term = _term;
158   }
set_base_expr(const string & expr)159   void set_base_expr(const string& expr) {
160     base_expr = expr;
161   }
set_merge_operator(const string & merge_op)162   void set_merge_operator(const string& merge_op) {
163     merge_operator = merge_op;
164   }
165 
166   bool check_for_single_identifier(const string& expr);
167 
prepend(const string & expr)168   void prepend(const string& expr) {
169     if (! check_for_single_identifier(expr))
170       exprs.push_front(expr);
171   }
append(const string & expr)172   void append(const string& expr) {
173     if (! check_for_single_identifier(expr))
174       exprs.push_back(expr);
175   }
remove(const string & expr)176   void remove(const string& expr) {
177     exprs.remove(expr);
178   }
179 
180   virtual void compile(scope_t& scope);
181 };
182 
183 class call_scope_t;
184 value_t source_command(call_scope_t& scope);
185 
186 } // namespace ledger
187 
188 #endif // _EXPR_H
189