ChaiScript / ChaiScript
1
// This file is distributed under the BSD License.
2
// See "license.txt" for details.
3
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
4
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
5
// http://www.chaiscript.com
6

7
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
8
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
9

10

11
#include <iostream>
12
#include <list>
13
#include <regex>
14

15
#ifdef _MSC_VER
16
#define _CRT_SECURE_NO_WARNINGS
17
#endif
18

19
#include <chaiscript/chaiscript_basic.hpp>
20
#include "../static_libs/chaiscript_parser.hpp"
21
#include "../static_libs/chaiscript_stdlib.hpp"
22

23

24
#ifdef READLINE_AVAILABLE
25
#include <readline/readline.h>
26
#include <readline/history.h>
27
#else
28

29
char *mystrdup (const char *s) {
30
  size_t len = strlen(s); // Space for length plus nul
31
  char *d = static_cast<char*>(malloc (len+1));
32
  if (d == nullptr) { return nullptr; }         // No memory
33
#ifdef CHAISCRIPT_MSVC
34
  strcpy_s(d, len+1, s);                        // Copy the characters
35
#else
36
  strncpy(d,s,len);                        // Copy the characters
37
#endif
38
  d[len] = '\0';
39
  return d;                            // Return the new string
40
}
41

42
char* readline(const char* p)
43
{
44
  std::string retval;
45
  std::cout << p ;
46
  std::getline(std::cin, retval);
47
  return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
48
}
49

50

51
void add_history(const char* /*unused*/){}
52
void using_history(){}
53
#endif
54

55

56

57 0
void *cast_module_symbol(std::vector<std::string> (*t_path)())
58
{
59
  union cast_union
60
  {
61
    std::vector<std::string> (*in_ptr)();
62
    void *out_ptr;
63
  };
64

65
  cast_union c;
66 0
  c.in_ptr = t_path;
67 0
  return c.out_ptr;
68
}
69

70 1
std::vector<std::string> default_search_paths()
71
{
72 1
  std::vector<std::string> paths;
73

74
#ifndef CHAISCRIPT_NO_DYNLOAD
75
#ifdef CHAISCRIPT_WINDOWS  // force no unicode
76
  CHAR path[4096];
77
  int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
78

79
  std::string exepath(path, size);
80

81
  size_t lastslash = exepath.rfind('\\');
82
  size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
83
  if (lastslash != std::string::npos)
84
  {
85
    paths.push_back(exepath.substr(0, lastslash));
86
  }
87

88
  if (secondtolastslash != std::string::npos)
89
  {
90
    return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
91
  }
92
#else
93

94 1
  std::string exepath;
95

96 1
  std::vector<char> buf(2048);
97 1
  ssize_t size = -1;
98

99 1
  if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0)
100
  {
101 1
    exepath = std::string(&buf.front(), static_cast<size_t>(size));
102
  }
103

104 1
  if (exepath.empty())
105
  {
106 0
    if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0)
107
    {
108 0
      exepath = std::string(&buf.front(), static_cast<size_t>(size));
109
    }
110
  }
111

112 1
  if (exepath.empty())
113
  {
114 0
    if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0)
115
    {
116 0
      exepath = std::string(&buf.front(), static_cast<size_t>(size));
117
    }
118
  }
119

120 1
  if (exepath.empty())
121
  {
122
    Dl_info rInfo;
123 0
    memset( &rInfo, 0, sizeof(rInfo) ); 
124 0
    if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) { 
125 0
      return paths;
126
    }
127

128 0
    exepath = std::string(rInfo.dli_fname);
129
  }
130

131 1
  size_t lastslash = exepath.rfind('/');
132

133 1
  size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
134 1
  if (lastslash != std::string::npos)
135
  {
136 1
    paths.push_back(exepath.substr(0, lastslash+1));
137
  }
138

139 1
  if (secondtolastslash != std::string::npos)
140
  {
141 1
    paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
142
  }
143
#endif
144
#endif // ifndef CHAISCRIPT_NO_DYNLOAD
145

146 1
  return paths;
147
}
148

