|
1 local t = { op = {}, keyword = {}, name = {}, eos = {}, string = {}, regex = {} }; |
|
2 |
|
3 local debug = function (...) io.stderr:write(table.concat({...}, "\t")); io.stderr:write"\n";end; |
|
4 local debug = function () end |
|
5 |
|
6 local function read_balanced(tokens, start, left, right) |
|
7 local c = 0; |
|
8 for i=start,#tokens do |
|
9 if tokens[i].type == "op" then |
|
10 local token = tokens[i].value; |
|
11 if token == left then |
|
12 c = c + 1; |
|
13 elseif token == right then |
|
14 c = c - 1; |
|
15 end |
|
16 end |
|
17 if c == 0 then return i; end |
|
18 end |
|
19 return start; |
|
20 end |
|
21 |
|
22 local pair_op = { ["("] = ")", ["{"] = "}", ["["] = "]" }; |
|
23 local function read_balanced_to(tokens, start, to) |
|
24 local c = 0; |
|
25 local i = start; |
|
26 while i <= #tokens do |
|
27 if tokens[i].type == "op" or tokens[i].type == "eos" then |
|
28 local token = tokens[i].value; |
|
29 if token == to then return i; end |
|
30 |
|
31 if pair_op[token] then |
|
32 i = read_balanced(tokens, i, token, pair_op[token]); |
|
33 end |
|
34 end |
|
35 i = i + 1; |
|
36 end |
|
37 return nil; |
|
38 end |
|
39 |
|
40 function js2lua(tokens, write) |
|
41 |
|
42 -- Scan |
|
43 local i = 1; |
|
44 while i <= #tokens do |
|
45 local token = tokens[i]; |
|
46 debug(token.type, token.value); |
|
47 if token.type == "keyword" and token.value == "function" then |
|
48 local j = read_balanced_to(tokens, i+3, ")"); -- Find matching ) |
|
49 j = j + 1; -- j now points to { |
|
50 local k = read_balanced_to(tokens, j+1, "}"); |
|
51 table.remove(tokens, j); -- Remove { |
|
52 tokens[k-1].type, tokens[k-1].value = "keyword", "end"; |
|
53 elseif token.type == "keyword" and token.value == "if" then |
|
54 table.remove(tokens, i+1); -- Remove ( |
|
55 local j = read_balanced_to(tokens, i, ")"); |
|
56 tokens[j].type, tokens[j].value = "keyword", "then"; |
|
57 |
|
58 -- Make sure to end a single-statement block |
|
59 if tokens[j+1].type ~= "op" or tokens[j+1].value ~= "{" then |
|
60 local eos = read_balanced_to(tokens, j+1, ";"); |
|
61 if tokens[eos+1].type ~= "keyword" or tokens[eos+1].value ~= "else" then |
|
62 table.insert(tokens, eos+1, { type = "keyword", value = "end" }); |
|
63 end |
|
64 end |
|
65 elseif token.type == "keyword" and token.value == "else" then |
|
66 if tokens[i+1].type == "keyword" and tokens[i+1].value == "if" then |
|
67 token.value = "elseif"; |
|
68 table.remove(tokens, i+1); |
|
69 |
|
70 table.remove(tokens, i+1); -- Remove ( |
|
71 local j = read_balanced_to(tokens, i, ")"); |
|
72 tokens[j].type, tokens[j].value = "keyword", "then"; |
|
73 end |
|
74 |
|
75 -- Make sure to end a single-statement block |
|
76 if tokens[i+1].type ~= "op" or tokens[i+1].value ~= "{" then |
|
77 local eos = read_balanced_to(tokens, i+1, ";"); |
|
78 if tokens[eos+1].type ~= "keyword" or tokens[eos+1].value ~= "else" then |
|
79 table.insert(tokens, eos+1, { type = "keyword", value = "end" }); |
|
80 end |
|
81 end |
|
82 elseif token.type == "op" and token.value == "+" and tokens[i-1].type == "string" then |
|
83 token.value = ".."; |
|
84 elseif token.type == "op" and token.value == "{" then |
|
85 elseif token.type == "keyword" and token.value == "var" then |
|
86 token.value = "local"; |
|
87 end |
|
88 i = i + 1; |
|
89 end |
|
90 |
|
91 -- Serialize |
|
92 local last_token_type; |
|
93 for _, token in ipairs(tokens) do |
|
94 if token.type == "string" then |
|
95 write("\""); |
|
96 elseif token.type == "name" then |
|
97 if last_token_type == "keyword" or last_token_type == "name" or last_token_type == "number" then |
|
98 write(" "); |
|
99 end |
|
100 elseif token.type == "keyword" then |
|
101 if last_token_type == "keyword" or last_token_type == "name" or last_token_type == "number" then |
|
102 write(" "); |
|
103 end |
|
104 end |
|
105 write(token.value); |
|
106 if token.type == "string" then |
|
107 write("\""); |
|
108 end |
|
109 last_token_type = token.type; |
|
110 end |
|
111 end |
|
112 |
|
113 return js2lua; |