summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <andreas@andreas-laptop>2010-07-23 20:17:12 +0200
committerAndreas Rumpf <andreas@andreas-laptop>2010-07-23 20:17:12 +0200
commit804e2ac89d378b87e0ec8c723f607aa4271c57bb (patch)
treeead60f389a638029f7c1625b0e8961179119e702
parent5a2163d71d79943a8fcdb34bef9b0bbecb8b40c7 (diff)
downloadNim-804e2ac89d378b87e0ec8c723f607aa4271c57bb.tar.gz
implemented user-defined pragmas
-rwxr-xr-xdoc/manual.txt42
-rwxr-xr-xrod/ast.nim3
-rwxr-xr-xrod/c2nim/cparse.nim2
-rw-r--r--rod/c2nim/tests/systest2.c17
-rwxr-xr-xrod/condsyms.nim25
-rwxr-xr-xrod/pragmas.nim275
-rwxr-xr-xrod/semdata.nim2
-rwxr-xr-xrod/semstmts.nim6
-rwxr-xr-xrod/wordrecg.nim8
-rw-r--r--tests/accept/compile/tuserpragma.nim7
-rwxr-xr-xweb/news.txt1
11 files changed, 237 insertions, 151 deletions
diff --git a/doc/manual.txt b/doc/manual.txt
index 7fce8ac85..36be32538 100755
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -2651,6 +2651,30 @@ Example:
 

 .. code-block:: nimrod

   {.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

@@ -2715,8 +2739,8 @@ strings automatically:
   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

 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:

@@ -2762,3 +2786,17 @@ string expressions in general:
 

 **Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant

 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.
+
diff --git a/rod/ast.nim b/rod/ast.nim
index 15e74198c..5b5676495 100755
--- a/rod/ast.nim
+++ b/rod/ast.nim
@@ -288,7 +288,8 @@ type
     skIterator,           # an iterator
     skConverter,          # a type converter
     skMacro,              # a macro
-    skTemplate,           # a template
+    skTemplate,           # a template; currently also misused for user-defined
+                          # pragmas
     skField,              # a field in a record or object
     skEnumField,          # an identifier in an enum
     skForVar,             # a for loop variable
diff --git a/rod/c2nim/cparse.nim b/rod/c2nim/cparse.nim
index a96aece3c..5da9f3015 100755
--- a/rod/c2nim/cparse.nim
+++ b/rod/c2nim/cparse.nim
@@ -11,6 +11,8 @@
 ## It translates a C source file into a Nimrod AST. Then the renderer can be
 ## used to convert the AST to its text representation.
 
+## XXX cleanup of declaration handling. Standalone enums.
+
 import 
   os, llstream, rnimsyn, clex, idents, strutils, pegs, ast, astalgo, msgs,
   options, strtabs
diff --git a/rod/c2nim/tests/systest2.c b/rod/c2nim/tests/systest2.c
new file mode 100644
index 000000000..bf3027cfc
--- /dev/null
+++ b/rod/c2nim/tests/systest2.c
@@ -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);
+
diff --git a/rod/condsyms.nim b/rod/condsyms.nim
index 0325a2b77..72cca33ee 100755
--- a/rod/condsyms.nim
+++ b/rod/condsyms.nim
@@ -24,11 +24,8 @@ proc countDefinedSymbols*(): int
 # implementation
 
 proc DefineSymbol(symbol: string) = 
-  var 
-    sym: PSym
-    i: PIdent
-  i = getIdent(symbol)
-  sym = StrTableGet(gSymbols, i)
+  var i = getIdent(symbol)
+  var sym = StrTableGet(gSymbols, i)
   if sym == nil: 
     new(sym)                  # circumvent the ID mechanism
     sym.kind = skConditional
@@ -37,20 +34,16 @@ proc DefineSymbol(symbol: string) =
   sym.position = 1
 
 proc UndefSymbol(symbol: string) = 
-  var sym: PSym
-  sym = StrTableGet(gSymbols, getIdent(symbol))
+  var sym = StrTableGet(gSymbols, getIdent(symbol))
   if sym != nil: sym.position = 0
   
 proc isDefined(symbol: PIdent): bool = 
-  var sym: PSym
-  sym = StrTableGet(gSymbols, symbol)
+  var sym = StrTableGet(gSymbols, symbol)
   result = (sym != nil) and (sym.position == 1)
 
 proc ListSymbols() = 
-  var 
-    it: TTabIter
-    s: PSym
-  s = InitTabIter(it, gSymbols)
+  var it: TTabIter
+  var s = InitTabIter(it, gSymbols)
   MessageOut("-- List of currently defined symbols --")
   while s != nil: 
     if s.position == 1: MessageOut(s.name.s)
@@ -58,10 +51,8 @@ proc ListSymbols() =
   MessageOut("-- End of list --")
 
 proc countDefinedSymbols(): int = 
-  var 
-    it: TTabIter
-    s: PSym
-  s = InitTabIter(it, gSymbols)
+  var it: TTabIter
+  var s = InitTabIter(it, gSymbols)
   result = 0
   while s != nil: 
     if s.position == 1: inc(result)
diff --git a/rod/pragmas.nim b/rod/pragmas.nim
index c52e4a10b..24c5be923 100755
--- a/rod/pragmas.nim
+++ b/rod/pragmas.nim
@@ -33,7 +33,7 @@ const
     wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal, 
     wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint, 
     wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks,
-    wInfChecks, wNanChecks}
+    wInfChecks, wNanChecks, wPragma}
   lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, 
     wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure, wDeprecated}
   typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, 
@@ -303,10 +303,9 @@ proc processCompile(c: PContext, n: PNode) =
   extccomp.addFileToLink(completeCFilePath(trunc, false))
 
 proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = 
-  var f, found: string
-  f = expectStrLit(c, n)
+  var f = expectStrLit(c, n)
   if splitFile(f).ext == "": f = toObjFile(f)
-  found = findFile(f)
+  var found = findFile(f)
   if found == "": found = f # use the default
   case feature
   of linkNormal: extccomp.addFileToLink(found)
@@ -325,137 +324,159 @@ proc PragmaCheckpoint(c: PContext, n: PNode) =
 
 proc noVal(n: PNode) = 
   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) = 
   if n == nil: return 
   for i in countup(0, sonsLen(n) - 1): 
     var it = n.sons[i]
     var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
     if key.kind == nkIdent: 
-      var k = whichKeyword(key.ident)
-      if k in validPragmas: 
-        case k
-        of wExportc: 
-          makeExternExport(sym, getOptionalStr(c, it, sym.name.s))
-          incl(sym.flags, sfUsed) # avoid wrong hints
-        of wImportc: makeExternImport(sym, getOptionalStr(c, it, sym.name.s))
-        of wAlign: 
-          if sym.typ == nil: invalidPragma(it)
-          sym.typ.align = expectIntLit(c, it)
-          if not IsPowerOfTwo(sym.typ.align) and (sym.typ.align != 0): 
-            liMessage(it.info, errPowerOfTwoExpected)
-        of wSize: 
-          if sym.typ == nil: invalidPragma(it)
-          var size = expectIntLit(c, it)
-          if not IsPowerOfTwo(size) or size <= 0 or size > 8: 
-            liMessage(it.info, errPowerOfTwoExpected)
-          else:
-            sym.typ.size = size
-        of wNodecl: 
-          noVal(it)
-          incl(sym.loc.Flags, lfNoDecl)
-        of wPure: 
-          noVal(it)
-          if sym != nil: incl(sym.flags, sfPure)
-        of wVolatile: 
-          noVal(it)
-          incl(sym.flags, sfVolatile)
-        of wRegister: 
-          noVal(it)
-          incl(sym.flags, sfRegister)
-        of wThreadVar: 
-          noVal(it)
-          incl(sym.flags, sfThreadVar)
-        of wDeadCodeElim: pragmaDeadCodeElim(c, it)
-        of wMagic: processMagic(c, it, sym)
-        of wCompileTime: 
-          noVal(it)
-          incl(sym.flags, sfCompileTime)
-          incl(sym.loc.Flags, lfNoDecl)
-        of wMerge: 
-          noval(it)
-          incl(sym.flags, sfMerge)
-        of wHeader: 
-          var lib = getLib(c, libHeader, getStrLitNode(c, it))
-          addToLib(lib, sym)
-          incl(sym.flags, sfImportc)
-          incl(sym.loc.flags, lfHeader)
-          incl(sym.loc.Flags, lfNoDecl) # implies nodecl, because
-                                        # otherwise header would not make sense
-          if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
-        of wNosideeffect: 
-          noVal(it)
-          incl(sym.flags, sfNoSideEffect)
-          if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
-        of wSideEffect: 
-          noVal(it)
-          incl(sym.flags, sfSideEffect)
-        of wNoReturn: 
-          noVal(it)
-          incl(sym.flags, sfNoReturn)
-        of wDynLib: 
-          processDynLib(c, it, sym)
-        of wCompilerProc: 
-          noVal(it)           # compilerproc may not get a string!
-          makeExternExport(sym, sym.name.s)
-          incl(sym.flags, sfCompilerProc)
-          incl(sym.flags, sfUsed) # suppress all those stupid warnings
-          registerCompilerProc(sym)
-        of wProcvar: 
-          noVal(it)
-          incl(sym.flags, sfProcVar)
-        of wDeprecated: 
-          noVal(it)
-          if sym != nil: incl(sym.flags, sfDeprecated)
-          else: incl(c.module.flags, sfDeprecated)
-        of wVarargs: 
-          noVal(it)
-          if sym.typ == nil: invalidPragma(it)
-          incl(sym.typ.flags, tfVarargs)
-        of wBorrow: 
-          noVal(it)
-          incl(sym.flags, sfBorrow)
-        of wFinal: 
-          noVal(it)
-          if sym.typ == nil: invalidPragma(it)
-          incl(sym.typ.flags, tfFinal)
-        of wAcyclic: 
-          noVal(it)
-          if sym.typ == nil: invalidPragma(it)
-          incl(sym.typ.flags, tfAcyclic)
-        of wTypeCheck: 
-          noVal(it)
-          incl(sym.flags, sfTypeCheck)
-        of wHint: liMessage(it.info, hintUser, expectStrLit(c, it))
-        of wWarning: liMessage(it.info, warnUser, expectStrLit(c, it))
-        of wError: liMessage(it.info, errUser, expectStrLit(c, it))
-        of wFatal: 
-          liMessage(it.info, errUser, expectStrLit(c, it))
-          quit(1)
-        of wDefine: processDefine(c, it)
-        of wUndef: processUndef(c, it)
-        of wCompile: processCompile(c, it)
-        of wLink: processCommonLink(c, it, linkNormal)
-        of wLinkSys: processCommonLink(c, it, linkSys)
-        of wPassL: extccomp.addLinkOption(expectStrLit(c, it))
-        of wPassC: extccomp.addCompileOption(expectStrLit(c, it))
-        of wBreakpoint: PragmaBreakpoint(c, it)
-        of wCheckpoint: PragmaCheckpoint(c, it)
-        of wPush: 
-          processPush(c, n, i + 1)
-          break 
-        of wPop: processPop(c, it)
-        of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, 
-           wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, 
-           wLinedir, wStacktrace, wLinetrace, wOptimization, wByRef, wCallConv, 
-           wDebugger, wProfiler, wFloatChecks, wNanChecks, wInfChecks: 
-          processOption(c, it) # calling conventions (boring...):
-        of firstCallConv..lastCallConv: 
-          assert(sym != nil)
-          if sym.typ == nil: invalidPragma(it)
-          sym.typ.callConv = wordToCallConv(k)
+      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)
+        if k in validPragmas: 
+          case k
+          of wExportc: 
+            makeExternExport(sym, getOptionalStr(c, it, sym.name.s))
+            incl(sym.flags, sfUsed) # avoid wrong hints
+          of wImportc: makeExternImport(sym, getOptionalStr(c, it, sym.name.s))
+          of wAlign: 
+            if sym.typ == nil: invalidPragma(it)
+            sym.typ.align = expectIntLit(c, it)
+            if not IsPowerOfTwo(sym.typ.align) and (sym.typ.align != 0): 
+              liMessage(it.info, errPowerOfTwoExpected)
+          of wSize: 
+            if sym.typ == nil: invalidPragma(it)
+            var size = expectIntLit(c, it)
+            if not IsPowerOfTwo(size) or size <= 0 or size > 8: 
+              liMessage(it.info, errPowerOfTwoExpected)
+            else:
+              sym.typ.size = size
+          of wNodecl: 
+            noVal(it)
+            incl(sym.loc.Flags, lfNoDecl)
+          of wPure: 
+            noVal(it)
+            if sym != nil: incl(sym.flags, sfPure)
+          of wVolatile: 
+            noVal(it)
+            incl(sym.flags, sfVolatile)
+          of wRegister: 
+            noVal(it)
+            incl(sym.flags, sfRegister)
+          of wThreadVar: 
+            noVal(it)
+            incl(sym.flags, sfThreadVar)
+          of wDeadCodeElim: pragmaDeadCodeElim(c, it)
+          of wMagic: processMagic(c, it, sym)
+          of wCompileTime: 
+            noVal(it)
+            incl(sym.flags, sfCompileTime)
+            incl(sym.loc.Flags, lfNoDecl)
+          of wMerge: 
+            noval(it)
+            incl(sym.flags, sfMerge)
+          of wHeader: 
+            var lib = getLib(c, libHeader, getStrLitNode(c, it))
+            addToLib(lib, sym)
+            incl(sym.flags, sfImportc)
+            incl(sym.loc.flags, lfHeader)
+            incl(sym.loc.Flags, lfNoDecl) 
+            # implies nodecl, because otherwise header would not make sense
+            if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
+          of wNosideeffect: 
+            noVal(it)
+            incl(sym.flags, sfNoSideEffect)
+            if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
+          of wSideEffect: 
+            noVal(it)
+            incl(sym.flags, sfSideEffect)
+          of wNoReturn: 
+            noVal(it)
+            incl(sym.flags, sfNoReturn)
+          of wDynLib: 
+            processDynLib(c, it, sym)
+          of wCompilerProc: 
+            noVal(it)           # compilerproc may not get a string!
+            makeExternExport(sym, sym.name.s)
+            incl(sym.flags, sfCompilerProc)
+            incl(sym.flags, sfUsed) # suppress all those stupid warnings
+            registerCompilerProc(sym)
+          of wProcvar: 
+            noVal(it)
+            incl(sym.flags, sfProcVar)
+          of wDeprecated: 
+            noVal(it)
+            if sym != nil: incl(sym.flags, sfDeprecated)
+            else: incl(c.module.flags, sfDeprecated)
+          of wVarargs: 
+            noVal(it)
+            if sym.typ == nil: invalidPragma(it)
+            incl(sym.typ.flags, tfVarargs)
+          of wBorrow: 
+            noVal(it)
+            incl(sym.flags, sfBorrow)
+          of wFinal: 
+            noVal(it)
+            if sym.typ == nil: invalidPragma(it)
+            incl(sym.typ.flags, tfFinal)
+          of wAcyclic: 
+            noVal(it)
+            if sym.typ == nil: invalidPragma(it)
+            incl(sym.typ.flags, tfAcyclic)
+          of wTypeCheck: 
+            noVal(it)
+            incl(sym.flags, sfTypeCheck)
+          of wHint: liMessage(it.info, hintUser, expectStrLit(c, it))
+          of wWarning: liMessage(it.info, warnUser, expectStrLit(c, it))
+          of wError: liMessage(it.info, errUser, expectStrLit(c, it))
+          of wFatal: 
+            liMessage(it.info, errUser, expectStrLit(c, it))
+            quit(1)
+          of wDefine: processDefine(c, it)
+          of wUndef: processUndef(c, it)
+          of wCompile: processCompile(c, it)
+          of wLink: processCommonLink(c, it, linkNormal)
+          of wLinkSys: processCommonLink(c, it, linkSys)
+          of wPassL: extccomp.addLinkOption(expectStrLit(c, it))
+          of wPassC: extccomp.addCompileOption(expectStrLit(c, it))
+          of wBreakpoint: PragmaBreakpoint(c, it)
+          of wCheckpoint: PragmaCheckpoint(c, it)
+          of wPush: 
+            processPush(c, n, i + 1)
+            break 
+          of wPop: processPop(c, it)
+          of wPragma: 
+            processPragma(c, n, i)
+            break
+          of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, 
+             wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, 
+             wLinedir, wStacktrace, wLinetrace, wOptimization, wByRef,
+             wCallConv, 
+             wDebugger, wProfiler, wFloatChecks, wNanChecks, wInfChecks: 
+            processOption(c, it) # calling conventions (boring...):
+          of firstCallConv..lastCallConv: 
+            assert(sym != nil)
+            if sym.typ == nil: invalidPragma(it)
+            sym.typ.callConv = wordToCallConv(k)
+          else: invalidPragma(it)
         else: invalidPragma(it)
-      else: invalidPragma(it)
     else: processNote(c, it)
   if (sym != nil) and (sym.kind != skModule): 
     if (lfExportLib in sym.loc.flags) and not (sfExportc in sym.flags): 
diff --git a/rod/semdata.nim b/rod/semdata.nim
index 5020f103d..ebad21ad8 100755
--- a/rod/semdata.nim
+++ b/rod/semdata.nim
@@ -51,6 +51,7 @@ type
     semExpr*: proc (c: PContext, n: PNode): PNode      # for the pragmas
     includedFiles*: TIntSet   # used to detect recursive include files
     filename*: string         # the module's filename
+    userPragmas*: TStrTable
   
 
 var gInstTypes*: TIdTable # map PType to PType
@@ -124,6 +125,7 @@ proc newContext(module: PSym, nimfile: string): PContext =
   result.converters = @ []
   result.filename = nimfile
   IntSetInit(result.includedFiles)
+  initStrTable(result.userPragmas)
 
 proc addConverter(c: PContext, conv: PSym) = 
   var L = len(c.converters)
diff --git a/rod/semstmts.nim b/rod/semstmts.nim
index 0f96e5b94..fdf931815 100755
--- a/rod/semstmts.nim
+++ b/rod/semstmts.nim
@@ -708,7 +708,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     pushOwner(s)
   s.options = gOptions
   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)
     if (n.sons[genericParamsPos] == nil): 
       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): 
         addDecl(c, newSym(skUnknown, getIdent("result"), nil))
       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: 
     if proto != nil: liMessage(n.info, errImplOfXexpected, proto.name.s)
     if {sfImportc, sfBorrow} * s.flags == {}: incl(s.flags, sfForward)
diff --git a/rod/wordrecg.nim b/rod/wordrecg.nim
index daadd57d0..ac7265f7d 100755
--- a/rod/wordrecg.nim
+++ b/rod/wordrecg.nim
@@ -42,10 +42,11 @@ type
     wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline, 
     wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangechecks, 
     wBoundchecks, wOverflowchecks, wNilchecks,
-    wFloatchecks, wNanChecks, wInfChecks,    
+    wFloatchecks, wNanChecks, wInfChecks,
     wAssertions, wWarnings, wW, 
     wHints, wOptimization, wSpeed, wSize, wNone, wPath, wP, wD, wU, wDebuginfo, 
     wCompileonly, wNolinking, wForcebuild, wF, wDeadCodeElim, wSafecode, 
+    wPragma,
     wCompileTime, wGc, wRefc, wBoehm, wA, wOpt, wO, wApp, wConsole, wGui, 
     wPassc, wT, wPassl, wL, wListcmd, wGendoc, wGenmapping, wOs, wCpu, 
     wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH, 
@@ -53,7 +54,7 @@ type
     wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar, 
     wAcyclic, wIndex, 
     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,
     wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar
     
@@ -91,6 +92,7 @@ const
     "assertions", "warnings", "w", "hints", 
     "optimization", "speed", "size", "none", "path", "p", "d", "u", "debuginfo", 
     "compileonly", "nolinking", "forcebuild", "f", "deadcodeelim", "safecode", 
+    "pragma",
     "compiletime", "gc", "refc", "boehm", "a", "opt", "o", "app", "console", 
     "gui", "passc", "t", "passl", "l", "listcmd", "gendoc", "genmapping", "os", 
     "cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v", 
@@ -98,7 +100,7 @@ const
     "skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints", 
     "nomain", "subschar", "acyclic", "index", 
     "compiletoc", "compiletocpp", "compiletoecmascript", "compiletollvm", 
-    "pretty", "doc", "pas", "gendepend", "listdef", "check", "parse", "scan", 
+    "pretty", "doc", "gendepend", "listdef", "check", "parse", "scan", 
     "boot", "lazy", "rst2html", "rst2tex", "i", 
     "write", "putenv", "prependenv", "appendenv", "threadvar"]
 
diff --git a/tests/accept/compile/tuserpragma.nim b/tests/accept/compile/tuserpragma.nim
new file mode 100644
index 000000000..784baa176
--- /dev/null
+++ b/tests/accept/compile/tuserpragma.nim
@@ -0,0 +1,7 @@
+
+{.pragma: rtl, cdecl, exportc.}
+
+proc myproc(x, y: int): int {.rtl} =
+  nil
+
+
diff --git a/web/news.txt b/web/news.txt
index dcb8cb144..dd7e330c0 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -42,6 +42,7 @@ Additions
 - Implemented implicit type arguments for generics.
 - Implemented ``{.size: sizeof(cint).}`` pragma for enum types. This is useful
   for interfacing with C.
+- Implemented ``{.pragma.}`` pragma for user defined pragmas.
 
 
 2010-03-14 Version 0.8.8 released