149 1
void help(int n) {
150 1
  if ( n >= 0 ) {
151 0
    std::cout << "ChaiScript evaluator.  To evaluate an expression, type it and press <enter>.\n";
152 0
    std::cout << "Additionally, you can inspect the runtime system using:\n";
153 0
    std::cout << "  dump_system() - outputs all functions registered to the system\n";
154 0
    std::cout << "  dump_object(x) - dumps information about the given symbol\n";
155
  } else {
156 1
    std::cout << "usage : chai [option]+\n";
157 1
    std::cout << "option:"                << '\n';
158 1
    std::cout << "   -h | --help"         << '\n';
159 1
    std::cout << "   -i | --interactive"  << '\n';
160 1
    std::cout << "   -c | --command cmd"  << '\n';
161 1
    std::cout << "   -v | --version"      << '\n';
162 1
    std::cout << "   -    --stdin"        << '\n';
163 1
    std::cout << "   filepath"            << '\n';
164
  }
165
}
166

167 1
std::string throws_exception(const std::function<void ()> &f)
168
{
169
  try {
170 1
    f();
171 1
  } catch (const std::exception &e) {
172 1
    return e.what();
173
  }
174

175 0
  return "";
176
}
177

178 1
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)
179
{
180
  try {
181 1
    f();
182 1
  } catch (const chaiscript::exception::eval_error &e) {
183 1
    return e;
184
  }
185

186 0
  throw std::runtime_error("no exception throw");
187
}
188

189 0
std::string get_next_command() {
190 0
  std::string retval("quit");
191 0
  if ( ! std::cin.eof() ) {
192 0
    char *input_raw = readline("eval> ");
193 0
    if ( input_raw != nullptr ) {
194 0
      add_history(input_raw);
195

196 0
      std::string val(input_raw);
197 0
      size_t pos = val.find_first_not_of("\t \n");
198 0
      if (pos != std::string::npos)
199
      {
200 0
        val.erase(0, pos);
201
      }
202 0
      pos = val.find_last_not_of("\t \n");
203 0
      if (pos != std::string::npos)
204
      {
205 0
        val.erase(pos+1, std::string::npos);
206
      }
207

208 0
      retval = val;
209

210 0
      ::free(input_raw);
211
    }
212
  }
213 0
  if(   retval == "quit"
214 0
     || retval == "exit"
215 0
     || retval == "help"
216 0
     || retval == "version") 
217
  {
218 0
    retval += "(0)";
219
  }
220 0
  return retval;
221
}
222

223
// We have to wrap exit with our own because Clang has a hard time with
224
// function pointers to functions with special attributes (system exit being marked NORETURN)
225 1
void myexit(int return_val) {
226 1
  exit(return_val);
227
}
228

229 0
void interactive(chaiscript::ChaiScript_Basic& chai)
230
{
231 0
  using_history();
232

233
  for (;;) {
234 0
    std::string input = get_next_command();
235
    try {
236
      // evaluate input
237 0
      chaiscript::Boxed_Value val = chai.eval(input);
238

239
      //Then, we try to print the result of the evaluation to the user
240 0
      if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
241
        try {
242 0
          std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << '\n';
243
        }
244 0
        catch (...) {} //If we can't, do nothing
245
      }
246
    }
247 0
    catch (const chaiscript::exception::eval_error &ee) {
248 0
      std::cout << ee.what();
249 0
      if ( !ee.call_stack.empty() ) {
250 0
        std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
251
      }
252 0
      std::cout << '\n';
253
    }
254 0
    catch (const std::exception &e) {
255 0
      std::cout << e.what();
256 0
      std::cout << '\n';
257
    }
258
  }
259
}
260

261 1
double now()
262
{
263
  using namespace std::chrono;
264 1
  auto now = high_resolution_clock::now();
265 1
  return duration_cast<duration<double>>(now.time_since_epoch()).count();
266
}
267

268 1
int main(int argc, char *argv[])
269
{
270

271
  // Disable deprecation warning for getenv call.
272
#ifdef CHAISCRIPT_MSVC
273
#pragma warning(push)
274
#pragma warning(disable : 4996)
275
#endif
276

277 1
  const char *usepath = getenv("CHAI_USE_PATH");
278 1
  const char *modulepath = getenv("CHAI_MODULE_PATH");
279

280
#ifdef CHAISCRIPT_MSVC
281
#pragma warning(pop)
282
#endif
283

284 1
  std::vector<std::string> usepaths;
285 1
  usepaths.push_back("");
286 1
  if (usepath != nullptr)
287
  {
288 1
    usepaths.push_back(usepath);
289
  }
290

291 1
  std::vector<std::string> modulepaths;
292 1
  std::vector<std::string> searchpaths = default_search_paths();
293 1
  modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
294 1
  modulepaths.push_back("");
295 1
  if (modulepath != nullptr)
296
  {
297 1
    modulepaths.push_back(modulepath);
298
  }
299

300 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(),modulepaths,usepaths);
301

