diff options
| -rw-r--r-- | README.md | 4 | ||||
| -rw-r--r-- | nimterop/ast.nim | 2 | ||||
| -rw-r--r-- | nimterop/globals.nim | 6 | ||||
| -rw-r--r-- | nimterop/grammar.nim | 74 | ||||
| -rw-r--r-- | tests/include/test.c | 38 | ||||
| -rw-r--r-- | tests/include/test.h | 21 | ||||
| -rw-r--r-- | tests/tnimterop_c.nim | 17 |
7 files changed, 112 insertions, 50 deletions
@@ -14,8 +14,8 @@ Most of the functionality is contained within the `toast` binary that is built w The nimterop feature set is still limited when compared with c2nim. Supported language constructs include: - `#define NAME VALUE` where `VALUE` is a number (int, float, hex) -- `struct X`, `typedef struct`, `enum X`, `typedef enum` -- Functions with primitive types, structs, enums and typedef structs/enums as params and return values +- `struct X`, `typedef struct`, `enum X`, `typedef enum`, `union X`, `typedef union` +- Functions with primitive types, structs, enums, unions and typedef structs/enums/unions as params and return values - Pointers to data types Given the simplicity and success of this approach so far, it seems feasible to continue on for more complex code. The goal is to make interop seamless so nimterop will focus on wrapping headers and not the outright conversion of C/C++ implementation. diff --git a/nimterop/ast.nim b/nimterop/ast.nim index df973b9..9a2ee3c 100644 --- a/nimterop/ast.nim +++ b/nimterop/ast.nim @@ -84,7 +84,7 @@ proc searchAst(root: TSNode) = if name in gStateRT.ast: for ast in gStateRT.ast[name]: if searchAstForNode(ast, node): - ast.tonim() + ast.tonim(ast, node) break gStateRT.data = @[] else: diff --git a/nimterop/globals.nim b/nimterop/globals.nim index e65a4b9..c4fe8ad 100644 --- a/nimterop/globals.nim +++ b/nimterop/globals.nim @@ -2,6 +2,8 @@ import tables import regex +import treesitter/runtime + type Kind* = enum exactlyOne @@ -13,7 +15,7 @@ type name*: string kind*: Kind children*: seq[ref Ast] - tonim*: proc () {.closure, locks: 0.} + tonim*: proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} regex*: Regex State* = object @@ -28,7 +30,7 @@ type ast*: Table[string, seq[ref Ast]] data*: seq[tuple[name, val: string]] - grammar*: seq[tuple[grammar: string, call: proc() {.locks: 0.}]] + grammar*: seq[tuple[grammar: string, call: proc(ast: ref Ast, node: TSNode) {.locks: 0.}]] var gStateCT* {.compiletime.}: State diff --git a/nimterop/grammar.nim b/nimterop/grammar.nim index 2233609..455d2e8 100644 --- a/nimterop/grammar.nim +++ b/nimterop/grammar.nim @@ -1,7 +1,9 @@ -import strformat, tables +import strformat, strutils, tables import regex +import treesitter/runtime + import "."/[getters, globals, lisp] proc initGrammar() = @@ -12,7 +14,7 @@ proc initGrammar() = (preproc_arg) ) """, - proc () {.closure, locks: 0.} = + proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} = let name = gStateRT.data[0].val.getIdentifier() val = gStateRT.data[1].val.getLit() @@ -41,7 +43,7 @@ proc initGrammar() = ) ) """, - proc () {.closure, locks: 0.} = + proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} = var name = gStateRT.data[1].val.getIdentifier() typ = gStateRT.data[0].val.getIdentifier() @@ -51,12 +53,31 @@ proc initGrammar() = gStateRT.typeStr &= &" {name}* = {typ}\n" )) - proc pStructCommon(name: string, fstart, fend: int, prefix="") = - let + proc pStructCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int) = + var nname = name.getIdentifier() + prefix = "" + union = "" + + case $node.tsNodeType(): + of "struct_specifier": + prefix = "struct " + of "union_specifier": + prefix = "union " + union = " {.union.}" + of "type_definition": + if node.getTSNodeNamedChildCountSansComments() != 0: + for i in 0 .. node.tsNodeNamedChildCount()-1: + let + nchild = $node.tsNodeNamedChild(i).tsNodeType() + if nchild != "comment": + if nchild == "union_specifier": + union = " {.union.}" + break + if nname notin gStateRT.types: gStateRT.types.add(nname) - gStateRT.typeStr &= &" {nname}* {{.importc: \"{prefix}{name}\", header: {gStateRT.currentHeader}, bycopy.}} = object\n" + gStateRT.typeStr &= &" {nname}* {{.importc: \"{prefix}{name}\", header: {gStateRT.currentHeader}, bycopy.}} = object{union}\n" var i = fstart @@ -69,13 +90,13 @@ proc initGrammar() = # struct X {} gStateRT.grammar.add((""" - (struct_specifier + (struct_specifier|union_specifier (type_identifier) (field_declaration_list (field_declaration+ (primitive_type|type_identifier?) (sized_type_specifier? - (primitive_type) + (primitive_type?) ) (struct_specifier? (type_identifier) @@ -88,14 +109,14 @@ proc initGrammar() = ) ) """, - proc () {.closure, locks: 0.} = - pStructCommon(gStateRT.data[0].val, 1, 0, "struct ") + proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} = + pStructCommon(ast, node, gStateRT.data[0].val, 1, 1) )) # typedef struct X {} gStateRT.grammar.add((""" (type_definition - (struct_specifier + (struct_specifier|union_specifier (field_declaration_list (field_declaration+ (primitive_type|type_identifier?) @@ -115,11 +136,11 @@ proc initGrammar() = (type_identifier) ) """, - proc () {.closure, locks: 0.} = - pStructCommon(gStateRT.data[^1].val, 0, 1) + proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} = + pStructCommon(ast, node, gStateRT.data[^1].val, 0, 1) )) - proc pEnumCommon(name: string, fstart, fend: int, prefix="") = + proc pEnumCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int) = let nname = name.getIdentifier() if nname notin gStateRT.types: @@ -151,8 +172,8 @@ proc initGrammar() = ) ) """, - proc () {.closure, locks: 0.} = - pEnumCommon(gStateRT.data[0].val, 1, 0) + proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} = + pEnumCommon(ast, node, gStateRT.data[0].val, 1, 0) )) # typedef enum {} X @@ -169,8 +190,8 @@ proc initGrammar() = (type_identifier) ) """, - proc () {.closure, locks: 0.} = - pEnumCommon(gStateRT.data[^1].val, 0, 1) + proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} = + pEnumCommon(ast, node, gStateRT.data[^1].val, 0, 1) )) # typ function(typ param1, ...) @@ -181,7 +202,7 @@ proc initGrammar() = (sized_type_specifier? (primitive_type?) ) - (struct_specifier? + (struct_specifier|union_specifier? (type_identifier) ) (function_declarator? @@ -193,7 +214,7 @@ proc initGrammar() = (sized_type_specifier? (primitive_type?) ) - (struct_specifier? + (struct_specifier|union_specifier? (type_identifier) ) (enum_specifier? @@ -216,7 +237,7 @@ proc initGrammar() = (sized_type_specifier? (primitive_type?) ) - (struct_specifier? + (struct_specifier|union_specifier? (type_identifier) ) (enum_specifier? @@ -232,7 +253,7 @@ proc initGrammar() = ) ) """, - proc () {.closure, locks: 0.} = + proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} = let ftyp = gStateRT.data[0].val.getIdentifier() fname = gStateRT.data[1].val @@ -277,10 +298,11 @@ proc parseGrammar*() = ast.tonim = gStateRT.grammar[i].call ast.initRegex() - if ast.name notin gStateRT.ast: - gStateRT.ast[ast.name] = @[ast] - else: - gStateRT.ast[ast.name].add(ast) + for n in ast.name.split("|"): + if n notin gStateRT.ast: + gStateRT.ast[n] = @[ast] + else: + gStateRT.ast[n].add(ast) proc printGrammar*() = for name in gStateRT.ast.keys(): diff --git a/tests/include/test.c b/tests/include/test.c index 885723e..d63c974 100644 --- a/tests/include/test.c +++ b/tests/include/test.c @@ -1,35 +1,51 @@ #include "test.h" int test_call_int() { - return 5; + return 5; } #ifdef FORCE -struct STRUCT1 _test_call_int_param_(int param1) { +struct STRUCT1 _test_call_param_(int param1) { struct STRUCT1 s; - + s.field1 = param1; - + return s; } #endif -STRUCT2 test_call_int_param2(int param1, STRUCT2 param2) { +STRUCT2 test_call_param2(int param1, STRUCT2 param2) { STRUCT2 s; - + s.field1 = param1 + param2.field1; - + return s; } -STRUCT2 test_call_int_param3(int param1, struct STRUCT1 param2) { +STRUCT2 test_call_param3(int param1, struct STRUCT1 param2) { STRUCT2 s; - + s.field1 = param1 + param2.field1; - + return s; } -ENUM2 test_call_int_param4(enum ENUM param1) { +ENUM2 test_call_param4(enum ENUM param1) { return enum4; +} + +union UNION1 test_call_param5(float param1) { + union UNION1 u; + + u.field2 = param1; + + return u; +} + +unsigned char test_call_param6(UNION2 param1) { + return param1.field2; +} + +int test_call_param7(union UNION1 param1) { + return param1.field1; }
\ No newline at end of file diff --git a/tests/include/test.h b/tests/include/test.h index 6138ca3..af7eeb8 100644 --- a/tests/include/test.h +++ b/tests/include/test.h @@ -36,8 +36,21 @@ typedef struct { int *field; } STRUCT4; +union UNION1 { + int field1; + float field2; +}; + +typedef union { + double field1; + unsigned char field2; +} UNION2; + int test_call_int(); -struct STRUCT1 _test_call_int_param_(int param1); -STRUCT2 test_call_int_param2(int param1, STRUCT2 param2); -STRUCT2 test_call_int_param3(int param1, struct STRUCT1 param2); -ENUM2 test_call_int_param4(enum ENUM param1); +struct STRUCT1 _test_call_param_(int param1); +STRUCT2 test_call_param2(int param1, STRUCT2 param2); +STRUCT2 test_call_param3(int param1, struct STRUCT1 param2); +ENUM2 test_call_param4(enum ENUM param1); +union UNION1 test_call_param5(float param1); +unsigned char test_call_param6(UNION2 param1); +int test_call_param7(union UNION1 param1);
\ No newline at end of file diff --git a/tests/tnimterop_c.nim b/tests/tnimterop_c.nim index eff7039..2477e61 100644 --- a/tests/tnimterop_c.nim +++ b/tests/tnimterop_c.nim @@ -28,6 +28,9 @@ var vptr: VOIDPTR iptr: INTPTR + u: UNION1 + u2: UNION2 + pt = 3 ct = 4 @@ -38,10 +41,16 @@ s3.field1 = 7 e = enum1 e2 = enum4 +u2.field2 = 'c' + check test_call_int() == 5 -check test_call_int_param(5).field1 == 5 -check test_call_int_param2(5, s2).field1 == 11 -check test_call_int_param3(5, s).field1 == 10 -check test_call_int_param4(e) == e2 +check test_call_param(5).field1 == 5 +check test_call_param2(5, s2).field1 == 11 +check test_call_param3(5, s).field1 == 10 +check test_call_param4(e) == e2 +check test_call_param5(5.0).field2 == 5.0 +check test_call_param6(u2) == 'c' +u.field1 = 4 +check test_call_param7(u) == 4 cAddStdDir() |
