]> git.lizzy.rs Git - metalua.git/blobdiff - src/samples/metalint/metalint.mlua
Merge branch 'master' of ssh://git.eclipse.org/gitroot/koneki/org.eclipse.koneki...
[metalua.git] / src / samples / metalint / metalint.mlua
diff --git a/src/samples/metalint/metalint.mlua b/src/samples/metalint/metalint.mlua
deleted file mode 100644 (file)
index e70f1f9..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
--{ extension 'match' }
--{ extension 'log' }
-
-require 'strict'
-require 'metalua.compiler'
-
-local VERBOSE          = false
-local PARSING_OWN_DECL = false
-local MY_GLOBALS       = { }
-local LOAD_SOURCE      = nil
-local DECLARATIONS     = { }
-local AUTOLOCALS       = { }
-
-
-local function debug_print(...)
-   if VERBOSE then return printf(...) end
-end
-
--- Lexer --
-decl_lexer = lexer.lexer:clone()
-decl_lexer:add{ 'module', 'free', 'end', 'private' }
-
--- Parser --
-
--- Merge two decl together
-local function merge (x, y)
-   --$log('merge', x, y)
-   for k, v in pairs (y) do
-      match x[k], v with
-      | `Free, _ | `Atom{x}, `Atom{x} -> -- pass
-      | _, `Free | nil, _ -> x[k] = v
-      | `Module{ _, mod_x }, `Module{ _, mod_y } -> merge (mod_x, mod_y)
-      | _, _ ->
-        $log("Merge failure", x[k], v)
-        error ("Can't merge type elements")
-      end
-   end
-end
-
--- break mutual dependency between decl_elem_parser and decl_parser
-local _decl_elem_parser = |...| decl_elem_parser(...)
-
--- Parse a name, presented as an `Id or a `String
-local function name(lx)
-   local a = lx:next()
-   if a.tag=='String' or a.tag=='Id' then return a[1]
-   else error("Name expected, got "..table.tostring(a,'nohash')) end
-end
-
-function decl_builder(x)
-   --$log('decl_builder', x)
-   local r = { }
-   for y in ivalues(x) do
-      if y.tag ~= 'Private' then merge (r, {[y[1]]=y}) end
-   end
-   return r
-end
-
-decl_parser = gg.list{
-   gg.sequence{ _decl_elem_parser, gg.optkeyword ';', builder = |x|x[1] },
-   terminators = 'end', builder = decl_builder }
-
-decl_elem_parser = gg.multisequence{
-   { 'module', name, decl_parser, 'end', builder = |x| `Module{x[1], x[2]} },
-   { 'free', name, builder = |x| `Free{x[1]} },
-   { 'private', _decl_elem_parser, builder = |x| PARSING_OWN_DECL and x[1] or `Private },
-   default = gg.sequence{ name, builder = |x| `Atom{x[1]} } }
-
-decl_elem_parser.transformers:add (function(x) x.loader = LOAD_SOURCE end)
-
-function parse_decl_lib (libname)
-   debug_print ("Loading decl lib "..libname)
-   local fd, msg = package.findfile (libname, os.getenv 'LUA_DPATH' or "?.dlua")
-   if not fd then error ("Can't find declaration file for "..libname) end
-   local src = fd:read '*a'
-   fd:close()
-   return parse_decl_expr (src)
-end
-
-function parse_decl_expr (src)
-   local lx = decl_lexer:newstream (src)
-   local r  = decl_parser (lx)
-   --$log('result of parse_decl', r)
-   merge(DECLARATIONS, r)
-   return r
-end
-
-function parse_decl_file (filename)
-   debug_print ("Loading decl file "..filename)
-   local src = mlc.luastring_of_luafile (filename)
-   return parse_decl_expr (src)
-end
-
--- AST checker --
-require 'walk.id'
-
-local function index_autolocal (e, loader)
-   --$log('index_autolocals', loader)
-   local is_mine = false
-   local function get_name(x)
-      match x with
-      | `Index{ y, `String{key} } -> return get_name(y)..'~'..key
-      | `Invoke{ y, `String{key}, _ } -> 
-         error('autolocals for invocation not implemented '..table.tostring(x))
-      | `Id{ name } -> is_mine = MY_GLOBALS[name]; return '~'..name
-      | _ -> error(table.tostring(x)..'\n')
-      end
-   end
-   local name = get_name(e)
-   if is_mine then return end -- Don't index my own global vars
-   local x = AUTOLOCALS[name]
-   if not x then x={ }; AUTOLOCALS[name] = x end
-   table.insert(x, { e, loader })
-end
-
-local walk_cfg = { id = { }, stat = { }, expr = { } }
-
-function walk_cfg.id.free(x, ...)
-   --$log('in free id walker', x)
-   local parents = {...}
-   local dic = DECLARATIONS
-   local name = x[1]
-   for p in ivalues (parents) do
-      local decl = dic[name]
-      if not decl then error("Not declared: "..name) end
-      match p with
-      | `Index{ _x, `String{n} } | `Invoke{ _x, `String{n}, ...} if _x==x ->
-         match decl with
-         | `Free{...} -> break
-         | `Atom{...} -> error (name.." is not a module")
-         | `Module{ _, dic2 } -> dic, name, x = dic2, n, p
-         end
-      | _ -> -- x == last checked variable
-         debug_print("Checked "..table.tostring(x, 'nohash')..
-                  ", found in "..table.tostring(decl.loader, 'nohash'))
-         index_autolocal (x, decl.loader)
-         break
-      end
-   end
-end
-
-local function try_load_decl (kind, mod_name)
-   local success, r = pcall(_G['parse_decl_'..kind], mod_name) 
-   if not success then 
-      debug_print("Warning, error when trying to load %s:\n%s", mod_name, r)
-   else
-      return r
-   end   
-end
-
-local function call_walker(x)
-   --$log('in call walker', x)
-   match x with
-   | `Call{ `Id 'require', `String{ mod_name } } ->
-      if not DECLARATIONS[mod_name] then 
-         LOAD_SOURCE = `Require{x}
-         try_load_decl('lib', mod_name) 
-      end
-   | `Module{ `Id 'module', _ } -> -- no package.seeall
-      DECLARATIONS = { }           -- reset declarations
-   | _ -> -- pass
-   end
-end
-   
-walk_cfg.expr.down = call_walker
-walk_cfg.stat.down = call_walker
-
-local CHECKED_AST, CHECKED_NAME
-
-function check_src_file(name)
-   debug_print ("Checking file "..name)
-   CHECKED_NAME = name
-   CHECKED_AST  = mlc.ast_of_luafile (name)
-   --$log(ast,'nohash')
-   PARSING_OWN_DECL = true
-   local x = try_load_decl('lib', name:gsub("%.m?lua$", ""))
-   for name in keys(x) do MY_GLOBALS[name] = true end
-   PARSING_OWN_DECL = false
-   walk_id.block (walk_cfg, CHECKED_AST)
-   printf("File %s checked successfully", name)
-end
-
-local function replace_autolocals ()
-   local top_defs, req_defs = { }, { }
-   for k, v in pairs (AUTOLOCALS) do
-      local original = table.shallow_copy(v[1][1])
-      local loader   = v[1][2]
-      match loader with
-      | `Require{ r } ->
-         local defs =  req_defs[r] 
-         if not defs then defs={ }; req_defs[r]=defs end
-         defs[k] = original
-      | `Base | `Directive ->
-         top_defs[k] = original
-      end
-      for exlo in ivalues (v) do 
-         local expr, this_loader = unpack(exlo)
-         assert (this_loader[1]==loader[1] and this_loader.tag==loader.tag,
-                 "Autolocal lost by homonymous declarations")
-         expr <- `Id{k}
-      end
-   end
-
-   -- Insert beginning-of-file local declarations
-   local top_locals = `Local{ { }, { } }
-   for k, v in pairs(top_defs) do
-      table.insert(top_locals[1], `Id{k})
-      table.insert(top_locals[2], v)
-   end
-   table.insert (CHECKED_AST, 1, top_locals)
-   
-   -- Insert declarations after require() statements
-   for req_stat, renamings in pairs (req_defs) do
-      local req_locals = `Local{ { }, { } }
-      local r2 = table.shallow_copy(req_stat)
-      req_stat <- { r2, req_locals }; req_stat.tag = nil
-      for k, v in pairs (renamings) do
-         table.insert(req_locals[1], `Id{k})
-         table.insert(req_locals[2], v)
-      end
-   end
-
-   if clopts_cfg.debug then table.print(CHECKED_AST, 'nohash', 60) end
-   local chunk = mlc.luacstring_of_ast (CHECKED_AST)
-   local f = io.open (CHECKED_NAME:gsub('%.m?lua', '')..'.luac', 'w')
-   f:write(chunk)
-   f:close()
-end
-
--- RAM dumper --
-
-function decl_dump(name, f)
-   match type(f) with
-   | 'nil'      -> f=io.stdout
-   | 'string'   -> f=io.open(f, 'w') or error ("Can't open file "..f)
-   | 'userdata' -> -- pass
-   | t          -> error ("Invalid target file type "..t)
-   end
-   local indentation, acc, seen = 0, { }, { }
-   local function esc(n)
-      if n:gmatch "[%a_][%w_]*" and not decl_lexer.alpha[n] then return n else return '"'..n..'"' end
-   end
-   local function add_line(...) table.insert(acc, table.concat{'  ':rep(indentation), ...}) end
-   local function rec(n, v)
-      if seen[v] then add_line ('free ', esc(n), ";")
-      elseif type(v)=='table' then
-         seen[v] = true
-         add_line ('module ', esc(n))
-         indentation += 1
-         for n2, v2 in pairs(v) do
-            if type(n2)=='string' then rec (n2, v2) end
-         end
-         indentation -= 1
-         add_line 'end;'
-      else
-         add_line (esc(n), ';')
-      end
-   end
-   rec(name, _G[name])
-   for line in ivalues (acc) do
-      f:write(line, '\n')
-   end
-   if f~=io.stdout then f:close() end
-end
-
-
--- options handling --
-require 'clopts'
-
-local cl_parser = clopts {
-   check_src_file,
-
-   {  short = 'd', long = 'debug', type = 'boolean', 
-      usage = 'print debug traces', action = function(x) VERBOSE=x end },
-
-   {  short = 'l', long = 'decl_lib', type = 'string*', usage = 'load decl lib', 
-      action = function (x) LOAD_SOURCE=`Directive; return parse_decl_lib(x) end },
-
-   {  short = 'f', long = 'decl_file', type = 'string*', usage = 'load decl file',
-      action = function (x) LOAD_SOURCE=`Directive; return parse_decl_file(x) end },
-
-   {  short = 'x', long = 'decl_expr', type = 'string*',
-      usage = 'decl expression to eval',
-      action = function (x) LOAD_SOURCE=`Directive; return parse_decl_expr(x) end },
-
-   {  short = 'a', long = 'autolocals', type = 'boolean', 
-      usage = 'compiles the program with autolocals' } }
-
-LOAD_SOURCE = `Base
-try_load_decl('lib', 'base')
-clopts_cfg = cl_parser (...)
-if clopts_cfg.autolocals then
-   replace_autolocals()
-end
\ No newline at end of file