Support for unions

This commit is contained in:
Ganesh Viswanathan 2018-12-04 23:37:08 -06:00
commit dfe06fd9d4
7 changed files with 112 additions and 50 deletions

View file

@ -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: 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) - `#define NAME VALUE` where `VALUE` is a number (int, float, hex)
- `struct X`, `typedef struct`, `enum X`, `typedef enum` - `struct X`, `typedef struct`, `enum X`, `typedef enum`, `union X`, `typedef union`
- Functions with primitive types, structs, enums and typedef structs/enums as params and return values - Functions with primitive types, structs, enums, unions and typedef structs/enums/unions as params and return values
- Pointers to data types - 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. 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.

View file

@ -84,7 +84,7 @@ proc searchAst(root: TSNode) =
if name in gStateRT.ast: if name in gStateRT.ast:
for ast in gStateRT.ast[name]: for ast in gStateRT.ast[name]:
if searchAstForNode(ast, node): if searchAstForNode(ast, node):
ast.tonim() ast.tonim(ast, node)
break break
gStateRT.data = @[] gStateRT.data = @[]
else: else:

View file

@ -2,6 +2,8 @@ import tables
import regex import regex
import treesitter/runtime
type type
Kind* = enum Kind* = enum
exactlyOne exactlyOne
@ -13,7 +15,7 @@ type
name*: string name*: string
kind*: Kind kind*: Kind
children*: seq[ref Ast] children*: seq[ref Ast]
tonim*: proc () {.closure, locks: 0.} tonim*: proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.}
regex*: Regex regex*: Regex
State* = object State* = object
@ -28,7 +30,7 @@ type
ast*: Table[string, seq[ref Ast]] ast*: Table[string, seq[ref Ast]]
data*: seq[tuple[name, val: string]] 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 var
gStateCT* {.compiletime.}: State gStateCT* {.compiletime.}: State

View file

