2016-05-01 11:31:02 +08:00
|
|
|
// Functions for storing and retrieving function information. These functions also take care of
|
|
|
|
// autoloading functions in the $fish_function_path. Actual function evaluation is taken care of by
|
|
|
|
// the parser and to some degree the builtin handling library.
|
|
|
|
//
|
2016-05-19 06:30:21 +08:00
|
|
|
#include "config.h" // IWYU pragma: keep
|
|
|
|
|
2016-04-21 14:00:54 +08:00
|
|
|
// IWYU pragma: no_include <type_traits>
|
2016-05-01 11:31:02 +08:00
|
|
|
#include <dirent.h>
|
2011-12-27 11:18:46 +08:00
|
|
|
#include <pthread.h>
|
2016-05-01 11:31:02 +08:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <wchar.h>
|
2017-02-14 12:37:27 +08:00
|
|
|
|
2018-02-10 13:53:06 +08:00
|
|
|
#include <algorithm>
|
2012-01-14 15:44:18 +08:00
|
|
|
#include <map>
|
2016-05-01 11:31:02 +08:00
|
|
|
#include <memory>
|
2015-07-25 23:14:25 +08:00
|
|
|
#include <string>
|
2017-08-20 00:55:06 +08:00
|
|
|
#include <unordered_map>
|
2018-02-10 13:53:06 +08:00
|
|
|
#include <unordered_set>
|
2015-07-25 23:14:25 +08:00
|
|
|
#include <utility>
|
2005-09-20 21:26:39 +08:00
|
|
|
|
2015-07-25 23:14:25 +08:00
|
|
|
#include "autoload.h"
|
2005-09-20 21:26:39 +08:00
|
|
|
#include "common.h"
|
2016-05-01 11:31:02 +08:00
|
|
|
#include "env.h"
|
2005-10-06 06:37:08 +08:00
|
|
|
#include "event.h"
|
2016-05-01 11:31:02 +08:00
|
|
|
#include "fallback.h" // IWYU pragma: keep
|
|
|
|
#include "function.h"
|
|
|
|
#include "intern.h"
|
2007-04-22 17:50:26 +08:00
|
|
|
#include "parser_keywords.h"
|
2016-05-01 11:31:02 +08:00
|
|
|
#include "reader.h"
|
|
|
|
#include "wutil.h" // IWYU pragma: keep
|
2005-09-20 21:26:39 +08:00
|
|
|
|
2018-02-11 09:38:57 +08:00
|
|
|
class function_info_t {
|
|
|
|
public:
|
2018-02-12 08:37:38 +08:00
|
|
|
/// Immutable properties of the function.
|
|
|
|
std::shared_ptr<const function_properties_t> props;
|
|
|
|
/// Function description. This may be changed after the function is created.
|
|
|
|
wcstring description;
|
|
|
|
/// File where this function was defined (intern'd string).
|
|
|
|
const wchar_t *const definition_file;
|
|
|
|
/// Mapping of all variables that were inherited from the function definition scope to their
|
|
|
|
/// values.
|
|
|
|
const std::map<wcstring, env_var_t> inherit_vars;
|
|
|
|
/// Flag for specifying that this function was automatically loaded.
|
|
|
|
const bool is_autoload;
|
|
|
|
|
|
|
|
/// Constructs relevant information from the function_data.
|
|
|
|
function_info_t(function_data_t data, const wchar_t *filename, bool autoload);
|
|
|
|
|
|
|
|
/// Used by function_copy.
|
|
|
|
function_info_t(const function_info_t &data, const wchar_t *filename, bool autoload);
|
2018-02-11 09:38:57 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Table containing all functions.
|
2017-08-20 00:55:06 +08:00
|
|
|
typedef std::unordered_map<wcstring, function_info_t> function_map_t;
|
2012-01-14 15:44:18 +08:00
|
|
|
static function_map_t loaded_functions;
|
2011-12-27 11:18:46 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Functions that shouldn't be autoloaded (anymore).
|
2017-08-20 04:29:52 +08:00
|
|
|
static std::unordered_set<wcstring> function_tombstones;
|
2015-03-11 21:14:56 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Lock for functions.
|
2017-08-19 03:26:35 +08:00
|
|
|
static std::recursive_mutex functions_lock;
|
2011-12-27 11:18:46 +08:00
|
|
|
|
2015-04-08 17:58:29 +08:00
|
|
|
static bool function_remove_ignore_autoload(const wcstring &name, bool tombstone = true);
|
2015-03-11 21:14:56 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Callback when an autoloaded function is removed.
|
2017-01-30 10:56:55 +08:00
|
|
|
void autoloaded_function_removed(const wcstring &cmd) {
|
2015-04-08 17:58:29 +08:00
|
|
|
function_remove_ignore_autoload(cmd, false);
|
2012-01-26 10:40:08 +08:00
|
|
|
}
|
|
|
|
|
2017-01-30 10:56:55 +08:00
|
|
|
// Function autoloader
|
|
|
|
static autoload_t function_autoloader(L"fish_function_path", autoloaded_function_removed);
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Kludgy flag set by the load function in order to tell function_add that the function being
|
|
|
|
/// defined is autoloaded. There should be a better way to do this...
|
2012-03-04 07:20:30 +08:00
|
|
|
static bool is_autoload = false;
|
2006-02-08 17:20:05 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Make sure that if the specified function is a dynamically loaded function, it has been fully
|
|
|
|
/// loaded.
|
|
|
|
static int load(const wcstring &name) {
|
2011-12-27 13:56:23 +08:00
|
|
|
ASSERT_IS_MAIN_THREAD();
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2012-11-19 08:30:30 +08:00
|
|
|
bool was_autoload = is_autoload;
|
|
|
|
int res;
|
2015-03-11 21:14:56 +08:00
|
|
|
|
2015-04-06 23:38:18 +08:00
|
|
|
bool no_more_autoload = function_tombstones.count(name) > 0;
|
2016-05-01 11:31:02 +08:00
|
|
|
if (no_more_autoload) return 0;
|
2015-03-11 21:14:56 +08:00
|
|
|
|
2012-01-14 15:44:18 +08:00
|
|
|
function_map_t::iterator iter = loaded_functions.find(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (iter != loaded_functions.end() && !iter->second.is_autoload) {
|
|
|
|
// We have a non-autoload version already.
|
2012-11-19 08:30:30 +08:00
|
|
|
return 0;
|
2011-12-27 11:18:46 +08:00
|
|
|
}
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2012-11-19 08:30:30 +08:00
|
|
|
is_autoload = true;
|
|
|
|
res = function_autoloader.load(name, true);
|
|
|
|
is_autoload = was_autoload;
|
|
|
|
return res;
|
2006-02-08 17:20:05 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Insert a list of all dynamically loaded functions into the specified list.
|
2017-08-20 04:29:52 +08:00
|
|
|
static void autoload_names(std::unordered_set<wcstring> &names, int get_hidden) {
|
2012-11-19 08:30:30 +08:00
|
|
|
size_t i;
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2017-08-28 15:25:41 +08:00
|
|
|
const auto path_var = env_get(L"fish_function_path");
|
2017-08-06 12:40:27 +08:00
|
|
|
if (path_var.missing_or_empty()) return;
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2012-01-11 04:51:09 +08:00
|
|
|
wcstring_list_t path_list;
|
2017-08-28 15:25:41 +08:00
|
|
|
path_var->to_list(path_list);
|
2006-02-09 01:37:18 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
for (i = 0; i < path_list.size(); i++) {
|
2012-11-19 08:30:30 +08:00
|
|
|
const wcstring &ndir_str = path_list.at(i);
|
|
|
|
const wchar_t *ndir = (wchar_t *)ndir_str.c_str();
|
|
|
|
DIR *dir = wopendir(ndir);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (!dir) continue;
|
2012-11-19 08:30:30 +08:00
|
|
|
|
|
|
|
wcstring name;
|
2016-05-01 11:31:02 +08:00
|
|
|
while (wreaddir(dir, name)) {
|
2012-11-19 08:30:30 +08:00
|
|
|
const wchar_t *fn = name.c_str();
|
|
|
|
const wchar_t *suffix;
|
2016-05-01 11:31:02 +08:00
|
|
|
if (!get_hidden && fn[0] == L'_') continue;
|
2012-11-19 08:30:30 +08:00
|
|
|
|
|
|
|
suffix = wcsrchr(fn, L'.');
|
2016-05-01 11:31:02 +08:00
|
|
|
if (suffix && (wcscmp(suffix, L".fish") == 0)) {
|
2012-01-14 15:44:18 +08:00
|
|
|
wcstring name(fn, suffix - fn);
|
|
|
|
names.insert(name);
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir(dir);
|
2012-11-18 18:23:22 +08:00
|
|
|
}
|
2006-02-08 17:20:05 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
static std::map<wcstring, env_var_t> snapshot_vars(const wcstring_list_t &vars) {
|
|
|
|
std::map<wcstring, env_var_t> result;
|
2018-02-12 08:37:38 +08:00
|
|
|
for (const wcstring &name : vars) {
|
|
|
|
auto var = env_get(name);
|
|
|
|
if (var) result[name] = std::move(*var);
|
2014-10-03 06:59:24 +08:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-02-12 08:37:38 +08:00
|
|
|
function_info_t::function_info_t(function_data_t data, const wchar_t *filename, bool autoload)
|
|
|
|
: props(std::make_shared<const function_properties_t>(std::move(data.props))),
|
|
|
|
description(std::move(data.description)),
|
2016-05-01 11:31:02 +08:00
|
|
|
definition_file(intern(filename)),
|
|
|
|
inherit_vars(snapshot_vars(data.inherit_vars)),
|
2018-02-12 08:37:38 +08:00
|
|
|
is_autoload(autoload) {}
|
2016-05-01 11:31:02 +08:00
|
|
|
|
|
|
|
function_info_t::function_info_t(const function_info_t &data, const wchar_t *filename,
|
2018-02-10 13:53:06 +08:00
|
|
|
bool autoload)
|
2018-02-12 08:37:38 +08:00
|
|
|
: props(data.props),
|
2016-05-01 11:31:02 +08:00
|
|
|
description(data.description),
|
|
|
|
definition_file(intern(filename)),
|
|
|
|
inherit_vars(data.inherit_vars),
|
2018-02-12 08:37:38 +08:00
|
|
|
is_autoload(autoload) {}
|
2016-05-01 11:31:02 +08:00
|
|
|
|
2018-02-10 13:53:06 +08:00
|
|
|
void function_add(const function_data_t &data, const parser_t &parser) {
|
2016-10-10 05:38:26 +08:00
|
|
|
UNUSED(parser);
|
2012-03-04 07:20:30 +08:00
|
|
|
ASSERT_IS_MAIN_THREAD();
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-10-24 04:58:12 +08:00
|
|
|
CHECK(!data.name.empty(), ); //!OCLINT(multiple unary operator)
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Remove the old function.
|
2012-11-19 08:30:30 +08:00
|
|
|
function_remove(data.name);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Create and store a new function.
|
2012-03-04 07:20:30 +08:00
|
|
|
const wchar_t *filename = reader_current_filename();
|
2013-12-21 09:44:37 +08:00
|
|
|
|
2018-02-10 13:53:06 +08:00
|
|
|
const function_map_t::value_type new_pair(data.name,
|
|
|
|
function_info_t(data, filename, is_autoload));
|
2012-05-19 05:00:36 +08:00
|
|
|
loaded_functions.insert(new_pair);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Add event handlers.
|
2018-02-11 09:36:39 +08:00
|
|
|
for (const event_t &event : data.events) {
|
|
|
|
event_add_handler(event);
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
|
|
|
|
2018-02-12 09:21:24 +08:00
|
|
|
std::shared_ptr<const function_properties_t> function_get_properties(const wcstring &name) {
|
|
|
|
if (parser_keywords_is_reserved(name)) return nullptr;
|
|
|
|
scoped_rlock locker(functions_lock);
|
|
|
|
auto where = loaded_functions.find(name);
|
|
|
|
if (where != loaded_functions.end()) {
|
|
|
|
return where->second.props;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
int function_exists(const wcstring &cmd) {
|
|
|
|
if (parser_keywords_is_reserved(cmd)) return 0;
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2012-01-29 06:56:13 +08:00
|
|
|
load(cmd);
|
2012-11-18 18:23:22 +08:00
|
|
|
return loaded_functions.find(cmd) != loaded_functions.end();
|
2011-12-27 11:18:46 +08:00
|
|
|
}
|
2010-09-18 09:51:16 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
void function_load(const wcstring &cmd) {
|
|
|
|
if (!parser_keywords_is_reserved(cmd)) {
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2015-10-08 09:59:41 +08:00
|
|
|
load(cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
int function_exists_no_autoload(const wcstring &cmd, const env_vars_snapshot_t &vars) {
|
|
|
|
if (parser_keywords_is_reserved(cmd)) return 0;
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2016-05-01 11:31:02 +08:00
|
|
|
return loaded_functions.find(cmd) != loaded_functions.end() ||
|
|
|
|
function_autoloader.can_load(cmd, vars);
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
static bool function_remove_ignore_autoload(const wcstring &name, bool tombstone) {
|
|
|
|
// Note: the lock may be held at this point, but is recursive.
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2015-03-11 21:14:56 +08:00
|
|
|
function_map_t::iterator iter = loaded_functions.find(name);
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Not found. Not erasing.
|
|
|
|
if (iter == loaded_functions.end()) return false;
|
2015-03-11 21:14:56 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Removing an auto-loaded function. Prevent it from being auto-reloaded.
|
|
|
|
if (iter->second.is_autoload && tombstone) function_tombstones.insert(name);
|
2015-03-11 21:14:56 +08:00
|
|
|
|
|
|
|
loaded_functions.erase(iter);
|
|
|
|
event_t ev(EVENT_ANY);
|
2016-05-01 11:31:02 +08:00
|
|
|
ev.function_name = name;
|
2015-03-11 21:14:56 +08:00
|
|
|
event_remove(ev);
|
|
|
|
return true;
|
2012-01-26 10:40:08 +08:00
|
|
|
}
|
2006-02-05 21:10:35 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
void function_remove(const wcstring &name) {
|
|
|
|
if (function_remove_ignore_autoload(name)) function_autoloader.unload(name);
|
2012-01-24 12:32:36 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
static const function_info_t *function_get(const wcstring &name) {
|
|
|
|
// The caller must lock the functions_lock before calling this; however our mutex is currently
|
|
|
|
// recursive, so trylock will never fail. We need a way to correctly check if a lock is locked
|
|
|
|
// (or better yet, make our lock non-recursive).
|
|
|
|
// ASSERT_IS_LOCKED(functions_lock);
|
2012-01-24 12:32:36 +08:00
|
|
|
function_map_t::iterator iter = loaded_functions.find(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (iter == loaded_functions.end()) {
|
2012-05-19 05:00:36 +08:00
|
|
|
return NULL;
|
2012-01-24 12:32:36 +08:00
|
|
|
}
|
2016-05-05 06:19:47 +08:00
|
|
|
return &iter->second;
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
bool function_get_definition(const wcstring &name, wcstring *out_definition) {
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2012-05-19 05:00:36 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (func && out_definition) {
|
2018-02-12 08:37:38 +08:00
|
|
|
out_definition->assign(func->props->body_node.get_source(func->props->parsed_source->src));
|
2012-05-18 10:37:46 +08:00
|
|
|
}
|
|
|
|
return func != NULL;
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
2007-04-17 04:06:11 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
std::map<wcstring, env_var_t> function_get_inherit_vars(const wcstring &name) {
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2014-10-03 06:59:24 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
return func ? func->inherit_vars : std::map<wcstring, env_var_t>();
|
2014-10-03 06:59:24 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
bool function_get_desc(const wcstring &name, wcstring *out_desc) {
|
|
|
|
// Empty length string goes to NULL.
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2012-05-19 05:00:36 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (out_desc && func && !func->description.empty()) {
|
2012-05-18 10:46:08 +08:00
|
|
|
out_desc->assign(_(func->description.c_str()));
|
|
|
|
return true;
|
2012-01-24 12:43:39 +08:00
|
|
|
}
|
2016-10-29 08:42:50 +08:00
|
|
|
|
|
|
|
return false;
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
void function_set_desc(const wcstring &name, const wcstring &desc) {
|
2012-11-19 08:30:30 +08:00
|
|
|
load(name);
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2012-05-19 05:00:36 +08:00
|
|
|
function_map_t::iterator iter = loaded_functions.find(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (iter != loaded_functions.end()) {
|
2012-05-19 05:00:36 +08:00
|
|
|
iter->second.description = desc;
|
|
|
|
}
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
bool function_copy(const wcstring &name, const wcstring &new_name) {
|
2012-03-04 07:20:30 +08:00
|
|
|
bool result = false;
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2012-01-14 15:44:18 +08:00
|
|
|
function_map_t::const_iterator iter = loaded_functions.find(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (iter != loaded_functions.end()) {
|
|
|
|
// This new instance of the function shouldn't be tied to the definition file of the
|
|
|
|
// original, so pass NULL filename, etc.
|
|
|
|
const function_map_t::value_type new_pair(new_name,
|
2018-02-10 13:53:06 +08:00
|
|
|
function_info_t(iter->second, NULL, false));
|
2012-05-19 05:00:36 +08:00
|
|
|
loaded_functions.insert(new_pair);
|
2012-03-04 07:20:30 +08:00
|
|
|
result = true;
|
2012-01-14 15:44:18 +08:00
|
|
|
}
|
2012-11-19 08:30:30 +08:00
|
|
|
return result;
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
wcstring_list_t function_get_names(int get_hidden) {
|
2017-08-20 04:29:52 +08:00
|
|
|
std::unordered_set<wcstring> names;
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2012-11-19 08:30:30 +08:00
|
|
|
autoload_names(names, get_hidden);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2017-08-20 04:29:52 +08:00
|
|
|
for (const auto &func : loaded_functions) {
|
|
|
|
const wcstring &name = func.first;
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Maybe skip hidden.
|
2016-10-23 02:21:13 +08:00
|
|
|
if (!get_hidden && (name.empty() || name.at(0) == L'_')) {
|
|
|
|
continue;
|
2012-01-14 15:44:18 +08:00
|
|
|
}
|
|
|
|
names.insert(name);
|
|
|
|
}
|
|
|
|
return wcstring_list_t(names.begin(), names.end());
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
2005-10-06 06:37:08 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
const wchar_t *function_get_definition_file(const wcstring &name) {
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2012-05-19 05:00:36 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
2012-01-24 12:43:39 +08:00
|
|
|
return func ? func->definition_file : NULL;
|
2006-01-26 22:48:10 +08:00
|
|
|
}
|
|
|
|
|
2017-01-10 14:49:33 +08:00
|
|
|
bool function_is_autoloaded(const wcstring &name) {
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2017-01-10 14:49:33 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
|
|
|
return func->is_autoload;
|
|
|
|
}
|
|
|
|
|
2018-02-10 13:53:06 +08:00
|
|
|
int function_get_definition_lineno(const wcstring &name) {
|
2017-08-19 03:26:35 +08:00
|
|
|
scoped_rlock locker(functions_lock);
|
2012-05-19 05:00:36 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
2018-02-10 13:53:06 +08:00
|
|
|
if (!func) return -1;
|
|
|
|
// return one plus the number of newlines at offsets less than the start of our function's statement (which includes the header).
|
|
|
|
// TODO: merge with line_offset_of_character_at_offset?
|
2018-02-12 08:37:38 +08:00
|
|
|
auto block_stat = func->props->body_node.try_get_parent<grammar::block_statement>();
|
2018-02-10 13:53:06 +08:00
|
|
|
assert(block_stat && "Function body is not part of block statement");
|
|
|
|
auto source_range = block_stat.source_range();
|
|
|
|
assert(source_range && "Function has no source range");
|
|
|
|
uint32_t func_start = source_range->start;
|
2018-02-12 08:37:38 +08:00
|
|
|
const wcstring &source = func->props->parsed_source->src;
|
2018-02-10 13:53:06 +08:00
|
|
|
assert(func_start <= source.size() && "function start out of bounds");
|
|
|
|
return 1 + std::count(source.begin(), source.begin() + func_start, L'\n');
|
2006-01-26 22:48:10 +08:00
|
|
|
}
|
2015-08-16 04:37:17 +08:00
|
|
|
|
2018-02-16 13:58:02 +08:00
|
|
|
void function_invalidate_path() { function_autoloader.invalidate(); }
|
|
|
|
|
2017-08-06 06:08:39 +08:00
|
|
|
// Setup the environment for the function. There are three components of the environment:
|
|
|
|
// 1. argv
|
|
|
|
// 2. named arguments
|
|
|
|
// 3. inherited variables
|
2016-05-01 11:31:02 +08:00
|
|
|
void function_prepare_environment(const wcstring &name, const wchar_t *const *argv,
|
|
|
|
const std::map<wcstring, env_var_t> &inherited_vars) {
|
2015-08-16 04:37:17 +08:00
|
|
|
env_set_argv(argv);
|
2018-02-12 09:21:24 +08:00
|
|
|
auto props = function_get_properties(name);
|
|
|
|
if (props && !props->named_arguments.empty()) {
|
2017-08-06 06:08:39 +08:00
|
|
|
const wchar_t *const *arg = argv;
|
2018-02-12 09:21:24 +08:00
|
|
|
for (const wcstring &named_arg : props->named_arguments) {
|
2017-08-06 06:08:39 +08:00
|
|
|
if (*arg) {
|
2018-02-12 09:21:24 +08:00
|
|
|
env_set_one(named_arg, ENV_LOCAL | ENV_USER, *arg);
|
2017-08-06 06:08:39 +08:00
|
|
|
arg++;
|
|
|
|
} else {
|
2018-02-12 09:21:24 +08:00
|
|
|
env_set_empty(named_arg, ENV_LOCAL | ENV_USER);
|
2017-08-06 06:08:39 +08:00
|
|
|
}
|
2015-08-16 04:37:17 +08:00
|
|
|
}
|
|
|
|
}
|
2016-05-01 11:31:02 +08:00
|
|
|
|
2018-02-12 09:21:24 +08:00
|
|
|
for (const auto &kv : inherited_vars) {
|
|
|
|
env_set(kv.first, ENV_LOCAL | ENV_USER, kv.second.as_list());
|
2015-08-16 04:37:17 +08:00
|
|
|
}
|
|
|
|
}
|