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