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:
- `#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.

View file

@ -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:

View file

@ -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

View file

@ -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():

View file

@ -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;
}

View file

@ -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);

View file

@ -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()