@ -1,7 +1,9 @@
import strformat, tables import strformat, strutils, tables
import regex import regex
import treesitter/runtime
import "."/[getters, globals, lisp] import "."/[getters, globals, lisp]
proc initGrammar() = proc initGrammar() =
@ -12,7 +14,7 @@ proc initGrammar() =
(preproc_arg) (preproc_arg)
) )
""", """,
proc () {.closure, locks: 0.} = proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} =
let let
name = gStateRT.data[0].val.getIdentifier() name = gStateRT.data[0].val.getIdentifier()
val = gStateRT.data[1].val.getLit() 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 var
name = gStateRT.data[1].val.getIdentifier() name = gStateRT.data[1].val.getIdentifier()
typ = gStateRT.data[0].val.getIdentifier() typ = gStateRT.data[0].val.getIdentifier()
@ -51,12 +53,31 @@ proc initGrammar() =
gStateRT.typeStr &= &" {name}* = {typ}\n" gStateRT.typeStr &= &" {name}* = {typ}\n"
)) ))
proc pStructCommon(name: string, fstart, fend: int, prefix="") = proc pStructCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int) =
let var
nname = name.getIdentifier() 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: if nname notin gStateRT.types:
gStateRT.types.add(nname) 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 var
i = fstart i = fstart
@ -69,13 +90,13 @@ proc initGrammar() =
# struct X {} # struct X {}
gStateRT.grammar.add((""" gStateRT.grammar.add(("""
(struct_specifier (struct_specifier|union_specifier
(type_identifier) (type_identifier)
(field_declaration_list (field_declaration_list
(field_declaration+ (field_declaration+
(primitive_type|type_identifier?) (primitive_type|type_identifier?)
(sized_type_specifier? (sized_type_specifier?
(primitive_type) (primitive_type?)
) )
(struct_specifier? (struct_specifier?
(type_identifier) (type_identifier)
@ -88,14 +109,14 @@ proc initGrammar() =
) )
) )
""", """,
proc () {.closure, locks: 0.} = proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} =
pStructCommon(gStateRT.data[0].val, 1, 0, "struct ") pStructCommon(ast, node, gStateRT.data[0].val, 1, 1)
)) ))
# typedef struct X {} # typedef struct X {}
gStateRT.grammar.add((""" gStateRT.grammar.add(("""
(type_definition (type_definition
(struct_specifier (struct_specifier|union_specifier
(field_declaration_list (field_declaration_list
(field_declaration+ (field_declaration+
(primitive_type|type_identifier?) (primitive_type|type_identifier?)
@ -115,11 +136,11 @@ proc initGrammar() =
(type_identifier) (type_identifier)
) )
""", """,
proc () {.closure, locks: 0.} = proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} =
pStructCommon(gStateRT.data[^1].val, 0, 1) 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 let
nname = name.getIdentifier() nname = name.getIdentifier()
if nname notin gStateRT.types: if nname notin gStateRT.types:
@ -151,8 +172,8 @@ proc initGrammar() =
) )
) )
""", """,
proc () {.closure, locks: 0.} = proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} =
pEnumCommon(gStateRT.data[0].val, 1, 0) pEnumCommon(ast, node, gStateRT.data[0].val, 1, 0)
)) ))
# typedef enum {} X # typedef enum {} X
@ -169,8 +190,8 @@ proc initGrammar() =
(type_identifier) (type_identifier)
) )
""", """,
proc () {.closure, locks: 0.} = proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} =
pEnumCommon(gStateRT.data[^1].val, 0, 1) pEnumCommon(ast, node, gStateRT.data[^1].val, 0, 1)
)) ))
# typ function(typ param1, ...) # typ function(typ param1, ...)
@ -181,7 +202,7 @@ proc initGrammar() =
(sized_type_specifier? (sized_type_specifier?
(primitive_type?) (primitive_type?)
) )
(struct_specifier? (struct_specifier|union_specifier?
(type_identifier) (type_identifier)
) )
(function_declarator? (function_declarator?
@ -193,7 +214,7 @@ proc initGrammar() =
(sized_type_specifier? (sized_type_specifier?
(primitive_type?) (primitive_type?)
) )
(struct_specifier? (struct_specifier|union_specifier?
(type_identifier) (type_identifier)
) )
(enum_specifier? (enum_specifier?
@ -216,7 +237,7 @@ proc initGrammar() =
(sized_type_specifier? (sized_type_specifier?
(primitive_type?) (primitive_type?)
) )
(struct_specifier? (struct_specifier|union_specifier?
(type_identifier) (type_identifier)
) )
(enum_specifier? (enum_specifier?
@ -232,7 +253,7 @@ proc initGrammar() =
) )
) )
""", """,
proc () {.closure, locks: 0.} = proc (ast: ref Ast, node: TSNode) {.closure, locks: 0.} =
let let
ftyp = gStateRT.data[0].val.getIdentifier() ftyp = gStateRT.data[0].val.getIdentifier()
fname = gStateRT.data[1].val fname = gStateRT.data[1].val
@ -277,10 +298,11 @@ proc parseGrammar*() =
ast.tonim = gStateRT.grammar[i].call ast.tonim = gStateRT.grammar[i].call
ast.initRegex() ast.initRegex()
if ast.name notin gStateRT.ast: for n in ast.name.split("|"):
gStateRT.ast[ast.name] = @[ast] if n notin gStateRT.ast:
else: gStateRT.ast[n] = @[ast]
gStateRT.ast[ast.name].add(ast) else:
gStateRT.ast[n].add(ast)
proc printGrammar*() = proc printGrammar*() =
for name in gStateRT.ast.keys(): for name in gStateRT.ast.keys():

View file

@ -5,7 +5,7 @@ int test_call_int() {
} }
#ifdef FORCE #ifdef FORCE
struct STRUCT1 _test_call_int_param_(int param1) { struct STRUCT1 _test_call_param_(int param1) {
struct STRUCT1 s; struct STRUCT1 s;
s.field1 = param1; s.field1 = param1;
@ -14,7 +14,7 @@ struct STRUCT1 _test_call_int_param_(int param1) {
} }
#endif #endif
STRUCT2 test_call_int_param2(int param1, STRUCT2 param2) { STRUCT2 test_call_param2(int param1, STRUCT2 param2) {
STRUCT2 s; STRUCT2 s;
s.field1 = param1 + param2.field1; s.field1 = param1 + param2.field1;
@ -22,7 +22,7 @@ STRUCT2 test_call_int_param2(int param1, STRUCT2 param2) {
return s; return s;
} }
STRUCT2 test_call_int_param3(int param1, struct STRUCT1 param2) { STRUCT2 test_call_param3(int param1, struct STRUCT1 param2) {
STRUCT2 s; STRUCT2 s;
s.field1 = param1 + param2.field1; s.field1 = param1 + param2.field1;
@ -30,6 +30,22 @@ STRUCT2 test_call_int_param3(int param1, struct STRUCT1 param2) {
return s; return s;
} }
ENUM2 test_call_int_param4(enum ENUM param1) { ENUM2 test_call_param4(enum ENUM param1) {
return enum4; 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;
}

View file

@ -36,8 +36,21 @@ typedef struct {
int *field; int *field;
} STRUCT4; } STRUCT4;
union UNION1 {
int field1;
float field2;
};
typedef union {
double field1;
unsigned char field2;
} UNION2;
int test_call_int(); int test_call_int();
struct STRUCT1 _test_call_int_param_(int param1); struct STRUCT1 _test_call_param_(int param1);
STRUCT2 test_call_int_param2(int param1, STRUCT2 param2); STRUCT2 test_call_param2(int param1, STRUCT2 param2);
STRUCT2 test_call_int_param3(int param1, struct STRUCT1 param2); STRUCT2 test_call_param3(int param1, struct STRUCT1 param2);
ENUM2 test_call_int_param4(enum ENUM param1); 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);

View file

@ -28,6 +28,9 @@ var
vptr: VOIDPTR vptr: VOIDPTR
iptr: INTPTR iptr: INTPTR
u: UNION1
u2: UNION2
pt = 3 pt = 3
ct = 4 ct = 4
@ -38,10 +41,16 @@ s3.field1 = 7
e = enum1 e = enum1
e2 = enum4 e2 = enum4
u2.field2 = 'c'
check test_call_int() == 5 check test_call_int() == 5
check test_call_int_param(5).field1 == 5 check test_call_param(5).field1 == 5
check test_call_int_param2(5, s2).field1 == 11 check test_call_param2(5, s2).field1 == 11
check test_call_int_param3(5, s).field1 == 10 check test_call_param3(5, s).field1 == 10
check test_call_int_param4(e) == e2 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() cAddStdDir()