Commits

Bart van Strien committed 40c4877

Create 'registerSpecialForm', to dynamically define special forms, switch all inbuilts over to use that, and add 'cond' special form for an elseif tree

  • Participants
  • Parent commits 5b94ef1

Comments (0)

Files changed (3)

File fplua/compiler.lua

 
 local compileItem
 
+local specialForms = {}
+
+local function registerSpecialForm(command, f)
+	local commands
+	if type(command) == "table" then
+		commands = command
+	else
+		commands = {command}
+	end
+
+	for i, v in ipairs(commands) do
+		specialForms[v] = f
+	end
+end
+
 local function compileBlock(ast)
 	local output
 	local command = table.remove(ast, 1)
 	command = aliases[command] or command
-	if command == "=" then
-		output = ("%s = %s"):format(ast[1],
-			compileItem(ast[2]))
-	elseif command == "do" then
-		local subBlocks = {}
-		for i, v in ipairs(ast) do
-			table.insert(subBlocks, compileItem(v))
-		end
-		output = ("do\n%s\nend"):
-			format(table.concat(subBlocks, "\n"))
-	elseif command == "function" or command == "function=" then
-		local args = {}
-		local subBlocks = {}
-		local name = ""
-		if command == "function=" then
-			name = table.remove(ast, 1)
-		end
-		for i, v in ipairs(table.remove(ast, 1)) do
-			table.insert(args, v)
-		end
-		for i, v in ipairs(ast) do
-			table.insert(subBlocks, compileItem(v))
-		end
-		output = ("function %s(%s)\n%s\nend"):
-			format(name, table.concat(args, ", "),
-				table.concat(subBlocks, "\n"))
-	elseif command == "local" then
-		output = ("local %s "):format(ast[1])
-	elseif command == "local=" then
-		output = ("local %s = %s"):format(ast[1],
-			compileItem(ast[2]))
-	elseif command == "if" then
-		local condition = compileItem(ast[1])
-		local thenbranch = compileItem(ast[2])
-		local elsebranch = ""
-		if #ast > 2 then
-			elsebranch = ("\nelse\n%s"):format(compileItem(ast[3]))
-		end
-		output = ("if %s then\n%s%s\nend"):format(condition, thenbranch, elsebranch)
-	elseif command == "for=" then
-		local var = table.remove(ast, 1)
-		local values = table.concat(
-			table.remove(ast, 1), ", ")
-		local subBlocks = {}
-		for i, v in ipairs(ast) do
-			table.insert(subBlocks, compileItem(v))
-		end
-		output = ("for %s = %s do\n%s\nend"):format(
-			var, values,
-			table.concat(subBlocks, "\n"))
-	elseif command == "for" then
-		local vars = table.concat(
-			table.remove(ast, 1), ", ")
-		local generator = compileItem(table.remove(ast, 1))
-		local subBlocks = {}
-		for i, v in ipairs(ast) do
-			table.insert(subBlocks, compileItem(v))
-		end
-		output = ("for %s in %s do\n%s\nend"):format(
-			vars, generator,
-			table.concat(subBlocks, "\n"))
-	elseif command == "while" then
-		local subBlocks = {}
-		for i, v in ipairs(ast) do
-			table.insert(subBlocks, compileItem(v))
-		end
-		output = ("while %s do\n%s\nend"):
-			format(table.remove(subBlocks, 1), table.concat(subBlocks, "\n"))
-	elseif command == "until" then
-		local subBlocks = {}
-		for i, v in ipairs(ast) do
-			table.insert(subBlocks, compileItem(v))
-		end
-		local condition = table.remove(subBlocks, 1)
-		output = ("repeat\n%s\nuntil %s"):
-			format(table.concat(subBlocks, "\n"), condition)
-	elseif command == "[]" then
-		output = ("(%s)[%s]"):format(compileItem(ast[1]), compileItem(ast[2]))
-	elseif command == "return" then
-		local subBlocks = {}
-		for i, v in ipairs(ast) do
-			table.insert(subBlocks, compileItem(v))
-		end
-		output = ("return %s"):format(table.concat(subBlocks, ", "))
-	elseif command == "break" then
-		output = "break"
-	elseif command == "{" then
-		local subBlocks = {}
-		for i, v in ipairs(ast) do
-			table.insert(subBlocks, compileItem(v))
-		end
-		output = ("{ %s }"):format(table.concat(subBlocks, ", "))
+	if specialForms[command] then
+		output = specialForms[command](command, ast, compileItem)
 	elseif infixOps[command] then
 		local out = {}
 		for i, v in ipairs(ast) do
 	return compileItem(ast)
 end
 
