koffi 2.12.3 → 2.12.5-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_armhf/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_loong64/koffi.node +0 -0
- package/build/koffi/linux_riscv64d/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/musl_arm64/koffi.node +0 -0
- package/build/koffi/musl_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/index.d.ts +15 -13
- package/index.js +9 -9
- package/indirect.js +9 -9
- package/package.json +2 -2
- package/src/core/base/base.cc +395 -74
- package/src/core/base/base.hh +44 -11
- package/src/core/base/crc.inc +2232 -0
- package/src/core/base/crc_gen.py +109 -0
- package/src/koffi/src/ffi.cc +45 -28
- package/src/koffi/src/parser.cc +15 -21
- package/src/koffi/src/parser.hh +2 -3
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
# this software and associated documentation files (the “Software”), to deal in
|
|
7
|
+
# the Software without restriction, including without limitation the rights to use,
|
|
8
|
+
# copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
|
9
|
+
# Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
# subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
17
|
+
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
19
|
+
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
20
|
+
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
21
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
# OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
# This script uses the database of mimetypes distributed here: https://github.com/jshttp/mime-db
|
|
25
|
+
# to produce the X-header file mimetypes.inc
|
|
26
|
+
|
|
27
|
+
import os
|
|
28
|
+
import argparse
|
|
29
|
+
|
|
30
|
+
CRC32_POLY = 0xEDB88320
|
|
31
|
+
CRC32C_POLY = 0x82F63B78
|
|
32
|
+
CRC64_XZ_POLY = 0xC96C5795D7870F42
|
|
33
|
+
CRC64_NVME_POLY = 0x9A6C9329AC4BC9B5
|
|
34
|
+
|
|
35
|
+
LICENSE_HEADER = """// Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
|
|
36
|
+
|
|
37
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
38
|
+
// this software and associated documentation files (the “Software”), to deal in
|
|
39
|
+
// the Software without restriction, including without limitation the rights to use,
|
|
40
|
+
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
|
41
|
+
// Software, and to permit persons to whom the Software is furnished to do so,
|
|
42
|
+
// subject to the following conditions:
|
|
43
|
+
|
|
44
|
+
// The above copyright notice and this permission notice shall be included in all
|
|
45
|
+
// copies or substantial portions of the Software.
|
|
46
|
+
|
|
47
|
+
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
|
48
|
+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
49
|
+
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
50
|
+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
51
|
+
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
52
|
+
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
53
|
+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
54
|
+
// OTHER DEALINGS IN THE SOFTWARE."""
|
|
55
|
+
|
|
56
|
+
def write_crc32_table(f, name, poly):
|
|
57
|
+
f.write(f'static const uint32_t {name}[256] = {{')
|
|
58
|
+
for i in range(0, 256):
|
|
59
|
+
value = i
|
|
60
|
+
for j in range(0, 8):
|
|
61
|
+
value = (value >> 1) ^ (poly if value & 1 else 0)
|
|
62
|
+
|
|
63
|
+
if i % 6 == 0:
|
|
64
|
+
f.write('\n ')
|
|
65
|
+
f.write(f' 0x{value:08X}u,')
|
|
66
|
+
f.write('\n};\n\n')
|
|
67
|
+
|
|
68
|
+
def write_crc64_tables(f, name, poly):
|
|
69
|
+
for table in range(0, 16):
|
|
70
|
+
count = table * 8 + 8
|
|
71
|
+
|
|
72
|
+
f.write(f'static const uint64_t {name}{table}[256] = {{')
|
|
73
|
+
for i in range(0, 256):
|
|
74
|
+
value = i
|
|
75
|
+
for j in range(0, count):
|
|
76
|
+
value = (value >> 1) ^ (poly if value & 1 else 0)
|
|
77
|
+
|
|
78
|
+
if i % 4 == 0:
|
|
79
|
+
f.write('\n ')
|
|
80
|
+
f.write(f' 0x{value:016X}ull,')
|
|
81
|
+
f.write('\n};\n')
|
|
82
|
+
|
|
83
|
+
f.write('\n')
|
|
84
|
+
|
|
85
|
+
if __name__ == "__main__":
|
|
86
|
+
parser = argparse.ArgumentParser(description = 'Update CRC tables header file')
|
|
87
|
+
parser.add_argument('-O', '--output_file', dest = 'output_file', action = 'store', help = 'Output file')
|
|
88
|
+
args = parser.parse_args()
|
|
89
|
+
|
|
90
|
+
if args.output_file is None:
|
|
91
|
+
output_file = os.path.join(os.path.dirname(__file__), 'crc.inc')
|
|
92
|
+
else:
|
|
93
|
+
output_file = args.output_file
|
|
94
|
+
|
|
95
|
+
with open(output_file, 'w') as f:
|
|
96
|
+
f.write(f'''{LICENSE_HEADER}
|
|
97
|
+
|
|
98
|
+
// This file is autogenerated by crc_gen.py
|
|
99
|
+
|
|
100
|
+
namespace RG {{
|
|
101
|
+
|
|
102
|
+
''')
|
|
103
|
+
|
|
104
|
+
write_crc32_table(f, 'Crc32Table', CRC32_POLY)
|
|
105
|
+
write_crc32_table(f, 'Crc32CTable', CRC32C_POLY)
|
|
106
|
+
write_crc64_tables(f, 'Crc64XzTable', CRC64_XZ_POLY)
|
|
107
|
+
write_crc64_tables(f, 'Crc64NvmeTable', CRC64_NVME_POLY)
|
|
108
|
+
|
|
109
|
+
f.write('}\n')
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -242,24 +242,25 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
242
242
|
return env.Null();
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
bool
|
|
245
|
+
bool skip = (info.Length() > 1);
|
|
246
|
+
bool named = skip && !IsNullOrUndefined(info[0]);
|
|
246
247
|
bool redefine = named && CheckValueTag(instance, info[0], &TypeInfoMarker);
|
|
247
248
|
|
|
248
249
|
if (named && !info[0].IsString() && !redefine) {
|
|
249
250
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
250
251
|
return env.Null();
|
|
251
252
|
}
|
|
252
|
-
if (!IsObject(info[
|
|
253
|
+
if (!IsObject(info[skip])) {
|
|
253
254
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for members, expected object", GetValueType(instance, info[1]));
|
|
254
255
|
return env.Null();
|
|
255
256
|
}
|
|
256
257
|
|
|
257
258
|
Napi::String name = info[0].As<Napi::String>();
|
|
258
|
-
Napi::Object obj = info[
|
|
259
|
+
Napi::Object obj = info[skip].As<Napi::Object>();
|
|
259
260
|
Napi::Array keys = GetOwnPropertyNames(obj);
|
|
260
261
|
|
|
261
262
|
RG_DEFER_NC(err_guard, count = instance->types.count) {
|
|
262
|
-
Size start = count + !
|
|
263
|
+
Size start = count + !skip;
|
|
263
264
|
|
|
264
265
|
for (Size i = start; i < instance->types.count; i++) {
|
|
265
266
|
const TypeInfo *it = &instance->types[i];
|
|
@@ -409,24 +410,25 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
|
|
|
409
410
|
return env.Null();
|
|
410
411
|
}
|
|
411
412
|
|
|
412
|
-
bool
|
|
413
|
+
bool skip = (info.Length() > 1);
|
|
414
|
+
bool named = skip && !IsNullOrUndefined(info[0]);
|
|
413
415
|
bool redefine = named && CheckValueTag(instance, info[0], &TypeInfoMarker);
|
|
414
416
|
|
|
415
417
|
if (named && !info[0].IsString() && !redefine) {
|
|
416
418
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
417
419
|
return env.Null();
|
|
418
420
|
}
|
|
419
|
-
if (!IsObject(info[
|
|
421
|
+
if (!IsObject(info[skip])) {
|
|
420
422
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for members, expected object", GetValueType(instance, info[1]));
|
|
421
423
|
return env.Null();
|
|
422
424
|
}
|
|
423
425
|
|
|
424
426
|
Napi::String name = info[0].As<Napi::String>();
|
|
425
|
-
Napi::Object obj = info[
|
|
427
|
+
Napi::Object obj = info[skip].As<Napi::Object>();
|
|
426
428
|
Napi::Array keys = GetOwnPropertyNames(obj);
|
|
427
429
|
|
|
428
430
|
RG_DEFER_NC(err_guard, count = instance->types.count) {
|
|
429
|
-
Size start = count + !
|
|
431
|
+
Size start = count + !skip;
|
|
430
432
|
|
|
431
433
|
for (Size i = start; i < instance->types.count; i++) {
|
|
432
434
|
const TypeInfo *it = &instance->types[i];
|
|
@@ -584,7 +586,7 @@ static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
|
|
|
584
586
|
Napi::Env env = info.Env();
|
|
585
587
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
586
588
|
|
|
587
|
-
bool named = (info.Length() >= 1);
|
|
589
|
+
bool named = (info.Length() >= 1) && !IsNullOrUndefined(info[0]);
|
|
588
590
|
|
|
589
591
|
if (named && !info[0].IsString()) {
|
|
590
592
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
@@ -621,7 +623,8 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
|
|
|
621
623
|
return env.Null();
|
|
622
624
|
}
|
|
623
625
|
|
|
624
|
-
bool
|
|
626
|
+
bool skip = (info.Length() > 1) && !info[1].IsNumber();
|
|
627
|
+
bool named = skip && !IsNullOrUndefined(info[0]);
|
|
625
628
|
|
|
626
629
|
if (named && !info[0].IsString()) {
|
|
627
630
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
@@ -630,18 +633,18 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
|
|
|
630
633
|
|
|
631
634
|
std::string name = named ? info[0].As<Napi::String>() : std::string();
|
|
632
635
|
|
|
633
|
-
const TypeInfo *type = ResolveType(info[
|
|
636
|
+
const TypeInfo *type = ResolveType(info[skip]);
|
|
634
637
|
if (!type)
|
|
635
638
|
return env.Null();
|
|
636
639
|
|
|
637
640
|
int count = 0;
|
|
638
|
-
if (info.Length() >= 2u +
|
|
639
|
-
if (!info[1 +
|
|
640
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for count, expected number", GetValueType(instance, info[1 +
|
|
641
|
+
if (info.Length() >= 2u + skip) {
|
|
642
|
+
if (!info[1 + skip].IsNumber()) {
|
|
643
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for count, expected number", GetValueType(instance, info[1 + skip]));
|
|
641
644
|
return env.Null();
|
|
642
645
|
}
|
|
643
646
|
|
|
644
|
-
count = info[1 +
|
|
647
|
+
count = info[1 + skip].As<Napi::Number>();
|
|
645
648
|
|
|
646
649
|
if (count < 1 || count > 4) {
|
|
647
650
|
ThrowError<Napi::TypeError>(env, "Value of count must be between 1 and 4");
|
|
@@ -727,7 +730,8 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
|
|
|
727
730
|
return env.Null();
|
|
728
731
|
}
|
|
729
732
|
|
|
730
|
-
bool
|
|
733
|
+
bool skip = (info.Length() > 1) && !info[1].IsFunction();
|
|
734
|
+
bool named = skip && !IsNullOrUndefined(info[0]);
|
|
731
735
|
|
|
732
736
|
if (named && !info[0].IsString()) {
|
|
733
737
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
@@ -736,7 +740,7 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
|
|
|
736
740
|
|
|
737
741
|
Napi::String name = info[0].As<Napi::String>();
|
|
738
742
|
|
|
739
|
-
const TypeInfo *src = ResolveType(info[
|
|
743
|
+
const TypeInfo *src = ResolveType(info[skip]);
|
|
740
744
|
if (!src)
|
|
741
745
|
return env.Null();
|
|
742
746
|
if (src->primitive != PrimitiveKind::Pointer &&
|
|
@@ -753,8 +757,8 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
|
|
|
753
757
|
|
|
754
758
|
DisposeFunc *dispose;
|
|
755
759
|
Napi::Function dispose_func;
|
|
756
|
-
if (info.Length() >= 2u +
|
|
757
|
-
Napi::Function func = info[1 +
|
|
760
|
+
if (info.Length() >= 2u + skip && !IsNullOrUndefined(info[1 + skip])) {
|
|
761
|
+
Napi::Function func = info[1 + skip].As<Napi::Function>();
|
|
758
762
|
|
|
759
763
|
if (!func.IsFunction()) {
|
|
760
764
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, func));
|
|
@@ -989,7 +993,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
989
993
|
return WrapType(env, instance, type);
|
|
990
994
|
}
|
|
991
995
|
|
|
992
|
-
static bool ParseClassicFunction(const Napi::CallbackInfo &info, FunctionInfo *out_func)
|
|
996
|
+
static bool ParseClassicFunction(const Napi::CallbackInfo &info, bool concrete, FunctionInfo *out_func)
|
|
993
997
|
{
|
|
994
998
|
Napi::Env env = info.Env();
|
|
995
999
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
@@ -1010,6 +1014,8 @@ static bool ParseClassicFunction(const Napi::CallbackInfo &info, FunctionInfo *o
|
|
|
1010
1014
|
parameters = info[3u].As<Napi::Array>();
|
|
1011
1015
|
}
|
|
1012
1016
|
|
|
1017
|
+
bool named = true;
|
|
1018
|
+
|
|
1013
1019
|
#if defined(_WIN32)
|
|
1014
1020
|
if (name.IsNumber()) {
|
|
1015
1021
|
out_func->ordinal_name = name.As<Napi::Number>().Int32Value();
|
|
@@ -1017,11 +1023,16 @@ static bool ParseClassicFunction(const Napi::CallbackInfo &info, FunctionInfo *o
|
|
|
1017
1023
|
}
|
|
1018
1024
|
#endif
|
|
1019
1025
|
if (!name.IsString()) {
|
|
1020
|
-
|
|
1021
|
-
|
|
1026
|
+
if (!concrete && IsNullOrUndefined(name)) {
|
|
1027
|
+
named = false;
|
|
1028
|
+
} else {
|
|
1029
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string or integer", GetValueType(instance, name));
|
|
1030
|
+
return false;
|
|
1031
|
+
}
|
|
1022
1032
|
}
|
|
1023
1033
|
|
|
1024
|
-
|
|
1034
|
+
// Leave anonymous naming responsibility to caller
|
|
1035
|
+
out_func->name = named ? DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr : nullptr;
|
|
1025
1036
|
|
|
1026
1037
|
out_func->ret.type = ResolveType(ret);
|
|
1027
1038
|
if (!out_func->ret.type)
|
|
@@ -1086,7 +1097,7 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
|
|
|
1086
1097
|
RG_DEFER_N(err_guard) { instance->callbacks.RemoveLast(1); };
|
|
1087
1098
|
|
|
1088
1099
|
if (info.Length() >= 3) {
|
|
1089
|
-
if (!ParseClassicFunction(info, func))
|
|
1100
|
+
if (!ParseClassicFunction(info, false, func))
|
|
1090
1101
|
return env.Null();
|
|
1091
1102
|
} else if (info.Length() >= 1) {
|
|
1092
1103
|
if (!info[0].IsString()) {
|
|
@@ -1095,13 +1106,19 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
|
|
|
1095
1106
|
}
|
|
1096
1107
|
|
|
1097
1108
|
std::string proto = info[0u].As<Napi::String>();
|
|
1098
|
-
if (!ParsePrototype(env, proto.c_str(), func))
|
|
1109
|
+
if (!ParsePrototype(env, proto.c_str(), false, func))
|
|
1099
1110
|
return env.Null();
|
|
1100
1111
|
} else {
|
|
1101
1112
|
ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, got %1", info.Length());
|
|
1102
1113
|
return env.Null();
|
|
1103
1114
|
}
|
|
1104
1115
|
|
|
1116
|
+
bool named = func->name;
|
|
1117
|
+
|
|
1118
|
+
if (!named) {
|
|
1119
|
+
func->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1105
1122
|
if (!AnalyseFunction(env, instance, func))
|
|
1106
1123
|
return env.Null();
|
|
1107
1124
|
|
|
@@ -1112,7 +1129,7 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
|
|
|
1112
1129
|
func->required_parameters += 2;
|
|
1113
1130
|
|
|
1114
1131
|
// We cannot fail after this check
|
|
1115
|
-
if (instance->types_map.Find(func->name)) {
|
|
1132
|
+
if (named && instance->types_map.Find(func->name)) {
|
|
1116
1133
|
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", func->name);
|
|
1117
1134
|
return env.Null();
|
|
1118
1135
|
}
|
|
@@ -1649,7 +1666,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
|
|
|
1649
1666
|
func->lib = lib->Ref();
|
|
1650
1667
|
|
|
1651
1668
|
if (info.Length() >= 3) {
|
|
1652
|
-
if (!ParseClassicFunction(info, func))
|
|
1669
|
+
if (!ParseClassicFunction(info, true, func))
|
|
1653
1670
|
return env.Null();
|
|
1654
1671
|
} else if (info.Length() >= 1) {
|
|
1655
1672
|
if (!info[0].IsString()) {
|
|
@@ -1658,7 +1675,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
|
|
|
1658
1675
|
}
|
|
1659
1676
|
|
|
1660
1677
|
std::string proto = info[0u].As<Napi::String>();
|
|
1661
|
-
if (!ParsePrototype(env, proto.c_str(), func))
|
|
1678
|
+
if (!ParsePrototype(env, proto.c_str(), true, func))
|
|
1662
1679
|
return env.Null();
|
|
1663
1680
|
} else {
|
|
1664
1681
|
ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, got %1", info.Length());
|
package/src/koffi/src/parser.cc
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
namespace RG {
|
|
29
29
|
|
|
30
|
-
bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
|
|
30
|
+
bool PrototypeParser::Parse(const char *str, bool concrete, FunctionInfo *out_func)
|
|
31
31
|
{
|
|
32
32
|
tokens.Clear();
|
|
33
33
|
offset = 0;
|
|
@@ -41,7 +41,18 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
|
|
|
41
41
|
return false;
|
|
42
42
|
}
|
|
43
43
|
offset += (offset < tokens.len && DetectCallConvention(tokens[offset], &out_func->convention));
|
|
44
|
-
|
|
44
|
+
|
|
45
|
+
if (offset >= tokens.len) {
|
|
46
|
+
MarkError("Unexpected end of prototype, expected identifier");
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (IsIdentifier(tokens[offset])) {
|
|
50
|
+
Span<const char> tok = tokens[offset++];
|
|
51
|
+
out_func->name = DuplicateString(tok, &instance->str_alloc).ptr;
|
|
52
|
+
} else if (concrete) {
|
|
53
|
+
MarkError("Unexpected token '%1', expected identifier", tokens[offset]);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
45
56
|
|
|
46
57
|
Consume("(");
|
|
47
58
|
offset += (offset + 1 < tokens.len && tokens[offset] == "void" && tokens[offset + 1] == ")");
|
|
@@ -169,23 +180,6 @@ const TypeInfo *PrototypeParser::ParseType(int *out_directions)
|
|
|
169
180
|
return instance->void_type;
|
|
170
181
|
}
|
|
171
182
|
|
|
172
|
-
const char *PrototypeParser::ParseIdentifier()
|
|
173
|
-
{
|
|
174
|
-
if (offset >= tokens.len) {
|
|
175
|
-
MarkError("Unexpected end of prototype, expected identifier");
|
|
176
|
-
return "";
|
|
177
|
-
}
|
|
178
|
-
if (!IsIdentifier(tokens[offset])) {
|
|
179
|
-
MarkError("Unexpected token '%1', expected identifier", tokens[offset]);
|
|
180
|
-
return "";
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
Span<const char> tok = tokens[offset++];
|
|
184
|
-
const char *ident = DuplicateString(tok, &instance->str_alloc).ptr;
|
|
185
|
-
|
|
186
|
-
return ident;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
183
|
bool PrototypeParser::Consume(const char *expect)
|
|
190
184
|
{
|
|
191
185
|
if (offset >= tokens.len) {
|
|
@@ -217,10 +211,10 @@ bool PrototypeParser::IsIdentifier(Span<const char> tok) const
|
|
|
217
211
|
return IsAsciiAlpha(tok[0]) || tok[0] == '_';
|
|
218
212
|
}
|
|
219
213
|
|
|
220
|
-
bool ParsePrototype(Napi::Env env, const char *str, FunctionInfo *out_func)
|
|
214
|
+
bool ParsePrototype(Napi::Env env, const char *str, bool concrete, FunctionInfo *out_func)
|
|
221
215
|
{
|
|
222
216
|
PrototypeParser parser(env);
|
|
223
|
-
return parser.Parse(str, out_func);
|
|
217
|
+
return parser.Parse(str, concrete, out_func);
|
|
224
218
|
}
|
|
225
219
|
|
|
226
220
|
}
|
package/src/koffi/src/parser.hh
CHANGED
|
@@ -44,13 +44,12 @@ class PrototypeParser {
|
|
|
44
44
|
public:
|
|
45
45
|
PrototypeParser(Napi::Env env) : env(env), instance(env.GetInstanceData<InstanceData>()) {}
|
|
46
46
|
|
|
47
|
-
bool Parse(const char *str, FunctionInfo *out_func);
|
|
47
|
+
bool Parse(const char *str, bool concrete, FunctionInfo *out_func);
|
|
48
48
|
|
|
49
49
|
private:
|
|
50
50
|
void Tokenize(const char *str);
|
|
51
51
|
|
|
52
52
|
const TypeInfo *ParseType(int *out_directions);
|
|
53
|
-
const char *ParseIdentifier();
|
|
54
53
|
|
|
55
54
|
bool Consume(const char *expect);
|
|
56
55
|
bool Match(const char *expect);
|
|
@@ -68,6 +67,6 @@ private:
|
|
|
68
67
|
}
|
|
69
68
|
};
|
|
70
69
|
|
|
71
|
-
bool ParsePrototype(Napi::Env env, const char *str, FunctionInfo *out_func);
|
|
70
|
+
bool ParsePrototype(Napi::Env env, const char *str, bool concrete, FunctionInfo *out_func);
|
|
72
71
|
|
|
73
72
|
}
|