aboutsummaryrefslogtreecommitdiffstats
path: root/tools/erlparse.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tools/erlparse.lua')
-rw-r--r--tools/erlparse.lua198
1 files changed, 198 insertions, 0 deletions
diff --git a/tools/erlparse.lua b/tools/erlparse.lua
new file mode 100644
index 00000000..174585d3
--- /dev/null
+++ b/tools/erlparse.lua
@@ -0,0 +1,198 @@
+-- Prosody IM
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
+--
+-- This project is MIT/X11 licensed. Please see the
+-- COPYING file in the source package for more information.
+--
+
+local string_byte, string_char = string.byte, string.char;
+local t_concat, t_insert = table.concat, table.insert;
+local type, tonumber, tostring = type, tonumber, tostring;
+
+local file = nil;
+local last = nil;
+local line = 1;
+local function read(expected)
+ local ch;
+ if last then
+ ch = last; last = nil;
+ else
+ ch = file:read(1);
+ if ch == "\n" then line = line + 1; end
+ end
+ if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil").." on line "..line); 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, _minus = string_byte("AaZz09@_ -", 1, 10);
+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) or ch == _minus;
+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 escapes = {["\\b"]="\b", ["\\d"]="\127", ["\\e"]="\27", ["\\f"]="\f", ["\\n"]="\n", ["\\r"]="\r", ["\\s"]=" ", ["\\t"]="\t", ["\\v"]="\v", ["\\\""]="\"", ["\\'"]="'", ["\\\\"]="\\"};
+local function readString()
+ read("\""); -- skip quote
+ local slash = nil;
+ local str = {};
+ while true do
+ local ch = read();
+ if slash then
+ slash = slash..ch;
+ if not escapes[slash] then error("Unknown escape sequence: "..slash); end
+ str[#str+1] = escapes[slash];
+ slash = nil;
+ elseif ch == "\"" then
+ break;
+ elseif ch == "\\" then
+ slash = ch;
+ else
+ str[#str+1] = ch;
+ end
+ end
+ return t_concat(str);
+end
+local function readAtom1()
+ local var = { read() };
+ while isAtom(peek()) do
+ var[#var+1] = read();
+ end
+ return t_concat(var);
+end
+local function readAtom2()
+ local str = { read("'") };
+ local slash = nil;
+ while true do
+ local ch = read();
+ str[#str+1] = ch;
+ if ch == "'" and not slash then break; end
+ end
+ return t_concat(str);
+end
+local function readNumber()
+ local num = { read() };
+ while isNumeric(peek()) do
+ num[#num+1] = read();
+ end
+ if peek() == "." then
+ num[#num+1] = read();
+ while isNumeric(peek()) do
+ num[#num+1] = read();
+ end
+ end
+ return tonumber(t_concat(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) ~= "number" or item > 255 then
+ s = nil;
+ elseif s then
+ s[#s+1] = string_char(item);
+ end
+ t_insert(t, item);
+ end
+ read(); -- read }, or ], or >
+ if s and #s > 0 then
+ return t_concat(s)
+ else
+ return t
+ end;
+end
+local function readBinary()
+ read("<"); -- read <
+ -- Discard PIDs
+ if isNumeric(peek()) then
+ while peek() ~= ">" do read(); end
+ read(">");
+ return {};
+ end
+ local t = readTuple();
+ read(">") -- read >
+ local ch = peek();
+ if type(t) == "string" then
+ -- binary is a list of integers
+ return t;
+ elseif type(t) == "table" 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;