aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_eval_defs.h
blob: e0d06f3e9347290010036da0ac0362dfc5a03877 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#pragma once

#include <stdbool.h>

#include "nvim/eval/typval_defs.h"
#include "nvim/pos_defs.h"

/// A list used for saving values of "emsg_silent".  Used by ex_try() to save the
/// value of "emsg_silent" if it was non-zero.  When this is done, the CSF_SILENT
/// flag below is set.
typedef struct eslist_elem eslist_T;
struct eslist_elem {
  int saved_emsg_silent;  ///< saved value of "emsg_silent"
  eslist_T *next;         ///< next element on the list
};

enum {
  /// For conditional commands a stack is kept of nested conditionals.
  /// When cs_idx < 0, there is no conditional command.
  CSTACK_LEN = 50,
};

typedef struct {
  int cs_flags[CSTACK_LEN];       ///< CSF_ flags
  char cs_pending[CSTACK_LEN];    ///< CSTP_: what's pending in ":finally"
  union {
    void *csp_rv[CSTACK_LEN];     ///< return typeval for pending return
    void *csp_ex[CSTACK_LEN];     ///< exception for pending throw
  } cs_pend;
  void *cs_forinfo[CSTACK_LEN];   ///< info used by ":for"
  int cs_line[CSTACK_LEN];        ///< line nr of ":while"/":for" line
  int cs_idx;                     ///< current entry, or -1 if none
  int cs_looplevel;               ///< nr of nested ":while"s and ":for"s
  int cs_trylevel;                ///< nr of nested ":try"s
  eslist_T *cs_emsg_silent_list;  ///< saved values of "emsg_silent"
  int cs_lflags;                  ///< loop flags: CSL_ flags
} cstack_T;
#define cs_rettv       cs_pend.csp_rv
#define cs_exception   cs_pend.csp_ex

/// There is no CSF_IF, the lack of CSF_WHILE, CSF_FOR and CSF_TRY means ":if"
/// was used.
enum {
  CSF_TRUE     = 0x0001,  ///< condition was TRUE
  CSF_ACTIVE   = 0x0002,  ///< current state is active
  CSF_ELSE     = 0x0004,  ///< ":else" has been passed
  CSF_WHILE    = 0x0008,  ///< is a ":while"
  CSF_FOR      = 0x0010,  ///< is a ":for"

  CSF_TRY      = 0x0100,  ///< is a ":try"
  CSF_FINALLY  = 0x0200,  ///< ":finally" has been passed
  CSF_THROWN   = 0x0800,  ///< exception thrown to this try conditional
  CSF_CAUGHT   = 0x1000,  ///< exception caught by this try conditional
  CSF_FINISHED = 0x2000,  ///< CSF_CAUGHT was handled by finish_exception()
  CSF_SILENT   = 0x4000,  ///< "emsg_silent" reset by ":try"
};
// Note that CSF_ELSE is only used when CSF_TRY and CSF_WHILE are unset
// (an ":if"), and CSF_SILENT is only used when CSF_TRY is set.

/// What's pending for being reactivated at the ":endtry" of this try
/// conditional:
enum {
  CSTP_NONE      = 0,   ///< nothing pending in ":finally" clause
  CSTP_ERROR     = 1,   ///< an error is pending
  CSTP_INTERRUPT = 2,   ///< an interrupt is pending
  CSTP_THROW     = 4,   ///< a throw is pending
  CSTP_BREAK     = 8,   ///< ":break" is pending
  CSTP_CONTINUE  = 16,  ///< ":continue" is pending
  CSTP_RETURN    = 24,  ///< ":return" is pending
  CSTP_FINISH    = 32,  ///< ":finish" is pending
};

/// Flags for the cs_lflags item in cstack_T.
enum {
  CSL_HAD_LOOP = 1,     ///< just found ":while" or ":for"
  CSL_HAD_ENDLOOP = 2,  ///< just found ":endwhile" or ":endfor"
  CSL_HAD_CONT = 4,     ///< just found ":continue"
  CSL_HAD_FINA = 8,     ///< just found ":finally"
};

/// A list of error messages that can be converted to an exception.  "throw_msg"
/// is only set in the first element of the list.  Usually, it points to the
/// original message stored in that element, but sometimes it points to a later
/// message in the list.  See cause_errthrow().
typedef struct msglist msglist_T;
struct msglist {
  msglist_T *next;  ///< next of several messages in a row
  char *msg;        ///< original message, allocated
  char *throw_msg;  ///< msg to throw: usually original one
  char *sfile;      ///< value from estack_sfile(), allocated
  linenr_T slnum;   ///< line number for "sfile"
  bool multiline;   ///< whether this is a multiline message
};

/// The exception types.
typedef enum {
  ET_USER,       ///< exception caused by ":throw" command
  ET_ERROR,      ///< error exception
  ET_INTERRUPT,  ///< interrupt exception triggered by Ctrl-C
} except_type_T;

/// Structure describing an exception.
/// (don't use "struct exception", it's used by the math library).
typedef struct vim_exception except_T;
struct vim_exception {
  except_type_T type;   ///< exception type
  char *value;          ///< exception value
  msglist_T *messages;  ///< message(s) causing error exception
  char *throw_name;     ///< name of the throw point
  linenr_T throw_lnum;  ///< line number of the throw point
  list_T *stacktrace;   ///< stacktrace
  except_T *caught;     ///< next exception on the caught stack
};

/// Structure to save the error/interrupt/exception state between calls to
/// enter_cleanup() and leave_cleanup().  Must be allocated as an automatic
/// variable by the (common) caller of these functions.
typedef struct cleanup_stuff cleanup_T;
struct cleanup_stuff {
  int pending;          ///< error/interrupt/exception state
  except_T *exception;  ///< exception value
};

/// Exception state that is saved and restored when calling timer callback
/// functions and deferred functions.
typedef struct exception_state_S exception_state_T;
struct exception_state_S {
  except_T *estate_current_exception;
  bool estate_did_throw;
  bool estate_need_rethrow;
  int estate_trylevel;
  int estate_did_emsg;
};