-return compileAst
+registerSpecialForm("do", function(command, ast, compileItem)
+	local subBlocks = {}
+	for i, v in ipairs(ast) do
+		table.insert(subBlocks, compileItem(v))
+	end
+	return ("do\n%s\nend"):format(table.concat(subBlocks, "\n"))
+end)
+
+registerSpecialForm({"=", "local="}, function(command, ast, compileItem)
+	local targets
+	if ast[1].ast then
+		targets = table.concat(ast[1], ", ")
+	else
+		targets = ast[1]
+	end
+	table.remove(ast, 1)
+	local subBlocks = {}
+	for i, v in ipairs(ast) do
+		table.insert(subBlocks, compileItem(v))
+	end
+	return ("%s%s = %s"):format(command == "local=" and "local " or "",
+			targets,
+			table.concat(subBlocks, ", "))
+end)
+
+registerSpecialForm({"function", "function="}, function(command, ast, compileItem)
+	local args = {}
+	local subBlocks = {}
+	local name = ""
+	if command == "function=" then
+		name = table.remove(ast, 1)
+	end
+	for i, v in ipairs(table.remove(ast, 1)) do
+		table.insert(args, v)
+	end
+	for i, v in ipairs(ast) do
+		table.insert(subBlocks, compileItem(v))
+	end
+	return ("function %s(%s)\n%s\nend"):
+		format(name, table.concat(args, ", "),
+			table.concat(subBlocks, "\n"))
+end)
+
+registerSpecialForm("local", function(command, ast, compileItem)
+	return ("local %s "):format(table.concat(ast, ", "))
+end)
+
+registerSpecialForm("if", function(command, ast, compileItem)
+	local condition = compileItem(ast[1])
+	local thenbranch = compileItem(ast[2])
+	local elsebranch = ""
+	if #ast > 2 then
+		elsebranch = ("\nelse\n%s"):format(compileItem(ast[3]))
+	end
+	return ("if %s then\n%s%s\nend"):format(condition, thenbranch, elsebranch)
+end)
+
+registerSpecialForm("for=", function(command, ast, compileItem)
+	local var = table.remove(ast, 1)
+	local values = table.concat(
+		table.remove(ast, 1), ", ")
+	local subBlocks = {}
+	for i, v in ipairs(ast) do
+		table.insert(subBlocks, compileItem(v))
+	end
+	return ("for %s = %s do\n%s\nend"):format(
+		var, values,
+		table.concat(subBlocks, "\n"))
+end)
+
+registerSpecialForm("for", function(command, ast, compileItem)
+	local vars = table.concat(
+		table.remove(ast, 1), ", ")
+	local generator = compileItem(table.remove(ast, 1))
+	local subBlocks = {}
+	for i, v in ipairs(ast) do
+		table.insert(subBlocks, compileItem(v))
+	end
+	return ("for %s in %s do\n%s\nend"):format(
+		vars, generator,
+		table.concat(subBlocks, "\n"))
+end)
+
+registerSpecialForm("while", function(command, ast, compileItem)
+	local subBlocks = {}
+	for i, v in ipairs(ast) do
+		table.insert(subBlocks, compileItem(v))
+	end
+	return ("while %s do\n%s\nend"):
+		format(table.remove(subBlocks, 1), table.concat(subBlocks, "\n"))
+end)
+
+registerSpecialForm("until", function(command, ast, compileItem)
+	local subBlocks = {}
+	for i, v in ipairs(ast) do
+		table.insert(subBlocks, compileItem(v))
+	end
+	local condition = table.remove(subBlocks, 1)
+	return ("repeat\n%s\nuntil %s"):
+		format(table.concat(subBlocks, "\n"), condition)
+end)
+
+registerSpecialForm("[]", function(command, ast, compileItem)
+	return ("(%s)[%s]"):format(compileItem(ast[1]), compileItem(ast[2]))
+end)
+
+registerSpecialForm("return", function(command, ast, compileItem)
+	local subBlocks = {}
+	for i, v in ipairs(ast) do
+		table.insert(subBlocks, compileItem(v))
+	end
+	return ("return %s"):format(table.concat(subBlocks, ", "))
+end)
+
+registerSpecialForm("break", function(command, ast, compileItem)
+	return "break"
+end)
+
+registerSpecialForm("{", function(command, ast, compileItem)
+	local subBlocks = {}
+	for i, v in ipairs(ast) do
+		table.insert(subBlocks, compileItem(v))
+	end
+	return ("{ %s }"):format(table.concat(subBlocks, ", "))
+end)
+
+registerSpecialForm("cond", function(command, ast, compileItem)
+	local branches = {}
+	for i, v in ipairs(ast) do
+		local branch = {}
+		branch.condition = compileItem(table.remove(v, 1))
+		for i, v in ipairs(v) do
+			table.insert(branch, compileItem(v))
+		end
+		table.insert(branches, branch)
+	end
+
+	local output = {}
+	ifStatement = "if"
+	for i, v in ipairs(branches) do
+		table.insert(output,
+			("%s %s then\n%s"):format(
+				ifStatement, v.condition,
+					table.concat(v, "\n")))
+		ifStatement = "elseif"
+	end
+	table.insert(output, "end")
+	return table.concat(output, "\n")
+end)
+
+return compileAst, registerSpecialForm

File fplua/fplua.lua

+local compileAst, registerSpecialForm = require "fplua.compiler"
 local fplua = setmetatable({
 	reader = require "fplua.reader",
-	compileAst = require "fplua.compiler"
+	compileAst = compileAst,
+	registerSpecialForm = registerSpecialForm,
 }, {__index = require "fplua.utils"})
 
 function fplua.loadstring(s, chunkname)
 
 (for (i v) (ipairs results)
   (print v))
+
+(cond
+ ((== 5 3) (print "Lies"))
+ ((== (/ 0 0) (/ 0 0)) (print "More or less lies"))
+ (true (print "Truth!")))