Created
January 19, 2014 04:30
-
-
Save Varriount/8500498 to your computer and use it in GitHub Desktop.
A nimrod pragma macro which generates helper procs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import macros | |
| from winlean import useWinUnicode | |
| when useWinUnicode: | |
| type winString = WideCString | |
| let apiPrefix = "W" | |
| else: | |
| type winString = CString | |
| let apiPrefix = "A" | |
| macro WinImport*(baseProc: stmt): stmt {.immediate.} = | |
| ## A pragma meant to be used with procedures that wrap the Windows API | |
| ## Given a base procedure without a 'W' or 'A' suffix, generates two more | |
| ## Procedures: | |
| ## - A conversion/wrapper procedure with the same name, | |
| ## except that all WinString arguments are changed to string arguments, | |
| ## which are automatically converted to the WinString type as needed. | |
| ## - A raw procedure with the same behavior as the original, except that | |
| ## the name has a 'W' or 'A' suffix, depending on whether unicode or | |
| ## ansi api's are used. | |
| # TODO - Return type conversion | |
| # TODO - Fix use of implicit return | |
| # TODO - Get rid of paramsIdent? | |
| result = newStmtList() | |
| var apiName: string | |
| case baseProc.name.kind | |
| of nnkPostfix: | |
| apiName = $baseProc.name[1] & apiPrefix | |
| else: | |
| apiName = $baseProc.name & apiPrefix | |
| # Calculate the new importc pragma | |
| var cImportPragma = newNimNode(nnkExprColonExpr) | |
| cImportPragma.add(newIdentNode("importc"), newStrLitNode(apiName)) | |
| baseProc.pragma.add(cImportPragma) | |
| # Generate the raw procedure | |
| var rawProc = copy(baseProc) | |
| case baseProc.name.kind | |
| of nnkPostfix: | |
| rawProc.name[1] = newIdentNode(apiName) | |
| else: | |
| rawProc.name= newIdentNode(apiName) | |
| # Generate the conversion proc | |
| var conversionProc = copy(baseProc) | |
| conversionProc.pragma= newEmptyNode() | |
| conversionProc.body= newStmtList() | |
| # Generate the conversion call, and modify the conversion procs parameters. | |
| var conversionCall = newCall(apiName) | |
| for i in 1.. <conversionProc.params.len: # Skip the first value (return type) | |
| var currentParams = conversionProc.params[i] | |
| var paramsType = currentParams[currentParams.len-2] | |
| var paramsIdents = newSeq[PNimrodNode]() | |
| for k in 0..len(currentParams)-3: | |
| paramsIdents.add(currentParams[k]) | |
| if paramsType.kind != nnkEmpty and $paramsType == "WinString": | |
| currentParams[currentParams.len-2] = newIdentNode("string") | |
| for param in paramsIdents: | |
| conversionCall.add(newCall("newWideCString", copy(param))) | |
| else: | |
| for param in paramsIdents: | |
| conversionCall.add(copy(param)) | |
| # Add the call to the conversionProc | |
| var callParent = conversionProc.body | |
| if baseProc.params[0].kind != nnkEmpty and $baseProc.params[0] != "void": | |
| callParent = newNimNode(nnkReturnStmt) | |
| conversionProc.body.add(callParent) | |
| callParent.add(conversionCall) | |
| # Add the other procs. Order is important! | |
| result.add(baseProc) | |
| result.add(rawProc) | |
| result.add(conversionProc) | |
| echo(repr(result)) | |
| proc CreateDirectory*(pathName: WinString, security: pointer=nil): int32 {. | |
| WinImport, dynlib: "kernel32", stdcall.} | |
| when isMainModule: | |
| var x = createDirectory("CreatedDirectory") | |
| echo(x) | |
| # dumpTree: | |
| # proc getLost(e, s:string) = | |
| # getFound(convert(e), convert(s)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment