1 // Copyright 2016-2021 Doug Moen
2 // Licensed under the Apache License, version 2.0
3 // See accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0
4 
5 #ifndef LIBCURV_ANALYSER_H
6 #define LIBCURV_ANALYSER_H
7 
8 #include <libcurv/meaning.h>
9 #include <libcurv/builtin.h>
10 
11 namespace curv {
12 
13 // Local analysis state that changes when entering a new name-binding scope.
14 struct Environ
15 {
16     Environ* parent_;
17     Source_State& sstate_;
18     slot_t frame_nslots_;
19     slot_t frame_maxslots_;
20 
21     // constructor for root environment of a source file
EnvironEnviron22     Environ(Source_State& analyser)
23     :
24         parent_(nullptr),
25         sstate_(analyser),
26         frame_nslots_(0),
27         frame_maxslots_(0)
28     {}
29 
30     // constructor for child environment. parent is != nullptr.
EnvironEnviron31     Environ(Environ* parent)
32     :
33         parent_(parent),
34         sstate_(parent->sstate_),
35         frame_nslots_(0),
36         frame_maxslots_(0)
37     {}
38 
make_slotEnviron39     slot_t make_slot()
40     {
41         slot_t slot = frame_nslots_++;
42         if (frame_maxslots_ < frame_nslots_)
43             frame_maxslots_ = frame_nslots_;
44         return slot;
45     }
46 
47     Shared<Meaning> lookup(const Identifier& id);
48     Unique<const Locative> lookup_lvar(const Identifier& id, unsigned edepth);
49     virtual Shared<Meaning> single_lookup(const Identifier&) = 0;
50     virtual Unique<const Locative> single_lvar_lookup(const Identifier&);
51 };
52 
53 struct Builtin_Environ : public Environ
54 {
55 protected:
56     const Namespace& names;
57 public:
Builtin_EnvironBuiltin_Environ58     Builtin_Environ(const Namespace& n, Source_State& a)
59     :
60         Environ(a),
61         names(n)
62     {}
63     virtual Shared<Meaning> single_lookup(const Identifier&);
64 };
65 
66 // Interp is the second argument of Phrase::analyse().
67 // It means "interpretation": how to interpret the phrase, relative to the
68 // environment.
69 //
70 // 'edepth' is the number of nested environments surrounding the phrase
71 // in which an lvar (a local variable on the left side of a := statement)
72 // can be looked up. The parent phrase computes an edepth for each of its
73 // subphrases. Ultimately the edepth is passed to Environ::lvar_lookup().
74 // * If PH is a phrase that binds local variables (let, where, for),
75 //   the body of PH has PH's edepth + 1.
76 // * Otherwise, if PH is a phrase with sequential order of evaluation for each
77 //   of its subphrases (eg, semicolon or do phrase), then the edepth of each
78 //   subphrase is the same as its parent.
79 // * The common case is a compound phrase that doesn't have a defined order
80 //   of evaluation. In this case, the edepth of each subphrase is 0, which means
81 //   that you can't assign local variables inside that phrase that are defined
82 //   outside that phrase. If you could do so, then the order of evaluation
83 //   would be exposed. For example, the + operator is commutative, so A+B is
84 //   equivalent to B+A, so we don't support assignment inside a plus phrase.
85 struct Interp
86 {
87 private:
88     unsigned edepth_ = 0;
89     bool is_expr_ = true;
InterpInterp90     Interp(unsigned d, bool ie) : edepth_(d), is_expr_(ie) {}
91 public:
exprInterp92     static Interp expr() { return {0, true}; }
93     static Interp stmt(unsigned d = 0) { return {d, false}; }
edepthInterp94     int edepth() const { return edepth_; }
is_exprInterp95     bool is_expr() const { return is_expr_; }
is_stmtInterp96     bool is_stmt() const { return !is_expr_; }
deepenInterp97     Interp deepen() const { return {edepth_+1, is_expr_}; }
to_exprInterp98     Interp to_expr() const { return {edepth_, true}; }
to_stmtInterp99     Interp to_stmt() const { return {edepth_, false}; }
100 };
101 
102 // Analyse a Phrase, throw an error if it is not an Operation.
103 Shared<Operation> analyse_op(const Phrase& ph, Environ& env,
104     Interp terp=Interp::expr());
105 
106 // Evaluate the phrase as a constant expression in the builtin environment.
107 Value std_eval(const Phrase& ph, Environ& env);
108 
109 } // namespace
110 #endif // header guard
111