Fix #125 - no more types import

This commit is contained in:
Ganesh Viswanathan 2020-06-29 21:47:00 -05:00
commit f543124d7e
10 changed files with 99 additions and 88 deletions

View file

@ -2,4 +2,4 @@
The following modules are available to users of Nimterop.
]##
import "."/[docs, cimport, build, types, plugin]
import "."/[build, cimport, docs, plugin]

View file

@ -17,8 +17,7 @@ All `{.compileTime.}` procs must be used in a compile time context, e.g. using:
import hashes, macros, os, strformat, strutils
import "."/[build, globals, paths, types]
export types
import "."/[build, globals, paths]
proc interpPath(dir: string): string=
# TODO: more robust: needs a DirSep after "$projpath"
@ -153,7 +152,7 @@ proc getToast(fullpaths: seq[string], recurse: bool = false, dynlib: string = ""
# see https://github.com/nimterop/nimterop/issues/69
(result, ret) = execAction(cmd, die = false, cache = (not gStateCT.nocache),
cacheKey = getCacheValue(fullpaths))
cacheKey = getCacheValue(toastExe) & getCacheValue(fullpaths))
doAssert ret == 0, getToastError(result)
macro cOverride*(body): untyped =

42
nimterop/enumtype.nim Normal file
View file

@ -0,0 +1,42 @@
import macros
macro defineEnum(typ: untyped): untyped =
result = newNimNode(nnkStmtList)
# Enum mapped to distinct cint
result.add quote do:
type `typ`* = distinct cint
for i in ["+", "-", "*", "div", "mod", "shl", "shr", "or", "and", "xor", "<", "<=", "==", ">", ">="]:
let
ni = newIdentNode(i)
typout = if i[0] in "<=>": newIdentNode("bool") else: typ # comparisons return bool
if i[0] == '>': # cannot borrow `>` and `>=` from templates
let
nopp = if i.len == 2: newIdentNode("<=") else: newIdentNode("<")
result.add quote do:
proc `ni`*(x: `typ`, y: cint): `typout` = `nopp`(y, x)
proc `ni`*(x: cint, y: `typ`): `typout` = `nopp`(y, x)
proc `ni`*(x, y: `typ`): `typout` = `nopp`(y, x)
else:
result.add quote do:
proc `ni`*(x: `typ`, y: cint): `typout` {.borrow.}
proc `ni`*(x: cint, y: `typ`): `typout` {.borrow.}
proc `ni`*(x, y: `typ`): `typout` {.borrow.}
result.add quote do:
proc `ni`*(x: `typ`, y: int): `typout` = `ni`(x, y.cint)
proc `ni`*(x: int, y: `typ`): `typout` = `ni`(x.cint, y)
let
divop = newIdentNode("/") # `/`()
dlrop = newIdentNode("$") # `$`()
notop = newIdentNode("not") # `not`()
result.add quote do:
proc `divop`*(x, y: `typ`): `typ` = `typ`((x.float / y.float).cint)
proc `divop`*(x: `typ`, y: cint): `typ` = `divop`(x, `typ`(y))
proc `divop`*(x: cint, y: `typ`): `typ` = `divop`(`typ`(x), y)
proc `divop`*(x: `typ`, y: int): `typ` = `divop`(x, y.cint)
proc `divop`*(x: int, y: `typ`): `typ` = `divop`(x.cint, y)
proc `dlrop`*(x: `typ`): string {.borrow.}
proc `notop`*(x: `typ`): `typ` {.borrow.}

View file

@ -54,7 +54,7 @@ type
constIdentifiers*: HashSet[string] # Const names for enum casting
identifiers*: TableRef[string, string] # Symbols that have been declared so far indexed by nimName
skippedSyms*: HashSet[string] # Symbols that have been skipped due to being unwrappable or
# the user provided override is blank
# the user provided override is blank
# Nim compiler objects
constSection*, enumSection*, pragmaSection*, procSection*, typeSection*, varSection*: PNode
@ -70,6 +70,9 @@ type
# Controls whether or not the current expression
# should validate idents against currently defined idents
skipIdentValidation*: bool
# Top level header for wrapper output - include imported types, pragmas and other info
wrapperHeader*: string
else:
# cimport.nim specific
compile*: seq[string] # `cCompile()` list of files already processed

View file

@ -1481,6 +1481,11 @@ proc addEnum(gState: State, node: TSNode) =
if node.getName() == "type_definition" and node.len > 1:
gState.addTypeTyped(node, ftname = name, offset = offset)
if gEnumMacro.nBl:
# Add enum generation macro once
gState.wrapperHeader &= gEnumMacro
gEnumMacro = ""
proc addProc(gState: State, node, rnode: TSNode, commentNodes: seq[TSNode]) =
# Add a proc
#
@ -1822,10 +1827,7 @@ proc setupPragmas(gState: State, root: TSNode, fullpath: string) =
proc initNim*(gState: State) =
# Initialize for parseNim() one time
gecho """import nimterop/types
{.push hint[ConvFromXtoItselfNotNeeded]: off.}
"""
gState.wrapperHeader = "{.push hint[ConvFromXtoItselfNotNeeded]: off.}\n"
# Track identifiers already rendered and corresponding PNodes
gState.identifiers = newTable[string, string]()
@ -1876,6 +1878,7 @@ proc printNim*(gState: State) =
tree.add gState.varSection
tree.add gState.procSection
gecho gState.wrapperHeader
gecho tree.renderTree()
gecho "{.pop.}"

View file

@ -95,7 +95,7 @@ proc getNameInfo*(gState: State, node: TSNode, kind: NimSymKind, parent = ""):
result.name = gState.getIdentifier(result.origname, kind, parent)
if result.name.nBl:
if kind == nskType:
result.name = result.name.getType()
result.name = gState.getType(result.name, parent)
result.info = gState.getLineInfo(node)
proc getPtrType*(str: string): string =

