aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api/vimscript.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api/vimscript.c')
-rw-r--r--src/nvim/api/vimscript.c285
1 files changed, 82 insertions, 203 deletions
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index c75bf21572..477cbe2428 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -11,18 +11,21 @@
#include "nvim/api/private/helpers.h"
#include "nvim/api/vimscript.h"
#include "nvim/ascii_defs.h"
+#include "nvim/buffer_defs.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/ex_docmd.h"
-#include "nvim/func_attr.h"
#include "nvim/garray.h"
+#include "nvim/garray_defs.h"
#include "nvim/globals.h"
#include "nvim/memory.h"
#include "nvim/runtime.h"
#include "nvim/vim_defs.h"
#include "nvim/viml/parser/expressions.h"
#include "nvim/viml/parser/parser.h"
+#include "nvim/viml/parser/parser_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/vimscript.c.generated.h"
@@ -48,7 +51,7 @@
/// @return Dictionary containing information about execution, with these keys:
/// - output: (string|nil) Output if `opts.output` is true.
Dictionary nvim_exec2(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *err)
- FUNC_API_SINCE(11)
+ FUNC_API_SINCE(11) FUNC_API_RET_ALLOC
{
Dictionary result = ARRAY_DICT_INIT;
@@ -145,7 +148,7 @@ void nvim_command(String command, Error *err)
/// @param expr Vimscript expression string
/// @param[out] err Error details, if any
/// @return Evaluation result or expanded object
-Object nvim_eval(String expr, Error *err)
+Object nvim_eval(String expr, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
static int recursive = 0; // recursion depth
@@ -176,7 +179,7 @@ Object nvim_eval(String expr, Error *err)
api_set_error(err, kErrorTypeException,
"Failed to evaluate expression: '%.*s'", 256, expr.data);
} else {
- rv = vim_to_object(&rettv);
+ rv = vim_to_object(&rettv, arena, false);
}
}
@@ -193,7 +196,7 @@ Object nvim_eval(String expr, Error *err)
/// @param self `self` dict, or NULL for non-dict functions
/// @param[out] err Error details, if any
/// @return Result of the function call
-static Object _call_function(String fn, Array args, dict_T *self, Error *err)
+static Object _call_function(String fn, Array args, dict_T *self, Arena *arena, Error *err)
{
static int recursive = 0; // recursion depth
Object rv = OBJECT_INIT;
@@ -208,9 +211,7 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
typval_T vim_args[MAX_FUNC_ARGS + 1];
size_t i = 0; // also used for freeing the variables
for (; i < args.size; i++) {
- if (!object_to_vim(args.items[i], &vim_args[i], err)) {
- goto free_vim_args;
- }
+ object_to_vim(args.items[i], &vim_args[i], err);
}
// Initialize `force_abort` and `suppress_errthrow` at the top level.
@@ -233,18 +234,17 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
TRY_WRAP(err, {
// call_func() retval is deceptive, ignore it. Instead we set `msg_list`
// (see above) to capture abort-causing non-exception errors.
- (void)call_func(fn.data, (int)fn.size, &rettv, (int)args.size,
- vim_args, &funcexe);
+ call_func(fn.data, (int)fn.size, &rettv, (int)args.size,
+ vim_args, &funcexe);
});
if (!ERROR_SET(err)) {
- rv = vim_to_object(&rettv);
+ rv = vim_to_object(&rettv, arena, false);
}
tv_clear(&rettv);
recursive--;
-free_vim_args:
while (i > 0) {
tv_clear(&vim_args[--i]);
}
@@ -260,10 +260,10 @@ free_vim_args:
/// @param args Function arguments packed in an Array
/// @param[out] err Error details, if any
/// @return Result of the function call
-Object nvim_call_function(String fn, Array args, Error *err)
+Object nvim_call_function(String fn, Array args, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
- return _call_function(fn, args, NULL, err);
+ return _call_function(fn, args, NULL, arena, err);
}
/// Calls a Vimscript |Dictionary-function| with the given arguments.
@@ -275,7 +275,7 @@ Object nvim_call_function(String fn, Array args, Error *err)
/// @param args Function arguments packed in an Array
/// @param[out] err Error details, if any
/// @return Result of the function call
-Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
+Object nvim_call_dict_function(Object dict, String fn, Array args, Arena *arena, Error *err)
FUNC_API_SINCE(4)
{
Object rv = OBJECT_INIT;
@@ -298,9 +298,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
mustfree = true;
break;
case kObjectTypeDictionary:
- if (!object_to_vim(dict, &rettv, err)) {
- goto end;
- }
+ object_to_vim(dict, &rettv, err);
break;
default:
api_set_error(err, kErrorTypeValidation,
@@ -339,7 +337,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
goto end;
}
- rv = _call_function(fn, args, self_dict, err);
+ rv = _call_function(fn, args, self_dict, arena, err);
end:
if (mustfree) {
tv_clear(&rettv);
@@ -353,9 +351,7 @@ typedef struct {
Object *ret_node_p;
} ExprASTConvStackItem;
-/// @cond DOXYGEN_NOT_A_FUNCTION
typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
-/// @endcond
/// Parse a Vimscript expression.
///
@@ -369,8 +365,8 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// - "l" when needing to start parsing with lvalues for
/// ":let" or ":for".
/// Common flag sets:
-/// - "m" to parse like for ":echo".
-/// - "E" to parse like for "<C-r>=".
+/// - "m" to parse like for `":echo"`.
+/// - "E" to parse like for `"<C-r>="`.
/// - empty string for ":call".
/// - "lm" to parse for ":let".
/// @param[in] highlight If true, return value will also include "highlight"
@@ -389,12 +385,12 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// - "arg": String, error message argument.
/// - "len": Amount of bytes successfully parsed. With flags equal to ""
/// that should be equal to the length of expr string.
-/// (“Successfully parsed” here means “participated in AST
-/// creation”, not “till the first error”.)
+/// ("Successfully parsed" here means "participated in AST
+/// creation", not "till the first error".)
/// - "ast": AST, either nil or a dictionary with these keys:
/// - "type": node type, one of the value names from ExprASTNodeType
/// stringified without "kExprNode" prefix.
-/// - "start": a pair [line, column] describing where node is "started"
+/// - "start": a pair `[line, column]` describing where node is "started"
/// where "line" is always 0 (will not be 0 if you will be
/// using this API on e.g. ":let", but that is not
/// present yet). Both elements are Integers.
@@ -431,7 +427,8 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// - "svalue": String, value for "SingleQuotedString" and
/// "DoubleQuotedString" nodes.
/// @param[out] err Error details, if any
-Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, Error *err)
+Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, Arena *arena,
+ Error *err)
FUNC_API_SINCE(4) FUNC_API_FAST
{
int pflags = 0;
@@ -473,82 +470,40 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
+ (size_t)(east.err.msg != NULL) // "error"
+ (size_t)highlight // "highlight"
+ 0);
- Dictionary ret = {
- .items = xmalloc(ret_size * sizeof(ret.items[0])),
- .size = 0,
- .capacity = ret_size,
- };
- ret.items[ret.size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ast"),
- .value = NIL,
- };
- ret.items[ret.size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("len"),
- .value = INTEGER_OBJ((Integer)(pstate.pos.line == 1
- ? parser_lines[0].size
- : pstate.pos.col)),
- };
+
+ Dictionary ret = arena_dict(arena, ret_size);
+ PUT_C(ret, "len", INTEGER_OBJ((Integer)(pstate.pos.line == 1
+ ? parser_lines[0].size
+ : pstate.pos.col)));
if (east.err.msg != NULL) {
- Dictionary err_dict = {
- .items = xmalloc(2 * sizeof(err_dict.items[0])),
- .size = 2,
- .capacity = 2,
- };
- err_dict.items[0] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("message"),
- .value = CSTR_TO_OBJ(east.err.msg),
- };
- if (east.err.arg == NULL) {
- err_dict.items[1] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("arg"),
- .value = STRING_OBJ(STRING_INIT),
- };
- } else {
- err_dict.items[1] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("arg"),
- .value = STRING_OBJ(((String) {
- .data = xmemdupz(east.err.arg, (size_t)east.err.arg_len),
- .size = (size_t)east.err.arg_len,
- })),
- };
- }
- ret.items[ret.size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("error"),
- .value = DICTIONARY_OBJ(err_dict),
- };
+ Dictionary err_dict = arena_dict(arena, 2);
+ PUT_C(err_dict, "message", CSTR_TO_ARENA_OBJ(arena, east.err.msg));
+ PUT_C(err_dict, "arg", CBUF_TO_ARENA_OBJ(arena, east.err.arg, (size_t)east.err.arg_len));
+ PUT_C(ret, "error", DICTIONARY_OBJ(err_dict));
}
if (highlight) {
- Array hl = (Array) {
- .items = xmalloc(kv_size(colors) * sizeof(hl.items[0])),
- .capacity = kv_size(colors),
- .size = kv_size(colors),
- };
+ Array hl = arena_array(arena, kv_size(colors));
for (size_t i = 0; i < kv_size(colors); i++) {
const ParserHighlightChunk chunk = kv_A(colors, i);
- Array chunk_arr = (Array) {
- .items = xmalloc(4 * sizeof(chunk_arr.items[0])),
- .capacity = 4,
- .size = 4,
- };
- chunk_arr.items[0] = INTEGER_OBJ((Integer)chunk.start.line);
- chunk_arr.items[1] = INTEGER_OBJ((Integer)chunk.start.col);
- chunk_arr.items[2] = INTEGER_OBJ((Integer)chunk.end_col);
- chunk_arr.items[3] = CSTR_TO_OBJ(chunk.group);
- hl.items[i] = ARRAY_OBJ(chunk_arr);
+ Array chunk_arr = arena_array(arena, 4);
+ ADD_C(chunk_arr, INTEGER_OBJ((Integer)chunk.start.line));
+ ADD_C(chunk_arr, INTEGER_OBJ((Integer)chunk.start.col));
+ ADD_C(chunk_arr, INTEGER_OBJ((Integer)chunk.end_col));
+ ADD_C(chunk_arr, CSTR_AS_OBJ(chunk.group));
+
+ ADD_C(hl, ARRAY_OBJ(chunk_arr));
}
- ret.items[ret.size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("highlight"),
- .value = ARRAY_OBJ(hl),
- };
+ PUT_C(ret, "highlight", ARRAY_OBJ(hl));
}
kvi_destroy(colors);
// Walk over the AST, freeing nodes in process.
ExprASTConvStack ast_conv_stack;
kvi_init(ast_conv_stack);
+ Object ast = NIL;
kvi_push(ast_conv_stack, ((ExprASTConvStackItem) {
.node_p = &east.root,
- .ret_node_p = &ret.items[0].value,
+ .ret_node_p = &ast,
}));
while (kv_size(ast_conv_stack)) {
ExprASTConvStackItem cur_item = kv_last(ast_conv_stack);
@@ -575,28 +530,17 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
|| node->type == kExprNodeSingleQuotedString) // "svalue"
+ (node->type == kExprNodeAssignment) // "augmentation"
+ 0);
- Dictionary ret_node = {
- .items = xmalloc(items_size * sizeof(ret_node.items[0])),
- .capacity = items_size,
- .size = 0,
- };
+ Dictionary ret_node = arena_dict(arena, items_size);
*cur_item.ret_node_p = DICTIONARY_OBJ(ret_node);
}
Dictionary *ret_node = &cur_item.ret_node_p->data.dictionary;
if (node->children != NULL) {
const size_t num_children = 1 + (node->children->next != NULL);
- Array children_array = {
- .items = xmalloc(num_children * sizeof(children_array.items[0])),
- .capacity = num_children,
- .size = num_children,
- };
+ Array children_array = arena_array(arena, num_children);
for (size_t i = 0; i < num_children; i++) {
- children_array.items[i] = NIL;
+ ADD_C(children_array, NIL);
}
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("children"),
- .value = ARRAY_OBJ(children_array),
- };
+ PUT_C(*ret_node, "children", ARRAY_OBJ(children_array));
kvi_push(ast_conv_stack, ((ExprASTConvStackItem) {
.node_p = &node->children,
.ret_node_p = &children_array.items[0],
@@ -608,126 +552,60 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
}));
} else {
kv_drop(ast_conv_stack, 1);
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("type"),
- .value = CSTR_TO_OBJ(east_node_type_tab[node->type]),
- };
- Array start_array = {
- .items = xmalloc(2 * sizeof(start_array.items[0])),
- .capacity = 2,
- .size = 2,
- };
- start_array.items[0] = INTEGER_OBJ((Integer)node->start.line);
- start_array.items[1] = INTEGER_OBJ((Integer)node->start.col);
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("start"),
- .value = ARRAY_OBJ(start_array),
- };
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("len"),
- .value = INTEGER_OBJ((Integer)node->len),
- };
+ PUT_C(*ret_node, "type", CSTR_AS_OBJ(east_node_type_tab[node->type]));
+ Array start_array = arena_array(arena, 2);
+ ADD_C(start_array, INTEGER_OBJ((Integer)node->start.line));
+ ADD_C(start_array, INTEGER_OBJ((Integer)node->start.col));
+ PUT_C(*ret_node, "start", ARRAY_OBJ(start_array));
+
+ PUT_C(*ret_node, "len", INTEGER_OBJ((Integer)node->len));
switch (node->type) {
case kExprNodeDoubleQuotedString:
- case kExprNodeSingleQuotedString:
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("svalue"),
- .value = STRING_OBJ(((String) {
- .data = node->data.str.value,
- .size = node->data.str.size,
- })),
- };
+ case kExprNodeSingleQuotedString: {
+ Object str = CBUF_TO_ARENA_OBJ(arena, node->data.str.value, node->data.str.size);
+ PUT_C(*ret_node, "svalue", str);
+ xfree(node->data.str.value);
break;
+ }
case kExprNodeOption:
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("scope"),
- .value = INTEGER_OBJ(node->data.opt.scope),
- };
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ident"),
- .value = STRING_OBJ(((String) {
- .data = xmemdupz(node->data.opt.ident,
- node->data.opt.ident_len),
- .size = node->data.opt.ident_len,
- })),
- };
+ PUT_C(*ret_node, "scope", INTEGER_OBJ(node->data.opt.scope));
+ PUT_C(*ret_node, "ident", CBUF_TO_ARENA_OBJ(arena, node->data.opt.ident,
+ node->data.opt.ident_len));
break;
case kExprNodePlainIdentifier:
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("scope"),
- .value = INTEGER_OBJ(node->data.var.scope),
- };
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ident"),
- .value = STRING_OBJ(((String) {
- .data = xmemdupz(node->data.var.ident,
- node->data.var.ident_len),
- .size = node->data.var.ident_len,
- })),
- };
+ PUT_C(*ret_node, "scope", INTEGER_OBJ(node->data.var.scope));
+ PUT_C(*ret_node, "ident", CBUF_TO_ARENA_OBJ(arena, node->data.var.ident,
+ node->data.var.ident_len));
break;
case kExprNodePlainKey:
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ident"),
- .value = STRING_OBJ(((String) {
- .data = xmemdupz(node->data.var.ident,
- node->data.var.ident_len),
- .size = node->data.var.ident_len,
- })),
- };
+ PUT_C(*ret_node, "ident", CBUF_TO_ARENA_OBJ(arena, node->data.var.ident,
+ node->data.var.ident_len));
break;
case kExprNodeEnvironment:
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ident"),
- .value = STRING_OBJ(((String) {
- .data = xmemdupz(node->data.env.ident,
- node->data.env.ident_len),
- .size = node->data.env.ident_len,
- })),
- };
+ PUT_C(*ret_node, "ident", CBUF_TO_ARENA_OBJ(arena, node->data.env.ident,
+ node->data.env.ident_len));
break;
case kExprNodeRegister:
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("name"),
- .value = INTEGER_OBJ(node->data.reg.name),
- };
+ PUT_C(*ret_node, "name", INTEGER_OBJ(node->data.reg.name));
break;
case kExprNodeComparison:
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("cmp_type"),
- .value = CSTR_TO_OBJ(eltkn_cmp_type_tab[node->data.cmp.type]),
- };
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ccs_strategy"),
- .value = CSTR_TO_OBJ(ccs_tab[node->data.cmp.ccs]),
- };
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("invert"),
- .value = BOOLEAN_OBJ(node->data.cmp.inv),
- };
+ PUT_C(*ret_node, "cmp_type", CSTR_AS_OBJ(eltkn_cmp_type_tab[node->data.cmp.type]));
+ PUT_C(*ret_node, "ccs_strategy", CSTR_AS_OBJ(ccs_tab[node->data.cmp.ccs]));
+ PUT_C(*ret_node, "invert", BOOLEAN_OBJ(node->data.cmp.inv));
break;
case kExprNodeFloat:
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("fvalue"),
- .value = FLOAT_OBJ(node->data.flt.value),
- };
+ PUT_C(*ret_node, "fvalue", FLOAT_OBJ(node->data.flt.value));
break;
case kExprNodeInteger:
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ivalue"),
- .value = INTEGER_OBJ((Integer)(node->data.num.value > API_INTEGER_MAX
- ? API_INTEGER_MAX
- : (Integer)node->data.num.value)),
- };
+ PUT_C(*ret_node, "ivalue", INTEGER_OBJ((Integer)(node->data.num.value > API_INTEGER_MAX
+ ? API_INTEGER_MAX
+ : (Integer)node->data.num.value)));
break;
case kExprNodeAssignment: {
const ExprAssignmentType asgn_type = node->data.ass.type;
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("augmentation"),
- .value = STRING_OBJ(asgn_type == kExprAsgnPlain
- ? (String)STRING_INIT
- : cstr_to_string(expr_asgn_type_tab[asgn_type])),
- };
+ String str = (asgn_type == kExprAsgnPlain
+ ? (String)STRING_INIT : cstr_as_string(expr_asgn_type_tab[asgn_type]));
+ PUT_C(*ret_node, "augmentation", STRING_OBJ(str));
break;
}
case kExprNodeMissing:
@@ -768,6 +646,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
}
}
kvi_destroy(ast_conv_stack);
+ PUT_C(ret, "ast", ast);
assert(ret.size == ret.capacity);
// Should be a no-op actually, leaving it in case non-nodes will need to be