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_FRAME_H 6 #define LIBCURV_FRAME_H 7 8 #include <libcurv/tail_array.h> 9 #include <libcurv/value.h> 10 #include <libcurv/slot.h> 11 #include <libcurv/module.h> 12 13 namespace curv { 14 15 struct Context; 16 struct Frame_Base; 17 struct Function; 18 struct Operation; 19 struct Phrase; 20 struct String_Ref; 21 struct System; 22 struct Source_State; 23 24 /// A Frame is an evaluation context. 25 /// 26 /// You can think of a Frame as containing all of the registers used 27 /// by the Curv virtual machine. 28 /// 29 /// A program (source file) has a frame for evaluating the top level 30 /// program expression. 31 /// Calls to builtin and user-defined functions have call frames. 32 using Frame = Tail_Array<Frame_Base>; 33 34 struct Frame_Base 35 { 36 // sstate_ contains shared state for processing the current source file, 37 // and provides handles to global state. 38 // A reference is stored in every Frame: consider this a VM register. 39 Source_State& sstate_; 40 41 /// Frames are linked into a stack. This is metadata used for printing 42 /// a stack trace and by the debugger. It is not used during evaluation. 43 Frame* parent_frame_; 44 45 /// Slot array containing the values of nonlocal bindings. 46 /// 47 /// This is: 48 /// * the slot array of a Closure value, for a function call frame. 49 /// * nullptr, for a builtin function call, or a program frame. 50 Module* nonlocals_; 51 52 // Registers used by tail_eval_frame and Operation::tail_eval. 53 // next_op_ is the next Operation to be executed by the tail-evaluation 54 // interpreter loop, or it is nullptr, in which case result_ holds the 55 // evaluation result. 56 const Operation* next_op_; 57 Value result_; 58 59 // If this is a function call frame, then `func_` is the function that 60 // was called. Otherwise, nullptr. Used to initialize caller_. 61 // Used to print stack traces (At_Phrase only). 62 // When calling a Closure, a counted reference to `func_` keeps 63 // the 'nonlocals_' and 'next_op_' objects alive. 64 Shared<const Function> func_; 65 66 // If this is a function call frame (call_phrase_ != nullptr), then caller_ 67 // is a function whose definition lexically encloses the call_phrase_. 68 // Otherwise it is nullptr. Used to print stack traces. 69 Shared<const Function> caller_; 70 71 /// If this is a function call frame, then call_phrase_ is the source code 72 /// for the function call, otherwise it's nullptr. 73 /// 74 /// Program frames do not have a call_phrase_. If the call_phrase_ is null, 75 /// then the frame does not appear in a stack trace. 76 /// 77 /// In the common case, *call_phrase_ is a Call_Phrase. However, in the 78 /// case of a builtin function B that takes a function F as an argument, 79 /// there is no Call_Phrase in Curv source code where F is called, so 80 /// Call_Phrase is a best effort approximation, such as the call to B. 81 Shared<const Phrase> call_phrase_; 82 83 // Tail array, containing the slots used for local bindings: 84 // function arguments, block bindings and other local, temporary values. 85 using value_type = Value; 86 slot_t size_; 87 value_type array_[0]; 88 89 Value& operator[](slot_t i) 90 { 91 assert(i < size_); 92 return array_[i]; 93 } 94 95 Frame_Base(Source_State&, Frame* parent, 96 Shared<const Function> caller, Shared<const Phrase> call_phrase); 97 }; 98 99 // Shared state while analysing/evaluating a source file. 100 // Referenced by Environ (analysis) and Frame (evaluation). 101 struct Source_State 102 { 103 System& system_; 104 105 // If file_frame_ != nullptr, then we are processing a source file due to 106 // an evaluation-time call to `file`, and this is the Frame of the `file` 107 // call. It's used to add a stack trace to analysis time errors. 108 Frame* file_frame_; 109 110 // Have we already emitted a 'deprecated' warning for this topic? 111 // Used to prevent an avalanche of warning messages. 112 bool var_deprecated_ = false; 113 bool paren_empty_list_deprecated_ = false; 114 bool paren_list_deprecated_ = false; 115 bool not_deprecated_ = false; 116 bool dot_string_deprecated_ = false; 117 bool string_colon_deprecated_ = false; 118 bool where_deprecated_ = false; 119 bool bracket_index_deprecated_ = false; 120 bool at_deprecated_ = false; 121 Source_StateSource_State122 Source_State(System& sys, Frame* ff) : system_(sys), file_frame_(ff) {} 123 124 void deprecate(bool Source_State::*, int, const Context&, String_Ref); 125 static const char dot_string_deprecated_msg[]; 126 }; 127 128 Value tail_eval_frame(std::unique_ptr<Frame>); 129 130 } // namespace curv 131 #endif // header guard 132