Skip to content

Commit

Permalink
fix: make transpiler experimental
Browse files Browse the repository at this point in the history
  • Loading branch information
pgagnidze committed May 31, 2023
1 parent 95c9ebf commit 03e4e21
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 29 deletions.
6 changes: 3 additions & 3 deletions NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Check out the new [sysinfo.ena](./example/sysinfo.ena) program that shows variou
The design choices remain consistent with the principles discussed in the lectures and exercises,
adhering to established best practices and prioritizing simplicity in the syntax of common programming languages.

An additional feature is the transpiler option, which allows for the conversion of Ena code into Lua code.
An additional feature is the transpiler option (for testing only, functionality is not fully developed and may be inconsistent.), which allows for the conversion of Ena code into Lua code.
This enables users to visualize how the Ena code would appear in widely recognized programming languages.
Additionally, the Lua code can be further transpiled into languages such as Python, Typescript, and more.

Expand Down Expand Up @@ -97,7 +97,7 @@ options are:
| --trace | -t | Trace the program. |
| --result | -r | Show the result. |
| --pegdebug | -p | Run the PEG debugger. |
| --transpile | -tp | Transpile to Lua. |
| --transpile | -tp | Transpile to Lua. (experimental) |
| --translate | -tr | Translate messages to Georgian. |

For example:
Expand Down Expand Up @@ -150,7 +150,7 @@ Check out the [Issues](https://github.com/pgagnidze/ena/issues) for more details
- Added the CI/CD for the tests to ensure stability and quality.
- Developed a CLI (Command-Line Interface) tool that offers convenient options for users to interact with the project.
- Created a syntax highlighter specifically for Visual Studio Code, enhancing the code editing experience for users working with the project.
- Implemented the transpiler option, allowing the conversion of Ena code into Lua code, which enables users to evaluate and utilize the code in a more established programming language.
- Implemented the transpiler option (experimental), allowing the conversion of Ena code into Lua code, which enables users to evaluate and utilize the code in a more established programming language.

## References

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ options-ები მოიცავს:
| --trace | -t | მიჰყევით პროგრამის მსვლელობას. |
| --result | -r | აჩვენეთ შედეგი. |
| --pegdebug | -p | გაუშვით PEG დებაგერი. |
| --transpile | -tp | ტრანსპილაცია Lua-ში. |
| --transpile | -tp | ტრანსპილაცია Lua-ში. (ექსპერიმენტული) |
| --translate | -tr | თარგმნეთ წერილები ქართულ ენაზე. |

მაგალითისთვის:
Expand Down
6 changes: 3 additions & 3 deletions ena.lua
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,12 @@ if show.result then
io.stdout:write((show.translate and translator.success.showResult or "Result") .. ":\n", tostring(result), "\n\n")
end

-- transpile --
-- transpile: experimental --
if show.transpile then
local transpiledCode = transpiler.transpile(ast)
io.stdout:write(
(show.transpile and translator.success.showTranspile or "Transpiled") .. ":\n",
(show.translate and translator.success.showTranspile or "Transpiled") .. ":\n",
tostring(transpiledCode),
"\n\n"
"\n"
)
end
87 changes: 65 additions & 22 deletions ena/transpiler.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
--[[
This transpiler is experimental. It supports the following AST nodes:
- function, functionCall, block, if, while, arrayElement, newArray, statementSequence, assignment, local
- boolean, number, string, nil, print, exec, variable, emptyStatement, binaryOp, unaryOp, return
]]

local module = {}
local Transpiler = {}
local translator = require "ena.lang.translator"
Expand Down Expand Up @@ -78,20 +84,14 @@ local handlers = {
local index = transpiler:transpile(node.index, indentLevel)
return array .. "[" .. index .. "]"
end,
-- We use 'size' as a string expression to dynamically determine the size of the table
-- We use a metatable to provide a default value for all indices up to size
-- Note: This assumes that 'size' is a valid Lua expression and that it evaluates to a number
["newArray"] = function(transpiler, node, indentLevel, indent)
local size = transpiler:transpile(node.size, indentLevel)
local initialValue = transpiler:transpile(node.initialValue, indentLevel)
if type(size) == "string" then
-- We use 'size' as a string expression to dynamically determine the size of the table
-- We use a metatable to provide a default value for all indices up to size
-- Note: This assumes that 'size' is a valid Lua expression and that it evaluates to a number
return "(function()\n" ..
indent .. " local t = setmetatable({}, {__index = function() return " .. initialValue .. " end})\n" ..
indent .. " for i = 1, " .. size .. " do\n" ..
indent .. " t[i] = " .. initialValue .. "\n" ..
indent .. " end\n" ..
indent .. " return t\n" ..
indent .. "end)()"
return "newArray(" .. size .. ", " .. initialValue .. ")"
end
local arrayElements = {}
for _ = 1, size do
Expand Down Expand Up @@ -130,12 +130,8 @@ local handlers = {
return indent .. "print(" .. transpiler:transpile(node.toPrint, indentLevel) .. ")"
end,
["exec"] = function(transpiler, node, indentLevel, indent)
return "(function()\n" ..
indent .. ' local command = ' .. transpiler:transpile(node.command, indentLevel) .. '\n' ..
indent .. ' local file = assert(io.popen(command, "r"), "failed to execute command " .. command)\n' ..
indent .. ' local output = file:read("*all")\n' ..
indent .. ' return string.gsub(output, "^%s*(.-)%s*$", "%1")\n' ..
indent .. "end)()"
local command = transpiler:transpile(node.command, indentLevel)
return "exec(" .. command .. ")"
end,
["variable"] = function(transpiler, node, indentLevel, indent)
return node.value
Expand All @@ -155,10 +151,20 @@ local handlers = {
-- Check if either operand is a string or a variable
if node.firstChild.tag == "string" or node.firstChild.tag == "variable" or
node.secondChild.tag == "string" or node.secondChild.tag == "variable" then
-- Generate code that checks the type of the operands at runtime
return "(function() local a = " .. transpiler:transpile(node.firstChild, indentLevel) ..
"; local b = " .. transpiler:transpile(node.secondChild, indentLevel) ..
"; if type(a) == 'string' or type(b) == 'string' then return a .. b else return a + b end end)()"
-- Traverse the binary tree to collect all the operands of + operations
local args = {}
local stack = {node}
while #stack > 0 do
local current = table.remove(stack)
if current.tag == "binaryOp" and current.op == "+" then
table.insert(stack, current.firstChild)
table.insert(stack, current.secondChild)
else
table.insert(args, 1, transpiler:transpile(current, indentLevel))
end
end
-- Join the operands together in a single call to addOrConcat
return "addOrConcat(" .. table.concat(args, ", ") .. ")"
end
end
return transpiler:transpile(node.firstChild, indentLevel) ..
Expand Down Expand Up @@ -200,15 +206,52 @@ end
function module.transpile(ast)
local transpiler = Transpiler:new()
local luaCodeParts = {}
table.insert(
luaCodeParts,
[[
function newArray(size, initialValue)
local t = setmetatable({}, {__index = function() return initialValue end})
for i = 1, size do
t[i] = initialValue
end
return t
end
function exec(command)
local file = assert(io.popen(command, "r"), "failed to execute command " .. command)
local output = file:read("*all")
return string.gsub(output, "^%s*(.-)%s*$", "%1")
end
function addOrConcat(...)
local args = {...}
local result = args[1]
for i = 2, #args do
if type(result) == 'string' or type(args[i]) == 'string' then
result = result .. args[i]
else
result = result + args[i]
end
end
return result
end
]]
)
for _, node in ipairs(ast) do
table.insert(luaCodeParts, transpiler:transpile(node))
end
table.insert(luaCodeParts, "\nmain()")
table.insert(luaCodeParts, [[
main()
-- EXPERIMENTAL: This transpiler is for testing only. Functionality is not fully developed and may be inconsistent. --
]])
local luaCode = table.concat(luaCodeParts, "")
local georgianCharacters = replaceGeorgianCharacters(luaCode)
local replacedMain = string.gsub(georgianCharacters, "mthavari", "main")
return replacedMain

end

return module

0 comments on commit 03e4e21

Please sign in to comment.