# MoonPlus ![CI](https://github.com/pigpigyyy/MoonPlus/workflows/build-test/badge.svg) MoonPlus is a compiler with features from [Moonscript language](https://github.com/leafo/moonscript) 0.5.0 and implementing new features to make Moonscript more up to date. Since original Moonscript has been used to write web framework [lapis](https://github.com/leafo/lapis) and run a few business web sites like [itch.io](https://itch.io) and [streak.club](https://streak.club) with some large code bases. The original language is getting too hard to adopt new language features for those may break the stablility for existing applications. So MoonPlus is a new code base for pushing the language to go forward and may be a playground to try introducing new language syntax or programing paradigms to make Moonscript language more expressive and productive. ## Features * No other dependencies needed except modified **parserlib** library from Achilleas Margaritis with some performance enhancement. **lpeg** library is no longer needed. * Written in C++17. * Support full Moonscript language features, generate the same Lua codes with original compiler. * Reserve line numbers from Moonscript sources in compiled Lua codes to help with debugging. ## Installation Install [luarocks](https://luarocks.org), a package manager for Lua modules. Then install Lua module with ```sh > luarocks install moonplus ``` ## Usage ```Lua require("moonp")("main") -- require `main.moon` local moonp = require("moonp") print(moonp.to_lua[[ f = -> print "hello world" f! ]],{ implicit_return_root = true, reserve_line_number = false, lint_global = false }) ``` ## Changes The original Moonscript language 0.5.0 support can be found in the `0.5.0` branch. Moonscript with new features is in the master branch. Here are the new features introduced in MoonPlus. * Multi-line comment. * Usage for symbol `\` to escape new line. Will compile codes: ```Moonscript str = --[[ This is a multi line comment. It's OK. ]] strA \ -- comment 1 .. strB \ -- comment 2 .. strC func --[[ip]] "192.168.126.110", --[[port]] 3000 ```   to: ```Lua local str = strA .. strB .. strC func("192.168.126.110", 3000) ``` * Back call features with new operator and syntax. For example: ```Moonscript {1,2,3} \ |> map((x)-> x * 2) \ |> filter((x)-> x > 4) \ |> reduce(0, (a,b)-> a + b) \ |> print do (data) <- http.get "ajaxtest" body[".result"]\html data (processed) <- http.post "ajaxprocess", data body[".result"]\append processed print "done" ```   will be compiled to: ```Lua print(reduce(filter(map({ 1, 2, 3 }, function(x) return x * 2 end), function(x) return x > 4 end), 0, function(a, b) return a + b end)) do http.get("ajaxtest", function(data) body[".result"]:html(data) return http.post("ajaxprocess", data, function(processed) body[".result"]:append(processed) return print("done") end) end) end ``` * Existential operator support. Generate codes from: ```Moonscript func?! x = tab?.value print abc?["hello world"]?.xyz if print and x? print x ```   to: ```Lua if func ~= nil then func() end local x if tab ~= nil then x = tab.value end print((function() if abc ~= nil then local _obj_0 = abc["hello world"] if _obj_0 ~= nil then return _obj_0.xyz end return nil end return nil end)()) if print and (x ~= nil) then print(x) end ``` * More usages for `import` keyword. Will compile codes from: ```Moonscript import 'module' import "module.part" import "d-a-s-h-e-s" import "player" as Player import "lpeg" as {:C, :Ct, :Cmt} ```   to: ```Lua local module = require('module') local part = require("module.part") local d_a_s_h_e_s = require("d-a-s-h-e-s") local Player = require("player") local C, Ct, Cmt do local _obj_0 = require("lpeg") C, Ct, Cmt = _obj_0.C, _obj_0.Ct, _obj_0.Cmt end ``` * Can do slash call with Lua keywords. Generate codes from: ```Moonscript c.repeat.if\then("xyz")\else res ```   to: ```Lua local _call_3 = c["repeat"]["if"] local _call_4 = _call_3["then"](_call_3, "xyz") _call_4["else"](_call_4, res) ``` * Feature of `Reusing variable` which helps generate reduced Lua codes. For example, MoonPlus will generate codes from: ```Moonscript with leaf .world 1,2,3 with leaf g = .what.is.this print g for x in *something print x ```   to: ```Lua leaf.world(1, 2, 3) do local g = leaf.what.is.this print(g) end for _index_0 = 1, #something do local x = something[_index_0] print(x) end ```   instead of: ```lua do local _with_0 = leaf _with_0.world(1, 2, 3) end do local _with_0 = leaf local g = _with_0.what.is.this end local _list_0 = something for _index_0 = 1, #_list_0 do local x = _list_0[_index_0] print(x) end ``` * Expression list appears at the middle of code block is not allowed. For codes like: ```Moonscript -- Moonscript 0.5.0 f = (x)-> "abc",123 -- valid meaningless codes x + 1 ``` in original Moonscript compiles to: ```Lua local f f = function(x) local _ = "abc", 123 -- report error in MoonPlus return x + 1 end ``` This feature may lead to some silenced errors. For example: ```Moonscript -- expected codes tree\addChild with Node! \addChild subNode -- in original Moonscript, codes will still run after adding a break tree\addChild with Node! \addChild subNode ``` the original Moonscript will compile these codes to: ```Lua -- expected codes tree:addChild((function() do local _with_0 = Node() _with_0:addChild(subNode) return _with_0 end end)()) -- codes added with a break will still run local _ -- report error in MoonPlus instead of creating do -- an anonymous function to bind the object method local _base_0 = tree local _fn_0 = _base_0.addChild _ = function(...) return _fn_0(_base_0, ...) end end do local _with_0 = Node() _with_0:addChild(subNode) end ``` ## Standalone Compiler Usage Test compiler with `make test`. Run `moonp` complier in project folder with: ```shell make ./moonp -h ``` ## License MIT