Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 63 additions & 14 deletions src/genny/languages/cpp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var
procs {.compiletime.}: string
classes {.compiletime.}: string
members {.compiletime.}: string
hasRaisingProcs {.compiletime.}: bool

proc unCapitalize(s: string): string =
s[0].toLowerAscii() & s[1 .. ^1]
Expand Down Expand Up @@ -121,6 +122,31 @@ proc cppReturnValue(returnType: NimNode, call: string): string =
else:
call

proc addCppCall(
returnType: NimNode,
call: string,
raises: bool
) =
if not raises:
members.add " "
if returnType.kind != nnkEmpty:
members.add "return "
members.add cppReturnValue(returnType, call)
members.add ";\n"
return

hasRaisingProcs = true
if returnType.kind == nnkEmpty:
members.add &" {call};\n"
members.add " throwIfError();\n"
else:
members.add &" auto result = {call};\n"
if returnType.isStringType:
members.add " throwIfError(result);\n"
else:
members.add " throwIfError();\n"
members.add &" return {cppReturnValue(returnType, \"result\")};\n"

proc dllProc*(procName: string, args: openarray[string], restype: string) =
var argStr = ""
for arg in args:
Expand Down Expand Up @@ -160,6 +186,7 @@ proc exportProcCpp*(
procType = sym.getTypeInst()
procParams = procType[0][1 .. ^1]
procReturn = procType[0][0]
procRaises = sym.raises()

var apiProcName = ""
if owner != nil:
Expand Down Expand Up @@ -190,17 +217,13 @@ proc exportProcCpp*(
members.add ", "
members.removeSuffix ", "
members.add ") {\n"
members.add " "
if procReturn.kind != nnkEmpty:
members.add "return "
var call = &"$lib_{apiProcName}("
for param in procParams:
call.add cppArgValue(param[1], param[0].getParamName())
call.add ", "
call.removeSuffix ", "
call.add ")"
members.add cppReturnValue(procReturn, call)
members.add ";\n"
addCppCall(procReturn, call, procRaises)
members.add "};\n\n"

else:
Expand Down Expand Up @@ -240,18 +263,13 @@ proc exportProcCpp*(
members.removeSuffix ", "
members.add ") "
members.add "{\n"
if procReturn.kind == nnkEmpty:
members.add &" "
else:
members.add &" return "
var call = &"$lib_{apiProcName}(*this, "
for param in procParams[1..^1]:
call.add cppArgValue(param[1], param[0].getParamName())
call.add ", "
call.removeSuffix ", "
call.add ")"
members.add cppReturnValue(procReturn, call)
members.add ";\n"
addCppCall(procReturn, call, procRaises)
members.add "};\n\n"

proc exportObjectCpp*(
Expand Down Expand Up @@ -435,13 +453,17 @@ proc exportRefObjectCpp*(
members.removeSuffix ", "
members.add ")"
members.add " {\n"
members.add &" this->reference = "
members.add &" auto result = "
members.add &"{constructorLibProc}("
for param in constructorParams:
members.add cppArgValue(param[1], param[0].getParamName())
members.add ", "
members.removeSuffix ", "
members.add ").reference;\n"
members.add ");\n"
if constructorRaises:
hasRaisingProcs = true
members.add " throwIfError();\n"
members.add " this->reference = result.reference;\n"
members.add "}\n\n"

var dllParams: seq[(NimNode, NimNode)]
Expand Down Expand Up @@ -562,6 +584,7 @@ const header = """

#include <cstddef>
#include <cstdint>
#include <stdexcept>
#include <string>

"""
Expand Down Expand Up @@ -616,11 +639,36 @@ void GennyBuffer::free() {

"""

const errorMembers = """
struct $LibException : public std::runtime_error {
explicit $LibException(const std::string& message) : std::runtime_error(message) {}
};

static inline void throwIfError() {
if ($lib_check_error()) {
throw $LibException(gennyBufferToString($lib_take_error()));
}
}

static inline void throwIfError(GennyBuffer buffer) {
if ($lib_check_error()) {
$lib_genny_buffer_unref(buffer);
throw $LibException(gennyBufferToString($lib_take_error()));
}
}

"""

const footer = """
#endif
"""

proc writeCpp*(dir, lib: string) =
let errorBlock =
if hasRaisingProcs:
errorMembers
else:
""
createDir(dir)
writeFile(&"{dir}/{toSnakeCase(lib)}.hpp", (
header &
Expand All @@ -632,7 +680,8 @@ proc writeCpp*(dir, lib: string) =
procs &
"}\n\n" &
bufferMembers &
errorBlock &
members &
footer
).replace("$lib", toSnakeCase(lib)).replace("$LIB", lib.toUpperAscii())
).replace("$Lib", lib).replace("$lib", toSnakeCase(lib)).replace("$LIB", lib.toUpperAscii())
)
44 changes: 39 additions & 5 deletions src/genny/languages/node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,30 @@ proc jsReturnValue(returnType: NimNode, call: string): string =
else:
call

proc addNodeCall(
returnType: NimNode,
call: string,
raises: bool
) =
if not raises:
types.add " "
if returnType.kind != nnkEmpty:
types.add "return "
types.add jsReturnValue(returnType, call)
types.add ";\n"
return

if returnType.kind == nnkEmpty:
types.add &" {call};\n"
types.add " throwIfError();\n"
else:
types.add &" const result = {call};\n"
if returnType.isStringType:
types.add " throwIfError(result);\n"
else:
types.add " throwIfError();\n"
types.add &" return {jsReturnValue(returnType, \"result\")};\n"

proc convertExportFromNode*(sym: NimNode): string =
discard

Expand Down Expand Up @@ -219,9 +243,6 @@ proc exportProcNode*(
types.add &", "
types.removeSuffix ", "
types.add ") {\n"
types.add " "
if procReturn.kind != nnkEmpty:
types.add "return "
var call = &"{apiProcName}("
for i, param in procParams[0 .. ^1]:
if isRefObject and i == 0:
Expand All @@ -232,8 +253,7 @@ proc exportProcNode*(
call.add &", "
call.removeSuffix ", "
call.add ")"
types.add jsReturnValue(procReturn, call)
types.add ";\n"
addNodeCall(procReturn, call, procRaises)
types.add "}\n\n"

proc exportObjectNode*(
Expand Down Expand Up @@ -343,6 +363,7 @@ proc exportRefObjectNode*(
constructorLibProc = &"$lib_{toSnakeCase(constructor.repr)}"
constructorType = constructor.getTypeInst()
constructorParams = constructorType[0][1 .. ^1]
constructorRaises = constructor.raises()

# Declare constructor C function
declareFunc(constructorLibProc, constructorParams, "'uint64'")
Expand All @@ -361,6 +382,8 @@ proc exportRefObjectNode*(
types.add ", "
types.removeSuffix ", "
types.add ");\n"
if constructorRaises:
types.add " throwIfError();\n"
types.add &" return new {objName}(ref);\n"
types.add "}\n\n"

Expand Down Expand Up @@ -477,6 +500,17 @@ class $LibException extends Error {
}
}

exports.$LibException = $LibException;

function throwIfError(buffer = null) {
if (checkError()) {
if (buffer !== null && buffer !== 0 && buffer !== 0n) {
$lib_genny_buffer_unref(buffer);
}
throw new $LibException(takeError());
}
}

function runeToInt(value) {
assert.strictEqual(typeof value, 'string', 'expected rune string');
const chars = Array.from(value);
Expand Down
18 changes: 18 additions & 0 deletions tests/generated/internal.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ proc test_genny_buffer_unref*(buffer: GennyBuffer) {.raises: [], cdecl, exportc,
proc test_simple_call*(a: int): int {.raises: [], cdecl, exportc, dynlib.} =
simpleCall(a)

proc test_check_error*(): bool {.raises: [], cdecl, exportc, dynlib.} =
checkError()

proc test_take_error*(): GennyBuffer {.raises: [], cdecl, exportc, dynlib.} =
newGennyBuffer(takeError())

proc test_maybe_message*(message: cstring, fail: bool): GennyBuffer {.raises: [], cdecl, exportc, dynlib.} =
try:
result = newGennyBuffer(maybeMessage(message.`$`, fail))
except testError as e:
lastError = e

proc test_maybe_number*(value: int, fail: bool): int {.raises: [], cdecl, exportc, dynlib.} =
try:
result = maybeNumber(value, fail)
except testError as e:
lastError = e

proc test_simple_obj*(simple_a: int, simple_b: byte, simple_c: bool): SimpleObj {.raises: [], cdecl, exportc, dynlib.} =
result.simple_a = simple_a
result.simple_b = simple_b
Expand Down
8 changes: 8 additions & 0 deletions tests/generated/test.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ void test_genny_buffer_unref(GennyBuffer buffer);
*/
intptr_t test_simple_call(intptr_t a);

char test_check_error();

GennyBuffer test_take_error();

GennyBuffer test_maybe_message(const char* message, char fail);

intptr_t test_maybe_number(intptr_t value, char fail);

SimpleObj test_simple_obj(intptr_t simple_a, uint8_t simple_b, char simple_c);

char test_simple_obj_eq(SimpleObj a, SimpleObj b);
Expand Down
52 changes: 50 additions & 2 deletions tests/generated/test.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <cstddef>
#include <cstdint>
#include <stdexcept>
#include <string>

static constexpr auto SIMPLE_CONST = 123;
Expand Down Expand Up @@ -157,6 +158,14 @@ void test_genny_buffer_unref(GennyBuffer buffer);

std::intptr_t test_simple_call(std::intptr_t a);

bool test_check_error();

GennyBuffer test_take_error();

GennyBuffer test_maybe_message(const char* message, bool fail);

std::intptr_t test_maybe_number(std::intptr_t value, bool fail);

SimpleObj test_simple_obj(std::intptr_t simple_a, std::uint8_t simple_b, bool simple_c);

bool test_simple_obj_eq(SimpleObj a, SimpleObj b);
Expand Down Expand Up @@ -262,16 +271,54 @@ void GennyBuffer::free() {
test_genny_buffer_unref(*this);
}

struct testException : public std::runtime_error {
explicit testException(const std::string& message) : std::runtime_error(message) {}
};

static inline void throwIfError() {
if (test_check_error()) {
throw testException(gennyBufferToString(test_take_error()));
}
}

static inline void throwIfError(GennyBuffer buffer) {
if (test_check_error()) {
test_genny_buffer_unref(buffer);
throw testException(gennyBufferToString(test_take_error()));
}
}

std::intptr_t simpleCall(std::intptr_t a) {
return test_simple_call(a);
};

bool checkError() {
return test_check_error();
};

std::string takeError() {
return gennyBufferToString(test_take_error());
};

std::string maybeMessage(const char* message, bool fail) {
auto result = test_maybe_message(message, fail);
throwIfError(result);
return gennyBufferToString(result);
};

std::intptr_t maybeNumber(std::intptr_t value, bool fail) {
auto result = test_maybe_number(value, fail);
throwIfError();
return result;
};

SimpleObj simpleObj(std::intptr_t simpleA, std::uint8_t simpleB, bool simpleC) {
return test_simple_obj(simpleA, simpleB, simpleC);
};

SimpleRefObj::SimpleRefObj() {
this->reference = test_new_simple_ref_obj().reference;
auto result = test_new_simple_ref_obj();
this->reference = result.reference;
}

std::intptr_t SimpleRefObj::getSimpleRefA(){
Expand Down Expand Up @@ -335,7 +382,8 @@ void SeqInt::free(){
}

RefObjWithSeq::RefObjWithSeq() {
this->reference = test_new_ref_obj_with_seq().reference;
auto result = test_new_ref_obj_with_seq();
this->reference = result.reference;
}

std::intptr_t RefObjWithSeq::dataSize(){
Expand Down
Loading
Loading