diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 60c98fa..ac7a661 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -37,6 +37,20 @@ local compiler_index = { self._indent = self._indent + amount end, + pretty = function(self, tbl) + local out = {} + for _, line in ipairs(tbl) do + if type(line) == "table" then + self:indent(1) + table.insert(out, indent_char..self:pretty(line)) + self:indent(-1) + else + table.insert(out, line) + end + end + return table.concat(out, "\n"..self:ichar()) + end, + has_name = function(self, name) for i = #self._scope,1,-1 do if self._scope[i][name] then return true end @@ -110,10 +124,13 @@ local compiler_index = { local to_bind = {} local final_names = {} for _, name in ipairs(names) do - if type(name) == "table" then - name = name[2] + if ntype(name) == ":" then + name = self:value(name[2]) to_bind[name] = true + else + name = self:value(name) end + table.insert(final_names, name) self:put_name(name) end @@ -211,6 +228,33 @@ local compiler_index = { return ("while %s do\n%s\n%send"):format(self:value(cond), self:block(block, 1), ichr) end, + name_list = function(self, node) + return table.concat(self:values(node), ", ") + end, + + comprehension = function(self, node) + local _, exp, names, iter, when = unpack(node) + local insert = ("table.insert(tmp, %s)"):format(self:value(exp)) + + if when then + insert = { + ("if %s then"):format(self:value(when)), { + insert + }, "end" + } + end + + return self:pretty{ + "(function()", { + "local tmp = {}", + ("for %s in %s do"):format(self:name_list(names), self:value(iter)), + type(insert) == "table" and insert or {insert}, + "end", + "return tmp" + }, "end)()" + } + end, + block = function(self, node, inc) self:push() if inc then self:indent(inc) end @@ -302,6 +346,9 @@ local compiler_index = { exp = function(self, node) local values = {} for i = 2, #node do + if i % 2 == 1 and node[i] == "!=" then + node[i] = "~=" + end table.insert(values, self:value(node[i])) end return table.concat(values, " ") @@ -329,6 +376,11 @@ local compiler_index = { return node end, + self = function(self, node) + local _, val = unpack(node) + return "self."..self:value(val) + end, + -- a list of values values = function(self, items, start) start = start or 1 diff --git a/moonscript/parse.lua b/moonscript/parse.lua index dbfd8e8..dd7c202 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -124,6 +124,14 @@ local build_grammar = wrap(function() return Space * word end + local function op(word) + if word:match("^%w*$") then + keywords[word] = true + end + return Space * C(word) + end + + local function sym(chars) return Space * chars end @@ -160,6 +168,8 @@ local build_grammar = wrap(function() return false end + local Name = sym"@" * Name / mark"self" + Name + -- make sure name is not a keyword local Name = Cmt(Name, function(str, pos, name) if keywords[name] then return false end @@ -187,7 +197,7 @@ local build_grammar = wrap(function() OutBlock = Cmt("", pop_indent), Import = key"import"* Ct(ImportNameList) * key"from" * Exp / mark"import", - ImportName = (Ct(C(sym":") * Name) + Name), + ImportName = (Ct(sym":" / trim * Name) + Name), ImportNameList = ImportName * (sym"," * ImportName)^0, NameList = Name * (sym"," * Name)^0, @@ -198,14 +208,24 @@ local build_grammar = wrap(function() While = key"while" * Exp * key"do"^-1 * Body / mark"while", + Comprehension = sym"[" * Exp * key"for" * Ct(NameList) * + key"in" * Exp * + (key"when" * Exp)^-1 * + sym"]" / mark"comprehension", + Assign = Ct(AssignableList) * sym"=" * Ct(TableBlock + ExpList) / mark"assign", + -- we can ignore precedence for now + OtherOps = op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<" + op">", + Assignable = Cmt(Chain, check_assignable) + Name, AssignableList = Assignable * (sym"," * Assignable)^0, - Exp = Ct(Term * (FactorOp * Term)^0) / flatten_or_mark"exp", + Exp = Ct(Factor * (OtherOps * Factor)^0) / flatten_or_mark"exp", + Factor = Ct(Term * (FactorOp * Term)^0) / flatten_or_mark"exp", Term = Ct(Value * (TermOp * Value)^0) / flatten_or_mark"exp", Value = TableLit + + Comprehension + ColonChain + Ct(KeyValueList) / mark"table" + Assign + FunLit + String + @@ -297,48 +317,17 @@ local build_grammar = wrap(function() end) -local grammar = build_grammar() - -- parse a string -- returns tree, or nil and error message function string(str) local g = build_grammar() - return grammar:match(str) + return g:match(str) end - -local program = [[ -if two_dads - do something - if yum - heckyes 23 - -print 2 - -print dadas - -{1,2,3,4} - -(a,b) -> - throw nuts - -print 100 - -]] - -local program = [[ - -hi = (a) -> print a - -if true - hi 100 - -]] - local program3 = [[ -- hello class Hello - @something = 2323 + @something: 2323 hello: () -> print 200 diff --git a/tests/inputs/lists.moon b/tests/inputs/lists.moon new file mode 100644 index 0000000..d415692 --- /dev/null +++ b/tests/inputs/lists.moon @@ -0,0 +1,13 @@ + +hi = [x*2 for _, x in ipairs{1,2,3,4}] + +items = {1,2,3,4,5,6} + +mm = [@x for @x in ipairs items] + +[z for z in ipairs items when z > 4] + +rad = [{a} for a in ipairs { + 1,2,3,4,5,6, +} when good_number a] + diff --git a/tests/outputs/lists.lua b/tests/outputs/lists.lua new file mode 100644 index 0000000..f278f9d --- /dev/null +++ b/tests/outputs/lists.lua @@ -0,0 +1,52 @@ +local hi = (function() + local tmp = {} + for _, x in ipairs({ + 1, + 2, + 3, + 4 +}) do + table.insert(tmp, x * 2) + end + return tmp +end)() +local items = { + 1, + 2, + 3, + 4, + 5, + 6 +} +local mm = (function() + local tmp = {} + for self.x in ipairs(items) do + table.insert(tmp, self.x) + end + return tmp +end)(); +(function() + local tmp = {} + for z in ipairs(items) do + if z > 4 then + table.insert(tmp, z) + end + end + return tmp +end)() +local rad = (function() + local tmp = {} + for a in ipairs({ + 1, + 2, + 3, + 4, + 5, + 6 +}) do + if good_number(a) then + table.insert(tmp, { a }) + end + end + return tmp +end)() \ No newline at end of file