X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=tools%2Ferlparse.lua;h=dc3a2f94e6d44c3d03fa20d09dc57c94bec31d69;hb=626b9b6d3924314d9d9c0e389f8be82002f695cf;hp=0bd4b3b84a61988c03ca383b61509ac24363c3f1;hpb=ee85d0c79aa2d7bfa3f1280f19792e1d007b6519;p=prosody.git diff --git a/tools/erlparse.lua b/tools/erlparse.lua index 0bd4b3b8..dc3a2f94 100644 --- a/tools/erlparse.lua +++ b/tools/erlparse.lua @@ -1,21 +1,27 @@ -- Prosody IM --- Copyright (C) 2008-2009 Matthew Wild --- Copyright (C) 2008-2009 Waqas Hussain +-- 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); end - if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil")); end + 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) @@ -27,86 +33,133 @@ local function peek() 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); +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); + ch = string_byte(ch) or 0; + return (ch >= _0 and ch <= _9) or ch == _minus; 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 == __; +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"; + ch = string_byte(ch) or "x"; return ch <= _space; end +local escapes = {["\\b"]="\b", ["\\d"]="\d", ["\\e"]="\e", ["\\f"]="\f", ["\\n"]="\n", ["\\r"]="\r", ["\\s"]="\s", ["\\t"]="\t", ["\\v"]="\v", ["\\\""]="\"", ["\\'"]="'", ["\\\\"]="\\"}; local function readString() read("\""); -- skip quote local slash = nil; - local str = ""; + local str = {}; while true do local ch = read(); - if ch == "\"" and not slash then break; end - str = str..ch; + 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 - 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(); + return t_concat(str); +end +local function readAtom1() + local var = { read() }; + while isAtom(peek()) do + var[#var+1] = read(); end - read(">"); read(">"); -- read >> - return str; + return t_concat(var); end -local function readVar() - local var = read(); - while isVar(peek()) do - var = var..read(); +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 var; + return t_concat(str); end local function readNumber() - local num = read(); + local num = { read() }; while isNumeric(peek()) do - num = num..read(); + num[#num+1] = read(); end - return tonumber(num); + return tonumber(t_concat(num)); end local readItem = nil; local function readTuple() local t = {}; - read(); -- read { or [ + local s = {}; -- string representation + read(); -- read {, or [, or < while true do local item = readItem(); if not item then break; end - table.insert(t, item); + 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 - 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 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 readSpecialString(); + return readBinary(); elseif isSpace(ch) or ch == "," or ch == "|" then read(); return readItem();