diff options
| author | Ganesh Viswanathan <dev@genotrance.com> | 2018-11-21 23:45:12 -0600 |
|---|---|---|
| committer | Ganesh Viswanathan <dev@genotrance.com> | 2018-11-21 23:45:12 -0600 |
| commit | b9b5174759b6dd1f94404b2f63637d406aec4983 (patch) | |
| tree | 1f26d0fe80a14614e64cd1215800f9f857a0c123 | |
| parent | a8bb2dc01f99a2866f586f6e1491a512ce9b3cfa (diff) | |
| download | nimterop-b9b5174759b6dd1f94404b2f63637d406aec4983.tar.gz nimterop-b9b5174759b6dd1f94404b2f63637d406aec4983.zip | |
More pointer support, cpp mode default in toast, cleanup
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | nimterop/ast.nim | 86 | ||||
| -rw-r--r-- | nimterop/cimport.nim | 32 | ||||
| -rw-r--r-- | nimterop/getters.nim | 5 | ||||
| -rw-r--r-- | nimterop/git.nim | 14 | ||||
| -rw-r--r-- | nimterop/globals.nim | 2 | ||||
| -rw-r--r-- | nimterop/lisp.nim | 10 | ||||
| -rw-r--r-- | tests/include/test.c | 4 | ||||
| -rw-r--r-- | tests/include/test.h | 9 | ||||
| -rw-r--r-- | tests/tnimterop.nim | 9 | ||||
| -rw-r--r-- | toast.nim | 48 |
11 files changed, 132 insertions, 89 deletions
@@ -65,6 +65,8 @@ Detailed documentation is still forthcoming. `cAddSearchDir("XXX")` - add directory XXX to search path in calls to `cSearchPath()` +`cAddStdDir("XXX")` - add standard "c" [default] or "cpp" include paths to search path + `cSearchPath("header.h")` - return a file or directory found in search path configured using `cSearchPath()` - can be used in `cCompile()`, `cIncludeDir()` and `cImport()` calls `gitPull()` - pull a git repository prior to C/C++ interop diff --git a/nimterop/ast.nim b/nimterop/ast.nim index b825efe..a84f503 100644 --- a/nimterop/ast.nim +++ b/nimterop/ast.nim @@ -21,7 +21,7 @@ proc addHeader*(fullpath: string) = # proc pPreprocDef(node: ref Ast) = - if node.children.len() == 2: + if node.children.len == 2: let name = getNodeValIf(node.children[0], identifier) val = getNodeValIf(node.children[1], preproc_arg) @@ -37,30 +37,42 @@ proc pPreprocDef(node: ref Ast) = # proc typeScan(node: ref Ast, sym, id: Sym, offset: string): string = - if node.sym != sym or node.children.len() != 2: + if node.sym != sym or node.children.len != 2: return - let - pname = getNodeValIf(node.children[1], id) + var + name = getNodeValIf(node.children[1], id) ptyp = getNodeValIf(node.children[0], primitive_type) ttyp = getNodeValIf(node.children[0], type_identifier) + ptrname = false + + if name.len == 0 and node.children[1].sym == pointer_declarator and node.children[1].children.len == 1: + name = getNodeValIf(node.children[1].children[0], id) + ptrname = true - if pname.len() == 0: + if name.len == 0: return elif ptyp.nBl: - result = &"{offset}{pname.getIdentifier()}: {ptyp.getType()}" + ptyp = ptyp.getType() + if ptyp != "object" and ptrname: + ptyp = &"ptr {ptyp}" + result = &"{offset}{name.getIdentifier()}: {ptyp}" elif ttyp.nBl: - result = &"{offset}{pname.getIdentifier()}: {ttyp}" - elif node.children[0].sym in [struct_specifier, enum_specifier] and node.children[0].children.len() == 1: - let styp = getNodeValIf(node.children[0].children[0], type_identifier) + if ptrname: + ttyp = &"ptr {ttyp}" + result = &"{offset}{name.getIdentifier()}: {ttyp}" + elif node.children[0].sym in [struct_specifier, enum_specifier] and node.children[0].children.len == 1: + var styp = getNodeValIf(node.children[0].children[0], type_identifier) if styp.nBl: - result = &"{offset}{pname.getIdentifier()}: {styp}" + if ptrname: + styp = &"ptr {styp}" + result = &"{offset}{name.getIdentifier()}: {styp}" else: return proc pStructSpecifier(node: ref Ast, name = "") = var stmt: string - if node.children.len() == 1 and name notin gTypes: + if node.children.len == 1 and name notin gTypes: case node.children[0].sym: of type_identifier: let typ = getNodeValIf(node.children[0], type_identifier) @@ -68,18 +80,18 @@ proc pStructSpecifier(node: ref Ast, name = "") = gTypes.add(name) if name != typ: # typedef struct X Y - gTypeStr &= &" {name}* = {typ} #1 pStructSpecifier()\n" + gTypeStr &= &" {name.getIdentifier()}* = {typ} #1 pStructSpecifier()\n" else: # typedef struct X X - gTypeStr &= &" {name}* {{.importc: \"{name}\", header: {gCurrentHeader}, bycopy.}} = object #2 pStructSpecifier()\n" + gTypeStr &= &" {name.getIdentifier()}* {{.importc: \"{name}\", header: {gCurrentHeader}, bycopy.}} = object #2 pStructSpecifier()\n" of field_declaration_list: # typedef struct { fields } X - stmt = &" {name}* {{.importc: \"{name}\", header: {gCurrentHeader}, bycopy.}} = object #3 pStructSpecifier()\n" + stmt = &" {name.getIdentifier()}* {{.importc: \"{name}\", header: {gCurrentHeader}, bycopy.}} = object #3 pStructSpecifier()\n" for field in node.children[0].children: let ts = typeScan(field, field_declaration, field_identifier, " ") - if ts.len() == 0: + if ts.len == 0: return stmt &= ts & "\n" @@ -88,7 +100,7 @@ proc pStructSpecifier(node: ref Ast, name = "") = else: discard - elif name.len() == 0 and node.children.len() == 2 and node.children[1].sym == field_declaration_list: + elif name.len == 0 and node.children.len == 2 and node.children[1].sym == field_declaration_list: let ename = getNodeValIf(node.children[0], type_identifier) if ename.nBl and ename notin gTypes: # struct X { fields } @@ -96,7 +108,7 @@ proc pStructSpecifier(node: ref Ast, name = "") = for field in node.children[1].children: let ts = typeScan(field, field_declaration, field_identifier, " ") - if ts.len() == 0: + if ts.len == 0: return stmt &= ts & "\n" @@ -109,12 +121,12 @@ proc pEnumSpecifier(node: ref Ast, name = "") = elid: int stmt: string - if node.children.len() == 1 and node.children[0].sym == enumerator_list: + if node.children.len == 1 and node.children[0].sym == enumerator_list: # typedef enum { fields } X ename = name elid = 0 - stmt = &" {name}* = enum #1 pEnumSpecifier()\n" - elif name.len() == 0 and node.children.len() == 2 and node.children[1].sym == enumerator_list: + stmt = &" {name.getIdentifier()}* = enum #1 pEnumSpecifier()\n" + elif name.len == 0 and node.children.len == 2 and node.children[1].sym == enumerator_list: ename = getNodeValIf(node.children[0], type_identifier) elid = 1 if ename.nBl: @@ -126,9 +138,9 @@ proc pEnumSpecifier(node: ref Ast, name = "") = for field in node.children[elid].children: if field.sym == enumerator: let fname = getNodeValIf(field.children[0], identifier) - if field.children.len() == 1: + if field.children.len == 1: stmt &= &" {fname}\n" - elif field.children.len() == 2 and field.children[1].sym == number_literal: + elif field.children.len == 2 and field.children[1].sym == number_literal: let num = getNodeValIf(field.children[1], number_literal) stmt &= &" {fname} = {num}\n" else: @@ -139,25 +151,31 @@ proc pEnumSpecifier(node: ref Ast, name = "") = gTypeStr &= stmt proc pTypeDefinition(node: ref Ast) = - if node.children.len() == 2: + if node.children.len == 2: var name = getNodeValIf(node.children[1], type_identifier) - pname = getNodeValIf(node.children[1], pointer_declarator) ptyp = getNodeValIf(node.children[0], primitive_type) ttyp = getNodeValIf(node.children[0], type_identifier) + ptrname = false - if name.len() == 0 and node.children[1].sym == pointer_declarator and node.children[1].children.len() == 1: + if name.len == 0 and node.children[1].sym == pointer_declarator and node.children[1].children.len == 1: name = getNodeValIf(node.children[1].children[0], type_identifier) + ptrname = true if name.nBl and name notin gTypes: if ptyp.nBl: # typedef int X gTypes.add(name) - gTypeStr &= &" {name}* = {ptyp.getType()} #1 pTypeDefinition()\n" + ptyp = ptyp.getType() + if ptyp != "object" and ptrname: + ptyp = &"ptr {ptyp}" + gTypeStr &= &" {name.getIdentifier()}* = {ptyp} #1 pTypeDefinition()\n" elif ttyp.nBl: # typedef X Y gTypes.add(name) - gTypeStr &= &" {name}* = {ttyp} #2 pTypeDefinition()\n" + if ptrname: + ttyp = &"ptr {ttyp}" + gTypeStr &= &" {name.getIdentifier()}* = {ttyp} #2 pTypeDefinition()\n" else: case node.children[0].sym: of struct_specifier: @@ -168,20 +186,20 @@ proc pTypeDefinition(node: ref Ast) = discard proc pFunctionDeclarator(node: ref Ast, typ: string) = - if node.children.len() == 2: + if node.children.len == 2: let name = getNodeValIf(node.children[0], identifier) if name.nBl and name notin gProcs and node.children[1].sym == parameter_list: # typ function(typ param1, ...) - var stmt = &"# pFunctionDeclarator()\nproc {name}*(" + var stmt = &"# pFunctionDeclarator()\nproc {name.getIdentifier()}*(" - for i in 0 .. node.children[1].children.len()-1: + for i in 0 .. node.children[1].children.len-1: let ts = typeScan(node.children[1].children[i], parameter_declaration, identifier, "") - if ts.len() == 0: + if ts.len == 0: return stmt &= ts - if i != node.children[1].children.len()-1: + if i != node.children[1].children.len-1: stmt &= ", " if typ != "void": @@ -195,7 +213,7 @@ proc pFunctionDeclarator(node: ref Ast, typ: string) = gProcStr &= stmt proc pDeclaration*(node: ref Ast) = - if node.children.len() == 2 and node.children[1].sym == function_declarator: + if node.children.len == 2 and node.children[1].sym == function_declarator: let ptyp = getNodeValIf(node.children[0], primitive_type) ttyp = getNodeValIf(node.children[0], type_identifier) @@ -204,7 +222,7 @@ proc pDeclaration*(node: ref Ast) = pFunctionDeclarator(node.children[1], ptyp.getType()) elif ttyp.nBl: pFunctionDeclarator(node.children[1], ttyp) - elif node.children[0].sym == struct_specifier and node.children[0].children.len() == 1: + elif node.children[0].sym == struct_specifier and node.children[0].children.len == 1: let styp = getNodeValIf(node.children[0].children[0], type_identifier) if styp.nBl: pFunctionDeclarator(node.children[1], styp) diff --git a/nimterop/cimport.nim b/nimterop/cimport.nim index 91dd404..a47443c 100644 --- a/nimterop/cimport.nim +++ b/nimterop/cimport.nim @@ -17,7 +17,7 @@ proc findPath(path: string, fail = true): string = proc cSearchPath*(path: string): string = result = findPath(path, fail = false) - if result.len() == 0: + if result.len == 0: var found = false for inc in gSearchDirs: result = (inc & "/" & path).replace("\\", "/") @@ -31,12 +31,12 @@ proc cSearchPath*(path: string): string = macro cDebug*(): untyped = gDebug = true -macro cDefine*(name: static[string], val: static[string] = ""): untyped = +macro cDefine*(name: static string, val: static string = ""): untyped = result = newNimNode(nnkStmtList) var str = "-D" & name if val.nBl: - str &= "=\"" & val & "\"" + str &= &"=\"{val}\"" result.add(quote do: {.passC: `str`.} @@ -45,36 +45,37 @@ macro cDefine*(name: static[string], val: static[string] = ""): untyped = if gDebug: echo result.repr -macro cAddSearchDir*(dir: static[string]): untyped = +macro cAddSearchDir*(dir: static string): untyped = result = newNimNode(nnkStmtList) let fullpath = cSearchPath(dir) if fullpath notin gSearchDirs: gSearchDirs.add(fullpath) -macro cIncludeDir*(dir: static[string]): untyped = +macro cIncludeDir*(dir: static string): untyped = result = newNimNode(nnkStmtList) let fullpath = findPath(dir) - str = "-I\"" & fullpath & "\"" + str = &"-I\"{fullpath}\"" if fullpath notin gIncludeDirs: gIncludeDirs.add(fullpath) - result.add(quote do: - {.passC: `str`.} - ) + result.add(quote do: + {.passC: `str`.} + ) if gDebug: echo result.repr -macro cIncludeC*(): untyped = +macro cAddStdDir*(mode = "c"): untyped = result = newNimNode(nnkStmtList) var inc = false - for line in getGccPaths().splitLines(): + + for line in getGccPaths(mode.strVal()).splitLines(): if "#include <...> search starts here" in line: inc = true continue @@ -82,10 +83,11 @@ macro cIncludeC*(): untyped = break if inc: - result = quote do: - cIncludeDir(line) + let sline = line.strip() + result.add quote do: + cAddSearchDir(`sline`) -macro cCompile*(path: static[string]): untyped = +macro cCompile*(path: static string): untyped = result = newNimNode(nnkStmtList) var @@ -129,7 +131,7 @@ macro cCompile*(path: static[string]): untyped = if gDebug: echo result.repr -macro cImport*(filename: static[string]): untyped = +macro cImport*(filename: static string): untyped = result = newNimNode(nnkStmtList) result.add addReorder() diff --git a/nimterop/getters.nim b/nimterop/getters.nim index b4f9df6..0412522 100644 --- a/nimterop/getters.nim +++ b/nimterop/getters.nim @@ -23,10 +23,11 @@ proc getNodeValIf*(node: ref Ast, esym: Sym): string = return gCode[node.start .. node.stop-1].strip() proc getGccPaths*(mode = "c"): string = - let + var nul = when defined(Windows): "nul" else: "/dev/null" + mmode = if mode == "cpp": "c++" else: mode - return staticExec("gcc -Wp,-v -x" & mode & " " & nul) + return staticExec("gcc -Wp,-v -x" & mmode & " " & nul) proc getLineCol*(node: ref Ast): tuple[line, col: int] = result.line = 1 diff --git a/nimterop/git.nim b/nimterop/git.nim index f06e9ba..b55b365 100644 --- a/nimterop/git.nim +++ b/nimterop/git.nim @@ -18,7 +18,7 @@ proc execAction*(cmd: string): string = echo result quit(1) -macro extractZip*(zipfile, outdir: static[string]): untyped = +macro extractZip*(zipfile, outdir: static string): untyped = var cmd = "unzip -o $#" if defined(Windows): cmd = "powershell -nologo -noprofile -command \"& { Add-Type -A " & @@ -28,7 +28,7 @@ macro extractZip*(zipfile, outdir: static[string]): untyped = echo "Extracting " & zipfile discard execAction(&"cd \"{getProjectPath()/outdir}\" && " & cmd % zipfile) -macro downloadUrl*(url, outdir: static[string]): untyped = +macro downloadUrl*(url, outdir: static string): untyped = let file = url.extractFilename() ext = file.splitFile().ext.toLowerAscii() @@ -45,7 +45,7 @@ macro downloadUrl*(url, outdir: static[string]): untyped = discard quote do: extractZip(`file`, `outdir`) -macro gitReset*(outdir: static[string]): untyped = +macro gitReset*(outdir: static string): untyped = echo "Resetting " & outdir let cmd = &"cd \"{getProjectPath()/outdir}\" && git reset --hard" @@ -53,7 +53,7 @@ macro gitReset*(outdir: static[string]): untyped = sleep(1000) echo " Retrying ..." -macro gitCheckout*(file, outdir: static[string]): untyped = +macro gitCheckout*(file, outdir: static string): untyped = echo "Resetting " & file let cmd = &"cd \"{getProjectPath()/outdir}\" && git checkout $#" % file.replace(outdir & "/", "") @@ -61,7 +61,7 @@ macro gitCheckout*(file, outdir: static[string]): untyped = sleep(500) echo " Retrying ..." -macro gitPull*(url: static[string], outdirN = "", plistN = "", checkoutN = ""): untyped = +macro gitPull*(url: static string, outdirN = "", plistN = "", checkoutN = ""): untyped = let outdir = getProjectPath()/outdirN.strVal() plist = plistN.strVal() @@ -78,14 +78,14 @@ macro gitPull*(url: static[string], outdirN = "", plistN = "", checkoutN = ""): discard execAction(&"cd \"{outdir}\" && git init .") discard execAction(&"cd \"{outdir}\" && git remote add origin " & url) - if plist.len() != 0: + if plist.len != 0: let sparsefile = &"{outdir}/.git/info/sparse-checkout" discard execAction(&"cd \"{outdir}\" && git config core.sparsecheckout true") writeFile(sparsefile, plist) echo "Wrote" - if checkout.len() != 0: + if checkout.len != 0: echo "Checking out " & checkout discard execAction(&"cd \"{outdir}\" && git pull --tags origin master") discard execAction(&"cd \"{outdir}\" && git checkout {checkout}") diff --git a/nimterop/globals.nim b/nimterop/globals.nim index e2e155d..ccc4ec2 100644 --- a/nimterop/globals.nim +++ b/nimterop/globals.nim @@ -37,4 +37,4 @@ var gTypeStr* {.compiletime.}: string template nBl*(s: untyped): untyped = - (s.len() != 0)
\ No newline at end of file + (s.len != 0)
\ No newline at end of file diff --git a/nimterop/lisp.nim b/nimterop/lisp.nim index cf723b7..2727c18 100644 --- a/nimterop/lisp.nim +++ b/nimterop/lisp.nim @@ -13,7 +13,7 @@ proc tokenize(fullpath: string) = gTokens = @[] idx = 0 - for i in staticExec("toast -u " & fullpath): + for i in staticExec("toast -m " & fullpath): case i: of ' ', '\n', '\r', '(', ')': if collect.nBl: @@ -24,17 +24,17 @@ proc tokenize(fullpath: string) = else: collect &= $i - if gTokens.len() == 0: + if gTokens.len == 0: echo "toast binary not installed - nimble install nimterop to force build" quit(1) proc readFromTokens(): ref Ast = - if idx == gTokens.len(): + if idx == gTokens.len: echo "Bad AST" quit(1) if gTokens[idx] == "(": - if gTokens.len() - idx < 2: + if gTokens.len - idx < 2: echo "Corrupt AST" quit(1) if gTokens[idx+1] != "comment": @@ -60,7 +60,7 @@ proc readFromTokens(): ref Ast = proc printAst*(node: ref Ast, offset=""): string = result = offset & "(" & $node.sym & " " & $node.start & " " & $node.stop - if node.children.len() != 0: + if node.children.len != 0: result &= "\n" for child in node.children: result &= printAst(child, offset & " ") diff --git a/tests/include/test.c b/tests/include/test.c index 8d801b7..885723e 100644 --- a/tests/include/test.c +++ b/tests/include/test.c @@ -4,13 +4,15 @@ int test_call_int() { return 5; } -struct STRUCT1 test_call_int_param(int param1) { +#ifdef FORCE +struct STRUCT1 _test_call_int_param_(int param1) { struct STRUCT1 s; s.field1 = param1; return s; } +#endif STRUCT2 test_call_int_param2(int param1, STRUCT2 param2) { STRUCT2 s; diff --git a/tests/include/test.h b/tests/include/test.h index 60d1660..7de6eed 100644 --- a/tests/include/test.h +++ b/tests/include/test.h @@ -29,8 +29,15 @@ typedef enum { enum6 } ENUM2; +typedef void * VOIDPTR; +typedef int * INTPTR; + +typedef struct { + int *field; +} STRUCT4; + int test_call_int(); -struct STRUCT1 test_call_int_param(int param1); +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);
\ No newline at end of file diff --git a/tests/tnimterop.nim b/tests/tnimterop.nim index a05cecd..dd822cb 100644 --- a/tests/tnimterop.nim +++ b/tests/tnimterop.nim @@ -2,6 +2,7 @@ import nimterop/cimport cDebug() +cDefine("FORCE") cIncludeDir "include" cAddSearchDir "include" cCompile cSearchPath("test.c") @@ -18,10 +19,14 @@ var s: STRUCT1 s2: STRUCT2 s3: STRUCT3 + s4: STRUCT4 e: ENUM e2: ENUM2 = enum5 + vptr: VOIDPTR + iptr: INTPTR + pt = 3 ct = 4 @@ -31,9 +36,11 @@ s3.field1 = 7 e = enum1 e2 = enum4 - + doAssert test_call_int() == 5 doAssert test_call_int_param(5).field1 == 5 doAssert test_call_int_param2(5, s2).field1 == 11 doAssert test_call_int_param3(5, s).field1 == 10 doAssert test_call_int_param4(e) == e2 + +cAddStdDir() @@ -6,30 +6,28 @@ import treesitter/[runtime, c, cpp] const HELP = """ > toast header.h -""" +-m minimized output - non-pretty +-c C mode - CPP is default""" -var - gPretty = true - -proc printLisp(root: TSNode, data: var string) = +proc printLisp(root: TSNode, data: var string, pretty = true) = var node = root nextnode: TSNode depth = 0 - + while true: if not node.tsNodeIsNull(): - if gPretty: + if pretty: stdout.write spaces(depth) stdout.write "(" & $node.tsNodeType() & " " & $node.tsNodeStartByte() & " " & $node.tsNodeEndByte() if node.tsNodeNamedChildCount() != 0: - if gPretty: + if pretty: echo "" nextnode = node.tsNodeNamedChild(0) depth += 1 else: - if gPretty: + if pretty: echo ")" else: stdout.write ")" @@ -39,7 +37,7 @@ proc printLisp(root: TSNode, data: var string) = while true: node = node.tsNodeParent() depth -= 1 - if gPretty: + if pretty: echo spaces(depth) & ")" else: stdout.write ")" @@ -54,11 +52,11 @@ proc printLisp(root: TSNode, data: var string) = if node == root: break -proc process(path: string, mode="") = +proc process(path: string, mode="cpp", pretty = true) = if not existsFile(path): echo "Invalid path " & path return - + var parser = tsParserNew() ext = path.splitFile().ext @@ -67,14 +65,14 @@ proc process(path: string, mode="") = defer: parser.tsParserDelete() - - if mode.len() != 0: + + if mode.len != 0: pmode = mode elif ext in [".h", ".c"]: pmode = "c" elif ext in [".hxx", ".hpp", ".hh", ".H", ".h++", ".cpp", ".cxx", ".cc", ".C", ".c++"]: pmode = "cpp" - + if "cplusplus" in data or "extern \"C\"" in data: pmode = "cpp" @@ -91,23 +89,29 @@ proc process(path: string, mode="") = quit() var - tree = parser.tsParserParseString(nil, data.cstring, data.len().uint32) + tree = parser.tsParserParseString(nil, data.cstring, data.len.uint32) root = tree.tsTreeRootNode() defer: tree.tsTreeDelete() - - printLisp(root, data) + + printLisp(root, data, pretty) proc parseCli() = - let params = commandLineParams() + var + mode = "cpp" + params = commandLineParams() + pretty = true + for param in params: if param in ["-h", "--help", "-?", "/?", "/h"]: echo HELP quit() - elif param == "-u": - gPretty = false + elif param == "-c": + mode = "c" + elif param == "-m": + pretty = false else: - process(param) + process(param, mode, pretty) parseCli()
\ No newline at end of file |
