Compare commits
24 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
714fbe851f | ||
|
|
d053355ead | ||
|
|
5241aee0fc | ||
|
|
c87587a068 | ||
|
|
1fe199e1d8 | ||
|
|
ee58be398a | ||
|
|
166eae7a5a | ||
|
|
8d3d41f5d8 | ||
|
|
88917e9524 | ||
|
|
f84b155c3e | ||
|
|
68638c8bb6 | ||
|
|
248761da11 | ||
|
|
0ae87e82f5 | ||
|
|
8eb586fd80 | ||
|
|
fa1c4c636c | ||
|
|
b1a56279ff | ||
|
|
49607db05b | ||
|
|
48bde874e5 | ||
|
|
52e82bb2b4 | ||
|
|
27e30e30f7 | ||
|
|
0965eea3e9 | ||
|
|
e07983bbe3 | ||
|
|
127aa4688e | ||
|
|
cfd18e1008 |
14 changed files with 1336 additions and 292 deletions
10
config.nims
10
config.nims
|
|
@ -9,4 +9,12 @@ when defined(Windows):
|
||||||
switch("gc", "markAndSweep")
|
switch("gc", "markAndSweep")
|
||||||
|
|
||||||
# Retain stackTrace for clear errors
|
# Retain stackTrace for clear errors
|
||||||
switch("stackTrace", "on")
|
switch("stackTrace", "on")
|
||||||
|
|
||||||
|
# Path to compiler
|
||||||
|
switch("path", "$nim")
|
||||||
|
|
||||||
|
# Case objects
|
||||||
|
when not defined(danger):
|
||||||
|
switch("define", "nimOldCaseObjects")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ proc execTest(test: string) =
|
||||||
execCmd "nim cpp -r " & test
|
execCmd "nim cpp -r " & test
|
||||||
|
|
||||||
task buildToast, "build toast":
|
task buildToast, "build toast":
|
||||||
execCmd("nim c -f -d:danger nimterop/toast.nim")
|
execCmd("nim c -f nimterop/toast.nim")
|
||||||
|
|
||||||
task bt, "build toast":
|
task bt, "build toast":
|
||||||
execCmd("nim c -d:danger nimterop/toast.nim")
|
execCmd("nim c -d:danger nimterop/toast.nim")
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@ Module that should import everything so that `nim doc --project nimtero/all` run
|
||||||
|
|
||||||
# TODO: make sure it does import everything.
|
# TODO: make sure it does import everything.
|
||||||
|
|
||||||
import "."/[cimport, build, types, plugin, compat]
|
import "."/[cimport, build, types, plugin]
|
||||||
|
|
|
||||||
857
nimterop/ast2.nim
Normal file
857
nimterop/ast2.nim
Normal file
|
|
@ -0,0 +1,857 @@
|
||||||
|
import macros, os, sets, strutils, tables, times
|
||||||
|
|
||||||
|
import compiler/[ast, idents, options, renderer]
|
||||||
|
|
||||||
|
import "."/treesitter/api
|
||||||
|
|
||||||
|
import "."/[globals, getters]
|
||||||
|
|
||||||
|
proc addConst(nimState: NimState, node: TSNode) =
|
||||||
|
# #define X Y
|
||||||
|
#
|
||||||
|
# (preproc_def
|
||||||
|
# (identifier)
|
||||||
|
# (preproc_arg)
|
||||||
|
# )
|
||||||
|
decho("addConst()")
|
||||||
|
nimState.printDebug(node)
|
||||||
|
|
||||||
|
if node[0].getName() == "identifier" and
|
||||||
|
node[1].getName() == "preproc_arg":
|
||||||
|
let
|
||||||
|
constDef = newNode(nkConstDef)
|
||||||
|
|
||||||
|
# node[0] = identifier = const name
|
||||||
|
(name, info) = nimState.getNameInfo(node.getAtom(), nskConst)
|
||||||
|
# TODO - check blank and override
|
||||||
|
ident = nimState.getIdent(name, info)
|
||||||
|
|
||||||
|
# node[1] = preproc_arg = value
|
||||||
|
val = nimState.getNodeVal(node[1]).getLit()
|
||||||
|
|
||||||
|
# If supported literal
|
||||||
|
if val.kind != nkNilLit:
|
||||||
|
# const X* = Y
|
||||||
|
#
|
||||||
|
# nkConstDef(
|
||||||
|
# nkPostfix(
|
||||||
|
# nkIdent("*"),
|
||||||
|
# nkIdent("X")
|
||||||
|
# ),
|
||||||
|
# nkEmpty(),
|
||||||
|
# nkXLit(Y)
|
||||||
|
# )
|
||||||
|
constDef.add ident
|
||||||
|
constDef.add newNode(nkEmpty)
|
||||||
|
constDef.add val
|
||||||
|
|
||||||
|
# nkConstSection.add
|
||||||
|
nimState.constSection.add constDef
|
||||||
|
|
||||||
|
nimState.printDebug(constDef)
|
||||||
|
|
||||||
|
proc newTypeIdent(nimState: NimState, node: TSNode, override = ""): PNode =
|
||||||
|
# Create nkTypeDef PNode with first ident
|
||||||
|
#
|
||||||
|
# If `override`, use it instead of node.getAtom() for name
|
||||||
|
let
|
||||||
|
(name, info) = nimState.getNameInfo(node.getAtom(), nskType)
|
||||||
|
# TODO - check blank and override
|
||||||
|
ident =
|
||||||
|
if override.len != 0:
|
||||||
|
nimState.getIdent(override, info)
|
||||||
|
else:
|
||||||
|
nimState.getIdent(name, info)
|
||||||
|
|
||||||
|
# type name* =
|
||||||
|
#
|
||||||
|
# nkTypeDef(
|
||||||
|
# nkPostfix(
|
||||||
|
# nkIdent("*"),
|
||||||
|
# nkIdent(name)
|
||||||
|
# ),
|
||||||
|
# nkEmpty()
|
||||||
|
# )
|
||||||
|
result = newNode(nkTypeDef)
|
||||||
|
result.add ident
|
||||||
|
result.add newNode(nkEmpty)
|
||||||
|
|
||||||
|
proc newPtrTree(nimState: NimState, count: int, typ: PNode): PNode =
|
||||||
|
# Create nkPtrTy tree depending on count
|
||||||
|
#
|
||||||
|
# Reduce by 1 if Nim type available for ptr X - e.g. ptr cchar = cstring
|
||||||
|
var
|
||||||
|
count = count
|
||||||
|
chng = false
|
||||||
|
if typ.kind == nkIdent:
|
||||||
|
let
|
||||||
|
tname = typ.ident.s
|
||||||
|
ptname = getPtrType(tname)
|
||||||
|
if tname != ptname:
|
||||||
|
# If Nim type available, use that ident
|
||||||
|
result = nimState.getIdent(ptname, typ.info, exported = false)
|
||||||
|
chng = true
|
||||||
|
# One ptr reduced
|
||||||
|
count -= 1
|
||||||
|
if count > 0:
|
||||||
|
# Nested nkPtrTy(typ) depending on count
|
||||||
|
#
|
||||||
|
# [ptr ...] typ
|
||||||
|
#
|
||||||
|
# nkPtrTy(
|
||||||
|
# nkPtrTy(
|
||||||
|
# typ
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
result = newNode(nkPtrTy)
|
||||||
|
var
|
||||||
|
parent = result
|
||||||
|
child: PNode
|
||||||
|
for i in 1 ..< count:
|
||||||
|
child = newNode(nkPtrTy)
|
||||||
|
parent.add child
|
||||||
|
parent = child
|
||||||
|
parent.add typ
|
||||||
|
elif not chng:
|
||||||
|
# Either no ptr, or none left after Nim type adjustment
|
||||||
|
result = typ
|
||||||
|
|
||||||
|
proc newArrayTree(nimState: NimState, node: TSNode, typ, size: PNode): PNode =
|
||||||
|
# Create nkBracketExpr tree depending on input
|
||||||
|
let
|
||||||
|
(_, info) = nimState.getNameInfo(node, nskType)
|
||||||
|
ident = nimState.getIdent("array", info, exported = false)
|
||||||
|
|
||||||
|
# array[size, typ]
|
||||||
|
#
|
||||||
|
# nkBracketExpr(
|
||||||
|
# nkIdent("array"),
|
||||||
|
# size,
|
||||||
|
# typ
|
||||||
|
# )
|
||||||
|
result = newNode(nkBracketExpr)
|
||||||
|
result.add ident
|
||||||
|
result.add size
|
||||||
|
result.add typ
|
||||||
|
|
||||||
|
proc getTypeArray(nimState: NimState, node: TSNode): PNode
|
||||||
|
proc getTypeProc(nimState: NimState, name: string, node: TSNode): PNode
|
||||||
|
|
||||||
|
proc newIdentDefs(nimState: NimState, name: string, node: TSNode, offset: SomeInteger, exported = false): PNode =
|
||||||
|
# Create nkIdentDefs tree for specified proc parameter or object field
|
||||||
|
#
|
||||||
|
# For proc, param should not be exported
|
||||||
|
#
|
||||||
|
# pname: [ptr ..] typ
|
||||||
|
#
|
||||||
|
# nkIdentDefs(
|
||||||
|
# nkIdent(pname),
|
||||||
|
# typ,
|
||||||
|
# nkEmpty()
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# For object, field should be exported
|
||||||
|
#
|
||||||
|
# pname*: [ptr ..] typ
|
||||||
|
#
|
||||||
|
# nkIdentDefs(
|
||||||
|
# nkPostfix(
|
||||||
|
# nkIdent("*"),
|
||||||
|
# nkIdent(pname)
|
||||||
|
# ),
|
||||||
|
# typ,
|
||||||
|
# nkEmpty()
|
||||||
|
# )
|
||||||
|
result = newNode(nkIdentDefs)
|
||||||
|
|
||||||
|
let
|
||||||
|
start = getStartAtom(node)
|
||||||
|
|
||||||
|
# node[start] - param type
|
||||||
|
(tname, tinfo) = nimState.getNameInfo(node[start], nskType)
|
||||||
|
tident = nimState.getIdent(tname, tinfo, exported = false)
|
||||||
|
|
||||||
|
if start == node.len - 1:
|
||||||
|
# Only for proc with no named param - create a param name based on offset
|
||||||
|
#
|
||||||
|
# int func(char, int);
|
||||||
|
let
|
||||||
|
pname = "a" & $(offset+1)
|
||||||
|
pident = nimState.getIdent(pname, tinfo, exported)
|
||||||
|
result.add pident
|
||||||
|
result.add tident
|
||||||
|
result.add newNode(nkEmpty)
|
||||||
|
else:
|
||||||
|
let
|
||||||
|
fdecl = node[start+1].anyChildInTree("function_declarator")
|
||||||
|
adecl = node[start+1].anyChildInTree("array_declarator")
|
||||||
|
abst = node[start+1].getName() == "abstract_pointer_declarator"
|
||||||
|
if fdecl.isNil and adecl.isNil:
|
||||||
|
if abst:
|
||||||
|
# Only for proc with no named param with pointer type
|
||||||
|
# Create a param name based on offset
|
||||||
|
#
|
||||||
|
# int func(char *, int **);
|
||||||
|
let
|
||||||
|
pname = "a" & $(offset+1)
|
||||||
|
pident = nimState.getIdent(pname, tinfo, exported)
|
||||||
|
acount = node[start+1].getXCount("abstract_pointer_declarator")
|
||||||
|
result.add pident
|
||||||
|
result.add nimState.newPtrTree(acount, tident)
|
||||||
|
result.add newNode(nkEmpty)
|
||||||
|
else:
|
||||||
|
# Named param, simple type
|
||||||
|
let
|
||||||
|
(pname, pinfo) = nimState.getNameInfo(node[start+1].getAtom(), nskField, parent = name)
|
||||||
|
pident = nimState.getIdent(pname, pinfo, exported)
|
||||||
|
|
||||||
|
count = node[start+1].getPtrCount()
|
||||||
|
result.add pident
|
||||||
|
if count > 0:
|
||||||
|
result.add nimState.newPtrTree(count, tident)
|
||||||
|
else:
|
||||||
|
result.add tident
|
||||||
|
result.add newNode(nkEmpty)
|
||||||
|
elif not fdecl.isNil:
|
||||||
|
# Named param, function pointer
|
||||||
|
let
|
||||||
|
(pname, pinfo) = nimState.getNameInfo(node[start+1].getAtom(), nskField, parent = name)
|
||||||
|
pident = nimState.getIdent(pname, pinfo, exported)
|
||||||
|
result.add pident
|
||||||
|
result.add nimState.getTypeProc(name, node)
|
||||||
|
result.add newNode(nkEmpty)
|
||||||
|
elif not adecl.isNil:
|
||||||
|
# Named param, array type
|
||||||
|
let
|
||||||
|
(pname, pinfo) = nimState.getNameInfo(node[start+1].getAtom(), nskField, parent = name)
|
||||||
|
pident = nimState.getIdent(pname, pinfo, exported)
|
||||||
|
result.add pident
|
||||||
|
result.add nimState.getTypeArray(node)
|
||||||
|
result.add newNode(nkEmpty)
|
||||||
|
else:
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
proc newProcTree(nimState: NimState, name: string, node: TSNode, rtyp: PNode): PNode =
|
||||||
|
# Create nkProcTy tree for specified proc type
|
||||||
|
let
|
||||||
|
fparam = newNode(nkFormalParams)
|
||||||
|
|
||||||
|
# Add return type
|
||||||
|
fparam.add rtyp
|
||||||
|
|
||||||
|
if not node.isNil:
|
||||||
|
for i in 0 ..< node.len:
|
||||||
|
# Add nkIdentDefs for each param
|
||||||
|
let
|
||||||
|
param = nimState.newIdentDefs(name, node[i], i, exported = false)
|
||||||
|
if not param.isNil:
|
||||||
|
fparam.add param
|
||||||
|
|
||||||
|
# proc(pname: ptyp ..): rtyp
|
||||||
|
#
|
||||||
|
# nkProcTy(
|
||||||
|
# nkFormalParams(
|
||||||
|
# rtyp,
|
||||||
|
# nkIdentDefs( # multiple depending on params
|
||||||
|
# ..
|
||||||
|
# )
|
||||||
|
# ),
|
||||||
|
# nkEmpty()
|
||||||
|
# )
|
||||||
|
result = newNode(nkProcTy)
|
||||||
|
result.add fparam
|
||||||
|
result.add newNode(nkEmpty)
|
||||||
|
|
||||||
|
proc newRecListTree(nimState: NimState, name: string, node: TSNode): PNode =
|
||||||
|
# Create nkRecList tree for specified object
|
||||||
|
if not node.isNil:
|
||||||
|
# fname*: ftyp
|
||||||
|
# ..
|
||||||
|
#
|
||||||
|
# nkRecList(
|
||||||
|
# nkIdentDefs( # multiple depending on fields
|
||||||
|
# ..
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
result = newNode(nkRecList)
|
||||||
|
|
||||||
|
for i in 0 ..< node.len:
|
||||||
|
# Add nkIdentDefs for each field
|
||||||
|
let
|
||||||
|
field = nimState.newIdentDefs(name, node[i], i, exported = true)
|
||||||
|
if not field.isNil:
|
||||||
|
result.add field
|
||||||
|
|
||||||
|
proc addTypeObject(nimState: NimState, node: TSNode, override = "", duplicate = "") =
|
||||||
|
# Add a type of object
|
||||||
|
#
|
||||||
|
# If `override` is set, use it as the name
|
||||||
|
# If `duplicate` is set, don't add the same name
|
||||||
|
decho("addTypeObject()")
|
||||||
|
let
|
||||||
|
# TODO - check blank and override
|
||||||
|
typeDef = nimState.newTypeIdent(node, override)
|
||||||
|
name = $typeDef[0][1]
|
||||||
|
|
||||||
|
if name != duplicate:
|
||||||
|
# type X* = object
|
||||||
|
#
|
||||||
|
# nkTypeDef(
|
||||||
|
# nkPostfix(
|
||||||
|
# nkIdent("*"),
|
||||||
|
# nkIdent("X")
|
||||||
|
# ),
|
||||||
|
# nkEmpty(),
|
||||||
|
# nkObjectTy(
|
||||||
|
# nkEmpty(),
|
||||||
|
# nkEmpty(),
|
||||||
|
# nkEmpty()
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
let
|
||||||
|
obj = newNode(nkObjectTy)
|
||||||
|
obj.add newNode(nkEmpty)
|
||||||
|
obj.add newNode(nkEmpty)
|
||||||
|
|
||||||
|
let
|
||||||
|
fdlist = node.anyChildInTree("field_declaration_list")
|
||||||
|
if not fdlist.isNil and fdlist.len > 0:
|
||||||
|
# Add fields to object if present
|
||||||
|
obj.add nimState.newRecListTree(name, fdlist)
|
||||||
|
else:
|
||||||
|
obj.add newNode(nkEmpty)
|
||||||
|
|
||||||
|
typeDef.add obj
|
||||||
|
|
||||||
|
# nkTypeSection.add
|
||||||
|
nimState.typeSection.add typeDef
|
||||||
|
|
||||||
|
nimState.printDebug(typeDef)
|
||||||
|
|
||||||
|
proc addTypeTyped(nimState: NimState, node: TSNode, toverride = "", duplicate = "") =
|
||||||
|
# Add a type of a specified type
|
||||||
|
#
|
||||||
|
# If `toverride` is set, use it as the type name
|
||||||
|
# If `duplicate` is set, don't add the same name
|
||||||
|
decho("addTypeTyped()")
|
||||||
|
let
|
||||||
|
start = getStartAtom(node)
|
||||||
|
for i in start+1 ..< node.len:
|
||||||
|
# Add a type of a specific type
|
||||||
|
let
|
||||||
|
# node[i] = identifer = name
|
||||||
|
# TODO - check blank and override
|
||||||
|
typeDef = nimState.newTypeIdent(node[i])
|
||||||
|
|
||||||
|
# node[start] = identifier = type name
|
||||||
|
(tname0, tinfo) = nimState.getNameInfo(node[start].getAtom(), nskType)
|
||||||
|
|
||||||
|
# Override type name
|
||||||
|
tname = if toverride.len != 0: toverride else: tname0
|
||||||
|
|
||||||
|
ident = nimState.getIdent(tname, tinfo, exported = false)
|
||||||
|
|
||||||
|
# node[i] could have nested pointers
|
||||||
|
count = node[i].getPtrCount()
|
||||||
|
|
||||||
|
# Skip typedef X X;
|
||||||
|
if $typeDef[0][1] != tname:
|
||||||
|
if count > 0:
|
||||||
|
# If pointers
|
||||||
|
typeDef.add nimState.newPtrTree(count, ident)
|
||||||
|
else:
|
||||||
|
typeDef.add ident
|
||||||
|
|
||||||
|
# type X* = [ptr ..] Y
|
||||||
|
#
|
||||||
|
# nkTypeDef(
|
||||||
|
# nkPostfix(
|
||||||
|
# nkIdent("*"),
|
||||||
|
# nkIdent("X")
|
||||||
|
# ),
|
||||||
|
# nkEmpty(),
|
||||||
|
# nkPtrTy( # optional, nested
|
||||||
|
# nkIdent("Y")
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
|
||||||
|
# nkTypeSection.add
|
||||||
|
nimState.typeSection.add typeDef
|
||||||
|
|
||||||
|
nimState.printDebug(typeDef)
|
||||||
|
else:
|
||||||
|
nimState.addTypeObject(node, duplicate = duplicate)
|
||||||
|
|
||||||
|
proc getTypeArray(nimState: NimState, node: TSNode): PNode =
|
||||||
|
# Create array type tree
|
||||||
|
let
|
||||||
|
start = getStartAtom(node)
|
||||||
|
|
||||||
|
# node[start] = identifier = type name
|
||||||
|
(name, info) = nimState.getNameInfo(node[start].getAtom(), nskType)
|
||||||
|
ident = nimState.getIdent(name, info, exported = false)
|
||||||
|
|
||||||
|
# Top-most array declarator
|
||||||
|
adecl = node[start+1].firstChildInTree("array_declarator")
|
||||||
|
|
||||||
|
# node[start+1] could have nested arrays
|
||||||
|
acount = adecl.getArrayCount()
|
||||||
|
innermost = adecl.mostNestedChildInTree()
|
||||||
|
|
||||||
|
# node[start+1] could have nested pointers - type
|
||||||
|
tcount = node[start+1].getPtrCount()
|
||||||
|
|
||||||
|
# Name could be nested pointer to array
|
||||||
|
#
|
||||||
|
# (..
|
||||||
|
# (array_declarator
|
||||||
|
# (parenthesized_declarator
|
||||||
|
# (pointer_declarator ..
|
||||||
|
# (pointer_declarator <- search upwards from atom
|
||||||
|
# (type_identifier) <- atom
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
ncount = innermost[0].getAtom().tsNodeParent().getPtrCount(reverse = true)
|
||||||
|
|
||||||
|
result = ident
|
||||||
|
var
|
||||||
|
cnode = adecl
|
||||||
|
|
||||||
|
if tcount > 0:
|
||||||
|
# If pointers
|
||||||
|
result = nimState.newPtrTree(tcount, result)
|
||||||
|
|
||||||
|
for i in 0 ..< acount:
|
||||||
|
let
|
||||||
|
size = nimState.getNodeVal(cnode[1]).getLit()
|
||||||
|
if size.kind != nkNilLit:
|
||||||
|
result = nimState.newArrayTree(cnode, result, size)
|
||||||
|
cnode = cnode[0]
|
||||||
|
|
||||||
|
if ncount > 0:
|
||||||
|
result = nimState.newPtrTree(ncount, result)
|
||||||
|
|
||||||
|
proc addTypeArray(nimState: NimState, node: TSNode) =
|
||||||
|
# Add a type of array type
|
||||||
|
decho("addTypeArray()")
|
||||||
|
let
|
||||||
|
# node[1] = identifer = name
|
||||||
|
# TODO - check blank and override
|
||||||
|
typeDef = nimState.newTypeIdent(node[1])
|
||||||
|
|
||||||
|
typ = nimState.getTypeArray(node)
|
||||||
|
|
||||||
|
typeDef.add typ
|
||||||
|
|
||||||
|
# type X* = [ptr] array[x, [ptr] Y]
|
||||||
|
#
|
||||||
|
# nkTypeDef(
|
||||||
|
# nkPostfix(
|
||||||
|
# nkIdent("*"),
|
||||||
|
# nkIdent("X")
|
||||||
|
# ),
|
||||||
|
# nkEmpty(),
|
||||||
|
# nkPtrTy( # optional, nested
|
||||||
|
# nkBracketExpr(
|
||||||
|
# nkIdent("array")
|
||||||
|
# nkXLit(x),
|
||||||
|
# nkPtrTy( # optional, nested
|
||||||
|
# nkIdent("Y")
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
|
||||||
|
# nkTypeSection.add
|
||||||
|
nimState.typeSection.add typeDef
|
||||||
|
|
||||||
|
nimState.printDebug(typeDef)
|
||||||
|
|
||||||
|
proc getTypeProc(nimState: NimState, name: string, node: TSNode): PNode =
|
||||||
|
# Create proc type tree
|
||||||
|
let
|
||||||
|
# node[0] = identifier = return type name
|
||||||
|
(rname, rinfo) = nimState.getNameInfo(node[0].getAtom(), nskType)
|
||||||
|
|
||||||
|
# Parameter list
|
||||||
|
plist = node[1].anyChildInTree("parameter_list")
|
||||||
|
|
||||||
|
# node[1] could have nested pointers
|
||||||
|
tcount = node[1].getPtrCount()
|
||||||
|
|
||||||
|
# Name could be nested pointer to function
|
||||||
|
#
|
||||||
|
# (..
|
||||||
|
# (function_declarator
|
||||||
|
# (parenthesized_declarator
|
||||||
|
# (pointer_declarator ..
|
||||||
|
# (pointer_declarator <- search upwards from atom
|
||||||
|
# (type_identifier) <- atom
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
ncount = node[1].getAtom().tsNodeParent().getPtrCount(reverse = true)
|
||||||
|
|
||||||
|
# Return type
|
||||||
|
var
|
||||||
|
retType = nimState.getIdent(rname, rinfo, exported = false)
|
||||||
|
if tcount > 0:
|
||||||
|
retType = nimState.newPtrTree(tcount, retType)
|
||||||
|
|
||||||
|
# Proc with return type and params
|
||||||
|
result = nimState.newProcTree(name, plist, retType)
|
||||||
|
if ncount > 1:
|
||||||
|
result = nimState.newPtrTree(ncount-1, result)
|
||||||
|
|
||||||
|
proc addTypeProc(nimState: NimState, node: TSNode) =
|
||||||
|
# Add a type of proc type
|
||||||
|
decho("addTypeProc()")
|
||||||
|
let
|
||||||
|
# node[1] = identifier = name
|
||||||
|
# TODO - check blank and override
|
||||||
|
typeDef = nimState.newTypeIdent(node[1])
|
||||||
|
name = $typeDef[0][1]
|
||||||
|
|
||||||
|
procTy = nimState.getTypeProc(name, node)
|
||||||
|
|
||||||
|
typeDef.add procTy
|
||||||
|
|
||||||
|
# type X* = proc(a1: Y, a2: Z): P
|
||||||
|
#
|
||||||
|
# nkTypeDef(
|
||||||
|
# nkPostfix(
|
||||||
|
# nkIdent("*"),
|
||||||
|
# nkIdent("X")
|
||||||
|
# ),
|
||||||
|
# nkEmpty(),
|
||||||
|
# nkPtrTy( # optional, nested
|
||||||
|
# nkProcTy(
|
||||||
|
# nkFormalParams(
|
||||||
|
# nkPtrTy( # optional, nested
|
||||||
|
# nkIdent(retType)
|
||||||
|
# ),
|
||||||
|
# nkIdentDefs(
|
||||||
|
# nkIdent(param),
|
||||||
|
# nkPtrTy(
|
||||||
|
# nkIdent(ptype)
|
||||||
|
# ),
|
||||||
|
# nkEmpty()
|
||||||
|
# ),
|
||||||
|
# ...
|
||||||
|
# ),
|
||||||
|
# nkEmpty()
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
|
||||||
|
# nkTypeSection.add
|
||||||
|
nimState.typeSection.add typeDef
|
||||||
|
|
||||||
|
nimState.printDebug(typeDef)
|
||||||
|
|
||||||
|
proc addType(nimState: NimState, node: TSNode) =
|
||||||
|
decho("addType()")
|
||||||
|
nimState.printDebug(node)
|
||||||
|
|
||||||
|
if node.getName() == "struct_specifier":
|
||||||
|
# struct X;
|
||||||
|
#
|
||||||
|
# (struct_specifier
|
||||||
|
# (type_identifier)
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# struct X {};
|
||||||
|
#
|
||||||
|
# (struct_specifier
|
||||||
|
# (type_identifier)
|
||||||
|
# (field_declaration_list = "{}")
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# struct X { char *a1; };
|
||||||
|
#
|
||||||
|
# (struct_specifier
|
||||||
|
# (type_identifier)
|
||||||
|
# (field_declaration_list
|
||||||
|
# (field_declaration
|
||||||
|
# (type_identifier|primitive_type|)
|
||||||
|
# (struct_specifier
|
||||||
|
# (type_identifier)
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# (field_identifier)
|
||||||
|
# )
|
||||||
|
# (field_declaration ...)
|
||||||
|
# )
|
||||||
|
decho("addType(): case 1")
|
||||||
|
nimState.addTypeObject(node)
|
||||||
|
elif node.getName() == "type_definition":
|
||||||
|
if node.len >= 2:
|
||||||
|
let
|
||||||
|
fdlist = node[0].anyChildInTree("field_declaration_list")
|
||||||
|
if (fdlist.isNil or (not fdlist.isNil and fdlist.len == 0)) and
|
||||||
|
nimState.getNodeVal(node[1]) == "":
|
||||||
|
# typedef struct X;
|
||||||
|
#
|
||||||
|
# (type_definition
|
||||||
|
# (struct_specifier
|
||||||
|
# (type_identifier)
|
||||||
|
# )
|
||||||
|
# (type_definition = "")
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# typedef struct X {};
|
||||||
|
#
|
||||||
|
# (type_definition
|
||||||
|
# (struct_specifier
|
||||||
|
# (type_identifier)
|
||||||
|
# (field_declaration_list = "{}")
|
||||||
|
# )
|
||||||
|
# (type_definition = "")
|
||||||
|
# )
|
||||||
|
decho("addType(): case 2")
|
||||||
|
nimState.addTypeObject(node[0])
|
||||||
|
else:
|
||||||
|
let
|
||||||
|
fdecl = node[1].anyChildInTree("function_declarator")
|
||||||
|
adecl = node[1].anyChildInTree("array_declarator")
|
||||||
|
if fdlist.isNil():
|
||||||
|
if adecl.isNil and fdecl.isNil:
|
||||||
|
# typedef X Y;
|
||||||
|
# typedef X *Y;
|
||||||
|
# typedef struct X Y;
|
||||||
|
# typedef struct X *Y;
|
||||||
|
#
|
||||||
|
# (type_definition
|
||||||
|
# (type_qualifier?)
|
||||||
|
# (type_identifier|primitive_type|)
|
||||||
|
# (struct_specifier
|
||||||
|
# (type_identifier)
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# (pointer_declarator - optional, nested
|
||||||
|
# (type_identifier)
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
decho("addType(): case 3")
|
||||||
|
nimState.addTypeTyped(node)
|
||||||
|
elif not fdecl.isNil:
|
||||||
|
# typedef X (*Y)(a1, a2, a3);
|
||||||
|
# typedef X *(*Y)(a1, a2, a3);
|
||||||
|
# typedef struct X (*Y)(a1, a2, a3);
|
||||||
|
# typedef struct X *(*Y)(a1, a2, a3);
|
||||||
|
#
|
||||||
|
# (type_definition
|
||||||
|
# (type_qualifier?)
|
||||||
|
# (type_identifier|primitive_type|)
|
||||||
|
# (struct_specifier
|
||||||
|
# (type_identifier)
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# (pointer_declarator - optional, nested
|
||||||
|
# (function_declarator
|
||||||
|
# (parenthesized_declarator
|
||||||
|
# (pointer_declarator
|
||||||
|
# (type_identifer)
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# (parameter_list
|
||||||
|
# (parameter_declaration
|
||||||
|
# (struct_specifier|type_identifier|primitive_type|array_declarator|function_declarator)
|
||||||
|
# (identifier - optional)
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
decho("addType(): case 4")
|
||||||
|
nimState.addTypeProc(node)
|
||||||
|
elif not adecl.isNil:
|
||||||
|
# typedef struct X Y[a][..];
|
||||||
|
# typedef struct X *Y[a][..];
|
||||||
|
# typedef struct X *(*Y)[a][..];
|
||||||
|
#
|
||||||
|
# (type_definition
|
||||||
|
# (type_qualifier?)
|
||||||
|
# (type_identifier|primitive_type|)
|
||||||
|
# (struct_specifier
|
||||||
|
# (type_identifier)
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# (pointer_declarator - optional, nested
|
||||||
|
# (array_declarator - nested
|
||||||
|
# (pointer_declarator - optional, nested
|
||||||
|
# (type_identifier)
|
||||||
|
# )
|
||||||
|
# (number_literal)
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
decho("addType(): case 5")
|
||||||
|
nimState.addTypeArray(node)
|
||||||
|
else:
|
||||||
|
if node.firstChildInTree("field_declaration_list").isNil:
|
||||||
|
# typedef struct X { .. } Y, *Z;
|
||||||
|
#
|
||||||
|
# (type_definition
|
||||||
|
# (struct_specifier
|
||||||
|
# (type_identifier) - named struct <====
|
||||||
|
# (field_declaration_list
|
||||||
|
# (field_declaration - optional, multiple
|
||||||
|
# (type_identifier|primitive_type|)
|
||||||
|
# (function_declarator|array_declarator
|
||||||
|
# ..
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# (field_identifier)
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# (type_identifier)
|
||||||
|
# (pointer_declarator - optional, nested
|
||||||
|
# (type_identifier)
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
|
||||||
|
# First add struct as object
|
||||||
|
decho("addType(): case 6")
|
||||||
|
nimState.addTypeObject(node[0])
|
||||||
|
|
||||||
|
if node.len > 1 and nimState.getNodeVal(node[1]) != "":
|
||||||
|
# Add any additional names
|
||||||
|
nimState.addTypeTyped(node, duplicate = nimState.getNodeVal(node[0].getAtom()))
|
||||||
|
else:
|
||||||
|
# Same as above except unnamed struct
|
||||||
|
#
|
||||||
|
# typedef struct { .. } Y, *Z;
|
||||||
|
|
||||||
|
# Get any name that isn't a pointer
|
||||||
|
decho("addType(): case 7")
|
||||||
|
let
|
||||||
|
name = block:
|
||||||
|
var
|
||||||
|
name = ""
|
||||||
|
for i in 1 ..< node.len:
|
||||||
|
if node[i].getName() == "type_identifier":
|
||||||
|
name = nimState.getNodeVal(node[i].getAtom())
|
||||||
|
|
||||||
|
name
|
||||||
|
|
||||||
|
# Now add struct as object with specified name
|
||||||
|
nimState.addTypeObject(node[0], override = name)
|
||||||
|
|
||||||
|
if name.len != 0:
|
||||||
|
# Add any additional names except duplicate
|
||||||
|
nimState.addTypeTyped(node, toverride = name, duplicate = name)
|
||||||
|
|
||||||
|
proc addEnum(nimState: NimState, node: TSNode) =
|
||||||
|
decho("addEnum()")
|
||||||
|
nimState.printDebug(node)
|
||||||
|
|
||||||
|
proc addProc(nimState: NimState, node: TSNode) =
|
||||||
|
decho("addProc()")
|
||||||
|
nimState.printDebug(node)
|
||||||
|
|
||||||
|
proc processNode(nimState: NimState, node: TSNode): bool =
|
||||||
|
result = true
|
||||||
|
|
||||||
|
case node.getName()
|
||||||
|
of "preproc_def":
|
||||||
|
nimState.addConst(node)
|
||||||
|
of "type_definition":
|
||||||
|
if not node.firstChildInTree("enum_specifier").isNil():
|
||||||
|
nimState.addEnum(node)
|
||||||
|
else:
|
||||||
|
nimState.addType(node)
|
||||||
|
of "struct_specifier":
|
||||||
|
nimState.addType(node)
|
||||||
|
of "enum_specifier":
|
||||||
|
nimState.addEnum(node)
|
||||||
|
of "declaration":
|
||||||
|
nimState.addProc(node)
|
||||||
|
else:
|
||||||
|
# Unknown
|
||||||
|
result = false
|
||||||
|
|
||||||
|
proc searchTree(nimState: NimState, root: TSNode) =
|
||||||
|
# Search AST generated by tree-sitter for recognized elements
|
||||||
|
var
|
||||||
|
node = root
|
||||||
|
nextnode: TSNode
|
||||||
|
depth = 0
|
||||||
|
processed = false
|
||||||
|
|
||||||
|
while true:
|
||||||
|
if not node.isNil() and depth > -1:
|
||||||
|
processed = nimState.processNode(node)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not processed and node.len() != 0:
|
||||||
|
nextnode = node[0]
|
||||||
|
depth += 1
|
||||||
|
else:
|
||||||
|
nextnode = node.tsNodeNextNamedSibling()
|
||||||
|
|
||||||
|
if nextnode.isNil():
|
||||||
|
while true:
|
||||||
|
node = node.tsNodeParent()
|
||||||
|
depth -= 1
|
||||||
|
if depth == -1:
|
||||||
|
break
|
||||||
|
if node == root:
|
||||||
|
break
|
||||||
|
if not node.tsNodeNextNamedSibling().isNil():
|
||||||
|
node = node.tsNodeNextNamedSibling()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
node = nextnode
|
||||||
|
|
||||||
|
if node == root:
|
||||||
|
break
|
||||||
|
|
||||||
|
proc printNimHeader*(gState: State) =
|
||||||
|
gecho """# Generated at $1
|
||||||
|
# Command line:
|
||||||
|
# $2 $3
|
||||||
|
|
||||||
|
{.hint[ConvFromXtoItselfNotNeeded]: off.}
|
||||||
|
|
||||||
|
import nimterop/types
|
||||||
|
""" % [$now(), getAppFilename(), commandLineParams().join(" ")]
|
||||||
|
|
||||||
|
proc printNim*(gState: State, fullpath: string, root: TSNode) =
|
||||||
|
var
|
||||||
|
nimState = new(NimState)
|
||||||
|
#fp = fullpath.replace("\\", "/")
|
||||||
|
|
||||||
|
nimState.identifiers = newTable[string, string]()
|
||||||
|
|
||||||
|
nimState.gState = gState
|
||||||
|
nimState.currentHeader = getCurrentHeader(fullpath)
|
||||||
|
nimState.sourceFile = fullpath
|
||||||
|
|
||||||
|
# Nim compiler objects
|
||||||
|
nimState.identCache = newIdentCache()
|
||||||
|
nimState.config = newConfigRef()
|
||||||
|
|
||||||
|
nimState.constSection = newNode(nkConstSection)
|
||||||
|
nimState.enumSection = newNode(nkStmtList)
|
||||||
|
nimState.procSection = newNode(nkStmtList)
|
||||||
|
nimState.typeSection = newNode(nkTypeSection)
|
||||||
|
|
||||||
|
nimState.searchTree(root)
|
||||||
|
|
||||||
|
var
|
||||||
|
tree = newNode(nkStmtList)
|
||||||
|
tree.add nimState.enumSection
|
||||||
|
tree.add nimState.constSection
|
||||||
|
tree.add nimState.typeSection
|
||||||
|
tree.add nimState.procSection
|
||||||
|
|
||||||
|
gecho tree.renderTree()
|
||||||
|
|
@ -2,8 +2,6 @@ import hashes, macros, osproc, sets, strformat, strutils, tables
|
||||||
|
|
||||||
import os except findExe, sleep
|
import os except findExe, sleep
|
||||||
|
|
||||||
import "."/[compat]
|
|
||||||
|
|
||||||
proc sanitizePath*(path: string, noQuote = false, sep = $DirSep): string =
|
proc sanitizePath*(path: string, noQuote = false, sep = $DirSep): string =
|
||||||
result = path.multiReplace([("\\\\", sep), ("\\", sep), ("/", sep)])
|
result = path.multiReplace([("\\\\", sep), ("\\", sep), ("/", sep)])
|
||||||
if not noQuote:
|
if not noQuote:
|
||||||
|
|
@ -648,7 +646,7 @@ proc getGccPaths*(mode = "c"): seq[string] =
|
||||||
break
|
break
|
||||||
if inc:
|
if inc:
|
||||||
var
|
var
|
||||||
path = line.strip().myNormalizedPath()
|
path = line.strip().normalizedPath()
|
||||||
if path notin result:
|
if path notin result:
|
||||||
result.add path
|
result.add path
|
||||||
|
|
||||||
|
|
@ -667,13 +665,13 @@ proc getGccLibPaths*(mode = "c"): seq[string] =
|
||||||
if "LIBRARY_PATH=" in line:
|
if "LIBRARY_PATH=" in line:
|
||||||
for path in line[13 .. ^1].split(PathSep):
|
for path in line[13 .. ^1].split(PathSep):
|
||||||
var
|
var
|
||||||
path = path.strip().myNormalizedPath()
|
path = path.strip().normalizedPath()
|
||||||
if path notin result:
|
if path notin result:
|
||||||
result.add path
|
result.add path
|
||||||
break
|
break
|
||||||
elif '\t' in line:
|
elif '\t' in line:
|
||||||
var
|
var
|
||||||
path = line.strip().myNormalizedPath()
|
path = line.strip().normalizedPath()
|
||||||
if path notin result:
|
if path notin result:
|
||||||
result.add path
|
result.add path
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ const CIMPORT {.used.} = 1
|
||||||
|
|
||||||
include "."/globals
|
include "."/globals
|
||||||
|
|
||||||
import "."/[build, compat, paths, types]
|
import "."/[build, paths, types]
|
||||||
export types
|
export types
|
||||||
|
|
||||||
proc interpPath(dir: string): string=
|
proc interpPath(dir: string): string=
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,18 @@
|
||||||
import macros, strformat
|
import macros, strformat
|
||||||
|
|
||||||
when (NimMajor, NimMinor, NimPatch) >= (0, 19, 9):
|
from os import parentDir, getCurrentCompilerExe, DirSep
|
||||||
from os import parentDir, getCurrentCompilerExe, DirSep
|
proc getNimRootDir(): string =
|
||||||
proc getNimRootDir(): string =
|
#[
|
||||||
#[
|
hack, but works
|
||||||
hack, but works
|
alternatively (but more complex), use (from a nim file, not nims otherwise
|
||||||
alternatively (but more complex), use (from a nim file, not nims otherwise
|
you get Error: ambiguous call; both system.fileExists):
|
||||||
you get Error: ambiguous call; both system.fileExists):
|
import "$nim/testament/lib/stdtest/specialpaths.nim"
|
||||||
import "$nim/testament/lib/stdtest/specialpaths.nim"
|
nimRootDir
|
||||||
nimRootDir
|
]#
|
||||||
]#
|
fmt"{currentSourcePath}".parentDir.parentDir.parentDir
|
||||||
fmt"{currentSourcePath}".parentDir.parentDir.parentDir
|
|
||||||
else:
|
|
||||||
proc getCurrentCompilerExe*(): string =
|
|
||||||
"nim"
|
|
||||||
|
|
||||||
const
|
const
|
||||||
DirSep = when defined(windows): '\\' else: '/'
|
DirSep = when defined(windows): '\\' else: '/'
|
||||||
|
|
||||||
proc execAction(cmd: string): string =
|
proc execAction(cmd: string): string =
|
||||||
var
|
var
|
||||||
|
|
@ -80,4 +76,4 @@ proc buildDocs*(files: openArray[string], path: string, baseDir = getProjectPath
|
||||||
for i in 0 .. paramCount():
|
for i in 0 .. paramCount():
|
||||||
if paramStr(i) == "--publish":
|
if paramStr(i) == "--publish":
|
||||||
echo execAction(&"cd {path} && ghp-import --no-jekyll -fp {path}")
|
echo execAction(&"cd {path} && ghp-import --no-jekyll -fp {path}")
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@ import dynlib, macros, os, sequtils, sets, strformat, strutils, tables, times
|
||||||
|
|
||||||
import regex
|
import regex
|
||||||
|
|
||||||
import "."/[build, compat, globals, plugin, treesitter/api]
|
import compiler/[ast, idents, lineinfos, msgs, pathutils, renderer]
|
||||||
|
|
||||||
|
import "."/[build, globals, plugin, treesitter/api]
|
||||||
|
|
||||||
const gReserved = """
|
const gReserved = """
|
||||||
addr and as asm
|
addr and as asm
|
||||||
|
|
@ -26,6 +28,10 @@ when while
|
||||||
xor
|
xor
|
||||||
yield""".split(Whitespace).toHashSet()
|
yield""".split(Whitespace).toHashSet()
|
||||||
|
|
||||||
|
# Types related
|
||||||
|
|
||||||
|
# Types related
|
||||||
|
|
||||||
const gTypeMap* = {
|
const gTypeMap* = {
|
||||||
# char
|
# char
|
||||||
"char": "cchar",
|
"char": "cchar",
|
||||||
|
|
@ -91,6 +97,17 @@ proc getType*(str: string): string =
|
||||||
if gTypeMap.hasKey(result):
|
if gTypeMap.hasKey(result):
|
||||||
result = gTypeMap[result]
|
result = gTypeMap[result]
|
||||||
|
|
||||||
|
proc getPtrType*(str: string): string =
|
||||||
|
result = case str:
|
||||||
|
of "cchar":
|
||||||
|
"cstring"
|
||||||
|
of "object":
|
||||||
|
"pointer"
|
||||||
|
else:
|
||||||
|
str
|
||||||
|
|
||||||
|
# Identifier related
|
||||||
|
|
||||||
proc checkIdentifier(name, kind, parent, origName: string) =
|
proc checkIdentifier(name, kind, parent, origName: string) =
|
||||||
let
|
let
|
||||||
parentStr = if parent.nBl: parent & ":" else: ""
|
parentStr = if parent.nBl: parent & ":" else: ""
|
||||||
|
|
@ -165,6 +182,8 @@ proc addNewIdentifer*(nimState: NimState, name: string, override = false): bool
|
||||||
nimState.identifiers[nimName] = name
|
nimState.identifiers[nimName] = name
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
|
# Overrides related
|
||||||
|
|
||||||
proc getOverride*(nimState: NimState, name: string, kind: NimSymKind): string =
|
proc getOverride*(nimState: NimState, name: string, kind: NimSymKind): string =
|
||||||
doAssert name.nBl, "Blank identifier error"
|
doAssert name.nBl, "Blank identifier error"
|
||||||
|
|
||||||
|
|
@ -189,34 +208,146 @@ proc getOverrideFinal*(nimState: NimState, kind: NimSymKind): string =
|
||||||
for i in nimState.gState.onSymbolOverrideFinal(typ):
|
for i in nimState.gState.onSymbolOverrideFinal(typ):
|
||||||
result &= "\n" & nimState.getOverride(i, kind)
|
result &= "\n" & nimState.getOverride(i, kind)
|
||||||
|
|
||||||
proc getPtrType*(str: string): string =
|
proc getLit*(str: string): PNode =
|
||||||
result = case str:
|
|
||||||
of "ptr cchar":
|
|
||||||
"cstring"
|
|
||||||
of "ptr ptr cchar":
|
|
||||||
"ptr cstring"
|
|
||||||
of "ptr object":
|
|
||||||
"pointer"
|
|
||||||
of "ptr ptr object":
|
|
||||||
"ptr pointer"
|
|
||||||
else:
|
|
||||||
str
|
|
||||||
|
|
||||||
proc getLit*(str: string): string =
|
|
||||||
# Used to convert #define literals into const
|
# Used to convert #define literals into const
|
||||||
let
|
let
|
||||||
str = str.replace(re"/[/*].*?(?:\*/)?$", "").strip()
|
str = str.replace(re"/[/*].*?(?:\*/)?$", "").strip()
|
||||||
|
|
||||||
if str.contains(re"^[\-]?[\d]*[.]?[\d]+$") or # decimal
|
if str.contains(re"^[\-]?[\d]+$"): # decimal
|
||||||
str.contains(re"^0x[\da-fA-F]+$") or # hexadecimal
|
result = newIntNode(nkIntLit, parseInt(str))
|
||||||
str.contains(re"^'[[:ascii:]]'$") or # char
|
|
||||||
str.contains(re"""^"[[:ascii:]]+"$"""): # char *
|
elif str.contains(re"^[\-]?[\d]*[.]?[\d]+$"): # float
|
||||||
return str
|
result = newFloatNode(nkFloatLit, parseFloat(str))
|
||||||
|
|
||||||
|
# TODO - hex becomes int on render
|
||||||
|
elif str.contains(re"^0x[\da-fA-F]+$"): # hexadecimal
|
||||||
|
result = newIntNode(nkIntLit, parseHexInt(str))
|
||||||
|
|
||||||
|
elif str.contains(re"^'[[:ascii:]]'$"): # char
|
||||||
|
result = newNode(nkCharLit)
|
||||||
|
result.intVal = str[1].int64
|
||||||
|
|
||||||
|
elif str.contains(re"""^"[[:ascii:]]+"$"""): # char *
|
||||||
|
result = newStrNode(nkStrLit, str[1 .. ^2])
|
||||||
|
|
||||||
|
else:
|
||||||
|
result = newNode(nkNilLit)
|
||||||
|
|
||||||
|
# TSNode shortcuts
|
||||||
|
|
||||||
|
proc isNil*(node: TSNode): bool =
|
||||||
|
node.tsNodeIsNull()
|
||||||
|
|
||||||
|
proc len*(node: TSNode): int =
|
||||||
|
if not node.isNil:
|
||||||
|
result = node.tsNodeNamedChildCount().int
|
||||||
|
|
||||||
|
proc `[]`*(node: TSNode, i: SomeInteger): TSNode =
|
||||||
|
if i < node.len():
|
||||||
|
result = node.tsNodeNamedChild(i.uint32)
|
||||||
|
|
||||||
|
proc getName*(node: TSNode): string {.inline.} =
|
||||||
|
if not node.isNil:
|
||||||
|
return $node.tsNodeType()
|
||||||
|
|
||||||
|
proc getNodeVal*(gState: State, node: TSNode): string =
|
||||||
|
if not node.isNil:
|
||||||
|
return gState.code[node.tsNodeStartByte() .. node.tsNodeEndByte()-1].strip()
|
||||||
|
|
||||||
proc getNodeVal*(nimState: NimState, node: TSNode): string =
|
proc getNodeVal*(nimState: NimState, node: TSNode): string =
|
||||||
return nimState.gState.code[node.tsNodeStartByte() .. node.tsNodeEndByte()-1].strip()
|
nimState.gState.getNodeVal(node)
|
||||||
|
|
||||||
|
proc getAtom*(node: TSNode): TSNode =
|
||||||
|
if not node.isNil:
|
||||||
|
# Get child node which is topmost atom
|
||||||
|
if node.getName() in gAtoms:
|
||||||
|
return node
|
||||||
|
elif node.len() != 0:
|
||||||
|
return node[0].getAtom()
|
||||||
|
|
||||||
|
proc getStartAtom*(node: TSNode): int =
|
||||||
|
if not node.isNil:
|
||||||
|
# Skip const, volatile and other type qualifiers
|
||||||
|
for i in 0 .. node.len - 1:
|
||||||
|
if node[i].getAtom().getName() notin gAtoms:
|
||||||
|
result += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
proc getXCount*(node: TSNode, ntype: string, reverse = false): int =
|
||||||
|
if not node.isNil:
|
||||||
|
# Get number of ntype nodes nested in tree
|
||||||
|
var
|
||||||
|
cnode = node
|
||||||
|
while ntype in cnode.getName():
|
||||||
|
result += 1
|
||||||
|
if reverse:
|
||||||
|
cnode = cnode.tsNodeParent()
|
||||||
|
else:
|
||||||
|
if cnode.len() != 0:
|
||||||
|
cnode = cnode[0]
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
proc getPtrCount*(node: TSNode, reverse = false): int =
|
||||||
|
node.getXCount("pointer_declarator")
|
||||||
|
|
||||||
|
proc getArrayCount*(node: TSNode, reverse = false): int =
|
||||||
|
node.getXCount("array_declarator")
|
||||||
|
|
||||||
|
proc getDeclarator*(node: TSNode): TSNode =
|
||||||
|
if not node.isNil:
|
||||||
|
# Return if child is a function or array declarator
|
||||||
|
if node.getName() in ["function_declarator", "array_declarator"]:
|
||||||
|
return node
|
||||||
|
elif node.len() != 0:
|
||||||
|
return node[0].getDeclarator()
|
||||||
|
|
||||||
|
proc firstChildInTree*(node: TSNode, ntype: string): TSNode =
|
||||||
|
# Search for node type in tree - first children
|
||||||
|
var
|
||||||
|
cnode = node
|
||||||
|
while not cnode.isNil:
|
||||||
|
if cnode.getName() == ntype:
|
||||||
|
return cnode
|
||||||
|
cnode = cnode[0]
|
||||||
|
|
||||||
|
proc anyChildInTree*(node: TSNode, ntype: string): TSNode =
|
||||||
|
# Search for node type anywhere in tree - depth first
|
||||||
|
var
|
||||||
|
cnode = node
|
||||||
|
while not cnode.isNil:
|
||||||
|
if cnode.getName() == ntype:
|
||||||
|
return cnode
|
||||||
|
for i in 0 ..< cnode.len:
|
||||||
|
let
|
||||||
|
ccnode = cnode[i].anyChildInTree(ntype)
|
||||||
|
if not ccnode.isNil():
|
||||||
|
return ccnode
|
||||||
|
if cnode != node:
|
||||||
|
cnode = cnode.tsNodeNextNamedSibling()
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
proc mostNestedChildInTree*(node: TSNode): TSNode =
|
||||||
|
# Search for the most nested child of node's type in tree
|
||||||
|
var
|
||||||
|
cnode = node
|
||||||
|
ntype = cnode.getName()
|
||||||
|
while not cnode.isNil and cnode.len != 0 and cnode[0].getName() == ntype:
|
||||||
|
cnode = cnode[0]
|
||||||
|
result = cnode
|
||||||
|
|
||||||
|
proc inChildren*(node: TSNode, ntype: string): bool =
|
||||||
|
# Search for node type in immediate children
|
||||||
|
result = false
|
||||||
|
for i in 0 ..< node.len():
|
||||||
|
if (node[i]).getName() == ntype:
|
||||||
|
result = true
|
||||||
|
break
|
||||||
|
|
||||||
proc getLineCol*(gState: State, node: TSNode): tuple[line, col: int] =
|
proc getLineCol*(gState: State, node: TSNode): tuple[line, col: int] =
|
||||||
|
# Get line number and column info for node
|
||||||
result.line = 1
|
result.line = 1
|
||||||
result.col = 1
|
result.col = 1
|
||||||
for i in 0 .. node.tsNodeStartByte().int-1:
|
for i in 0 .. node.tsNodeStartByte().int-1:
|
||||||
|
|
@ -225,6 +356,150 @@ proc getLineCol*(gState: State, node: TSNode): tuple[line, col: int] =
|
||||||
result.line += 1
|
result.line += 1
|
||||||
result.col += 1
|
result.col += 1
|
||||||
|
|
||||||
|
proc getTSNodeNamedChildCountSansComments*(node: TSNode): int =
|
||||||
|
for i in 0 ..< node.len():
|
||||||
|
if node.getName() != "comment":
|
||||||
|
result += 1
|
||||||
|
|
||||||
|
proc getPxName*(node: TSNode, offset: int): string =
|
||||||
|
# Get the xth (grand)parent of the node
|
||||||
|
var
|
||||||
|
np = node
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
while not np.isNil() and count < offset:
|
||||||
|
np = np.tsNodeParent()
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
if count == offset and not np.isNil():
|
||||||
|
return np.getName()
|
||||||
|
|
||||||
|
proc printLisp*(gState: State, root: TSNode): string =
|
||||||
|
var
|
||||||
|
node = root
|
||||||
|
nextnode: TSNode
|
||||||
|
depth = 0
|
||||||
|
|
||||||
|
while true:
|
||||||
|
if not node.isNil() and depth > -1:
|
||||||
|
if gState.pretty:
|
||||||
|
result &= spaces(depth)
|
||||||
|
let
|
||||||
|
(line, col) = gState.getLineCol(node)
|
||||||
|
result &= &"({$node.tsNodeType()} {line} {col} {node.tsNodeEndByte() - node.tsNodeStartByte()}"
|
||||||
|
let
|
||||||
|
val = gState.getNodeVal(node)
|
||||||
|
if "\n" notin val and " " notin val:
|
||||||
|
result &= &" \"{val}\""
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if node.tsNodeNamedChildCount() != 0:
|
||||||
|
if gState.pretty:
|
||||||
|
result &= "\n"
|
||||||
|
nextnode = node.tsNodeNamedChild(0)
|
||||||
|
depth += 1
|
||||||
|
else:
|
||||||
|
if gState.pretty:
|
||||||
|
result &= ")\n"
|
||||||
|
else:
|
||||||
|
result &= ")"
|
||||||
|
nextnode = node.tsNodeNextNamedSibling()
|
||||||
|
|
||||||
|
if nextnode.isNil():
|
||||||
|
while true:
|
||||||
|
node = node.tsNodeParent()
|
||||||
|
depth -= 1
|
||||||
|
if depth == -1:
|
||||||
|
break
|
||||||
|
if gState.pretty:
|
||||||
|
result &= spaces(depth) & ")\n"
|
||||||
|
else:
|
||||||
|
result &= ")"
|
||||||
|
if node == root:
|
||||||
|
break
|
||||||
|
if not node.tsNodeNextNamedSibling().isNil():
|
||||||
|
node = node.tsNodeNextNamedSibling()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
node = nextnode
|
||||||
|
|
||||||
|
if node == root:
|
||||||
|
break
|
||||||
|
|
||||||
|
proc getCommented*(str: string): string =
|
||||||
|
"\n# " & str.strip().replace("\n", "\n# ")
|
||||||
|
|
||||||
|
proc printTree*(nimState: NimState, pnode: PNode, offset = "") =
|
||||||
|
if nimState.gState.debug and pnode.kind != nkNone:
|
||||||
|
stdout.write "\n# " & offset & $pnode.kind & "("
|
||||||
|
case pnode.kind
|
||||||
|
of nkCharLit:
|
||||||
|
stdout.write "'" & pnode.intVal.char & "')"
|
||||||
|
of nkIntLit..nkUInt64Lit:
|
||||||
|
stdout.write $pnode.intVal & ")"
|
||||||
|
of nkFloatLit..nkFloat128Lit:
|
||||||
|
stdout.write $pnode.floatVal & ")"
|
||||||
|
of nkStrLit..nkTripleStrLit:
|
||||||
|
stdout.write "\"" & pnode.strVal & "\")"
|
||||||
|
of nkSym:
|
||||||
|
stdout.write $pnode.sym & ")"
|
||||||
|
of nkIdent:
|
||||||
|
stdout.write "\"" & $pnode.ident.s & "\")"
|
||||||
|
else:
|
||||||
|
if pnode.sons.len != 0:
|
||||||
|
for i in 0 ..< pnode.sons.len:
|
||||||
|
nimState.printTree(pnode.sons[i], offset & " ")
|
||||||
|
if i != pnode.sons.len - 1:
|
||||||
|
stdout.write ","
|
||||||
|
stdout.write "\n# " & offset & ")"
|
||||||
|
else:
|
||||||
|
stdout.write ")"
|
||||||
|
if offset.len == 0:
|
||||||
|
necho ""
|
||||||
|
|
||||||
|
proc printDebug*(nimState: NimState, node: TSNode) =
|
||||||
|
if nimState.gState.debug:
|
||||||
|
necho ("Input => " & nimState.getNodeVal(node)).getCommented() & "\n" &
|
||||||
|
nimState.gState.printLisp(node).getCommented()
|
||||||
|
|
||||||
|
proc printDebug*(nimState: NimState, pnode: PNode) =
|
||||||
|
if nimState.gState.debug:
|
||||||
|
necho ("Output => " & $pnode).getCommented()
|
||||||
|
nimState.printTree(pnode)
|
||||||
|
|
||||||
|
# Compiler shortcuts
|
||||||
|
|
||||||
|
proc getLineInfo*(nimState: NimState, node: TSNode): TLineInfo =
|
||||||
|
# Get Nim equivalent line:col info from node
|
||||||
|
let
|
||||||
|
(line, col) = nimState.gState.getLineCol(node)
|
||||||
|
|
||||||
|
result = newLineInfo(nimState.config, nimState.sourceFile.AbsoluteFile, line, col)
|
||||||
|
|
||||||
|
proc getIdent*(nimState: NimState, name: string, info: TLineInfo, exported = true): PNode =
|
||||||
|
# Get ident PNode for name + info
|
||||||
|
let
|
||||||
|
exp = getIdent(nimState.identCache, "*")
|
||||||
|
ident = getIdent(nimState.identCache, name)
|
||||||
|
|
||||||
|
if exported:
|
||||||
|
result = newNode(nkPostfix)
|
||||||
|
result.add newIdentNode(exp, info)
|
||||||
|
result.add newIdentNode(ident, info)
|
||||||
|
else:
|
||||||
|
result = newIdentNode(ident, info)
|
||||||
|
|
||||||
|
proc getNameInfo*(nimState: NimState, node: TSNode, kind: NimSymKind, parent = ""):
|
||||||
|
tuple[name: string, info: TLineInfo] =
|
||||||
|
# Shortcut to get identifier name and info (node value and line:col)
|
||||||
|
let
|
||||||
|
name = nimState.getNodeVal(node)
|
||||||
|
result.name = nimState.getIdentifier(name, kind, parent)
|
||||||
|
if kind == nskType:
|
||||||
|
result.name = result.name.getType()
|
||||||
|
result.info = nimState.getLineInfo(node)
|
||||||
|
|
||||||
proc getCurrentHeader*(fullpath: string): string =
|
proc getCurrentHeader*(fullpath: string): string =
|
||||||
("header" & fullpath.splitFile().name.multiReplace([(".", ""), ("-", "")]))
|
("header" & fullpath.splitFile().name.multiReplace([(".", ""), ("-", "")]))
|
||||||
|
|
||||||
|
|
@ -291,91 +566,6 @@ proc getPreprocessor*(gState: State, fullpath: string, mode = "cpp"): string =
|
||||||
replace(re"__attribute__[ ]*\(\(.*?\)\)([ ,;])", "$1").
|
replace(re"__attribute__[ ]*\(\(.*?\)\)([ ,;])", "$1").
|
||||||
removeStatic()
|
removeStatic()
|
||||||
|
|
||||||
converter toString*(kind: Kind): string =
|
|
||||||
return case kind:
|
|
||||||
of exactlyOne:
|
|
||||||
""
|
|
||||||
of oneOrMore:
|
|
||||||
"+"
|
|
||||||
of zeroOrMore:
|
|
||||||
"*"
|
|
||||||
of zeroOrOne:
|
|
||||||
"?"
|
|
||||||
of orWithNext:
|
|
||||||
"!"
|
|
||||||
|
|
||||||
converter toKind*(kind: string): Kind =
|
|
||||||
return case kind:
|
|
||||||
of "+":
|
|
||||||
oneOrMore
|
|
||||||
of "*":
|
|
||||||
zeroOrMore
|
|
||||||
of "?":
|
|
||||||
zeroOrOne
|
|
||||||
of "!":
|
|
||||||
orWithNext
|
|
||||||
else:
|
|
||||||
exactlyOne
|
|
||||||
|
|
||||||
proc getNameKind*(name: string): tuple[name: string, kind: Kind, recursive: bool] =
|
|
||||||
if name[0] == '^':
|
|
||||||
result.recursive = true
|
|
||||||
result.name = name[1 .. ^1]
|
|
||||||
else:
|
|
||||||
result.name = name
|
|
||||||
result.kind = $name[^1]
|
|
||||||
|
|
||||||
if result.kind != exactlyOne:
|
|
||||||
result.name = result.name[0 .. ^2]
|
|
||||||
|
|
||||||
proc getTSNodeNamedChildCountSansComments*(node: TSNode): int =
|
|
||||||
if node.tsNodeNamedChildCount() != 0:
|
|
||||||
for i in 0 .. node.tsNodeNamedChildCount()-1:
|
|
||||||
if $node.tsNodeType() != "comment":
|
|
||||||
result += 1
|
|
||||||
|
|
||||||
proc getTSNodeNamedChildNames*(node: TSNode): seq[string] =
|
|
||||||
if node.tsNodeNamedChildCount() != 0:
|
|
||||||
for i in 0 .. node.tsNodeNamedChildCount()-1:
|
|
||||||
let
|
|
||||||
name = $node.tsNodeNamedChild(i).tsNodeType()
|
|
||||||
|
|
||||||
if name != "comment":
|
|
||||||
result.add(name)
|
|
||||||
|
|
||||||
proc getRegexForAstChildren*(ast: ref Ast): string =
|
|
||||||
result = "^"
|
|
||||||
for i in 0 .. ast.children.len-1:
|
|
||||||
let
|
|
||||||
kind: string = ast.children[i].kind
|
|
||||||
begin = if result[^1] == '|': "" else: "(?:"
|
|
||||||
case kind:
|
|
||||||
of "!":
|
|
||||||
result &= &"{begin}{ast.children[i].name}|"
|
|
||||||
else:
|
|
||||||
result &= &"{begin}{ast.children[i].name}){kind}"
|
|
||||||
result &= "$"
|
|
||||||
|
|
||||||
proc getAstChildByName*(ast: ref Ast, name: string): ref Ast =
|
|
||||||
for i in 0 .. ast.children.len-1:
|
|
||||||
if name in ast.children[i].name.split("|"):
|
|
||||||
return ast.children[i]
|
|
||||||
|
|
||||||
if ast.children.len == 1 and ast.children[0].name == ".":
|
|
||||||
return ast.children[0]
|
|
||||||
|
|
||||||
proc getPxName*(node: TSNode, offset: int): string =
|
|
||||||
var
|
|
||||||
np = node
|
|
||||||
count = 0
|
|
||||||
|
|
||||||
while not np.tsNodeIsNull() and count < offset:
|
|
||||||
np = np.tsNodeParent()
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
if count == offset and not np.tsNodeIsNull():
|
|
||||||
return $np.tsNodeType()
|
|
||||||
|
|
||||||
proc getNimExpression*(nimState: NimState, expr: string): string =
|
proc getNimExpression*(nimState: NimState, expr: string): string =
|
||||||
var
|
var
|
||||||
clean = expr.multiReplace([("\n", " "), ("\r", "")])
|
clean = expr.multiReplace([("\n", " "), ("\r", "")])
|
||||||
|
|
@ -435,42 +625,6 @@ proc getSplitComma*(joined: seq[string]): seq[string] =
|
||||||
for i in joined:
|
for i in joined:
|
||||||
result = result.concat(i.split(","))
|
result = result.concat(i.split(","))
|
||||||
|
|
||||||
proc getHeader*(nimState: NimState): string =
|
|
||||||
result =
|
|
||||||
if nimState.gState.dynlib.Bl:
|
|
||||||
&", header: {nimState.currentHeader}"
|
|
||||||
else:
|
|
||||||
""
|
|
||||||
|
|
||||||
proc getDynlib*(nimState: NimState): string =
|
|
||||||
result =
|
|
||||||
if nimState.gState.dynlib.nBl:
|
|
||||||
&", dynlib: {nimState.gState.dynlib}"
|
|
||||||
else:
|
|
||||||
""
|
|
||||||
|
|
||||||
proc getImportC*(nimState: NimState, origName, nimName: string): string =
|
|
||||||
if nimName != origName:
|
|
||||||
result = &"importc: \"{origName}\"{nimState.getHeader()}"
|
|
||||||
else:
|
|
||||||
result = nimState.impShort
|
|
||||||
|
|
||||||
proc getPragma*(nimState: NimState, pragmas: varargs[string]): string =
|
|
||||||
result = ""
|
|
||||||
for pragma in pragmas.items():
|
|
||||||
if pragma.nBl:
|
|
||||||
result &= pragma & ", "
|
|
||||||
if result.nBl:
|
|
||||||
result = " {." & result[0 .. ^3] & ".}"
|
|
||||||
|
|
||||||
result = result.replace(nimState.impShort & ", cdecl", nimState.impShort & "C")
|
|
||||||
|
|
||||||
let
|
|
||||||
dy = nimState.getDynlib()
|
|
||||||
|
|
||||||
if ", cdecl" in result and dy.nBl:
|
|
||||||
result = result.replace(".}", dy & ".}")
|
|
||||||
|
|
||||||
proc getComments*(nimState: NimState, strip = false): string =
|
proc getComments*(nimState: NimState, strip = false): string =
|
||||||
if not nimState.gState.nocomments and nimState.commentStr.nBl:
|
if not nimState.gState.nocomments and nimState.commentStr.nBl:
|
||||||
result = "\n" & nimState.commentStr
|
result = "\n" & nimState.commentStr
|
||||||
|
|
@ -505,6 +659,6 @@ proc loadPlugin*(gState: State, sourcePath: string) =
|
||||||
|
|
||||||
proc expandSymlinkAbs*(path: string): string =
|
proc expandSymlinkAbs*(path: string): string =
|
||||||
try:
|
try:
|
||||||
result = path.expandSymlink().absolutePath(path.parentDir()).myNormalizedPath()
|
result = path.expandSymlink().absolutePath(path.parentDir()).normalizedPath()
|
||||||
except:
|
except:
|
||||||
result = path
|
result = path
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ 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
|
||||||
|
|
@ -34,24 +35,6 @@ const
|
||||||
].concat(toSeq(gExpressions.items))
|
].concat(toSeq(gExpressions.items))
|
||||||
|
|
||||||
type
|
type
|
||||||
Kind = enum
|
|
||||||
exactlyOne
|
|
||||||
oneOrMore # +
|
|
||||||
zeroOrMore # *
|
|
||||||
zeroOrOne # ?
|
|
||||||
orWithNext # !
|
|
||||||
|
|
||||||
Ast = object
|
|
||||||
name*: string
|
|
||||||
kind*: Kind
|
|
||||||
recursive*: bool
|
|
||||||
children*: seq[ref Ast]
|
|
||||||
when not declared(CIMPORT):
|
|
||||||
tonim*: proc (ast: ref Ast, node: TSNode, nimState: NimState)
|
|
||||||
regex*: Regex
|
|
||||||
|
|
||||||
AstTable {.used.} = TableRef[string, seq[ref Ast]]
|
|
||||||
|
|
||||||
State = ref object
|
State = ref object
|
||||||
compile*, defines*, headers*, includeDirs*, searchDirs*, prefix*, suffix*, symOverride*: seq[string]
|
compile*, defines*, headers*, includeDirs*, searchDirs*, prefix*, suffix*, symOverride*: seq[string]
|
||||||
|
|
||||||
|
|
@ -67,7 +50,13 @@ type
|
||||||
NimState {.used.} = ref object
|
NimState {.used.} = ref object
|
||||||
identifiers*: TableRef[string, string]
|
identifiers*: TableRef[string, string]
|
||||||
|
|
||||||
commentStr*, constStr*, debugStr*, enumStr*, procStr*, skipStr*, typeStr*: string
|
commentStr*, debugStr*, skipStr*: string
|
||||||
|
|
||||||
|
# Nim compiler objects
|
||||||
|
when not declared(CIMPORT):
|
||||||
|
constSection*, enumSection*, procSection*, typeSection*: PNode
|
||||||
|
identCache*: IdentCache
|
||||||
|
config*: ConfigRef
|
||||||
|
|
||||||
gState*: State
|
gState*: State
|
||||||
|
|
||||||
|
|
@ -94,7 +83,7 @@ type CompileMode = enum
|
||||||
const modeDefault {.used.} = $cpp # TODO: USE this everywhere relevant
|
const modeDefault {.used.} = $cpp # TODO: USE this everywhere relevant
|
||||||
|
|
||||||
when not declared(CIMPORT):
|
when not declared(CIMPORT):
|
||||||
export gAtoms, gExpressions, gEnumVals, Kind, Ast, AstTable, State, NimState,
|
export gAtoms, gExpressions, gEnumVals, State, NimState,
|
||||||
nBl, Bl, CompileMode, modeDefault
|
nBl, Bl, CompileMode, modeDefault
|
||||||
|
|
||||||
# Redirect output to file when required
|
# Redirect output to file when required
|
||||||
|
|
@ -107,3 +96,7 @@ when not declared(CIMPORT):
|
||||||
template necho*(args: string) {.dirty.} =
|
template necho*(args: string) {.dirty.} =
|
||||||
let gState = nimState.gState
|
let gState = nimState.gState
|
||||||
gecho args
|
gecho args
|
||||||
|
|
||||||
|
template decho*(str: untyped): untyped =
|
||||||
|
if nimState.gState.debug:
|
||||||
|
necho str.getCommented()
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ proc treesitterSetup*() =
|
||||||
gitPull("https://github.com/tree-sitter/tree-sitter", cacheDir / "treesitter", """
|
gitPull("https://github.com/tree-sitter/tree-sitter", cacheDir / "treesitter", """
|
||||||
lib/include/*
|
lib/include/*
|
||||||
lib/src/*
|
lib/src/*
|
||||||
""", "0.15.5")
|
""", "0.16.2")
|
||||||
|
|
||||||
gitPull("https://github.com/JuliaStrings/utf8proc", cacheDir / "utf8proc", """
|
gitPull("https://github.com/JuliaStrings/utf8proc", cacheDir / "utf8proc", """
|
||||||
*.c
|
*.c
|
||||||
|
|
@ -36,7 +36,7 @@ src/*.h
|
||||||
src/*.c
|
src/*.c
|
||||||
src/*.cc
|
src/*.cc
|
||||||
src/tree_sitter/parser.h
|
src/tree_sitter/parser.h
|
||||||
""", "v0.15.0")
|
""", "v0.16.0")
|
||||||
|
|
||||||
writeFile(cacheDir / "treesitter_c" / "src" / "api.h", """
|
writeFile(cacheDir / "treesitter_c" / "src" / "api.h", """
|
||||||
const TSLanguage *tree_sitter_c();
|
const TSLanguage *tree_sitter_c();
|
||||||
|
|
@ -48,7 +48,7 @@ src/*.h
|
||||||
src/*.c
|
src/*.c
|
||||||
src/*.cc
|
src/*.cc
|
||||||
src/tree_sitter/parser.h
|
src/tree_sitter/parser.h
|
||||||
""", "v0.15.0")
|
""", "v0.16.0")
|
||||||
|
|
||||||
writeFile(cacheDir / "treesitter_cpp" / "src" / "api.h", """
|
writeFile(cacheDir / "treesitter_cpp" / "src" / "api.h", """
|
||||||
const TSLanguage *tree_sitter_cpp();
|
const TSLanguage *tree_sitter_cpp();
|
||||||
|
|
|
||||||
|
|
@ -2,58 +2,9 @@ import os, osproc, strformat, strutils, times
|
||||||
|
|
||||||
import "."/treesitter/[api, c, cpp]
|
import "."/treesitter/[api, c, cpp]
|
||||||
|
|
||||||
import "."/[ast, compat, globals, getters, grammar]
|
import "."/[ast2, globals, getters]
|
||||||
|
|
||||||
proc printLisp(gState: State, root: TSNode) =
|
proc process(gState: State, path: string) =
|
||||||
var
|
|
||||||
node = root
|
|
||||||
nextnode: TSNode
|
|
||||||
depth = 0
|
|
||||||
|
|
||||||
while true:
|
|
||||||
if not node.tsNodeIsNull() and depth > -1:
|
|
||||||
if gState.pretty:
|
|
||||||
stdout.write spaces(depth)
|
|
||||||
let
|
|
||||||
(line, col) = gState.getLineCol(node)
|
|
||||||
stdout.write &"({$node.tsNodeType()} {line} {col} {node.tsNodeEndByte() - node.tsNodeStartByte()}"
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
if node.tsNodeNamedChildCount() != 0:
|
|
||||||
if gState.pretty:
|
|
||||||
gecho ""
|
|
||||||
nextnode = node.tsNodeNamedChild(0)
|
|
||||||
depth += 1
|
|
||||||
else:
|
|
||||||
if gState.pretty:
|
|
||||||
gecho ")"
|
|
||||||
else:
|
|
||||||
stdout.write ")"
|
|
||||||
nextnode = node.tsNodeNextNamedSibling()
|
|
||||||
|
|
||||||
if nextnode.tsNodeIsNull():
|
|
||||||
while true:
|
|
||||||
node = node.tsNodeParent()
|
|
||||||
depth -= 1
|
|
||||||
if depth == -1:
|
|
||||||
break
|
|
||||||
if gState.pretty:
|
|
||||||
gecho spaces(depth) & ")"
|
|
||||||
else:
|
|
||||||
stdout.write ")"
|
|
||||||
if node == root:
|
|
||||||
break
|
|
||||||
if not node.tsNodeNextNamedSibling().tsNodeIsNull():
|
|
||||||
node = node.tsNodeNextNamedSibling()
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
node = nextnode
|
|
||||||
|
|
||||||
if node == root:
|
|
||||||
break
|
|
||||||
|
|
||||||
proc process(gState: State, path: string, astTable: AstTable) =
|
|
||||||
doAssert existsFile(path), &"Invalid path {path}"
|
doAssert existsFile(path), &"Invalid path {path}"
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
@ -91,9 +42,9 @@ proc process(gState: State, path: string, astTable: AstTable) =
|
||||||
tree.tsTreeDelete()
|
tree.tsTreeDelete()
|
||||||
|
|
||||||
if gState.past:
|
if gState.past:
|
||||||
gState.printLisp(root)
|
gecho gState.printLisp(root)
|
||||||
elif gState.pnim:
|
elif gState.pnim:
|
||||||
gState.printNim(path, root, astTable)
|
gState.printNim(path, root)
|
||||||
elif gState.preprocess:
|
elif gState.preprocess:
|
||||||
gecho gState.code
|
gecho gState.code
|
||||||
|
|
||||||
|
|
@ -109,7 +60,6 @@ proc main(
|
||||||
nocomments = false,
|
nocomments = false,
|
||||||
output = "",
|
output = "",
|
||||||
past = false,
|
past = false,
|
||||||
pgrammar = false,
|
|
||||||
pluginSourcePath: string = "",
|
pluginSourcePath: string = "",
|
||||||
pnim = false,
|
pnim = false,
|
||||||
prefix: seq[string] = @[],
|
prefix: seq[string] = @[],
|
||||||
|
|
@ -167,19 +117,12 @@ proc main(
|
||||||
doAssert gState.outputHandle.open(outputFile, fmWrite),
|
doAssert gState.outputHandle.open(outputFile, fmWrite),
|
||||||
&"Failed to write to {outputFile}"
|
&"Failed to write to {outputFile}"
|
||||||
|
|
||||||
# Process grammar into AST
|
if source.nBl:
|
||||||
let
|
|
||||||
astTable = parseGrammar()
|
|
||||||
|
|
||||||
if pgrammar:
|
|
||||||
# Print AST of grammar
|
|
||||||
gState.printGrammar(astTable)
|
|
||||||
elif source.nBl:
|
|
||||||
# Print source after preprocess or Nim output
|
# Print source after preprocess or Nim output
|
||||||
if gState.pnim:
|
if gState.pnim:
|
||||||
gState.printNimHeader()
|
gState.printNimHeader()
|
||||||
for src in source:
|
for src in source:
|
||||||
gState.process(src.expandSymlinkAbs(), astTable)
|
gState.process(src.expandSymlinkAbs())
|
||||||
|
|
||||||
# Close outputFile
|
# Close outputFile
|
||||||
if outputFile.len != 0:
|
if outputFile.len != 0:
|
||||||
|
|
@ -219,9 +162,9 @@ proc main(
|
||||||
|
|
||||||
# Rerun nim check on stubbed wrapper
|
# Rerun nim check on stubbed wrapper
|
||||||
(check, err) = execCmdEx(&"{gState.nim} check {outputFile}")
|
(check, err) = execCmdEx(&"{gState.nim} check {outputFile}")
|
||||||
doAssert err == 0, data & "# Nim check with stub failed:\n\n" & check
|
doAssert err == 0, data & "\n# Nim check with stub failed:\n\n" & check
|
||||||
else:
|
else:
|
||||||
doAssert err == 0, outputFile.readFile() & "# Nim check failed:\n\n" & check
|
doAssert err == 0, outputFile.readFile() & "\n# Nim check failed:\n\n" & check
|
||||||
|
|
||||||
# Print wrapper if temporarily redirected to file
|
# Print wrapper if temporarily redirected to file
|
||||||
if check and output.len == 0:
|
if check and output.len == 0:
|
||||||
|
|
@ -241,7 +184,6 @@ when isMainModule:
|
||||||
"nocomments": "exclude top-level comments from output",
|
"nocomments": "exclude top-level comments from output",
|
||||||
"output": "file to output content - default stdout",
|
"output": "file to output content - default stdout",
|
||||||
"past": "print AST output",
|
"past": "print AST output",
|
||||||
"pgrammar": "print grammar",
|
|
||||||
"pluginSourcePath": "Nim file to build and load as a plugin",
|
"pluginSourcePath": "Nim file to build and load as a plugin",
|
||||||
"pnim": "print Nim output",
|
"pnim": "print Nim output",
|
||||||
"preprocess": "run preprocessor on header",
|
"preprocess": "run preprocessor on header",
|
||||||
|
|
@ -260,7 +202,6 @@ when isMainModule:
|
||||||
"nocomments": 'c',
|
"nocomments": 'c',
|
||||||
"output": 'o',
|
"output": 'o',
|
||||||
"past": 'a',
|
"past": 'a',
|
||||||
"pgrammar": 'g',
|
|
||||||
"pnim": 'n',
|
"pnim": 'n',
|
||||||
"prefix": 'E',
|
"prefix": 'E',
|
||||||
"preprocess": 'p',
|
"preprocess": 'p',
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,7 @@
|
||||||
# see https://github.com/nimterop/nimterop/issues/79
|
import std/time_t as time_t_temp
|
||||||
|
type
|
||||||
when (NimMajor, NimMinor, NimPatch) < (0, 19, 9):
|
time_t* = time_t_temp.Time
|
||||||
# clean this up once upgraded; adapted from std/time_t
|
time64_t* = time_t_temp.Time
|
||||||
when defined(nimdoc):
|
|
||||||
type
|
|
||||||
impl = distinct int64
|
|
||||||
Time = impl
|
|
||||||
elif defined(windows):
|
|
||||||
when defined(i386) and defined(gcc):
|
|
||||||
type Time {.importc: "time_t", header: "<time.h>".} = distinct int32
|
|
||||||
else:
|
|
||||||
type Time {.importc: "time_t", header: "<time.h>".} = distinct int64
|
|
||||||
elif defined(posix):
|
|
||||||
import posix
|
|
||||||
type
|
|
||||||
time_t* = Time
|
|
||||||
time64_t* = Time
|
|
||||||
else:
|
|
||||||
import std/time_t as time_t_temp
|
|
||||||
type
|
|
||||||
time_t* = time_t_temp.Time
|
|
||||||
time64_t* = time_t_temp.Time
|
|
||||||
|
|
||||||
when defined(cpp):
|
when defined(cpp):
|
||||||
# http://www.cplusplus.com/reference/cwchar/wchar_t/
|
# http://www.cplusplus.com/reference/cwchar/wchar_t/
|
||||||
|
|
|
||||||
42
tests/include/test3.h
Normal file
42
tests/include/test3.h
Normal 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 const 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 { volatile char a1; };
|
||||||
|
struct A15 { char *a1; const 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
71
tests/tnimterop2.nim
Normal 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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue