1 /* Copyright (c) 1997-2021 2 Ewgenij Gawrilow, Michael Joswig, and the polymake team 3 Technische Universität Berlin, Germany 4 https://polymake.org 5 6 This program is free software; you can redistribute it and/or modify it 7 under the terms of the GNU General Public License as published by the 8 Free Software Foundation; either version 2, or (at your option) any 9 later version: http://www.gnu.org/licenses/gpl.txt. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 -------------------------------------------------------------------------------- 16 */ 17 18 #pragma once 19 20 #ifdef POLYMAKE_APPNAME 21 #error polymake::Main cannot be used in clients 22 #endif 23 24 #ifndef POLYMAKE_DEBUG 25 #define POLYMAKE_DEBUG 0 26 #endif 27 28 // for classes defined in external application code 29 #define POLYMAKE_APPNAME unknown 30 31 #include "polymake/client.h" 32 #include "polymake/vector" 33 #include <string> 34 35 namespace pm { namespace perl { 36 37 class Scope; 38 39 class Main { 40 public: 41 //! Initialize polymake for use in the current thread 42 //! 43 //! Only the first invocation in the program evaluates its arguments, 44 //! all subsequent invocations are only needed to register already initialized polymake system with other threads. 45 //! The calling application is responsible to prevent simultaneous execution of any polymake functions in several threads, 46 //! which includes all methods of this class, Scope, BigObject, BigObjectType, as well as call_function, prepare_call_function and 47 //! any other functions requiring interaction with polymake perl interpreter. 48 //! 49 //! @param user_opts configuration path, corresponds to --config-path option of the standalone main script 50 //! several path elements should be separated with ; 51 //! @param install_top override the location of polymake installation top (shared) directory specified during initial pre-build configuration 52 //! @param install_arch override the location of polymake installation binary directory specified during initial pre-build configuration 53 explicit Main(const std::string& user_opts = "user", 54 std::string install_top = "", 55 std::string install_arch = ""); 56 57 //! Get a greeting message 58 //! @param verbose integer between 0 and 2, larger value means longer text 59 std::string greeting(int verbose = 2); 60 61 //! Select the current application by name 62 void set_application(const AnyString& appname); 63 64 //! Select the current application by a big object belonging to it 65 void set_application_of(const BigObject& x); 66 67 //! Load an extension installed at the given path 68 //! shell_enable() must be called prior to this 69 void add_extension(const AnyString& path); 70 71 //! Load a rulefile specified by given path 72 void include(const AnyString& path); 73 74 //! Set a preference list 75 //! @param label_exp same as in the interactive shell command 76 void set_preference(const AnyString& label_exp); 77 78 //! Reset a preference list to default value as defined in the rules 79 //! @param label_exp same as in the interactive shell command 80 void reset_preference(const AnyString& label_exp); 81 82 //! Set a custom variable to a given value 83 template <typename T> set_custom(const AnyString & name,T && value)84 void set_custom(const AnyString& name, T&& value) 85 { 86 Value x; 87 x << std::forward<T>(value); 88 set_custom_var(name, AnyString(), x); 89 } 90 91 //! Set a custom hash entry to a given value 92 template <typename T> set_custom(const AnyString & name,const AnyString & key,T && value)93 void set_custom(const AnyString& name, const AnyString& key, T&& value) 94 { 95 Value x; 96 x << std::forward<T>(value); 97 set_custom_var(name, key, x); 98 } 99 100 //! Reset a custom variable or a custom hash entry to its default value as defined in the rules 101 void reset_custom(const AnyString& name, const AnyString& key = AnyString()); 102 103 //! Construct a new Scope object 104 Scope newScope(); 105 106 friend class Scope; 107 108 //! Load additional modules providing shell functionality. 109 //! This should be called prior to loading any application, otherwise methods querying 110 //! command completion and context help won't work. 111 void shell_enable(); 112 113 //! Execute a piece of polymake/perl code in the context of the current application as if it has been entered in an interactive shell 114 //! The input must be encoded in UTF-8. 115 //! @return a tuple of four elements: 116 //! <0> boolean indicating whether the input string could be parsed and executed 117 //! <1> the entire stdout output produced during the execution, in particular, results of print statements; 118 //! empty when <0> is false 119 //! <2> the entire stderr output produced during the execution, this may include various harmless warnings and credit notes; 120 //! empty when <0> is false 121 //! <3> the message of an exception raised during the execution (when <0> is true) or input parse error message (when <0> is false) 122 //! Note that the result for a syntactically correct but incomplete input (unfinished statement, open block, etc.) 123 //! will be {false, "", "", ""}. 124 using shell_execute_t = std::tuple<bool, std::string, std::string, std::string>; 125 shell_execute_t shell_execute(const std::string& input); 126 127 //! get all possible completions for the partial input string, as if the TAB key has been pressed at the end of the string 128 //! @return a tuple of three elements: 129 //! <0> offset from the end of the input string to the position where all completion proposals can be applied; 130 //! in other words, length of the intersection of the input string and the proposals 131 //! <1> optional delimiter character which can be appended after every completion proposal 132 //! <2> array of completion proposals 133 using shell_complete_t = std::tuple<int, char, std::vector<std::string>>; 134 shell_complete_t shell_complete(const std::string& input); 135 136 //! get documentation strings describing an item in the input string near given position 137 //! multiple results are possible when the input can't be parsed unambiguously, 138 //! e.g. when the item in question refers to an overloaded function 139 //! @param input a piece of polymake/perl code 140 //! @param pos cursor position within the input string; results will describe the item 141 //! under the cursor or at the closest location towards the begin 142 //! By default, end of line is assumed 143 //! @param full provide full documentation texts including parameter descriptions, examples, etc. 144 //! @param html documentation texts may include HTML markup 145 std::vector<std::string> shell_context_help(const std::string& input, size_t pos=std::string::npos, bool full=false, bool html=false); 146 147 //! Install a signal handler for the given signal. 148 //! 149 //! The signal can be SIGINT or a custom interceptible signal like SUGUSR1. 150 //! 151 //! If the application handles signals in a thread other than where polymake functions are executed, 152 //! it must deliver the signal agreed upon here to polymake thread using pthread_kill(). 153 //! It is in the caller's responsibility to ensure that the signal is not blocked by polymake's thread signal mask. 154 //! 155 //! If the signal arrives while polymake is busy e.g. computing object properties or executing a user function, 156 //! it will eventually stop and throw an exception, returning to the caller. If the signal arrives during shell_execute, 157 //! the exception will be reported as part of the result tuple. 158 //! Please be aware that the break can happen with arbitrarily large delay, because inner loops in pure C/C++ code not communicating 159 //! with polymake server are not interruptible yet. 160 void set_interrupt_signal(int signum); 161 162 //! Uninstall the interrupt signal handler installed earlier via set_interrupt_signal(). 163 void reset_interrupt_signal(); 164 165 private: 166 SV* lookup_extension(const AnyString& path); // currently unused 167 void call_app_method(const char* method, const AnyString& arg); 168 169 void set_custom_var(const AnyString& name, const AnyString& key, Value& x); 170 }; 171 172 class Scope { 173 friend class Main; 174 public: Scope(Scope && s)175 Scope(Scope&& s) 176 : pm_main(s.pm_main) 177 , saved(s.saved) 178 , id(s.id) 179 { 180 s.saved = nullptr; 181 } 182 183 ~Scope(); 184 185 //! Set a temporary preference list 186 //! It is reverted when this Scope object is destroyed 187 //! @param labels same as in the interactive shell command 188 void prefer_now(const AnyString& labels) const; 189 190 //! Assign a temporary value to a custom variable 191 //! It is reverted when this Scope object is destroyed 192 template <typename T> set_custom(const AnyString & name,T && value)193 void set_custom(const AnyString& name, T&& value) 194 { 195 Value x; 196 x << std::forward<T>(value); 197 set_custom_var(name, AnyString(), x); 198 } 199 200 //! Assign a temporary value to a custom hash entry 201 //! It is reverted when this Scope object is destroyed 202 template <typename T> set_custom(const AnyString & name,const AnyString & key,T && value)203 void set_custom(const AnyString& name, const AnyString& key, T&& value) 204 { 205 Value x; 206 x << std::forward<T>(value); 207 set_custom_var(name, key, x); 208 } 209 210 private: Scope(Main * main_arg,SV * sv)211 Scope(Main* main_arg, SV* sv) 212 : pm_main(main_arg) 213 , saved(sv) 214 , id(++depth) {} 215 216 Scope(const Scope& s) = delete; 217 Scope& operator= (const Scope&) = delete; 218 219 void set_custom_var(const AnyString& name, const AnyString& key, Value& value) const; 220 221 static unsigned int depth; 222 Main* pm_main; 223 SV* saved; 224 unsigned int id; 225 }; 226 227 } } 228 229 namespace polymake { 230 231 using pm::perl::Main; 232 using pm::perl::Scope; 233 234 } 235 236 237 // Local Variables: 238 // mode:C++ 239 // c-basic-offset:3 240 // indent-tabs-mode:nil 241 // End: 242