-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathgenerate_bindings.nims
More file actions
executable file
·178 lines (147 loc) · 5.27 KB
/
generate_bindings.nims
File metadata and controls
executable file
·178 lines (147 loc) · 5.27 KB
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
## This nimscript file is used to generate bindings (webui/bindings.nim) based on webui.h
## pre-requisites:
## 1. Nim: https://nim-lang.org/install.html
## 2. c2nim: nimble install c2nim
## Usage:
## nim scripts/generate_bindings.nims
import os, strformat, strutils
# Step 1: use c2nim to generate bindings (initial output)
let c2nim = findExe "c2nim"
if c2nim.len == 0:
raise newException(OSError, "c2nim not found; run `nimble install c2nim`")
quit(1)
else:
echo "Using c2nim at : ", c2nim
let root_path = currentSourcePath.parentDir.parentDir
let bindings_path = root_path / "webui" / "bindings.nim"
echo "Root dir: ", root_path
var cmd = fmt"{c2nim} -o:{bindings_path} --reordercomments "
cmd &= " --importc "
cmd &= " --def:webui_browser=WebuiBrowser "
cmd &= " --def:webui_runtime=WebuiRuntime "
cmd &= " --def:webui_event=WebuiEvent "
cmd &= " --def:webui_config=WebuiConfig "
cmd &= " --def:webui_event_t=Event "
cmd &= " --def:webui_logger_level=WebuiLoggerLevel "
cmd &= fmt"{root_path}/webui/webui/include/webui.h "
# cmd &= " --delete:_WIN32 "
echo "Running command: ", cmd
exec cmd
## Step 2: add the following code to include webui/bindings_include.nim, which defines some necessary macros and types
# fix the generated bindings file
let code_prefix = """
##[
This file is automatically generated by command : "nim scripts/generate_bindings.nims"
Do not edit this file directly.
Nim wrapper for [WebUI](https://github.com/webui-dev/webui)
:author: neroist
:WebUI Version: 2.5.0-Beta
See Nim Docs: https://yesdrx.github.io/nim-webui/
]##
include ./bindings_prefix.nim
"""
let code_suffix = """
include ./bindings_suffix.nim
"""
### Step 3: remove compiler related "when defined" blocks; add webui pragma; fix function names; fix callback annotations
## blocks like when defined(_WIN32) are commented out
proc removeWhenDefined(code: string): string =
var lines = code.splitLines()
var blocks : seq[tuple[startRow, endRow: int]]
var startRow, endRow = -1
for i in 0 ..< lines.len:
let row = lines[i]
if row.startsWith("when defined") or row.startsWith("when not defined"):
if startRow >= 0:
endRow = i
blocks.add((startRow, endRow))
startRow = i
endRow = -1
else:
startRow = i
elif startRow >= 0:
if row.startsWith(' ') or row.startsWith('\t'):
continue
elif row.startsWith("else"):
continue
elif row.startswith("#"):
continue
elif row.len == 0:
continue
elif row.startsWith("type") or row.startsWith("const") or row.startsWith("var") or row.startsWith("proc"):
endRow = i - 1
blocks.add((startRow, endRow))
startRow = -1
endRow = -1
else:
endRow = i
blocks.add((startRow, endRow))
startRow = -1
endRow = -1
for (startRow, endRow) in blocks:
for lineIdx in startRow .. endRow:
lines[lineIdx] = "# " & lines[lineIdx]
result = lines.join("\n")
## each proc definition is annotated with {.webui.} in addition to importc:
proc addWebuiPragma(code: string): string =
code.replace("importc:", "webui, importc:")
## remove "webui_" prefix from proc names
proc fixFunctionName(code: string): string =
code.replace(
"proc webui_", "proc "
).replace(
"proc bind", "proc `bind`"
).replace(
"char*", "char\\*"
) # fix docgen
## for the callback function type in arguments, annotate it with {.webui.}, as default call standard for function pointer is closure
proc fixCallbackAnnotation(code: string): string =
let callback_start = "proc ("
var annotation_inject_pos : seq[int]
var pos = 0
while true:
pos = code.find(callback_start, start = pos)
let start_pos = pos
if pos == -1:
break
pos += callback_start.len
while code[pos] != ')':
pos += 1
pos += 1
if code[pos] == ':':
pos += 1
while code[pos] == ' ' or code[pos] == '\t':
pos += 1
while code[pos] in {'a'..'z','A'..'Z', '0'..'9'}:
pos += 1
annotation_inject_pos.add(pos-1)
echo "adding webui pragma to function type: ", code[start_pos ..< pos], "\n"
var prev_end = 0
for injection_pos in annotation_inject_pos:
result &= code[prev_end .. injection_pos]
result &= " {.webui.}"
prev_end = injection_pos + 1
if prev_end < code.len:
result &= code[prev_end ..< code.len]
## add enum pragma to generate legacy constants
proc addEnumPragma(code: string): string =
code.replace(
"* = enum", "* {.renameEnumFields.} = enum"
).replace(
"WEBUI_EVENT_", "WEBUI_EVENTS_"
)
# code.replace(
# "WEBUI_EVENT_", "WEBUI_EVENTS_"
# )
## fix the generated code
let modified_code = (code_prefix & readFile(bindings_path) & code_suffix).removeWhenDefined(
).addWebuiPragma(
).fixFunctionName(
).fixCallbackAnnotation(
).addEnumPragma(
)
## output the final code
writeFile(
bindings_path,
modified_code
)