X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=tools%2Ferlparse.lua;h=f2d410a3626bd9dd512f9b57420d5e8b8265535b;hb=c034822c397733699c165142e9233462ddfed145;hp=37d4bb621dbd403f58793feea4ec79d5f65b7cf0;hpb=8aba1c77f0714f2460cc21660bb494fc217e042b;p=prosody.git diff --git a/tools/erlparse.lua b/tools/erlparse.lua index 37d4bb62..f2d410a3 100644 --- a/tools/erlparse.lua +++ b/tools/erlparse.lua @@ -1,150 +1,170 @@ --- Prosody IM v0.2 --- Copyright (C) 2008 Matthew Wild --- Copyright (C) 2008 Waqas Hussain +-- Prosody IM +-- Copyright (C) 2008-2009 Matthew Wild +-- Copyright (C) 2008-2009 Waqas Hussain -- --- This program is free software; you can redistribute it and/or --- modify it under the terms of the GNU General Public License --- as published by the Free Software Foundation; either version 2 --- of the License, or (at your option) any later version. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License --- along with this program; if not, write to the Free Software --- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. -- - -local file = nil; -local last = nil; -local function read(expected) - local ch; - if last then - ch = last; last = nil; - else ch = file:read(1); end - if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil")); end - return ch; -end -local function pushback(ch) - if last then error(); end - last = ch; -end -local function peek() - if not last then last = read(); end - return last; -end - -local _A, _a, _Z, _z, _0, _9, __, _space = string.byte("AaZz09_ ", 1, 8); -local function isAlpha(ch) - ch = string.byte(ch) or 0; - return (ch >= _A and ch <= _Z) or (ch >= _a and ch <= _z); -end -local function isNumeric(ch) - ch = string.byte(ch) or 0; - return (ch >= _0 and ch <= _9); -end -local function isVar(ch) - ch = string.byte(ch) or 0; - return (ch >= _A and ch <= _Z) or (ch >= _a and ch <= _z) or (ch >= _0 and ch <= _9) or ch == __; -end -local function isSpace(ch) - ch = string.byte(ch) or "x"; - return ch <= _space; -end - -local function readString() - read("\""); -- skip quote - local slash = nil; - local str = ""; - while true do - local ch = read(); - if ch == "\"" and not slash then break; end - str = str..ch; - end - str = str:gsub("\\.", {["\\b"]="\b", ["\\d"]="\d", ["\\e"]="\e", ["\\f"]="\f", ["\\n"]="\n", ["\\r"]="\r", ["\\s"]="\s", ["\\t"]="\t", ["\\v"]="\v", ["\\\""]="\"", ["\\'"]="'", ["\\\\"]="\\"}); - return str; -end -local function readSpecialString() - read("<"); read("<"); -- read << - local str = ""; - if peek() == "\"" then - str = readString(); - elseif peek() ~= ">" then - error(); - end - read(">"); read(">"); -- read >> - return str; -end -local function readVar() - local var = read(); - while isVar(peek()) do - var = var..read(); - end - return var; -end -local function readNumber() - local num = read(); - while isNumeric(peek()) do - num = num..read(); - end - return tonumber(num); -end -local readItem = nil; -local function readTuple() - local t = {}; - read(); -- read { or [ - while true do - local item = readItem(); - if not item then break; end - table.insert(t, item); - end - read(); -- read } or ] - return t; -end -readItem = function() - local ch = peek(); - if ch == nil then return nil end - if ch == "{" or ch == "[" then - return readTuple(); - elseif isAlpha(ch) then - return readVar(); - elseif isNumeric(ch) then - return readNumber(); - elseif ch == "\"" then - return readString(); - elseif ch == "<" then - return readSpecialString(); - elseif isSpace(ch) or ch == "," or ch == "|" then - read(); - return readItem(); - else - --print("Unknown char: "..ch); - return nil; - end -end -local function readChunk() - local x = readItem(); - if x then read("."); end - return x; -end -local function readFile(filename) - file = io.open(filename); - if not file then error("File not found: "..filename); os.exit(0); end - return function() - local x = readChunk(); - if not x and peek() then error("Invalid char: "..peek()); end - return x; - end; -end - -module "erlparse" - -function parseFile(file) - return readFile(file); -end - -return _M; + +local file = nil; +local last = nil; +local function read(expected) + local ch; + if last then + ch = last; last = nil; + else ch = file:read(1); end + if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil")); end + return ch; +end +local function pushback(ch) + if last then error(); end + last = ch; +end +local function peek() + if not last then last = read(); end + return last; +end + +local _A, _a, _Z, _z, _0, _9, __, _at, _space = string.byte("AaZz09@_ ", 1, 9); +local function isLowerAlpha(ch) + ch = string.byte(ch) or 0; + return (ch >= _a and ch <= _z); +end +local function isNumeric(ch) + ch = string.byte(ch) or 0; + return (ch >= _0 and ch <= _9); +end +local function isAtom(ch) + ch = string.byte(ch) or 0; + return (ch >= _A and ch <= _Z) or (ch >= _a and ch <= _z) or (ch >= _0 and ch <= _9) or ch == __ or ch == _at; +end +local function isSpace(ch) + ch = string.byte(ch) or "x"; + return ch <= _space; +end + +local function readString() + read("\""); -- skip quote + local slash = nil; + local str = ""; + while true do + local ch = read(); + if ch == "\"" and not slash then break; end + str = str..ch; + end + str = str:gsub("\\.", {["\\b"]="\b", ["\\d"]="\d", ["\\e"]="\e", ["\\f"]="\f", ["\\n"]="\n", ["\\r"]="\r", ["\\s"]="\s", ["\\t"]="\t", ["\\v"]="\v", ["\\\""]="\"", ["\\'"]="'", ["\\\\"]="\\"}); + return str; +end +local function readAtom1() + local var = read(); + while isAtom(peek()) do + var = var..read(); + end + return var; +end +local function readAtom2() + local str = read("'"); + local slash = nil; + while true do + local ch = read(); + str = str..ch; + if ch == "'" and not slash then break; end + end + return str; +end +local function readNumber() + local num = read(); + while isNumeric(peek()) do + num = num..read(); + end + return tonumber(num); +end +local readItem = nil; +local function readTuple() + local t = {}; + local s = ""; -- string representation + read(); -- read {, or [, or < + while true do + local item = readItem(); + if not item then break; end + if type(item) ~= type(0) or item > 255 then + s = nil; + elseif s then + s = s..string.char(item); + end + table.insert(t, item); + end + read(); -- read }, or ], or > + if s and s ~= "" then + return s + else + return t + end; +end +local function readBinary() + read("<"); -- read < + local t = readTuple(); + read(">") -- read > + local ch = peek(); + if type(t) == type("") then + -- binary is a list of integers + return t; + elseif type(t) == type({}) then + if t[1] then + -- binary contains string + return t[1]; + else + -- binary is empty + return ""; + end; + else + error(); + end +end +readItem = function() + local ch = peek(); + if ch == nil then return nil end + if ch == "{" or ch == "[" then + return readTuple(); + elseif isLowerAlpha(ch) then + return readAtom1(); + elseif ch == "'" then + return readAtom2(); + elseif isNumeric(ch) then + return readNumber(); + elseif ch == "\"" then + return readString(); + elseif ch == "<" then + return readBinary(); + elseif isSpace(ch) or ch == "," or ch == "|" then + read(); + return readItem(); + else + --print("Unknown char: "..ch); + return nil; + end +end +local function readChunk() + local x = readItem(); + if x then read("."); end + return x; +end +local function readFile(filename) + file = io.open(filename); + if not file then error("File not found: "..filename); os.exit(0); end + return function() + local x = readChunk(); + if not x and peek() then error("Invalid char: "..peek()); end + return x; + end; +end + +module "erlparse" + +function parseFile(file) + return readFile(file); +end + +return _M;