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