Update copyright headers for 2010
[prosody.git] / tools / erlparse.lua
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 --
8
9
10
11 local file = nil;
12 local last = nil;
13 local function read(expected)
14         local ch;
15         if last then
16                 ch = last; last = nil;
17         else ch = file:read(1); end
18         if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil")); end
19         return ch;
20 end
21 local function pushback(ch)
22         if last then error(); end
23         last = ch;
24 end
25 local function peek()
26         if not last then last = read(); end
27         return last;
28 end
29
30 local _A, _a, _Z, _z, _0, _9, __, _at, _space = string.byte("AaZz09@_ ", 1, 9);
31 local function isLowerAlpha(ch)
32         ch = string.byte(ch) or 0;
33         return (ch >= _a and ch <= _z);
34 end
35 local function isNumeric(ch)
36         ch = string.byte(ch) or 0;
37         return (ch >= _0 and ch <= _9);
38 end
39 local function isAtom(ch)
40         ch = string.byte(ch) or 0;
41         return (ch >= _A and ch <= _Z) or (ch >= _a and ch <= _z) or (ch >= _0 and ch <= _9) or ch == __ or ch == _at;
42 end
43 local function isSpace(ch)
44         ch = string.byte(ch) or "x";
45         return ch <= _space;
46 end
47
48 local escapes = {["\\b"]="\b", ["\\d"]="\d", ["\\e"]="\e", ["\\f"]="\f", ["\\n"]="\n", ["\\r"]="\r", ["\\s"]="\s", ["\\t"]="\t", ["\\v"]="\v", ["\\\""]="\"", ["\\'"]="'", ["\\\\"]="\\"};
49 local function readString()
50         read("\""); -- skip quote
51         local slash = nil;
52         local str = "";
53         while true do
54                 local ch = read();
55                 if slash then
56                         slash = slash..ch;
57                         if not escapes[slash] then error("Unknown escape sequence: "..slash); end
58                         str = str..escapes[slash];
59                         slash = nil;
60                 elseif ch == "\"" then
61                         break;
62                 elseif ch == "\\" then
63                         slash = ch;
64                 else
65                         str = str..ch;
66                 end
67         end
68         return str;
69 end
70 local function readAtom1()
71         local var = read();
72         while isAtom(peek()) do
73                 var = var..read();
74         end
75         return var;
76 end
77 local function readAtom2()
78         local str = read("'");
79         local slash = nil;
80         while true do
81                 local ch = read();
82                 str = str..ch;
83                 if ch == "'" and not slash then break; end
84         end
85         return str;
86 end
87 local function readNumber()
88         local num = read();
89         while isNumeric(peek()) do
90                 num = num..read();
91         end
92         return tonumber(num);
93 end
94 local readItem = nil;
95 local function readTuple()
96         local t = {};
97         local s = ""; -- string representation
98         read(); -- read {, or [, or <
99         while true do
100                 local item = readItem();
101                 if not item then break; end
102                 if type(item) ~= type(0) or item > 255 then
103                         s = nil;
104                 elseif s then
105                         s = s..string.char(item);
106                 end
107                 table.insert(t, item);
108         end
109         read(); -- read }, or ], or >
110         if s and s ~= "" then
111                 return s
112         else
113                 return t
114         end;
115 end
116 local function readBinary()
117         read("<"); -- read <
118         local t = readTuple();
119         read(">") -- read >
120         local ch = peek();
121         if type(t) == type("") then
122                 -- binary is a list of integers
123                 return t;
124         elseif type(t) == type({}) then
125                 if t[1] then
126                         -- binary contains string
127                         return t[1];
128                 else
129                         -- binary is empty
130                         return "";
131                 end;
132         else
133                 error();
134         end
135 end
136 readItem = function()
137         local ch = peek();
138         if ch == nil then return nil end
139         if ch == "{" or ch == "[" then
140                 return readTuple();
141         elseif isLowerAlpha(ch) then
142                 return readAtom1();
143         elseif ch == "'" then
144                 return readAtom2();
145         elseif isNumeric(ch) then
146                 return readNumber();
147         elseif ch == "\"" then
148                 return readString();
149         elseif ch == "<" then
150                 return readBinary();
151         elseif isSpace(ch) or ch == "," or ch == "|" then
152                 read();
153                 return readItem();
154         else
155                 --print("Unknown char: "..ch);
156                 return nil;
157         end
158 end
159 local function readChunk()
160         local x = readItem();
161         if x then read("."); end
162         return x;
163 end
164 local function readFile(filename)
165         file = io.open(filename);
166         if not file then error("File not found: "..filename); os.exit(0); end
167         return function()
168                 local x = readChunk();
169                 if not x and peek() then error("Invalid char: "..peek()); end
170                 return x;
171         end;
172 end
173
174 module "erlparse"
175
176 function parseFile(file)
177         return readFile(file);
178 end
179
180 return _M;