f149dc12
Andreas Rumpf
first somewhat wo...
|
1
2
3
4
5
6
7
8
9
10
11
12
|
import macros, strutils
const
pragmaPos = 4
paramPos = 3
intType = when sizeof(int) == 8: "longlong" else: "long"
uintType = when sizeof(int) == 8: "ulonglong" else: "ulong"
var
dllName {.compileTime.}: string = "SqueakNimTest"
stCode {.compileTime.}: string = ""
|
032258fd
Andreas Rumpf
various improvements
|
13
|
gPrefix {.compileTime.}: string = ""
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
14
|
|
032258fd
Andreas Rumpf
various improvements
|
15
|
template setModulename*(s, prefix: string) =
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
16
|
## Sets the DLL name. This is also used to set the 'category' in the generated
|
032258fd
Andreas Rumpf
various improvements
|
17
18
|
## classes. 'prefix' is added to every generated class that wraps a Nim
## object.
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
19
20
|
static:
dllName = s
|
032258fd
Andreas Rumpf
various improvements
|
21
|
gPrefix = prefix
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
template writeExternalLibrary*() =
static:
addf(stCode, """ExternalLibrary subclass: #$1
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: '$1'!
!$1 class methodsFor: 'primitives' stamp: 'SqueakNim'!
""", capitalize(dllName))
template writeSmallTalkCode*(filename: string) =
## You need to invoke this template to write the produced SmallTalk code to
## a file.
static:
writeFile(filename, stCode)
proc mapTypeToC(symbolicType: NimNode): string {.compileTime.} =
let t = symbolicType.getType
if symbolicType.kind == nnkSym and t.typeKind == ntyObject:
|
032258fd
Andreas Rumpf
various improvements
|
43
|
return gPrefix & $symbolicType
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
44
|
case t.typeKind
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
of ntyPtr, ntyVar:
expectKind t, nnkBracketExpr
result = mapTypeToC(t[1]) & "*"
of ntyCString: result = "char*"
of ntyInt: result = intType
of ntyInt8: result = "sbyte"
of ntyInt16: result = "short"
of ntyInt32: result = "long"
of ntyInt64: result = "longlong"
of ntyUInt: result = uintType
of ntyUInt8: result = "ubyte"
of ntyUInt16: result = "ushort"
of ntyUInt32: result = "ulong"
of ntyUInt64: result = "ulonglong"
of ntyFloat, ntyFloat64: result = "double"
of ntyFloat32: result = "float"
of ntyBool, ntyChar, ntyEnum: result = "char"
else: quit "Error: cannot wrap to Squeak " & treeRepr(t)
macro exportSt*(className: string; body: stmt): stmt =
# generates something like:
# system: aString
#"Some kind of comment"
#
# <apicall: long 'system' (char*) module: 'libSystem.dylib'>
# ^self externalCallFailed.
result = body
result[pragmaPos].add(ident"exportc", ident"dynlib", ident"cdecl")
let params = result[paramPos]
let procName = $result[0]
var st = procName
#echo treeRepr params
if params.len > 1:
expectKind params[1], nnkIdentDefs
let ident = $params[1][0]
if ident.len > 1:
st.add(ident.capitalize & ": " & ident)
else:
st.add(": " & ident)
# return type:
var apicall = "<cdecl: " & mapTypeToC(params[0]) & " '" &
procName & "' ("
var counter = 0
# parameter types:
for i in 1.. <params.len:
let param = params[i]
let L = param.len
for j in 0 .. param.len-3:
let name = param[j]
let typ = param[L-2]
if counter > 0:
apicall.add(" ")
st.addf(" $1: $1", name)
apicall.add(mapTypeToC(typ))
inc counter
apicall.add(") module: '" & dllName & "'>\n" &
|
032258fd
Andreas Rumpf
various improvements
|
102
103
|
"\t^self externalCallFailed.\n")
stCode.add(st & "\n\t\"Generated by NimSqueak\"\n\t" & apicall)
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
104
|
|
032258fd
Andreas Rumpf
various improvements
|
105
|
macro wrapObject*(typ: stmt): stmt =
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
106
|
## Declares a SmallTalk wrapper class.
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
107
108
109
110
|
var t = typ.getType()
if t.typeKind == ntyTypeDesc:
expectKind t, nnkBracketExpr
t = t[1]
|
032258fd
Andreas Rumpf
various improvements
|
111
112
|
expectKind t, nnkSym
let name = gPrefix & ($t).capitalize
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
113
114
115
116
117
118
119
|
if t.kind != nnkObjectTy: t = t.getType
expectKind t, nnkObjectTy
t = t[1]
expectKind t, nnkRecList
var fields = ""
for i in 0.. < t.len:
expectKind t[i], nnkSym
|
032258fd
Andreas Rumpf
various improvements
|
120
|
fields.addf "\t($# '$#')\n", $t[i], mapTypeToC(t[i])
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
121
122
123
124
125
126
127
128
129
130
131
132
133
|
let st = """ExternalStructure subclass: #$1
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: 'FFIConstants'
category: '$2'!
$1 class
instanceVariableNames: ''!
!$1 class methodsFor: 'field definition' stamp: 'SqueakNim'!
fields
^#(
|
032258fd
Andreas Rumpf
various improvements
|
134
|
$3
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
135
136
|
)! !
|
f149dc12
Andreas Rumpf
first somewhat wo...
|
137
138
139
140
141
|
$1 defineFields.
""" % [name, dllName, fields]
stCode.add(st)
result = newStmtList()
|