util.x509: Nameprep commonName once
[prosody.git] / tools / erlparse.lua
blob45bed265dbb2bfbd9d31e77eeffadb1d3131239f
1 -- Prosody IM
2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
4 --
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
9 local string_byte, string_char = string.byte, string.char;
10 local t_concat, t_insert = table.concat, table.insert;
11 local type, tonumber, tostring = type, tonumber, tostring;
13 local file = nil;
14 local last = nil;
15 local line = 1;
16 local function read(expected)
17 local ch;
18 if last then
19 ch = last; last = nil;
20 else
21 ch = file:read(1);
22 if ch == "\n" then line = line + 1; end
23 end
24 if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil").." on line "..line); end
25 return ch;
26 end
27 local function pushback(ch)
28 if last then error(); end
29 last = ch;
30 end
31 local function peek()
32 if not last then last = read(); end
33 return last;
34 end
36 local _A, _a, _Z, _z, _0, _9, __, _at, _space, _minus = string_byte("AaZz09@_ -", 1, 10);
37 local function isLowerAlpha(ch)
38 ch = string_byte(ch) or 0;
39 return (ch >= _a and ch <= _z);
40 end
41 local function isNumeric(ch)
42 ch = string_byte(ch) or 0;
43 return (ch >= _0 and ch <= _9) or ch == _minus;
44 end
45 local function isAtom(ch)
46 ch = string_byte(ch) or 0;
47 return (ch >= _A and ch <= _Z) or (ch >= _a and ch <= _z) or (ch >= _0 and ch <= _9) or ch == __ or ch == _at;
48 end
49 local function isSpace(ch)
50 ch = string_byte(ch) or "x";
51 return ch <= _space;
52 end
54 local escapes = {["\\b"]="\b", ["\\d"]="\127", ["\\e"]="\27", ["\\f"]="\f", ["\\n"]="\n", ["\\r"]="\r", ["\\s"]=" ", ["\\t"]="\t", ["\\v"]="\v", ["\\\""]="\"", ["\\'"]="'", ["\\\\"]="\\"};
55 local function readString()
56 read("\""); -- skip quote
57 local slash = nil;
58 local str = {};
59 while true do
60 local ch = read();
61 if slash then
62 slash = slash..ch;
63 if not escapes[slash] then error("Unknown escape sequence: "..slash); end
64 str[#str+1] = escapes[slash];
65 slash = nil;
66 elseif ch == "\"" then
67 break;
68 elseif ch == "\\" then
69 slash = ch;
70 else
71 str[#str+1] = ch;
72 end
73 end
74 return t_concat(str);
75 end
76 local function readAtom1()
77 local var = { read() };
78 while isAtom(peek()) do
79 var[#var+1] = read();
80 end
81 return t_concat(var);
82 end
83 local function readAtom2()
84 local str = { read("'") };
85 local slash = nil;
86 while true do
87 local ch = read();
88 str[#str+1] = ch;
89 if ch == "'" and not slash then break; end
90 end
91 return t_concat(str);
92 end
93 local function readNumber()
94 local num = { read() };
95 while isNumeric(peek()) do
96 num[#num+1] = read();
97 end
98 if peek() == "." then
99 num[#num+1] = read();
100 while isNumeric(peek()) do
101 num[#num+1] = read();
104 return tonumber(t_concat(num));
106 local readItem = nil;
107 local function readTuple()
108 local t = {};
109 local s = {}; -- string representation
110 read(); -- read {, or [, or <
111 while true do
112 local item = readItem();
113 if not item then break; end
114 if type(item) ~= "number" or item > 255 then
115 s = nil;
116 elseif s then
117 s[#s+1] = string_char(item);
119 t_insert(t, item);
121 read(); -- read }, or ], or >
122 if s and #s > 0 then
123 return t_concat(s)
124 else
125 return t
126 end;
128 local function readBinary()
129 read("<"); -- read <
130 -- Discard PIDs
131 if isNumeric(peek()) then
132 while peek() ~= ">" do read(); end
133 read(">");
134 return {};
136 local t = readTuple();
137 read(">") -- read >
138 local ch = peek();
139 if type(t) == "string" then
140 -- binary is a list of integers
141 return t;
142 elseif type(t) == "table" then
143 if t[1] then
144 -- binary contains string
145 return t[1];
146 else
147 -- binary is empty
148 return "";
149 end;
150 else
151 error();
154 readItem = function()
155 local ch = peek();
156 if ch == nil then return nil end
157 if ch == "{" or ch == "[" then
158 return readTuple();
159 elseif isLowerAlpha(ch) then
160 return readAtom1();
161 elseif ch == "'" then
162 return readAtom2();
163 elseif isNumeric(ch) then
164 return readNumber();
165 elseif ch == "\"" then
166 return readString();
167 elseif ch == "<" then
168 return readBinary();
169 elseif isSpace(ch) or ch == "," or ch == "|" then
170 read();
171 return readItem();
172 else
173 --print("Unknown char: "..ch);
174 return nil;
177 local function readChunk()
178 local x = readItem();
179 if x then read("."); end
180 return x;
182 local function readFile(filename)
183 file = io.open(filename);
184 if not file then error("File not found: "..filename); os.exit(0); end
185 return function()
186 local x = readChunk();
187 if not x and peek() then error("Invalid char: "..peek()); end
188 return x;
189 end;
192 local _M = {};
194 function _M.parseFile(file)
195 return readFile(file);
198 return _M;