Software / code / prosody
Comparison
tools/erlparse.lua @ 2948:1ac5ef6ce1a0
Merge 0.7->trunk
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Thu, 25 Mar 2010 19:40:38 +0000 |
| parent | 2947:ff7f6668b34f |
| child | 5079:2ab99e239d45 |
comparison
equal
deleted
inserted
replaced
| 2944:855c0eb80600 | 2948:1ac5ef6ce1a0 |
|---|---|
| 4 -- | 4 -- |
| 5 -- This project is MIT/X11 licensed. Please see the | 5 -- This project is MIT/X11 licensed. Please see the |
| 6 -- COPYING file in the source package for more information. | 6 -- COPYING file in the source package for more information. |
| 7 -- | 7 -- |
| 8 | 8 |
| 9 | 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; | |
| 10 | 12 |
| 11 local file = nil; | 13 local file = nil; |
| 12 local last = nil; | 14 local last = nil; |
| 15 local line = 1; | |
| 13 local function read(expected) | 16 local function read(expected) |
| 14 local ch; | 17 local ch; |
| 15 if last then | 18 if last then |
| 16 ch = last; last = nil; | 19 ch = last; last = nil; |
| 17 else ch = file:read(1); end | 20 else |
| 18 if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil")); end | 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 | |
| 19 return ch; | 25 return ch; |
| 20 end | 26 end |
| 21 local function pushback(ch) | 27 local function pushback(ch) |
| 22 if last then error(); end | 28 if last then error(); end |
| 23 last = ch; | 29 last = ch; |
| 25 local function peek() | 31 local function peek() |
| 26 if not last then last = read(); end | 32 if not last then last = read(); end |
| 27 return last; | 33 return last; |
| 28 end | 34 end |
| 29 | 35 |
| 30 local _A, _a, _Z, _z, _0, _9, __, _at, _space = string.byte("AaZz09@_ ", 1, 9); | 36 local _A, _a, _Z, _z, _0, _9, __, _at, _space, _minus = string_byte("AaZz09@_ -", 1, 10); |
| 31 local function isLowerAlpha(ch) | 37 local function isLowerAlpha(ch) |
| 32 ch = string.byte(ch) or 0; | 38 ch = string_byte(ch) or 0; |
| 33 return (ch >= _a and ch <= _z); | 39 return (ch >= _a and ch <= _z); |
| 34 end | 40 end |
| 35 local function isNumeric(ch) | 41 local function isNumeric(ch) |
| 36 ch = string.byte(ch) or 0; | 42 ch = string_byte(ch) or 0; |
| 37 return (ch >= _0 and ch <= _9); | 43 return (ch >= _0 and ch <= _9) or ch == _minus; |
| 38 end | 44 end |
| 39 local function isAtom(ch) | 45 local function isAtom(ch) |
| 40 ch = string.byte(ch) or 0; | 46 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; | 47 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 | 48 end |
| 43 local function isSpace(ch) | 49 local function isSpace(ch) |
| 44 ch = string.byte(ch) or "x"; | 50 ch = string_byte(ch) or "x"; |
| 45 return ch <= _space; | 51 return ch <= _space; |
| 46 end | 52 end |
| 47 | 53 |
| 48 local escapes = {["\\b"]="\b", ["\\d"]="\d", ["\\e"]="\e", ["\\f"]="\f", ["\\n"]="\n", ["\\r"]="\r", ["\\s"]="\s", ["\\t"]="\t", ["\\v"]="\v", ["\\\""]="\"", ["\\'"]="'", ["\\\\"]="\\"}; | 54 local escapes = {["\\b"]="\b", ["\\d"]="\d", ["\\e"]="\e", ["\\f"]="\f", ["\\n"]="\n", ["\\r"]="\r", ["\\s"]="\s", ["\\t"]="\t", ["\\v"]="\v", ["\\\""]="\"", ["\\'"]="'", ["\\\\"]="\\"}; |
| 49 local function readString() | 55 local function readString() |
| 50 read("\""); -- skip quote | 56 read("\""); -- skip quote |
| 51 local slash = nil; | 57 local slash = nil; |
| 52 local str = ""; | 58 local str = {}; |
| 53 while true do | 59 while true do |
| 54 local ch = read(); | 60 local ch = read(); |
| 55 if slash then | 61 if slash then |
| 56 slash = slash..ch; | 62 slash = slash..ch; |
| 57 if not escapes[slash] then error("Unknown escape sequence: "..slash); end | 63 if not escapes[slash] then error("Unknown escape sequence: "..slash); end |
| 58 str = str..escapes[slash]; | 64 str[#str+1] = escapes[slash]; |
| 59 slash = nil; | 65 slash = nil; |
| 60 elseif ch == "\"" then | 66 elseif ch == "\"" then |
| 61 break; | 67 break; |
| 62 elseif ch == "\\" then | 68 elseif ch == "\\" then |
| 63 slash = ch; | 69 slash = ch; |
| 64 else | 70 else |
| 65 str = str..ch; | 71 str[#str+1] = ch; |
| 66 end | 72 end |
| 67 end | 73 end |
| 68 return str; | 74 return t_concat(str); |
| 69 end | 75 end |
| 70 local function readAtom1() | 76 local function readAtom1() |
| 71 local var = read(); | 77 local var = { read() }; |
| 72 while isAtom(peek()) do | 78 while isAtom(peek()) do |
| 73 var = var..read(); | 79 var[#var+1] = read(); |
| 74 end | 80 end |
| 75 return var; | 81 return t_concat(var); |
| 76 end | 82 end |
| 77 local function readAtom2() | 83 local function readAtom2() |
| 78 local str = read("'"); | 84 local str = { read("'") }; |
| 79 local slash = nil; | 85 local slash = nil; |
| 80 while true do | 86 while true do |
| 81 local ch = read(); | 87 local ch = read(); |
| 82 str = str..ch; | 88 str[#str+1] = ch; |
| 83 if ch == "'" and not slash then break; end | 89 if ch == "'" and not slash then break; end |
| 84 end | 90 end |
| 85 return str; | 91 return t_concat(str); |
| 86 end | 92 end |
| 87 local function readNumber() | 93 local function readNumber() |
| 88 local num = read(); | 94 local num = { read() }; |
| 89 while isNumeric(peek()) do | 95 while isNumeric(peek()) do |
| 90 num = num..read(); | 96 num[#num+1] = read(); |
| 91 end | 97 end |
| 92 return tonumber(num); | 98 return tonumber(t_concat(num)); |
| 93 end | 99 end |
| 94 local readItem = nil; | 100 local readItem = nil; |
| 95 local function readTuple() | 101 local function readTuple() |
| 96 local t = {}; | 102 local t = {}; |
| 97 local s = ""; -- string representation | 103 local s = {}; -- string representation |
| 98 read(); -- read {, or [, or < | 104 read(); -- read {, or [, or < |
| 99 while true do | 105 while true do |
| 100 local item = readItem(); | 106 local item = readItem(); |
| 101 if not item then break; end | 107 if not item then break; end |
| 102 if type(item) ~= type(0) or item > 255 then | 108 if type(item) ~= "number" or item > 255 then |
| 103 s = nil; | 109 s = nil; |
| 104 elseif s then | 110 elseif s then |
| 105 s = s..string.char(item); | 111 s[#s+1] = string_char(item); |
| 106 end | 112 end |
| 107 table.insert(t, item); | 113 t_insert(t, item); |
| 108 end | 114 end |
| 109 read(); -- read }, or ], or > | 115 read(); -- read }, or ], or > |
| 110 if s and s ~= "" then | 116 if s and #s > 0 then |
| 111 return s | 117 return t_concat(s) |
| 112 else | 118 else |
| 113 return t | 119 return t |
| 114 end; | 120 end; |
| 115 end | 121 end |
| 116 local function readBinary() | 122 local function readBinary() |
| 117 read("<"); -- read < | 123 read("<"); -- read < |
| 124 -- Discard PIDs | |
| 125 if isNumeric(peek()) then | |
| 126 while peek() ~= ">" do read(); end | |
| 127 read(">"); | |
| 128 return {}; | |
| 129 end | |
| 118 local t = readTuple(); | 130 local t = readTuple(); |
| 119 read(">") -- read > | 131 read(">") -- read > |
| 120 local ch = peek(); | 132 local ch = peek(); |
| 121 if type(t) == type("") then | 133 if type(t) == "string" then |
| 122 -- binary is a list of integers | 134 -- binary is a list of integers |
| 123 return t; | 135 return t; |
| 124 elseif type(t) == type({}) then | 136 elseif type(t) == "table" then |
| 125 if t[1] then | 137 if t[1] then |
| 126 -- binary contains string | 138 -- binary contains string |
| 127 return t[1]; | 139 return t[1]; |
| 128 else | 140 else |
| 129 -- binary is empty | 141 -- binary is empty |