lib/js2lua.lua

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;