implemented user-defined pragmas
This commit is contained in:
parent
5a2163d71d
commit
804e2ac89d
11 changed files with 237 additions and 151 deletions
|
|
@ -2653,6 +2653,30 @@ Example:
|
||||||
{.deadCodeElim: on.}
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
|
|
||||||
|
Pragma pragma
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The `pragma`:idx: pragma can be used to declare user defined pragmas. This is
|
||||||
|
useful because Nimrod's templates and macros do not affect pragmas. User
|
||||||
|
defined pragmas are in a different module-wide scope than all other symbols.
|
||||||
|
They cannot be imported from a module.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
when appType == "lib":
|
||||||
|
{.pragma: rtl, exportc, dynlib, cdecl.}
|
||||||
|
else:
|
||||||
|
{.pragma: rtl, importc, dynlib: "client.dll", cdecl.}
|
||||||
|
|
||||||
|
proc p*(a, b: int): int {.rtl.} =
|
||||||
|
return a+b
|
||||||
|
|
||||||
|
In the example a new pragma named ``rtl`` is introduced that either imports
|
||||||
|
a symbol from a dynamic library or exports the symbol for dynamic library
|
||||||
|
generation.
|
||||||
|
|
||||||
|
|
||||||
Disabling certain messages
|
Disabling certain messages
|
||||||
--------------------------
|
--------------------------
|
||||||
Nimrod generates some warnings and hints ("line too long") that may annoy the
|
Nimrod generates some warnings and hints ("line too long") that may annoy the
|
||||||
|
|
@ -2715,8 +2739,8 @@ strings automatically:
|
||||||
printf("hallo %s", "world") # "world" will be passed as C string
|
printf("hallo %s", "world") # "world" will be passed as C string
|
||||||
|
|
||||||
|
|
||||||
Dynlib pragma
|
Dynlib pragma for import
|
||||||
-------------
|
------------------------
|
||||||
With the `dynlib`:idx: pragma a procedure can be imported from
|
With the `dynlib`:idx: pragma a procedure can be imported from
|
||||||
a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). The
|
a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). The
|
||||||
non-optional argument has to be the name of the dynamic library:
|
non-optional argument has to be the name of the dynamic library:
|
||||||
|
|
@ -2762,3 +2786,17 @@ string expressions in general:
|
||||||
|
|
||||||
**Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant
|
**Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant
|
||||||
strings, because they are precompiled.
|
strings, because they are precompiled.
|
||||||
|
|
||||||
|
Dynlib pragma for export
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
With the ``dynlib`` pragma a procedure can also be exported to
|
||||||
|
a dynamic library. The pragma then has no argument and has to be used in
|
||||||
|
conjunction with the ``exportc`` pragma:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
proc exportme(): int {.cdecl, export, dynlib.}
|
||||||
|
|
||||||
|
This is only useful if the program is compiled as a dynamic library via the
|
||||||
|
``--app:lib`` command line option.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,8 @@ type
|
||||||
skIterator, # an iterator
|
skIterator, # an iterator
|
||||||
skConverter, # a type converter
|
skConverter, # a type converter
|
||||||
skMacro, # a macro
|
skMacro, # a macro
|
||||||
skTemplate, # a template
|
skTemplate, # a template; currently also misused for user-defined
|
||||||
|
# pragmas
|
||||||
skField, # a field in a record or object
|
skField, # a field in a record or object
|
||||||
skEnumField, # an identifier in an enum
|
skEnumField, # an identifier in an enum
|
||||||
skForVar, # a for loop variable
|
skForVar, # a for loop variable
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
## It translates a C source file into a Nimrod AST. Then the renderer can be
|
## It translates a C source file into a Nimrod AST. Then the renderer can be
|
||||||
## used to convert the AST to its text representation.
|
## used to convert the AST to its text representation.
|
||||||
|
|
||||||
|
## XXX cleanup of declaration handling. Standalone enums.
|
||||||
|
|
||||||
import
|
import
|
||||||
os, llstream, rnimsyn, clex, idents, strutils, pegs, ast, astalgo, msgs,
|
os, llstream, rnimsyn, clex, idents, strutils, pegs, ast, astalgo, msgs,
|
||||||
options, strtabs
|
options, strtabs
|
||||||
|
|
|
||||||
17
rod/c2nim/tests/systest2.c
Normal file
17
rod/c2nim/tests/systest2.c
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifdef C2NIM
|
||||||
|
# header "iup.h"
|
||||||
|
# cdecl
|
||||||
|
# mangle "'GTK_'{.*}" "TGtk$1"
|
||||||
|
# mangle "'PGTK_'{.*}" "PGtk$1"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct stupidTAG {
|
||||||
|
mytype a, b;
|
||||||
|
} GTK_MyStruct, *PGTK_MyStruct;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
mytype a, b;
|
||||||
|
} GTK_MyStruct, *PGTK_MyStruct;
|
||||||
|
|
||||||
|
int IupConvertXYToPos(PIhandle ih, int x, int y);
|
||||||
|
|
||||||
|
|
@ -24,11 +24,8 @@ proc countDefinedSymbols*(): int
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc DefineSymbol(symbol: string) =
|
proc DefineSymbol(symbol: string) =
|
||||||
var
|
var i = getIdent(symbol)
|
||||||
sym: PSym
|
var sym = StrTableGet(gSymbols, i)
|
||||||
i: PIdent
|
|
||||||
i = getIdent(symbol)
|
|
||||||
sym = StrTableGet(gSymbols, i)
|
|
||||||
if sym == nil:
|
if sym == nil:
|
||||||
new(sym) # circumvent the ID mechanism
|
new(sym) # circumvent the ID mechanism
|
||||||
sym.kind = skConditional
|
sym.kind = skConditional
|
||||||
|
|
@ -37,20 +34,16 @@ proc DefineSymbol(symbol: string) =
|
||||||
sym.position = 1
|
sym.position = 1
|
||||||
|
|
||||||
proc UndefSymbol(symbol: string) =
|
proc UndefSymbol(symbol: string) =
|
||||||
var sym: PSym
|
var sym = StrTableGet(gSymbols, getIdent(symbol))
|
||||||
sym = StrTableGet(gSymbols, getIdent(symbol))
|
|
||||||
if sym != nil: sym.position = 0
|
if sym != nil: sym.position = 0
|
||||||
|
|
||||||
proc isDefined(symbol: PIdent): bool =
|
proc isDefined(symbol: PIdent): bool =
|
||||||
var sym: PSym
|
var sym = StrTableGet(gSymbols, symbol)
|
||||||
sym = StrTableGet(gSymbols, symbol)
|
|
||||||
result = (sym != nil) and (sym.position == 1)
|
result = (sym != nil) and (sym.position == 1)
|
||||||
|
|
||||||
proc ListSymbols() =
|
proc ListSymbols() =
|
||||||
var
|
var it: TTabIter
|
||||||
it: TTabIter
|
var s = InitTabIter(it, gSymbols)
|
||||||
s: PSym
|
|
||||||
s = InitTabIter(it, gSymbols)
|
|
||||||
MessageOut("-- List of currently defined symbols --")
|
MessageOut("-- List of currently defined symbols --")
|
||||||
while s != nil:
|
while s != nil:
|
||||||
if s.position == 1: MessageOut(s.name.s)
|
if s.position == 1: MessageOut(s.name.s)
|
||||||
|
|
@ -58,10 +51,8 @@ proc ListSymbols() =
|
||||||
MessageOut("-- End of list --")
|
MessageOut("-- End of list --")
|
||||||
|
|
||||||
proc countDefinedSymbols(): int =
|
proc countDefinedSymbols(): int =
|
||||||
var
|
var it: TTabIter
|
||||||
it: TTabIter
|
var s = InitTabIter(it, gSymbols)
|
||||||
s: PSym
|
|
||||||
s = InitTabIter(it, gSymbols)
|
|
||||||
result = 0
|
result = 0
|
||||||
while s != nil:
|
while s != nil:
|
||||||
if s.position == 1: inc(result)
|
if s.position == 1: inc(result)
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ const
|
||||||
wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal,
|
wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal,
|
||||||
wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint,
|
wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint,
|
||||||
wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks,
|
wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks,
|
||||||
wInfChecks, wNanChecks}
|
wInfChecks, wNanChecks, wPragma}
|
||||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||||
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure, wDeprecated}
|
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure, wDeprecated}
|
||||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||||
|
|
@ -303,10 +303,9 @@ proc processCompile(c: PContext, n: PNode) =
|
||||||
extccomp.addFileToLink(completeCFilePath(trunc, false))
|
extccomp.addFileToLink(completeCFilePath(trunc, false))
|
||||||
|
|
||||||
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
|
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
|
||||||
var f, found: string
|
var f = expectStrLit(c, n)
|
||||||
f = expectStrLit(c, n)
|
|
||||||
if splitFile(f).ext == "": f = toObjFile(f)
|
if splitFile(f).ext == "": f = toObjFile(f)
|
||||||
found = findFile(f)
|
var found = findFile(f)
|
||||||
if found == "": found = f # use the default
|
if found == "": found = f # use the default
|
||||||
case feature
|
case feature
|
||||||
of linkNormal: extccomp.addFileToLink(found)
|
of linkNormal: extccomp.addFileToLink(found)
|
||||||
|
|
@ -326,12 +325,30 @@ proc PragmaCheckpoint(c: PContext, n: PNode) =
|
||||||
proc noVal(n: PNode) =
|
proc noVal(n: PNode) =
|
||||||
if n.kind == nkExprColonExpr: invalidPragma(n)
|
if n.kind == nkExprColonExpr: invalidPragma(n)
|
||||||
|
|
||||||
|
proc processPragma(c: PContext, n: PNode, i: int) =
|
||||||
|
var it = n.sons[i]
|
||||||
|
if it.kind != nkExprColonExpr: invalidPragma(n)
|
||||||
|
elif it.sons[0].kind != nkIdent: invalidPragma(n)
|
||||||
|
elif it.sons[1].kind != nkIdent: invalidPragma(n)
|
||||||
|
|
||||||
|
var userPragma = NewSym(skTemplate, it.sons[1].ident, nil)
|
||||||
|
userPragma.info = it.info
|
||||||
|
var body = newNodeI(nkPragma, n.info)
|
||||||
|
for j in i+1 .. sonsLen(n)-1: addSon(body, n.sons[j])
|
||||||
|
userPragma.ast = body
|
||||||
|
StrTableAdd(c.userPragmas, userPragma)
|
||||||
|
|
||||||
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
||||||
if key.kind == nkIdent:
|
if key.kind == nkIdent:
|
||||||
|
var userPragma = StrTableGet(c.userPragmas, key.ident)
|
||||||
|
if userPragma != nil:
|
||||||
|
pragma(c, sym, userPragma.ast, validPragmas)
|
||||||
|
# XXX BUG: possible infinite recursion!
|
||||||
|
else:
|
||||||
var k = whichKeyword(key.ident)
|
var k = whichKeyword(key.ident)
|
||||||
if k in validPragmas:
|
if k in validPragmas:
|
||||||
case k
|
case k
|
||||||
|
|
@ -380,8 +397,8 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||||
addToLib(lib, sym)
|
addToLib(lib, sym)
|
||||||
incl(sym.flags, sfImportc)
|
incl(sym.flags, sfImportc)
|
||||||
incl(sym.loc.flags, lfHeader)
|
incl(sym.loc.flags, lfHeader)
|
||||||
incl(sym.loc.Flags, lfNoDecl) # implies nodecl, because
|
incl(sym.loc.Flags, lfNoDecl)
|
||||||
# otherwise header would not make sense
|
# implies nodecl, because otherwise header would not make sense
|
||||||
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
|
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
|
||||||
of wNosideeffect:
|
of wNosideeffect:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
|
|
@ -445,9 +462,13 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||||
processPush(c, n, i + 1)
|
processPush(c, n, i + 1)
|
||||||
break
|
break
|
||||||
of wPop: processPop(c, it)
|
of wPop: processPop(c, it)
|
||||||
|
of wPragma:
|
||||||
|
processPragma(c, n, i)
|
||||||
|
break
|
||||||
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
||||||
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||||
wLinedir, wStacktrace, wLinetrace, wOptimization, wByRef, wCallConv,
|
wLinedir, wStacktrace, wLinetrace, wOptimization, wByRef,
|
||||||
|
wCallConv,
|
||||||
wDebugger, wProfiler, wFloatChecks, wNanChecks, wInfChecks:
|
wDebugger, wProfiler, wFloatChecks, wNanChecks, wInfChecks:
|
||||||
processOption(c, it) # calling conventions (boring...):
|
processOption(c, it) # calling conventions (boring...):
|
||||||
of firstCallConv..lastCallConv:
|
of firstCallConv..lastCallConv:
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ type
|
||||||
semExpr*: proc (c: PContext, n: PNode): PNode # for the pragmas
|
semExpr*: proc (c: PContext, n: PNode): PNode # for the pragmas
|
||||||
includedFiles*: TIntSet # used to detect recursive include files
|
includedFiles*: TIntSet # used to detect recursive include files
|
||||||
filename*: string # the module's filename
|
filename*: string # the module's filename
|
||||||
|
userPragmas*: TStrTable
|
||||||
|
|
||||||
|
|
||||||
var gInstTypes*: TIdTable # map PType to PType
|
var gInstTypes*: TIdTable # map PType to PType
|
||||||
|
|
@ -124,6 +125,7 @@ proc newContext(module: PSym, nimfile: string): PContext =
|
||||||
result.converters = @ []
|
result.converters = @ []
|
||||||
result.filename = nimfile
|
result.filename = nimfile
|
||||||
IntSetInit(result.includedFiles)
|
IntSetInit(result.includedFiles)
|
||||||
|
initStrTable(result.userPragmas)
|
||||||
|
|
||||||
proc addConverter(c: PContext, conv: PSym) =
|
proc addConverter(c: PContext, conv: PSym) =
|
||||||
var L = len(c.converters)
|
var L = len(c.converters)
|
||||||
|
|
|
||||||
|
|
@ -708,7 +708,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
s.options = gOptions
|
s.options = gOptions
|
||||||
if n.sons[codePos] != nil:
|
if n.sons[codePos] != nil:
|
||||||
if {sfImportc, sfBorrow} * s.flags != {}:
|
# for DLL generation, it is annoying to check for sfImportc!
|
||||||
|
if sfBorrow in s.flags:
|
||||||
liMessage(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s)
|
liMessage(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s)
|
||||||
if (n.sons[genericParamsPos] == nil):
|
if (n.sons[genericParamsPos] == nil):
|
||||||
c.p = newProcCon(s)
|
c.p = newProcCon(s)
|
||||||
|
|
@ -720,6 +721,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
if (s.typ.sons[0] != nil) and (kind != skIterator):
|
if (s.typ.sons[0] != nil) and (kind != skIterator):
|
||||||
addDecl(c, newSym(skUnknown, getIdent("result"), nil))
|
addDecl(c, newSym(skUnknown, getIdent("result"), nil))
|
||||||
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos])
|
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos])
|
||||||
|
if sfImportc in s.flags:
|
||||||
|
# so we just ignore the body after semantic checking for importc:
|
||||||
|
n.sons[codePos] = nil
|
||||||
else:
|
else:
|
||||||
if proto != nil: liMessage(n.info, errImplOfXexpected, proto.name.s)
|
if proto != nil: liMessage(n.info, errImplOfXexpected, proto.name.s)
|
||||||
if {sfImportc, sfBorrow} * s.flags == {}: incl(s.flags, sfForward)
|
if {sfImportc, sfBorrow} * s.flags == {}: incl(s.flags, sfForward)
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ type
|
||||||
wAssertions, wWarnings, wW,
|
wAssertions, wWarnings, wW,
|
||||||
wHints, wOptimization, wSpeed, wSize, wNone, wPath, wP, wD, wU, wDebuginfo,
|
wHints, wOptimization, wSpeed, wSize, wNone, wPath, wP, wD, wU, wDebuginfo,
|
||||||
wCompileonly, wNolinking, wForcebuild, wF, wDeadCodeElim, wSafecode,
|
wCompileonly, wNolinking, wForcebuild, wF, wDeadCodeElim, wSafecode,
|
||||||
|
wPragma,
|
||||||
wCompileTime, wGc, wRefc, wBoehm, wA, wOpt, wO, wApp, wConsole, wGui,
|
wCompileTime, wGc, wRefc, wBoehm, wA, wOpt, wO, wApp, wConsole, wGui,
|
||||||
wPassc, wT, wPassl, wL, wListcmd, wGendoc, wGenmapping, wOs, wCpu,
|
wPassc, wT, wPassl, wL, wListcmd, wGendoc, wGenmapping, wOs, wCpu,
|
||||||
wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH,
|
wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH,
|
||||||
|
|
@ -53,7 +54,7 @@ type
|
||||||
wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar,
|
wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar,
|
||||||
wAcyclic, wIndex,
|
wAcyclic, wIndex,
|
||||||
wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM, wPretty,
|
wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM, wPretty,
|
||||||
wDoc, wPas, wGenDepend, wListDef, wCheck, wParse, wScan, wBoot, wLazy,
|
wDoc, wGenDepend, wListDef, wCheck, wParse, wScan, wBoot, wLazy,
|
||||||
wRst2html, wRst2tex, wI,
|
wRst2html, wRst2tex, wI,
|
||||||
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar
|
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar
|
||||||
|
|
||||||
|
|
@ -91,6 +92,7 @@ const
|
||||||
"assertions", "warnings", "w", "hints",
|
"assertions", "warnings", "w", "hints",
|
||||||
"optimization", "speed", "size", "none", "path", "p", "d", "u", "debuginfo",
|
"optimization", "speed", "size", "none", "path", "p", "d", "u", "debuginfo",
|
||||||
"compileonly", "nolinking", "forcebuild", "f", "deadcodeelim", "safecode",
|
"compileonly", "nolinking", "forcebuild", "f", "deadcodeelim", "safecode",
|
||||||
|
"pragma",
|
||||||
"compiletime", "gc", "refc", "boehm", "a", "opt", "o", "app", "console",
|
"compiletime", "gc", "refc", "boehm", "a", "opt", "o", "app", "console",
|
||||||
"gui", "passc", "t", "passl", "l", "listcmd", "gendoc", "genmapping", "os",
|
"gui", "passc", "t", "passl", "l", "listcmd", "gendoc", "genmapping", "os",
|
||||||
"cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v",
|
"cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v",
|
||||||
|
|
@ -98,7 +100,7 @@ const
|
||||||
"skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints",
|
"skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints",
|
||||||
"nomain", "subschar", "acyclic", "index",
|
"nomain", "subschar", "acyclic", "index",
|
||||||
"compiletoc", "compiletocpp", "compiletoecmascript", "compiletollvm",
|
"compiletoc", "compiletocpp", "compiletoecmascript", "compiletollvm",
|
||||||
"pretty", "doc", "pas", "gendepend", "listdef", "check", "parse", "scan",
|
"pretty", "doc", "gendepend", "listdef", "check", "parse", "scan",
|
||||||
"boot", "lazy", "rst2html", "rst2tex", "i",
|
"boot", "lazy", "rst2html", "rst2tex", "i",
|
||||||
"write", "putenv", "prependenv", "appendenv", "threadvar"]
|
"write", "putenv", "prependenv", "appendenv", "threadvar"]
|
||||||
|
|
||||||
|
|
|
||||||
7
tests/accept/compile/tuserpragma.nim
Normal file
7
tests/accept/compile/tuserpragma.nim
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
{.pragma: rtl, cdecl, exportc.}
|
||||||
|
|
||||||
|
proc myproc(x, y: int): int {.rtl} =
|
||||||
|
nil
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -42,6 +42,7 @@ Additions
|
||||||
- Implemented implicit type arguments for generics.
|
- Implemented implicit type arguments for generics.
|
||||||
- Implemented ``{.size: sizeof(cint).}`` pragma for enum types. This is useful
|
- Implemented ``{.size: sizeof(cint).}`` pragma for enum types. This is useful
|
||||||
for interfacing with C.
|
for interfacing with C.
|
||||||
|
- Implemented ``{.pragma.}`` pragma for user defined pragmas.
|
||||||
|
|
||||||
|
|
||||||
2010-03-14 Version 0.8.8 released
|
2010-03-14 Version 0.8.8 released
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue