summary refs log tree commit diff stats
path: root/compiler/pluginsupport.nim
blob: 19a0bc84d2ea6659d2a85e0b3b7e3ec92f52ec6c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#
#
#           The Nim Compiler
#        (c) Copyright 2015 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## Plugin support for the Nim compiler. Right now they
## need to be build with the compiler, no DLL support.

import ast, semdata, idents

type
  Transformation* = proc (c: PContext; n: PNode): PNode {.nimcall.}
  Plugin = ref object
    fn, module, package: PIdent
    t: Transformation
    next: Plugin

proc pluginMatches(p: Plugin; s: PSym): bool =
  if s.name.id != p.fn.id:
    return false
  let module = s.skipGenericOwner
  if module == nil or module.kind != skModule or
      module.name.id != p.module.id:
    return false
  let package = module.owner
  if package == nil or package.kind != skPackage or
      package.name.id != p.package.id:
    return false
  return true

var head: Plugin

proc getPlugin*(fn: PSym): Transformation =
  var it = head
  while it != nil:
    if pluginMatches(it, fn): return it.t
    it = it.next

proc registerPlugin*(package, module, fn: string; t: Transformation) =
  let oldHead = head
  head = Plugin(fn: getIdent(fn), module: getIdent(module),
                 package: getIdent(package), t: t, next: oldHead)
luaL_newlib(L,l)) #endif #ifndef STREQ # define STREQ(a, b) (strcmp (a, b) == 0) #endif /* Mark unused parameters required only to match a function type specification. */ #ifdef __GNUC__ # define LCURSES_UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) #else # define LCURSES_UNUSED(x) UNUSED_ ## x #endif /* LCURSES_STMT_BEG/END are used to create macros that expand to a single compound statement in a portable way. */ #if defined __GNUC__ && !defined __STRICT_ANSI__ && !defined __cplusplus # define LCURSES_STMT_BEG (void)( # define LCURSES_STMT_END ) #else # if (defined sun || defined __sun__) # define LCURSES_STMT_BEG if (1) # define LCURSES_STMT_END else (void)0 # else # define LCURSES_STMT_BEG do # define LCURSES_STMT_END while (0) # endif #endif /* The extra indirection to these macros is required so that if the arguments are themselves macros, they will get expanded too. */ #define LCURSES__SPLICE(_s, _t) _s##_t #define LCURSES_SPLICE(_s, _t) LCURSES__SPLICE(_s, _t) #define LCURSES__STR(_s) #_s #define LCURSES_STR(_s) LCURSES__STR(_s) /* The +1 is to step over the leading '_' that is required to prevent premature expansion of MENTRY arguments if we didn't add it. */ #define LCURSES__STR_1(_s) (#_s + 1) #define LCURSES_STR_1(_s) LCURSES__STR_1(_s) #define LCURSES_CONST(_f) LCURSES_STMT_BEG { \ lua_pushinteger(L, _f); \ lua_setfield(L, -2, #_f); \ } LCURSES_STMT_END #define LCURSES_FUNC(_s) {LCURSES_STR_1(_s), (_s)} #define pushokresult(b) pushboolresult((int) (b) == OK) #ifndef errno extern int errno; #endif /* ========================= * * Bad argument diagnostics. * * ========================= */ static int argtypeerror(lua_State *L, int narg, const char *expected) { const char *got = luaL_typename(L, narg); return luaL_argerror(L, narg, lua_pushfstring(L, "%s expected, got %s", expected, got)); } static lua_Integer checkinteger(lua_State *L, int narg, const char *expected) { lua_Integer d = lua_tointeger(L, narg); if (d == 0 && !lua_isinteger(L, narg)) argtypeerror(L, narg, expected); return d; } static int checkint(lua_State *L, int narg) { return (int)checkinteger(L, narg, "int"); } static chtype checkch(lua_State *L, int narg) { if (lua_isnumber(L, narg)) return (chtype)checkint(L, narg); if (lua_isstring(L, narg)) return *lua_tostring(L, narg); return argtypeerror(L, narg, "int or char"); } static chtype optch(lua_State *L, int narg, chtype def) { if (lua_isnoneornil(L, narg)) return def; if (lua_isnumber(L, narg) || lua_isstring(L, narg)) return checkch(L, narg); return argtypeerror(L, narg, "int or char or nil"); } static int optint(lua_State *L, int narg, lua_Integer def) { if (lua_isnoneornil(L, narg)) return (int) def; return (int)checkinteger(L, narg, "int or nil"); } #define pushboolresult(b) (lua_pushboolean(L, (b)), 1) #define pushintresult(n) (lua_pushinteger(L, (n)), 1) #define pushstringresult(s) (lua_pushstring(L, (s)), 1) /* ================== * * Utility functions. * * ================== */ #define pushintegerfield(k,v) LCURSES_STMT_BEG { \ lua_pushinteger(L, (lua_Integer) v); lua_setfield(L, -2, k); \ } LCURSES_STMT_END #define pushnumberfield(k,v) LCURSES_STMT_BEG { \ lua_pushnumber(L, (lua_Number) v); lua_setfield(L, -2, k); \ } LCURSES_STMT_END #define pushstringfield(k,v) LCURSES_STMT_BEG { \ if (v) { \ lua_pushstring(L, (const char *) v); \ lua_setfield(L, -2, k); \ } \ } LCURSES_STMT_END #define pushliteralfield(k,v) LCURSES_STMT_BEG { \ if (v) { \ lua_pushliteral(L, v); \ lua_setfield(L, -2, k); \ } \ } LCURSES_STMT_END #define settypemetatable(t) LCURSES_STMT_BEG { \ if (luaL_newmetatable(L, t) == 1) \ pushliteralfield("_type", t); \ lua_setmetatable(L, -2); \ } LCURSES_STMT_END #define setintegerfield(_p, _n) pushintegerfield(LCURSES_STR(_n), _p->_n) #define setnumberfield(_p, _n) pushnumberfield(LCURSES_STR(_n), _p->_n) #define setstringfield(_p, _n) pushstringfield(LCURSES_STR(_n), _p->_n) #endif /*LCURSES__HELPERS_C*/