View file

@ -580,7 +580,7 @@ proc processTSNode(gState: State, node: TSNode, typeofNode: var PNode): PNode =
of "sized_type_specifier", "primitive_type", "type_identifier":
# Input -> int, unsigned int, long int, etc
# Output -> cint, cuint, clong, etc
let ty = getType(node.val)
let ty = gState.getType(node.val, parent = node.getName())
if ty.len > 0:
# If ty is not empty, one of C's builtin types has been found
result = gState.getExprIdent(ty, nskType, parent=node.getName())

View file

@ -29,7 +29,13 @@ yield""".split(Whitespace).toHashSet()
# Types related
const
# Enum macro read from file - written into wrapper when required
gEnumMacroConst = staticRead(currentSourcePath.parentDir().parentDir() / "enumtype.nim")
var
gEnumMacro* = gEnumMacroConst
gTypeMap* = {
# char
"char": "cchar",
@ -107,13 +113,40 @@ var
"long double": "clongdouble",
# Misc Nim types
"Bool": "bool"
"Bool": "bool",
"ptrdiff_t": "ByteAddress"
}.toTable()
# Nim type names that shouldn't need to be wrapped again
gTypeMapValues* = toSeq(gTypeMap.values).toHashSet()
proc getType*(str: string): string =
# Types to import from C/Nim if used in wrapper
gTypeImport* = {
"time_t": """
import std/time_t as std_time_t
type time_t* = Time
""",
"time64_t": """
import std/time_t as std_time64_t
type time64_t* = Time
""",
"wchar_t": """
when defined(cpp):
# http://www.cplusplus.com/reference/cwchar/wchar_t/
# In C++, wchar_t is a distinct fundamental type (and thus it is
# not defined in <cwchar> nor any other header).
type wchar_t* {.importc.} = object
else:
type wchar_t* {.importc, header:"<cwchar>".} = object
""",
"va_list": """
type va_list* {.importc, header:"<stdarg.h>".} = object
"""}.toTable()
proc getType*(gState: State, str, parent: string): string =
if str == "void":
return "object"
@ -121,6 +154,10 @@ proc getType*(str: string): string =
if gTypeMap.hasKey(result):
result = gTypeMap[result]
elif parent.nBl and gTypeImport.hasKey(result) and not gState.identifierNodes.hasKey(result):
# Include C/Nim type imports once if a field/param and not already declared
gState.wrapperHeader &= "\n" & gTypeImport[result]
gTypeImport.del result
# Identifier related

View file

@ -2,7 +2,8 @@
import strutils, os
import ".."/[setup, paths, types]
include ".."/enumtype
import ".."/[paths, setup]
static:
treesitterSetup()

View file

@ -1,74 +0,0 @@
# see https://github.com/nimterop/nimterop/issues/79
import std/time_t as time_t_temp
type
time_t* = time_t_temp.Time
time64_t* = time_t_temp.Time
when defined(cpp):
# http://www.cplusplus.com/reference/cwchar/wchar_t/
# In C++, wchar_t is a distinct fundamental type (and thus it is
# not defined in <cwchar> nor any other header).
type
wchar_t* {.importc.} = object
else:
type
wchar_t* {.importc, header:"<cwchar>".} = object
type
ptrdiff_t* = ByteAddress
type
va_list* {.importc, header:"<stdarg.h>".} = object
template enumOp*(op, typ, typout) =
proc op*(x: typ, y: cint): typout {.borrow.}
proc op*(x: cint, y: typ): typout {.borrow.}
proc op*(x, y: typ): typout {.borrow.}
proc op*(x: typ, y: int): typout = op(x, y.cint)
proc op*(x: int, y: typ): typout = op(x.cint, y)
template defineEnum*(typ) =
# Create a `distinct cint` type for C enums since Nim enums
# need to be in order and cannot have duplicates.
type
typ* = distinct cint
# Enum operations allowed
enumOp(`+`, typ, typ)
enumOp(`-`, typ, typ)
enumOp(`*`, typ, typ)
enumOp(`<`, typ, bool)
enumOp(`<=`, typ, bool)
enumOp(`==`, typ, bool)
enumOp(`div`, typ, typ)
enumOp(`mod`, typ, typ)
# These don't work with `enumOp()` for some reason
proc `shl`*(x: typ, y: cint): typ {.borrow.}
proc `shl`*(x: cint, y: typ): typ {.borrow.}
proc `shl`*(x, y: typ): typ {.borrow.}
proc `shr`*(x: typ, y: cint): typ {.borrow.}
proc `shr`*(x: cint, y: typ): typ {.borrow.}
proc `shr`*(x, y: typ): typ {.borrow.}
proc `or`*(x: typ, y: cint): typ {.borrow.}
proc `or`*(x: cint, y: typ): typ {.borrow.}
proc `or`*(x, y: typ): typ {.borrow.}
proc `and`*(x: typ, y: cint): typ {.borrow.}
proc `and`*(x: cint, y: typ): typ {.borrow.}
proc `and`*(x, y: typ): typ {.borrow.}
proc `xor`*(x: typ, y: cint): typ {.borrow.}
proc `xor`*(x: cint, y: typ): typ {.borrow.}
proc `xor`*(x, y: typ): typ {.borrow.}
proc `/`*(x, y: typ): typ =
return (x.float / y.float).cint.typ
proc `/`*(x: typ, y: cint): typ = `/`(x, y.typ)
proc `/`*(x: cint, y: typ): typ = `/`(x.typ, y)
proc `$`*(x: typ): string {.borrow.}