diff --git a/nimterop/globals.nim b/nimterop/globals.nim index e0b9b8f..17b9518 100644 --- a/nimterop/globals.nim +++ b/nimterop/globals.nim @@ -55,6 +55,7 @@ type 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 + headersProcessed*: HashSet[string] # Headers already processed directly or recursively # Nim compiler objects constSection*, enumSection*, pragmaSection*, procSection*, typeSection*, varSection*: PNode diff --git a/nimterop/toast.nim b/nimterop/toast.nim index fbaa960..1cda239 100644 --- a/nimterop/toast.nim +++ b/nimterop/toast.nim @@ -136,7 +136,11 @@ proc main( gecho preMainOut gState.initNim() for src in source: - gState.process(src.expandSymlinkAbs()) + let + src = src.expandSymlinkAbs() + if src notin gState.headersProcessed: + gState.process(src) + gState.headersProcessed.incl src if gState.pnim: printNim(gState) diff --git a/nimterop/toastlib/ast2.nim b/nimterop/toastlib/ast2.nim index dc4d220..43ec8d3 100644 --- a/nimterop/toastlib/ast2.nim +++ b/nimterop/toastlib/ast2.nim @@ -137,7 +137,7 @@ proc newConstDef(gState: State, node: TSNode, fname = "", fval = ""): PNode = # In case symbol was skipped earlier gState.skippedSyms.excl origname else: - gecho &"# const '{origname}' is duplicate, skipped" + decho &"const '{origname}' is duplicate, skipped" else: gecho &"# const '{origname}' has unsupported value '{val.strip()}'" gState.skippedSyms.incl origname @@ -391,7 +391,7 @@ proc newXIdent(gState: State, node: TSNode, kind = nskType, fname = "", pragmas: gState.identifierNodes[name] = result else: - gecho &"# {getKeyword(kind)} '{origname}' is duplicate, skipped" + decho &"{getKeyword(kind)} '{origname}' is duplicate, skipped" proc newArrayTree(gState: State, node: TSNode, typ, size: PNode = nil): PNode = # Create nkBracketExpr tree depending on input @@ -1706,6 +1706,9 @@ proc addDef(gState: State, node: TSNode) = fdecl = node[start+1].firstChildInTree("function_declarator") if not fdecl.isNil: + if gState.getNodeError(fdecl): + return + if not gState.noHeader: gState.addProc(node[start+1], node[start], commentNodes) else: @@ -1716,19 +1719,14 @@ proc processNode(gState: State, node: TSNode): Status = const known = ["preproc_def", "type_definition", "struct_specifier", "union_specifier", "enum_specifier", - "declaration", "function_definition"].toHashSet() + "declaration"].toHashSet() result = success let name = node.getName() if name in known: # Recognized top-level nodes - let - err = node.anyChildInTree("ERROR") - if not err.isNil: - # Bail on errors - gState.printDebug(node) - gecho &"# tree-sitter parse error: '{gState.getNodeVal(node).splitLines()[0]}', skipped" + if gState.getNodeError(node): result = Status.error else: # Process nodes @@ -1750,8 +1748,11 @@ proc processNode(gState: State, node: TSNode): Status = gState.addEnum(node) of "declaration": gState.addDecl(node) - of "function_definition": - gState.addDef(node) + elif name == "function_definition": + # Separate since we only need to check function_declarator for errors and + # not the compound_statement which could have errors but does not impact + # wrapper generation + gState.addDef(node) else: # Unknown, will check child nodes result = unknown diff --git a/nimterop/toastlib/getters.nim b/nimterop/toastlib/getters.nim index 08ba604..bfbd4be 100644 --- a/nimterop/toastlib/getters.nim +++ b/nimterop/toastlib/getters.nim @@ -315,6 +315,7 @@ proc getPreprocessor*(gState: State, fullpath: string) = p = startProcess(getCompiler(), args = args, options = {poStdErrToStdOut, poUsePath}) outp = p.outputStream() line = "" + newHeaders: HashSet[string] # Include content only from file gState.code = "" @@ -323,17 +324,19 @@ proc getPreprocessor*(gState: State, fullpath: string) = # We want to keep blank lines here for comment processing if line.len > 1 and line[0] == '#' and line[1] == ' ': start = false - line = line.sanitizePath(noQuote = true) - if sfile in line or - (DirSep notin line and sfileName in line): + line = line.split('"')[1].sanitizePath(noQuote = true) + if sfile == line or + (DirSep notin line and sfileName == line): start = true elif gState.recurse: - if pDir.Bl or pDir in line: + if (pDir.Bl or pDir in line) and line notin gState.headersProcessed: start = true + newHeaders.incl line else: for inc in includeDirs: - if inc in line: + if line.startsWith(inc) and line notin gState.headersProcessed: start = true + newHeaders.incl line break else: if start: @@ -342,6 +345,7 @@ proc getPreprocessor*(gState: State, fullpath: string) = gState.code.add line & "\n" elif not p.running(): break p.close() + gState.headersProcessed.incl newHeaders # Plugin related @@ -393,3 +397,4 @@ proc expandSymlinkAbs*(path: string): string = result = path.expandFilename().normalizedPath() except: result = path + result = result.sanitizePath(noQuote = true) \ No newline at end of file diff --git a/nimterop/toastlib/tshelp.nim b/nimterop/toastlib/tshelp.nim index 3b7c2cc..bbe029f 100644 --- a/nimterop/toastlib/tshelp.nim +++ b/nimterop/toastlib/tshelp.nim @@ -399,3 +399,12 @@ proc getTSNodeNamedChildNames*(node: TSNode): seq[string] = if name != "comment": result.add(name) + +proc getNodeError*(gState: State, node: TSNode): bool = + let + err = node.anyChildInTree("ERROR") + if not err.isNil: + # Bail on errors + gState.printDebug(node) + gecho &"# tree-sitter parse error: '{gState.getNodeVal(node).splitLines()[0]}', skipped" + result = true \ No newline at end of file