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_SYSTEM_H
6 #define LIBCURV_SYSTEM_H
7 
8 #include <ostream>
9 #include <unordered_set>
10 #include <map>
11 #include <libcurv/filesystem.h>
12 #include <libcurv/builtin.h>
13 
14 namespace curv {
15 
16 struct Context;
17 struct Program;
18 
19 /// An abstract interface to the client and operating system.
20 ///
21 /// The System object is owned by the client, who is responsible for ensuring
22 /// that it exists for as long as references to it might exist in Curv
23 /// data structures.
24 struct System
25 {
26     /// This is the set of standard or builtin bindings
27     /// used by the `file` primitive to interpret Curv source files.
28     virtual const Namespace& std_namespace() = 0;
29 
30     // Set by the `-v` command line argument.
31     bool verbose_ = false;
32 
33     // Deprecation level (0, 1 or 2) for deprecation warnings.
34     // Set by the `--depr=N` command line argument.
35     int depr_ = 1;
36 
37     // Set to true if you want coloured text to be written on the console.
38     bool use_colour_ = false;
39 
40     // True if the json-api protocol is being used.
41     bool use_json_api_ = false;
42 
43     virtual std::ostream& console() = 0;
44 
45     // Write an exception object to an output stream, using the Curv colour
46     // scheme if use_colour is true. Special behaviour for curv::Exception.
47     // This static function is handy for printing an exception caught during
48     // the construction of a System object (otherwise, use System::message).
49     static void print_exception(
50         const char* prefix, const std::exception& exc,
51         std::ostream& out, bool use_colour = false);
52 
53     static void print_json_exception(
54         const char* type, const std::exception& exc, std::ostream& out);
55 
56     void error(const std::exception& exc);
57     void warning(const std::exception& exc);
58     void print(const char*);
59 
60     // This is non-empty while a `file` operation is being evaluated.
61     // It is used to detect recursive file references.
62     // Later, this may change to a file cache.
63     // Or, it could move into the Program structure.
64     std::unordered_set<Filesystem::path,Path_Hash> active_files_{};
65 
66     // Used by `file` to import a file based on its extension.
67     // The extension includes the leading '.', and "" means no extension.
68     // The extension is converted to lowercase on all platforms.
69     using Importer = void (*)(const Filesystem::path&, Program&, const Context&);
70     std::map<std::string,Importer> importers_;
71 };
72 
73 // RAII helper class, for use with System::active_files_.
74 struct Active_File
75 {
76     std::unordered_set<Filesystem::path,Path_Hash>& active_files_;
77     Filesystem::path& file_;
Active_FileActive_File78     Active_File(
79         std::unordered_set<Filesystem::path,Path_Hash>& af,
80         Filesystem::path& f)
81     :
82         active_files_(af),
83         file_(f)
84     {
85         active_files_.insert(file_);
86     }
~Active_FileActive_File87     ~Active_File()
88     {
89         active_files_.erase(file_);
90     }
91 };
92 
93 /// Default implementation of the System interface.
94 struct System_Impl : public System
95 {
96     Namespace std_namespace_;
97     std::ostream& console_;
98     System_Impl(std::ostream&);
99     void load_library(String_Ref path);
100     virtual const Namespace& std_namespace() override;
101     virtual std::ostream& console() override;
102 };
103 
104 } // namespace curv
105 #endif // header guard
106