302 1
  chai.add(chaiscript::fun(&myexit), "exit");
303 1
  chai.add(chaiscript::fun(&myexit), "quit");
304 1
  chai.add(chaiscript::fun(&help), "help");
305 1
  chai.add(chaiscript::fun(&throws_exception), "throws_exception");
306 1
  chai.add(chaiscript::fun(&get_eval_error), "get_eval_error");
307 1
  chai.add(chaiscript::fun(&now), "now");
308

309 1
  bool eval_error_ok = false;
310 1
  bool boxed_exception_ok = false;
311 1
  bool any_exception_ok = false;
312

313 1
  for (int i = 0; i < argc; ++i) {
314 1
    if ( i == 0 && argc > 1 ) {
315 1
      ++i;
316
    }
317

318
    std::string arg( i != 0 ? argv[i] : "--interactive" );
319

320
    enum { eInteractive
321
         , eCommand
322
         , eFile
323 1
    } mode = eCommand ;
324

325 1
    if  ( arg == "-c" || arg == "--command" ) {
326 1
      if ( (i+1) >= argc ) {
327 0
        std::cout << "insufficient input following " << arg << '\n';
328 0
        return EXIT_FAILURE;
329
      } 
330 1
        arg = argv[++i];
331
      
332
    } else if ( arg == "-" || arg == "--stdin" ) {
333 0
      arg = "" ;
334 0
      std::string line;
335 0
      while ( std::getline(std::cin, line) ) {
336 0
        arg += line + '\n' ;
337
      }
338 1
    } else if ( arg == "-v" || arg == "--version" ) {
339 1
      arg = "print(version())" ;
340 1
    } else if ( arg == "-h" || arg == "--help" ) {
341 1
      arg = "help(-1)";
342 1
    } else if ( arg == "-e" || arg == "--evalerrorok" ) {
343 1
      eval_error_ok = true;
344 1
      continue;
345 1
    } else if ( arg == "--exception" ) {
346 1
      boxed_exception_ok = true;
347 1
      continue;
348 1
    } else if ( arg == "--any-exception" ) {
349 1
      any_exception_ok = true;
350 1
      continue;
351
    } else if ( arg == "-i" || arg == "--interactive" ) {
352 0
      mode = eInteractive ;
353 1
    } else if ( arg.find('-') == 0 ) {
354 0
      std::cout << "unrecognised argument " << arg << '\n';
355 0
      return EXIT_FAILURE;
356
    } else {
357 1
      mode = eFile;
358
    }
359

360
    try {
361 1
      switch ( mode ) {
362 0
        case eInteractive:
363 0
          interactive(chai);
364 0
          break;
365 1
        case eCommand:
366 1
          chai.eval(arg);
367 1
          break;
368 1
        case eFile:
369 1
          chai.eval_file(arg);
370
      }
371
    }
372 1
    catch (const chaiscript::exception::eval_error &ee) {
373 1
      std::cout << ee.pretty_print();
374 1
      std::cout << '\n';
375

376 1
      if (!eval_error_ok) {
377 0
        return EXIT_FAILURE;
378
      }
379
    }
380 1
    catch (const chaiscript::Boxed_Value &e) {
381 1
      std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n';
382

383 1
      if (!boxed_exception_ok) {
384 0
        return EXIT_FAILURE;
385
      }
386
    }
387 1
    catch (const chaiscript::exception::load_module_error &e) {
388 1
      std::cout << "Unhandled module load error\n" << e.what() << '\n';
389
    }
390 1
    catch (std::exception &e) {
391 1
      std::cout << "Unhandled standard exception: " << e.what() << '\n';
392 1
      if (!any_exception_ok) {
393 0
        throw;
394
      }
395
    }
396 0
    catch (...) {
397 0
      std::cout << "Unhandled unknown exception" << '\n';
398 0
      if (!any_exception_ok) {
399 0
        throw;
400
      }
401
    }
402
  }
403

404 1
  return EXIT_SUCCESS;
405
}

Read our documentation on viewing source code .

Loading