Fix type bugs, enable basic tests

This commit is contained in:
Ganesh Viswanathan 2020-01-09 13:58:34 -06:00
commit 49607db05b
6 changed files with 223 additions and 60 deletions

View file

@ -36,19 +36,22 @@ task docs, "Generate docs":
task test, "Test": task test, "Test":
buildToastTask() buildToastTask()
execTest "tests/tnimterop_c.nim" execTest "tests/tnimterop2.nim"
execCmd "nim cpp -f -r tests/tnimterop_cpp.nim"
execCmd "./nimterop/toast -pnk -E=_ tests/include/toast.h" # Commented out until newalgo is ready
execTest "tests/tpcre.nim" # execTest "tests/tnimterop_c.nim"
# execCmd "nim cpp -f -r tests/tnimterop_cpp.nim"
# execCmd "./nimterop/toast -pnk -E=_ tests/include/toast.h"
# execTest "tests/tpcre.nim"
# Platform specific tests # Platform specific tests
when defined(Windows): # when defined(Windows):
execTest "tests/tmath.nim" # execTest "tests/tmath.nim"
if defined(OSX) or defined(Windows) or not existsEnv("TRAVIS"): # if defined(OSX) or defined(Windows) or not existsEnv("TRAVIS"):
execTest "tests/tsoloud.nim" # execTest "tests/tsoloud.nim"
# getHeader tests # getHeader tests
withDir("tests"): # withDir("tests"):
execCmd("nim e getheader.nims") # execCmd("nim e getheader.nims")
docsTask() docsTask()

View file

