aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/generators/c_grammar.lua
blob: ed6e30ea10a8b9b1761e0ed2dc7c92b25fe3d2ef (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
local lpeg = vim.lpeg

-- lpeg grammar for building api metadata from a set of header files. It
-- ignores comments and preprocessor commands and parses a very small subset
-- of C prototypes with a limited set of types
local P, R, S = lpeg.P, lpeg.R, lpeg.S
local C, Ct, Cc, Cg = lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cg

--- @param pat vim.lpeg.Pattern
local function rep(pat)
  return pat ^ 0
end

--- @param pat vim.lpeg.Pattern
local function rep1(pat)
  return pat ^ 1
end

--- @param pat vim.lpeg.Pattern
local function opt(pat)
  return pat ^ -1
end

local any = P(1) -- (consume one character)
local letter = R('az', 'AZ') + S('_$')
local num = R('09')
local alpha = letter + num
local nl = P('\r\n') + P('\n')
local not_nl = any - nl
local space = S(' \t')
local ws = space + nl
local fill = rep(ws)
local c_comment = P('//') * rep(not_nl)
local cdoc_comment = P('///') * opt(Ct(Cg(rep(space) * rep(not_nl), 'comment')))
local c_preproc = P('#') * rep(not_nl)
local dllexport = P('DLLEXPORT') * rep1(ws)

local typed_container = ((P('ArrayOf(') + P('DictOf(') + P('Dict(')) * rep1(any - P(')')) * P(')'))

local c_id = (typed_container + (letter * rep(alpha)))
local c_void = P('void')

local c_param_type = (
  ((P('Error') * fill * P('*') * fill) * Cc('error'))
  + ((P('Arena') * fill * P('*') * fill) * Cc('arena'))
  + ((P('lua_State') * fill * P('*') * fill) * Cc('lstate'))
  + C(opt(P('const ')) * c_id * rep1(ws) * rep1(P('*')))
  + (C(c_id) * rep1(ws))
)

local c_type = (C(c_void) * (ws ^ 1)) + c_param_type
local c_param = Ct(c_param_type * C(c_id))
local c_param_list = c_param * (fill * (P(',') * fill * c_param) ^ 0)
local c_params = Ct(c_void + c_param_list)

local impl_line = (any - P('}')) * opt(rep(not_nl)) * nl

local ignore_line = rep1(not_nl) * nl

local empty_line = Ct(Cc('empty') * nl * nl)

local c_proto = Ct(
  Cc('proto')
    * opt(dllexport)
    * opt(Cg(P('static') * fill * Cc(true), 'static'))
    * Cg(c_type, 'return_type')
    * Cg(c_id, 'name')
    * fill
    * (P('(') * fill * Cg(c_params, 'parameters') * fill * P(')'))
    * Cg(Cc(false), 'fast')
    * (fill * Cg((P('FUNC_API_SINCE(') * C(rep1(num))) * P(')'), 'since') ^ -1)
    * (fill * Cg((P('FUNC_API_DEPRECATED_SINCE(') * C(rep1(num))) * P(')'), 'deprecated_since') ^ -1)
    * (fill * Cg((P('FUNC_API_FAST') * Cc(true)), 'fast') ^ -1)
    * (fill * Cg((P('FUNC_API_RET_ALLOC') * Cc(true)), 'ret_alloc') ^ -1)
    * (fill * Cg((P('FUNC_API_NOEXPORT') * Cc(true)), 'noexport') ^ -1)
    * (fill * Cg((P('FUNC_API_REMOTE_ONLY') * Cc(true)), 'remote_only') ^ -1)
    * (fill * Cg((P('FUNC_API_LUA_ONLY') * Cc(true)), 'lua_only') ^ -1)
    * (fill * (Cg(P('FUNC_API_TEXTLOCK_ALLOW_CMDWIN') * Cc(true), 'textlock_allow_cmdwin') + Cg(
      P('FUNC_API_TEXTLOCK') * Cc(true),
      'textlock'
    )) ^ -1)
    * (fill * Cg((P('FUNC_API_REMOTE_IMPL') * Cc(true)), 'remote_impl') ^ -1)
    * (fill * Cg((P('FUNC_API_COMPOSITOR_IMPL') * Cc(true)), 'compositor_impl') ^ -1)
    * (fill * Cg((P('FUNC_API_CLIENT_IMPL') * Cc(true)), 'client_impl') ^ -1)
    * (fill * Cg((P('FUNC_API_CLIENT_IGNORE') * Cc(true)), 'client_ignore') ^ -1)
    * fill
    * (P(';') + (P('{') * nl + (impl_line ^ 0) * P('}')))
)

local dict_key = P('DictKey(') * Cg(rep1(any - P(')')), 'dict_key') * P(')')
local keyset_field =
  Ct(Cg(c_id, 'type') * ws * Cg(c_id, 'name') * fill * (dict_key ^ -1) * fill * P(';') * fill)
local c_keyset = Ct(
  P('typedef')
    * ws
    * P('struct')
    * fill
    * P('{')
    * fill
    * Cg(Ct(keyset_field ^ 1), 'fields')
    * P('}')
    * fill
    * P('Dict')
    * fill
    * P('(')
    * Cg(c_id, 'keyset_name')
    * fill
    * P(')')
    * P(';')
)

local grammar = Ct(
  rep1(empty_line + c_proto + cdoc_comment + c_comment + c_preproc + ws + c_keyset + ignore_line)
)
return { grammar = grammar, typed_container = typed_container }