Skip to content

Commit f98829e

Browse files
committed
Big update to NAPI generator with initial support for basic examples.
1 parent 4e58e26 commit f98829e

File tree

9 files changed

+2184
-22
lines changed

9 files changed

+2184
-22
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using CppSharp.AST;
2+
3+
namespace CppSharp.Extensions
4+
{
5+
public static class FunctionExtensions
6+
{
7+
public static bool IsNativeMethod(this Function function)
8+
{
9+
var method = function as Method;
10+
if (method == null)
11+
return false;
12+
13+
return method.Conversion == MethodConversionKind.None;
14+
}
15+
}
16+
}

src/Generator/Extensions/PrimitiveTypeExtensions.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@ namespace CppSharp.Extensions
77
{
88
public static class PrimitiveTypeExtensions
99
{
10+
public static bool IsIntegerType(this PrimitiveType type)
11+
{
12+
switch (type)
13+
{
14+
case PrimitiveType.Char:
15+
case PrimitiveType.SChar:
16+
case PrimitiveType.UChar:
17+
case PrimitiveType.Short:
18+
case PrimitiveType.UShort:
19+
case PrimitiveType.Int:
20+
case PrimitiveType.UInt:
21+
case PrimitiveType.Long:
22+
case PrimitiveType.ULong:
23+
case PrimitiveType.LongLong:
24+
case PrimitiveType.ULongLong:
25+
return true;
26+
default:
27+
return false;
28+
}
29+
}
30+
1031
public static (uint Width, uint Alignment) GetInfo(this PrimitiveType primitive, ParserTargetInfo targetInfo, out bool signed)
1132
{
1233
signed = false;

src/Generator/Generators/C/NAPI/NAPIGenerator.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,31 @@ public override List<GeneratorOutput> Generate()
3131
}
3232
}
3333

34+
var helpers = GenerateHelpers();
35+
OnUnitGenerated(helpers);
36+
outputs.Add(helpers);
37+
3438
return outputs;
3539
}
3640

