Support for unions
This commit is contained in:
parent
cb1c7f28cb
commit
dfe06fd9d4
7 changed files with 112 additions and 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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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():
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue