]> git.lizzy.rs Git - metalua.git/blobdiff - metalua/compiler/parser/misc.lua
Merge branch 'master' of ssh://git.eclipse.org/gitroot/koneki/org.eclipse.koneki...
[metalua.git] / metalua / compiler / parser / misc.lua
diff --git a/metalua/compiler/parser/misc.lua b/metalua/compiler/parser/misc.lua
new file mode 100644 (file)
index 0000000..a24b006
--- /dev/null
@@ -0,0 +1,175 @@
+-------------------------------------------------------------------------------
+-- Copyright (c) 2006-2013 Fabien Fleutot and others.
+--
+-- All rights reserved.
+--
+-- This program and the accompanying materials are made available
+-- under the terms of the Eclipse Public License v1.0 which
+-- accompanies this distribution, and is available at
+-- http://www.eclipse.org/legal/epl-v10.html
+--
+-- This program and the accompanying materials are also made available
+-- under the terms of the MIT public license which accompanies this
+-- distribution, and is available at http://www.lua.org/license.html
+--
+-- Contributors:
+--     Fabien Fleutot - API and implementation
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--
+-- Summary: metalua parser, miscellaneous utility functions.
+--
+-------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+--
+-- Exported API:
+-- * [mlp.fget()]
+-- * [mlp.id()]
+-- * [mlp.opt_id()]
+-- * [mlp.id_list()]
+-- * [mlp.string()]
+-- * [mlp.opt_string()]
+-- * [mlp.id2string()]
+--
+--------------------------------------------------------------------------------
+
+local gg       = require 'metalua.grammar.generator'
+
+-- TODO: replace splice-aware versions with naive ones, move etensions in ./meta
+
+return function(M)
+    local _M = gg.future(M)
+
+--[[ metaprog-free versions:
+    function M.id(lx)
+        if lx:peek().tag~='Id' then gg.parse_error(lx, "Identifier expected")
+        else return lx:next() end
+    end
+
+    function M.opt_id(lx)
+        if lx:peek().tag~='Id' then return lx:next() else return false end
+    end
+
+    function M.string(lx)
+        if lx:peek().tag~='String' then gg.parse_error(lx, "String expected")
+        else return lx:next() end
+    end
+
+    function M.opt_string(lx)
+        if lx:peek().tag~='String' then return lx:next() else return false end
+    end
+
+    --------------------------------------------------------------------------------
+    -- Converts an identifier into a string. Hopefully one day it'll handle
+    -- splices gracefully, but that proves quite tricky.
+    --------------------------------------------------------------------------------
+    function M.id2string (id)
+        if id.tag == "Id" then id.tag = "String"; return id
+        else error ("Identifier expected: "..table.tostring(id, 'nohash')) end
+    end
+--]]
+
+    --------------------------------------------------------------------------------
+    -- Try to read an identifier (possibly as a splice), or return [false] if no
+    -- id is found.
+    --------------------------------------------------------------------------------
+    function M.opt_id (lx)
+        local a = lx:peek();
+        if lx:is_keyword (a, "-{") then
+            local v = M.meta.splice(lx)
+            if v.tag ~= "Id" and v.tag ~= "Splice" then
+                gg.parse_error(lx, "Bad id splice")
+            end
+            return v
+        elseif a.tag == "Id" then return lx:next()
+        else return false end
+    end
+
+    --------------------------------------------------------------------------------
+    -- Mandatory reading of an id: causes an error if it can't read one.
+    --------------------------------------------------------------------------------
+    function M.id (lx)
+        return M.opt_id (lx) or gg.parse_error(lx,"Identifier expected")
+    end
+
+    --------------------------------------------------------------------------------
+    -- Common helper function
+    --------------------------------------------------------------------------------
+    M.id_list = gg.list { primary = _M.id, separators = "," }
+
+    --------------------------------------------------------------------------------
+    -- Converts an identifier into a string. Hopefully one day it'll handle
+    -- splices gracefully, but that proves quite tricky.
+    --------------------------------------------------------------------------------
+    function M.id2string (id)
+        --print("id2string:", disp.ast(id))
+        if id.tag == "Id" then id.tag = "String"; return id
+        elseif id.tag == "Splice" then
+            error ("id2string on splice not implemented")
+            -- Evaluating id[1] will produce `Id{ xxx },
+            -- and we want it to produce `String{ xxx }.
+            -- The following is the plain notation of:
+            -- +{ `String{ `Index{ `Splice{ -{id[1]} }, `Number 1 } } }
+            return { tag="String",  { tag="Index", { tag="Splice", id[1] },
+                                      { tag="Number", 1 } } }
+        else error ("Identifier expected: "..table.tostring(id, 'nohash')) end
+    end
+
+    --------------------------------------------------------------------------------
+    -- Read a string, possibly spliced, or return an error if it can't
+    --------------------------------------------------------------------------------
+    function M.string (lx)
+        local a = lx:peek()
+        if lx:is_keyword (a, "-{") then
+            local v = M.meta.splice(lx)
+            if v.tag ~= "String" and v.tag ~= "Splice" then
+                gg.parse_error(lx,"Bad string splice")
+            end
+            return v
+        elseif a.tag == "String" then return lx:next()
+        else error "String expected" end
+    end
+
+    --------------------------------------------------------------------------------
+    -- Try to read a string, or return false if it can't. No splice allowed.
+    --------------------------------------------------------------------------------
+    function M.opt_string (lx)
+        return lx:peek().tag == "String" and lx:next()
+    end
+
+    --------------------------------------------------------------------------------
+    -- Chunk reader: block + Eof
+    --------------------------------------------------------------------------------
+    function M.skip_initial_sharp_comment (lx)
+        -- Dirty hack: I'm happily fondling lexer's private parts
+        -- FIXME: redundant with lexer:newstream()
+        lx :sync()
+        local i = lx.src:match ("^#.-\n()", lx.i)
+        if i then
+            lx.i = i
+            lx.column_offset = i
+            lx.line = lx.line and lx.line + 1 or 1
+        end
+    end
+
+    local function chunk (lx)
+        if lx:peek().tag == 'Eof' then
+            return { } -- handle empty files
+        else
+            M.skip_initial_sharp_comment (lx)
+            local chunk = M.block (lx)
+            if lx:peek().tag ~= "Eof" then
+                gg.parse_error(lx, "End-of-file expected")
+            end
+            return chunk
+        end
+    end
+
+    -- chunk is wrapped in a sequence so that it has a "transformer" field.
+    M.chunk = gg.sequence { chunk, builder = unpack }
+
+    return M
+end
\ No newline at end of file