@ -13,6 +13,7 @@ proc addConst(nimState: NimState, node: TSNode) =
# (identifier) # (identifier)
# (preproc_arg) # (preproc_arg)
# ) # )
decho("addConst()")
nimState.printDebug(node) nimState.printDebug(node)
if node[0].getName() == "identifier" and if node[0].getName() == "identifier" and
@ -51,6 +52,8 @@ proc addConst(nimState: NimState, node: TSNode) =
proc newTypeIdent(nimState: NimState, node: TSNode, override = ""): PNode = proc newTypeIdent(nimState: NimState, node: TSNode, override = ""): PNode =
# Create nkTypeDef PNode with first ident # Create nkTypeDef PNode with first ident
#
# If `override`, use it instead of node.getAtom() for name
let let
(name, info) = nimState.getNameInfo(node.getAtom(), nskType) (name, info) = nimState.getNameInfo(node.getAtom(), nskType)
# TODO - check blank and override # TODO - check blank and override
@ -60,30 +63,46 @@ proc newTypeIdent(nimState: NimState, node: TSNode, override = ""): PNode =
else: else:
nimState.getIdent(name, info) nimState.getIdent(name, info)
# type name* =
#
# nkTypeDef(
# nkPostfix(
# nkIdent("*"),
# nkIdent(name)
# ),
# nkEmpty()
# )
result = newNode(nkTypeDef) result = newNode(nkTypeDef)
result.add ident result.add ident
result.add newNode(nkEmpty) result.add newNode(nkEmpty)
proc newPtrTree(count: int, typ: PNode): PNode = proc newPtrTree(nimState: NimState, count: int, typ: PNode): PNode =
# Create nkPtrTy tree depending on count # Create nkPtrTy tree depending on count
# #
# Reduce by 1 if Nim type available for ptr X - e.g. ptr cchar = cstring # Reduce by 1 if Nim type available for ptr X - e.g. ptr cchar = cstring
#
# nkPtrTy(
# nkPtrTy(
# typ
# )
# )
var var
count = count count = count
chng = false
if typ.kind == nkIdent: if typ.kind == nkIdent:
let let
tname = typ.ident.s tname = typ.ident.s
ptname = getPtrType(tname) ptname = getPtrType(tname)
if tname != ptname: if tname != ptname:
typ.ident.s = ptname # If Nim type available, use that ident
result = nimState.getIdent(ptname, typ.info, exported = false)
chng = true
# One ptr reduced
count -= 1 count -= 1
if count > 0: if count > 0:
# Nested nkPtrTy(typ) depending on count
#
# [ptr ...] typ
#
# nkPtrTy(
# nkPtrTy(
# typ
# )
# )
result = newNode(nkPtrTy) result = newNode(nkPtrTy)
var var
parent = result parent = result
@ -93,11 +112,17 @@ proc newPtrTree(count: int, typ: PNode): PNode =
parent.add child parent.add child
parent = child parent = child
parent.add typ parent.add typ
else: elif not chng:
# Either no ptr, or none left after Nim type adjustment
result = typ result = typ
proc newArrayTree(nimState: NimState, node: TSNode, typ, size: PNode): PNode = proc newArrayTree(nimState: NimState, node: TSNode, typ, size: PNode): PNode =
# Create nkBracketExpr tree depending on input # Create nkBracketExpr tree depending on input
let
(_, info) = nimState.getNameInfo(node, nskType)
ident = nimState.getIdent("array", info, exported = false)
# array[size, typ]
# #
# nkBracketExpr( # nkBracketExpr(
# nkIdent("array"), # nkIdent("array"),
@ -105,11 +130,6 @@ proc newArrayTree(nimState: NimState, node: TSNode, typ, size: PNode): PNode =
# typ # typ
# ) # )
result = newNode(nkBracketExpr) result = newNode(nkBracketExpr)
let
(_, info) = nimState.getNameInfo(node, nskType)
ident = nimState.getIdent("array", info, exported = false)
result.add ident result.add ident
result.add size result.add size
result.add typ result.add typ
@ -122,6 +142,8 @@ proc newIdentDefs(nimState: NimState, name: string, node: TSNode, offset: uint64
# #
# For proc, param should not be exported # For proc, param should not be exported
# #
# pname: [ptr ..] typ
#
# nkIdentDefs( # nkIdentDefs(
# nkIdent(pname), # nkIdent(pname),
# typ, # typ,
@ -130,6 +152,8 @@ proc newIdentDefs(nimState: NimState, name: string, node: TSNode, offset: uint64
# #
# For object, field should be exported # For object, field should be exported
# #
# pname*: [ptr ..] typ
#
# nkIdentDefs( # nkIdentDefs(
# nkPostfix( # nkPostfix(
# nkIdent("*"), # nkIdent("*"),
@ -171,7 +195,7 @@ proc newIdentDefs(nimState: NimState, name: string, node: TSNode, offset: uint64
pident = nimState.getIdent(pname, tinfo, exported) pident = nimState.getIdent(pname, tinfo, exported)
acount = node[1].getXCount("abstract_pointer_declarator") acount = node[1].getXCount("abstract_pointer_declarator")
result.add pident result.add pident
result.add newPtrTree(acount, tident) result.add nimState.newPtrTree(acount, tident)
result.add newNode(nkEmpty) result.add newNode(nkEmpty)
else: else:
# Named param, simple type # Named param, simple type
@ -182,7 +206,7 @@ proc newIdentDefs(nimState: NimState, name: string, node: TSNode, offset: uint64
count = node[1].getPtrCount() count = node[1].getPtrCount()
result.add pident result.add pident
if count > 0: if count > 0:
result.add newPtrTree(count, tident) result.add nimState.newPtrTree(count, tident)
else: else:
result.add tident result.add tident
result.add newNode(nkEmpty) result.add newNode(nkEmpty)
@ -207,18 +231,6 @@ proc newIdentDefs(nimState: NimState, name: string, node: TSNode, offset: uint64
proc newProcTree(nimState: NimState, name: string, node: TSNode, rtyp: PNode): PNode = proc newProcTree(nimState: NimState, name: string, node: TSNode, rtyp: PNode): PNode =
# Create nkProcTy tree for specified proc type # Create nkProcTy tree for specified proc type
#
# nkProcTy(
# nkFormalParams(
# rtyp,
# nkIdentDefs( # multiple depending on params
# ..
# )
# ),
# nkEmpty()
# )
result = newNode(nkProcTy)
let let
fparam = newNode(nkFormalParams) fparam = newNode(nkFormalParams)
@ -233,18 +245,32 @@ proc newProcTree(nimState: NimState, name: string, node: TSNode, rtyp: PNode): P
if not param.isNil: if not param.isNil:
fparam.add param fparam.add param
# proc(pname: ptyp ..): rtyp
#
# nkProcTy(
# nkFormalParams(
# rtyp,
# nkIdentDefs( # multiple depending on params
# ..
# )
# ),
# nkEmpty()
# )
result = newNode(nkProcTy)
result.add fparam result.add fparam
result.add newNode(nkEmpty) result.add newNode(nkEmpty)
proc newRecListTree(nimState: NimState, name: string, node: TSNode): PNode = proc newRecListTree(nimState: NimState, name: string, node: TSNode): PNode =
# Create nkRecList tree for specified object # Create nkRecList tree for specified object
#
# nkRecList(
# nkIdentDefs( # multiple depending on fields
# ..
# )
# )
if not node.isNil: if not node.isNil:
# fname*: ftyp
# ..
#
# nkRecList(
# nkIdentDefs( # multiple depending on fields
# ..
# )
# )
result = newNode(nkRecList) result = newNode(nkRecList)
for i in 0 ..< node.len: for i in 0 ..< node.len:
@ -259,6 +285,7 @@ proc addTypeObject(nimState: NimState, node: TSNode, override = "", duplicate =
# #
# If `override` is set, use it as the name # If `override` is set, use it as the name
# If `duplicate` is set, don't add the same name # If `duplicate` is set, don't add the same name
decho("addTypeObject()")
let let
# TODO - check blank and override # TODO - check blank and override
typeDef = nimState.newTypeIdent(node, override) typeDef = nimState.newTypeIdent(node, override)
@ -304,6 +331,7 @@ proc addTypeTyped(nimState: NimState, node: TSNode, toverride = "", duplicate =
# #
# If `toverride` is set, use it as the type name # If `toverride` is set, use it as the type name
# If `duplicate` is set, don't add the same name # If `duplicate` is set, don't add the same name
decho("addTypeTyped()")
for i in 1 ..< node.len: for i in 1 ..< node.len:
# Add a type of a specific type # Add a type of a specific type
let let
@ -326,7 +354,7 @@ proc addTypeTyped(nimState: NimState, node: TSNode, toverride = "", duplicate =
if $typeDef[0][1] != tname: if $typeDef[0][1] != tname:
if count > 0: if count > 0:
# If pointers # If pointers
typeDef.add newPtrTree(count, ident) typeDef.add nimState.newPtrTree(count, ident)
else: else:
typeDef.add ident typeDef.add ident
@ -348,7 +376,7 @@ proc addTypeTyped(nimState: NimState, node: TSNode, toverride = "", duplicate =
nimState.printDebug(typeDef) nimState.printDebug(typeDef)
else: else:
nimState.addTypeObject(node, duplicate) nimState.addTypeObject(node, duplicate = duplicate)
proc getTypeArray(nimState: NimState, node: TSNode): PNode = proc getTypeArray(nimState: NimState, node: TSNode): PNode =
# Create array type tree # Create array type tree
@ -388,7 +416,7 @@ proc getTypeArray(nimState: NimState, node: TSNode): PNode =
if tcount > 0: if tcount > 0:
# If pointers # If pointers
result = newPtrTree(tcount, result) result = nimState.newPtrTree(tcount, result)
for i in 0 ..< acount: for i in 0 ..< acount:
let let
@ -398,10 +426,11 @@ proc getTypeArray(nimState: NimState, node: TSNode): PNode =
cnode = cnode[0] cnode = cnode[0]
if ncount > 0: if ncount > 0:
result = newPtrTree(ncount, result) result = nimState.newPtrTree(ncount, result)
proc addTypeArray(nimState: NimState, node: TSNode) = proc addTypeArray(nimState: NimState, node: TSNode) =
# Add a type of array type # Add a type of array type
decho("addTypeArray()")
let let
# node[1] = identifer = name # node[1] = identifer = name
# TODO - check blank and override # TODO - check blank and override
@ -466,15 +495,16 @@ proc getTypeProc(nimState: NimState, name: string, node: TSNode): PNode =
var var
retType = nimState.getIdent(rname, rinfo, exported = false) retType = nimState.getIdent(rname, rinfo, exported = false)
if tcount > 0: if tcount > 0:
retType = newPtrTree(tcount, retType) retType = nimState.newPtrTree(tcount, retType)
# Proc with return type and params # Proc with return type and params
result = nimState.newProcTree(name, plist, retType) result = nimState.newProcTree(name, plist, retType)
if ncount > 1: if ncount > 1:
result = newPtrTree(ncount-1, result) result = nimState.newPtrTree(ncount-1, result)
proc addTypeProc(nimState: NimState, node: TSNode) = proc addTypeProc(nimState: NimState, node: TSNode) =
# Add a type of proc type # Add a type of proc type
decho("addTypeProc()")
let let
# node[1] = identifier = name # node[1] = identifier = name
# TODO - check blank and override # TODO - check blank and override
@ -519,6 +549,7 @@ proc addTypeProc(nimState: NimState, node: TSNode) =
nimState.printDebug(typeDef) nimState.printDebug(typeDef)
proc addType(nimState: NimState, node: TSNode) = proc addType(nimState: NimState, node: TSNode) =
decho("addType()")
nimState.printDebug(node) nimState.printDebug(node)
if node.getName() == "struct_specifier": if node.getName() == "struct_specifier":
@ -550,12 +581,14 @@ proc addType(nimState: NimState, node: TSNode) =
# ) # )
# (field_declaration ...) # (field_declaration ...)
# ) # )
decho("addType(): case 1")
nimState.addTypeObject(node) nimState.addTypeObject(node)
elif node.getName() == "type_definition": elif node.getName() == "type_definition":
if node.len >= 2: if node.len >= 2:
let let
fdlist = node[0].anyChildInTree("field_declaration_list") fdlist = node[0].anyChildInTree("field_declaration_list")
if nimState.getNodeVal(node[1]) == "": if (fdlist.isNil or (not fdlist.isNil and fdlist.len == 0)) and
nimState.getNodeVal(node[1]) == "":
# typedef struct X; # typedef struct X;
# #
# (type_definition # (type_definition
@ -574,6 +607,7 @@ proc addType(nimState: NimState, node: TSNode) =
# ) # )
# (type_definition = "") # (type_definition = "")
# ) # )
decho("addType(): case 2")
nimState.addTypeObject(node[0]) nimState.addTypeObject(node[0])
else: else:
let let
@ -596,6 +630,7 @@ proc addType(nimState: NimState, node: TSNode) =
# (type_identifier) # (type_identifier)
# ) # )
# ) # )
decho("addType(): case 3")
nimState.addTypeTyped(node) nimState.addTypeTyped(node)
elif not fdecl.isNil: elif not fdecl.isNil:
# typedef X (*Y)(a1, a2, a3); # typedef X (*Y)(a1, a2, a3);
@ -625,6 +660,7 @@ proc addType(nimState: NimState, node: TSNode) =
# ) # )
# ) # )
# ) # )
decho("addType(): case 4")
nimState.addTypeProc(node) nimState.addTypeProc(node)
elif not adecl.isNil: elif not adecl.isNil:
# typedef struct X Y[a][..]; # typedef struct X Y[a][..];
@ -646,6 +682,7 @@ proc addType(nimState: NimState, node: TSNode) =
# ) # )
# ) # )
# ) # )
decho("addType(): case 5")
nimState.addTypeArray(node) nimState.addTypeArray(node)
else: else:
if node.firstChildInTree("field_declaration_list").isNil: if node.firstChildInTree("field_declaration_list").isNil:
@ -673,6 +710,7 @@ proc addType(nimState: NimState, node: TSNode) =
# ) # )
# First add struct as object # First add struct as object
decho("addType(): case 6")
nimState.addTypeObject(node[0]) nimState.addTypeObject(node[0])
if node.len > 1 and nimState.getNodeVal(node[1]) != "": if node.len > 1 and nimState.getNodeVal(node[1]) != "":
@ -684,6 +722,7 @@ proc addType(nimState: NimState, node: TSNode) =
# typedef struct { .. } Y, *Z; # typedef struct { .. } Y, *Z;
# Get any name that isn't a pointer # Get any name that isn't a pointer
decho("addType(): case 7")
let let
name = block: name = block:
var var
@ -692,22 +731,21 @@ proc addType(nimState: NimState, node: TSNode) =
if node[i].getName() == "type_identifier": if node[i].getName() == "type_identifier":
name = nimState.getNodeVal(node[i].getAtom()) name = nimState.getNodeVal(node[i].getAtom())
if name.len == 0:
name = nimState.getUniqueIdentifier("STRUCT")
name name
# Now add struct as object with specified name # Now add struct as object with specified name
nimState.addTypeObject(node[0], override = name) nimState.addTypeObject(node[0], override = name)
if node.len > 1 and nimState.getNodeVal(node[1]) != "": if name.len != 0:
# Add any additional names except duplicate # Add any additional names except duplicate
nimState.addTypeTyped(node, toverride = name, duplicate = name) nimState.addTypeTyped(node, toverride = name, duplicate = name)
proc addEnum(nimState: NimState, node: TSNode) = proc addEnum(nimState: NimState, node: TSNode) =
decho("addEnum()")
nimState.printDebug(node) nimState.printDebug(node)
proc addProc(nimState: NimState, node: TSNode) = proc addProc(nimState: NimState, node: TSNode) =
decho("addProc()")
nimState.printDebug(node) nimState.printDebug(node)
proc processNode(nimState: NimState, node: TSNode): bool = proc processNode(nimState: NimState, node: TSNode): bool =

View file

@ -313,7 +313,10 @@ proc anyChildInTree*(node: TSNode, ntype: string): TSNode =
ccnode = cnode[i].anyChildInTree(ntype) ccnode = cnode[i].anyChildInTree(ntype)
if not ccnode.isNil(): if not ccnode.isNil():
return ccnode return ccnode
cnode = cnode.tsNodeNextNamedSibling() if cnode != node:
cnode = cnode.tsNodeNextNamedSibling()
else:
break
proc mostNestedChildInTree*(node: TSNode): TSNode = proc mostNestedChildInTree*(node: TSNode): TSNode =
# Search for the most nested child of node's type in tree # Search for the most nested child of node's type in tree
@ -444,6 +447,10 @@ proc printTree*(nimState: NimState, pnode: PNode, offset = "") =
if offset.len == 0: if offset.len == 0:
echo "" echo ""
template decho*(str: untyped): untyped =
if nimState.gState.debug:
echo str.getCommented()
proc printDebug*(nimState: NimState, node: TSNode) = proc printDebug*(nimState: NimState, node: TSNode) =
if nimState.gState.debug: if nimState.gState.debug:
echo ("Input => " & nimState.getNodeVal(node)).getCommented() echo ("Input => " & nimState.getNodeVal(node)).getCommented()

View file

@ -1,10 +1,11 @@
import sequtils, sets, tables import sequtils, sets, tables
import compiler/[ast, idents, options] import regex
import "."/plugin import "."/plugin
when not declared(CIMPORT): when not declared(CIMPORT):
import compiler/[ast, idents, options]
import "."/treesitter/api import "."/treesitter/api
const const
@ -50,9 +51,10 @@ type
commentStr*, debugStr*, skipStr*: string commentStr*, debugStr*, skipStr*: string
# Nim compiler objects # Nim compiler objects
constSection*, enumSection*, procSection*, typeSection*: PNode when not declared(CIMPORT):
identCache*: IdentCache constSection*, enumSection*, procSection*, typeSection*: PNode
config*: ConfigRef identCache*: IdentCache
config*: ConfigRef
gState*: State gState*: State

42
tests/include/test3.h Normal file
View file

@ -0,0 +1,42 @@
#define A 1
#define B 1.0
#define C 0x10
#define D "hello"
#define E 'c'
struct A0;
struct A1 {};
typedef struct A2;
typedef struct A3 {};
typedef struct A4 A4, *A4p;
typedef int A5;
typedef int *A6;
typedef A0 **A7;
typedef void *A8;
typedef char *A9[3];
typedef char *A10[3][6];
typedef char *(*A11)[3];
typedef int **(*A12)(int, int b, int *c, int *, int *count[4], int (*func)(int, int));
typedef int A13(int, int);
struct A14 { char a1; };
struct A15 { char *a1; int *a2[1]; };
typedef struct A16 { char f1; };
typedef struct A17 { char *a1; int *a2[1]; } A18, *A18p;
typedef struct { char *a1; int *a2[1]; } A19, *A19p;
typedef struct A20 { char a1; } A20, A21, *A21p;
//Expression
//typedef struct A21 { int **f1; int abc[123+132]; } A21;
//Unions
//union UNION1 {int f1; };
//typedef union UNION2 { int **f1; int abc[123+132]; } UNION2;
// Anonymous
//typedef struct { char a1; };

71
tests/tnimterop2.nim Normal file
View file

@ -0,0 +1,71 @@
import tables
import nimterop/[cimport]
static:
cDebug()
cImport("include/test3.h", flags="-d")
proc testFields(t: typedesc, fields: Table[string, string] = initTable[string, string]()) =
var
obj: t
count = 0
for name, value in obj.fieldPairs():
count += 1
assert name in fields, $t & "." & name & " invalid"
assert $fields[name] == $typeof(value),
"typeof(" & $t & ":" & name & ") != " & fields[name] & ", is " & $typeof(value)
assert count == fields.len, "Failed for " & $t
assert A == 1
assert B == 1.0
assert C == 0x10
assert D == "hello"
assert E == 'c'
assert A0 is object
testFields(A0)
assert A1 is object
testFields(A1)
assert A2 is object
testFields(A2)
assert A3 is object
testFields(A3)
assert A4 is object
testFields(A4)
assert A4p is ptr A4
assert A5 is cint
assert A6 is ptr cint
assert A7 is ptr ptr A0
assert A8 is pointer
assert A9 is array[3, cstring]
assert A10 is array[3, array[6, cstring]]
assert A11 is ptr array[3, cstring]
assert A12 is proc(a1: cint, b: cint, c: ptr cint, a4: ptr cint, count: array[4, ptr cint], `func`: proc(a1: cint, a2: cint): cint): ptr ptr cint
assert A13 is proc(a1: cint, a2: cint): cint
assert A14 is object
testFields(A14, {"a1": "cchar"}.toTable())
assert A15 is object
testFields(A15, {"a1": "cstring", "a2": "array[0..0, ptr cint]"}.toTable())
assert A16 is object
testFields(A16, {"f1": "cchar"}.toTable())
assert A17 is object
testFields(A17, {"a1": "cstring", "a2": "array[0..0, ptr cint]"}.toTable())
assert A18 is A17
assert A18p is ptr A17
assert A19 is object
testFields(A19, {"a1": "cstring", "a2": "array[0..0, ptr cint]"}.toTable())
assert A19p is ptr A19
assert A20 is object
testFields(A20, {"a1": "cchar"}.toTable())
assert A21 is A20
assert A21p is ptr A20