41+
public GeneratorOutput GenerateHelpers()
42+
{
43+
var helpersGen = new NAPIHelpers(Context);
44+
helpersGen.Process();
45+
46+
var output = new GeneratorOutput
47+
{
48+
TranslationUnit = new TranslationUnit { FilePath = "NAPIHelpers.h" },
49+
Outputs = new List<CodeGenerator> { helpersGen }
50+
};
51+
52+
return output;
53+
}
54+
3755
public override List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units)
3856
{
3957
var outputs = new List<CodeGenerator>();
4058

41-
var header = new NAPIHeaders(Context, units);
42-
outputs.Add(header);
43-
4459
var source = new NAPISources(Context, units);
4560
outputs.Add(source);
4661

src/Generator/Generators/C/NAPI/NAPIHeaders.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.IO;
23
using CppSharp.AST;
34

45
namespace CppSharp.Generators.Cpp
@@ -17,7 +18,7 @@ public NAPIHeaders(BindingContext context, IEnumerable<TranslationUnit> units)
1718

1819
public override void Process()
1920
{
20-
base.Process();
21+
return;
2122
}
2223
}
2324
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using CppSharp.AST;
4+
using CppSharp.Generators.C;
5+
6+
namespace CppSharp.Generators.Cpp
7+
{
8+
/// <summary>
9+
/// Generates a common Node N-API C/C++ common files.
10+
/// N-API documentation: https://nodejs.org/api/n-api.html
11+
/// </summary>
12+
public class NAPIHelpers : CppHeaders
13+
{
14+
public NAPIHelpers(BindingContext context)
15+
: base(context, null)
16+
{
17+
}
18+
19+
public override void Process()
20+
{
21+
GenerateFilePreamble(CommentKind.BCPL);
22+
23+
WriteLine("#pragma once");
24+
NewLine();
25+
26+
WriteInclude("math.h", CInclude.IncludeKind.Angled);
27+
WriteInclude("limits.h", CInclude.IncludeKind.Angled);
28+
NewLine();
29+
30+
GenerateHelpers();
31+
return;
32+
}
33+
34+
private void GenerateHelpers()
35+
{
36+
WriteLine(@"#define NAPI_CALL(env, call) \
37+
do { \
38+
napi_status status = (call); \
39+
if (status != napi_ok) { \
40+
const napi_extended_error_info* error_info = NULL; \
41+
napi_get_last_error_info((env), &error_info); \
42+
bool is_pending; \
43+
napi_is_exception_pending((env), &is_pending); \
44+
if (!is_pending) { \
45+
const char* message = (error_info->error_message == NULL) \
46+
? ""empty error message"" \
47+
: error_info->error_message; \
48+
napi_throw_error((env), NULL, message); \
49+
return NULL; \
50+
} \
51+
} \
52+
} while(0)");
53+
NewLine();
54+
55+
WriteLine(@"#define NAPI_CALL_NORET(env, call) \
56+
do { \
57+
napi_status status = (call); \
58+
if (status != napi_ok) { \
59+
const napi_extended_error_info* error_info = NULL; \
60+
napi_get_last_error_info((env), &error_info); \
61+
bool is_pending; \
62+
napi_is_exception_pending((env), &is_pending); \
63+
if (!is_pending) { \
64+
const char* message = (error_info->error_message == NULL) \
65+
? ""empty error message"" \
66+
: error_info->error_message; \
67+
napi_throw_error((env), NULL, message); \
68+
return; \
69+
} \
70+
} \
71+
} while(0)");
72+
NewLine();
73+
74+
WriteLine(@"static int napi_is_int32(napi_env env, napi_value value, int* integer) {
75+
double temp = 0;
76+
if (
77+
// We get the value as a double so we can check for NaN, Infinity and float:
78+
// https://github.com/nodejs/node/issues/26323
79+
napi_get_value_double(env, value, &temp) != napi_ok ||
80+
// Reject NaN:
81+
isnan(temp) ||
82+
// Reject Infinity and avoid undefined behavior when casting double to int:
83+
// https://groups.google.com/forum/#!topic/comp.lang.c/rhPzd4bgKJk
84+
temp < INT_MIN ||
85+
temp > INT_MAX ||
86+
// Reject float by casting double to int:
87+
(double) ((int) temp) != temp
88+
) {
89+
//napi_throw_error(env, NULL, ""argument must be an integer"");
90+
return 0;
91+
}
92+
if (integer)
93+
*integer = (int) temp;
94+
return 1;
95+
}");
96+
NewLine();
97+
98+
WriteLine(@"static int napi_is_uint32(napi_env env, napi_value value, int* integer) {
99+
double temp = 0;
100+
if (
101+
// We get the value as a double so we can check for NaN, Infinity and float:
102+
// https://github.com/nodejs/node/issues/26323
103+
napi_get_value_double(env, value, &temp) != napi_ok ||
104+
// Reject NaN:
105+
isnan(temp) ||
106+
// Reject Infinity and avoid undefined behavior when casting double to int:
107+
// https://groups.google.com/forum/#!topic/comp.lang.c/rhPzd4bgKJk
108+
temp < 0 ||
109+
temp > ULONG_MAX ||
110+
// Reject float by casting double to int:
111+
(double) ((unsigned long) temp) != temp
112+
) {
113+
//napi_throw_error(env, NULL, ""argument must be an integer"");
114+
return 0;
115+
}
116+
if (integer)
117+
*integer = (int) temp;
118+
return 1;
119+
}");
120+
NewLine();
121+
122+
WriteLine(@"#define NAPI_IS_BOOL(valuetype) (valuetype == napi_boolean)");
123+
WriteLine(@"#define NAPI_IS_NULL(valuetype) (valuetype == napi_null)");
124+
WriteLine(@"#define NAPI_IS_NUMBER(valuetype) (valuetype == napi_number)");
125+
WriteLine(@"#define NAPI_IS_BIGINT(valuetype) (valuetype == napi_bigint)");
126+
WriteLine(@"#define NAPI_IS_INT32(valuetype, value) (NAPI_IS_NUMBER(valuetype) && napi_is_int32(env, value, nullptr))");
127+
WriteLine(@"#define NAPI_IS_UINT32(valuetype, value) (NAPI_IS_NUMBER(valuetype) && napi_is_uint32(env, value, nullptr))");
128+
WriteLine(@"#define NAPI_IS_INT64(valuetype, value) (NAPI_IS_BIGINT(valuetype))");
129+
WriteLine(@"#define NAPI_IS_UINT64(valuetype, value) (NAPI_IS_BIGINT(valuetype))");
130+
NewLine();
131+
}
132+
}
133+
}

0 commit comments

Comments
 (0)