Releases: leafo/moonscript
Release list
v0.7.0
This update includes a bunch of syntax bug fixes and cleanups, with a few new features and an enhanced linter. This will be the last release using LPeg, future versions will use the new parser.
Destructuring updates
Function arguments can be destructured
A function argument can now be written as a table literal to destructure the value passed in. The destructuring patterns are the same ones supported by assignment, including nested patterns, numeric keys, and @field targets:
dist = ({x: x1, y: y1}, {x: x2, y: y2}) ->
math.sqrt (x2 - x1)^2 + (y2 - y1)^2
class Point
new: ({x: @x, y: @y}) =>
render = (name, {:width, :height}, scale=1, ...) ->
print name, width, height, scale, ...The argument becomes an internal name and the fields are unpacked at the top of the function body:
render = function(name, _arg_0, scale, ...)
local width, height
width, height = _arg_0.width, _arg_0.height
if scale == nil then
scale = 1
end
return print(name, width, height, scale, ...)
endDestructured arguments always declare fresh locals, so a name in the pattern shadows an enclosing local of the same name instead of assigning to it.
Argument initialization now happens in the order the arguments are written, so a default value can reference a name that an earlier argument destructured:
scaled = ({:base}, amount = base * 2) -> base + amountBecause the destructured names are bound at the top of the body, a name in a pattern can not collide with another argument. ({:a}, a) -> and ({:self}) => are now compile errors.
Destructuring in multiple assignment
Destructuring can now be used mixed in with other names in multiple assignment (#367, #304):
num, {:message} = two_values!
head, {:content}, tail = mix!
{value: built}, {:status} = builder\build!Previously the assignment was split into separate statements, which broke destructuring output.
Better validation of destructuring targets
The names extracted by a destructuring pattern are now checked with the same rule the parser uses for assignment targets. @@class_field, index expressions, and slices are now allowed:
{x: obj.a, y: obj["b"], z: @prop, w: @@cls_prop} = tDestructuring into something that can never be assigned to is now a compile error instead of generating broken code:
{foo!} = thingreportsCan't destructure into chain ending in call{...} = thingreportsCan't destructure into '...'
Linter updates
Lint stages
The linter's checks are now organized into named stages: global_access, unused, constant_assign, and import_overwrite. Every stage runs by default. moonc --lint-stage limits reporting to the named stage, and --exclude-lint-stage reports everything but the named stage. Both options can be repeated, and they can not be combined.
moonc -l --lint-stage global_access --lint-stage unused .
moonc -l --exclude-lint-stage import_overwrite .New checks
import_overwrite reports an import that clobbers a name that is already bound in scope:
insert = "hello"
f = ->
import insert from table -- import overwrites existing binding `insert`constant_assign reports writing to a name that is tagged as constant. In this version, only the names created by import are tagged as constant. For this release, constant names are only checked in the linter. In the future we will make constant violation a compiler error.
import insert from table
insert = 5 -- assigning to constant `insert`Compact lint output
moonc --lint-format compact writes one line per issue in the familiar file:line:column: message shape, with the stage name appended, for editors and tools that parse compiler output (#465):
$ moonc -l --lint-format compact lint_example.moon
lint_example.moon:7:5: accessing global `my_nmuber` [global_access]Standard library updates
New class introspection functions
The moon module has four new functions, documented in the standard library reference:
is_class(value)tests if a value is a MoonScript class tableis_instance(value)tests if a value is an instance of a MoonScript classis_instance_of(value, cls)tests if a value is an instance ofclsor any of its parents. It throws an error ifvalueis not an instanceis_subclass_of(cls, parent)tests ifclsinherits fromparent. A class is not a subclass of itself. It throws an error ifclsis not a class
Unlike the old is_object, these can tell classes, instances, and __base tables apart.
is_object is now deprecated. It returns truthy for instances, classes, and __base tables, so it can not be used to distinguish them.
BREAKING: moon.type no longer returns the class object for a class
moon.type now returns the string "class" when given a class, and it only returns the class object for actual instances. Previously a class returned itself, and a __base table returned the class it belonged to, which made it impossible to tell an instance from the class it came from.
class MyClass
type MyClass! -- MyClass (unchanged)
type MyClass -- "class" (was MyClass)
type MyClass.__base -- "table" (was MyClass)BREAKING: changes to moonscript.util
These are internal helpers that were never documented, but they were reachable:
util.moon.typeis nowutil.mtype, to avoid the confusion with thetypefunction in themoonmoduleutil.moon.is_objectremoved, replaced byutil.moon.is_classandutil.moon.is_instanceutil.moon.is_aremoved, replaced byis_instance_ofin themoonmodule
Code Generation
Interpolated strings and nested expressions are parenthesized correctly
The compiler now knows Lua's operator precedence when writing out an expression, and it adds parentheses when a nested expression would otherwise be regrouped by the surrounding operators. String interpolation is the most common way to get a nested expression, and it was silently generating the wrong math (#320):
x = 10 / "#{b}.5"Before:
local x = 10 / tostring(b) .. ".5"After:
local x = 10 / (tostring(b) .. ".5")Because .. is right associative in Lua, an interpolated string on the left hand side of a .. is grouped as well. This is observable through the __concat metamethod:
prefix = "id: #{id}, " .. restBefore:
local prefix = "id: " .. tostring(id) .. ", " .. restAfter:
local prefix = ("id: " .. tostring(id) .. ", ") .. restPrefix operators are grouped in update assignments and switches
The check for whether a value needs to be wrapped in parentheses did not account for the prefix operators #, -, not, and ~, which parse greedily. An update assignment or a switch case with one of them on the left would compile to the wrong grouping (#457):
count -= #datum + 1
total *= -x + 1
flag and= not a or bBefore:
local count = count - #datum + 1
local total = total * -x + 1
local flag = flag and not a or bAfter:
local count = count - (#datum + 1)
local total = total * (-x + 1)
local flag = flag and (not a or b)Expression lines no longer use _
When an expression appears where a statement is expected, the compiler assigns it to a throwaway variable. It used to use the name _, which would clobber a variable of that name in the user's code (#309). It now uses an autogenerated _scrap_N name.
_ = 5
tbl.field
print _Before:
local _ = 5
_ = tbl.field
return print(_)After:
local _ = 5
local _scrap_0 = tbl.field
return print(_)local in a class body is hoisted
A local declaration is now hoisted to the top of the class body, so that methods defined on the class will have the local variable in scope. Previously only the names from regular assigns were hoisted.
class Counter
local cache
update: => cache or= "something..."Bug Fixes
- Updated all compiler thrown errors to ensure they include positional information so the error messages are more informative
- Trailing
continuein a loop body generated invalid Lua (breakwas followed by more statements) a, b = x\some_methodand other assignments of a single complex value to multiple names silently dropped every name after the first- A
\stubwithout a base crashed the compiler with an internal error. Inside awithblock it now uses thewithvalue, and outside of one it reportsShort-colon syntax must be called within a with block(#428) continueoutside of a loop is now a compile error with a line number instead of an internal error with a traceback- Destructuring against the result of an
if,switch,for,while,do,with, or comprehension declared the names in the wrong scope (#449, #411, #391, #451) - Destructuring against a receiver that can not be indexed directly, like
...,nil,not thing,#thing, or a table literal, generated invalid Lua - An expression inside a string interpolation that can't be parsed now throws a parse error instead of putting the malformed code as raw characters in the string
- Fixed broken
moonc --versionwhich reported missing argument instead of printing version (#471) - Errors raised without a position now report the position of the statement being compiled, instead of no position at all
- An internal compiler error no longer throws a second error while trying to r...
v0.6.0
New Features
Command Line Improvements
- Switched from alt_getopt to argparse - Both
moonandmooncnow use argparse for argument parsing, providing better help messages via--helpand more robust option handling - Added
-e/--executeflag tomoon- Execute MoonScript code directly from the command line:moon -e "print 'Hello World'" - New
--transformoption formoonc- Allows custom AST transformations before compilation by specifying a module that receives and returns the syntax tree - Improved
-(stdin) handling - Now properly enforces that-must be the only argument
moonc Option Renames
-wis now also available as--watch-lis now also available as--lint-tis now also available as--output-to
New Tools
- moon-tags - New script for generating ctags-compatible tag files for MoonScript, with support for:
- Class definitions
- Class methods
- Top-level function definitions (exported via
{:func}pattern) - Lapis route detection (
--lapisflag) - Optional line numbers (
--include-lineflag) - Optionally skip header (
--no-headerflag)
Utility Improvements
moon.p()now prints multiple arguments - Pass multiple values and each will be dumpedutil.dumpshows class names - When dumping objects, the class name is displayed (e.g.,<MyClass>{...})
Compiler Enhancements
- Lua keyword property access on self - Properties with Lua keyword names (like
@thenor@@then) now compile correctly using bracket notation instead of invalidself.then
Bug Fixes
- Fixed ambiguous Lua generation after
import- Semicolons are now correctly inserted when the next line starts with(, preventing parsing ambiguity - Fixed update operators with complex chain indexes - Expressions like
a[func()].x += 1now correctly lift the index expression to avoid double evaluation - Exit with proper error code -
moonnow exits with code 1 when the executed script fails - Fixed
moonc -- Reading from stdin now works correctly - Removed accidental debug print - Removed stray
print file, timein watcher code dump.treereturns string - Now returns the string instead of printing directly- Removed noisy "Built" message - Single file compilation no longer prints "Built" to stderr
Internal Changes
- Migrated CI from Travis to GitHub Actions
- Added comprehensive compiler and transform specs
- Improved binary building workflow for Windows and Linux
- Better error messages for invalid destructure assignments
- Updated
splat.moonto use argparse, added--strip-prefixoption
MoonScript v0.5.0
Windows binary: https://github.com/leafo/moonscript/releases/tag/win32-v0.5.0
Syntax updates
Function calls
Function calls with parentheses can now have free whitespace around the
arguments. Additionally, a line break may be used in place of a comma:
my_func(
"first arg"
=>
print "some func"
"third arg", "fourth arg"
)Function argument definitions
Just like the function all update, function argument definitions have no
whitespace restrictions between arguments, and line breaks can be used to
separate arguments:
some_func = (
name
type
action="print"
) =>
print name, type, actionAdditions
elseifcan be used part of anunlessblock (nymphium)unlessconditional expression can contain an assignment like anifstatement (#251)- Lua 5.3 bitwise operator support (nymphium) (Kawahara Satoru)
- Makefile is Lua version agnostic (nymphium)
- Lint flag can be used with
mooncwatch mode (ChickenNuggers) - Lint exits with status 1 if there was a problem detected (ChickenNuggers)
- Compiler can be used with lulpeg
Bug Fixes
- Slice boundaries can be full expressions (#233)
- Destructure works when used as loop variable in comprehension (#236)
- Proper name local hoisting works for classes again (#287)
- Quoted table key literals can now be parsed when table declaration is in single line (#286)
- Fix an issue where
elsecould get attached to wrongifstatement (#276) - Loop variables will no longer overwrite variables of the same name in the same scope (egonSchiele)
- A file being deleted will not crash polling watch mode (ChickenNuggers)
- The compiler will not try to compile a directory ending in
.moon(Gskartwii) - alt_getopt import works with modern version (Jon Allen)
- Code coverage not being able to find file from chunk name
win32-v0.5.0
v0.4.0
You can now find windows binaries through GithHub's releases. See win32-v0.4.0
Changes to super
super now looks up the parent method via the class reference, instead of a
(fixed) closure to the parent class.
Given the following code:
class MyThing extends OtherThing
the_method: =>
super!In the past super would compile to something like this:
_parent_0.the_method(self)Where _parent_0 was an internal local variable that contains a reference to
the parent class. Because the reference to parent is an internal local
variable, you could never swap out the parent unless resorting to the debug
library.
This version will compile to:
_class_0.__parent.__base.the_method(self)Where _class_0 is an internal local variable that contains the current class (MyThing).
Another difference is that the instance method is looked up on __base instead
of the class. The old variation would trigger the metamethod for looking up on
the instance, but a class method of the same name could conflict, take
precedence, and be retuned instead. By referencing __base directly we avoid
this issue.
Super on class methods
super can now be used on class methods. It works exactly as you would expect.
class MyThing extends OtherThing
@static_method: =>
print super!Calling super will compile to:
_class_0.__parent.static_method(self)Improved scoping for super
The scoping of super is more intelligent. You can warp your methods in other
code and super will still generate correctly. For example, syntax like this
will now work as expected:
class Sub extends Base
value: if debugging
=> super! + 100
else
=> super! + 10
other_value: some_decorator {
the_func: =>
super!
}super will refer to the lexically closest class declaration to find the name
of the method it should call on the parent.
Bug Fixes
- Nested
withblocks used incorrect ref (#214 by @geomaster) - Lua quote string literals had wrong precedence (#200 by @nonchip)
- Returning from
withblock would generate tworeturnstatements (#208) - Including
returnorbreakin acontinuewrapped block would generate invalid code (#215 #190 #183)
Other
- Refactor transformer out into multiple files
mooncommand line script rewritten in MoonScriptmoonscript.parse.build_grammarfunction for getting new instance of parser grammar- Chain AST updated to be simpler
win32-v0.4.0
MoonScript v0.2.4
I'm happy to announce MoonScript version 0.2.4, the CoffeeScript inspired language that compiles to Lua. It's been about 5 months since the last release.
As always, if you've got any questions or want to tell me about how you are using MoonScript you can email me or contact me on twitter.
You can find the full release notes on my blog: http://leafo.net/posts/moonscript_v024.html
Changes
- The way the subtraction operator works has changed. There was always a little confusion as to the rules regarding whitespace around it and it was recommended to always add whitespace around the operator when doing subtraction. Not anymore. Hopefully it now works how you would expect. (
a-bcompiles toa - band nota(-b)anymore). - The
moonlibrary is no longer sets a global variable and instead returns the module. Your code should now be:
moon = require "moon"- Generated code will reuse local variables when appropriate. Local variables are guaranteed to not have side effects when being accessed as opposed to expressions and global variables. MoonScript will now take advantage of this and reuse those variable without creating and copying to a temporary name.
- Reduced the creation of anonymous functions that are called immediately.
MoonScript uses this technique to convert a series of statements into a single expression. It's inefficient because it allocates a new function object and has to do a function call. It also obfuscates stack traces. MoonScript will flatten these functions into the current scope in a lot of situations now. - Reduced the amount of code generated for classes. Parent class code it left out if there is no parent.
New Things
- You can now put line breaks inside of string literals. It will be replaced with
\nin the generated code.
x = "hello
world"- Added
moonscript.basemodule. It's a way of including themoonscriptmodule without automatically installing the moonloader. - You are free to use any whitespace around the name list in an import statement. It has the same rules as an array table, meaning you can delimit names with line breaks.
import a, b
c, d from z- Added significantly better tests. Previously the testing suite would only verify that code compiled to an expected string. Now there are unit tests that execute the code as well. This will make it easier to change the generated output while still guaranteeing the semantics are the same.
Bug Fixes
bis not longer treated as self assign in{ a : b }- load functions will return
nilinstead of throwing error, as described in documentation - fixed an issue with
moon.mixinwhere it did not work as described
Other Stuff
Libraries
Some updates for libraries written in MoonScript:
- Lapis, the MoonScript powered web framework has come out with version
0.0.2. magick, LuaJIT FFI bindings to ImageMagickweb_sanitize, HTML sanitization
Games
Ludum Dare happened again, and I wrote another game in MoonScript:
Thanks
Thanks to everyone who provided feedback for this release. See you next time.
MoonScript v0.2.3-2
Fixed bug with moonloader not loading anything
MoonScript v0.2.3
Today marks MoonScript version 0.2.3, the CoffeeScript inspired language that compiles to Lua. It's been about 3 months since last release. I've got a couple new features, fixes, Lua 5.2 support and a backwards incompatible change.
You can follow me on twitter for updates or complaints. Also if you're using MoonScript I'd love to hear about it: leafot@gmail.com.
You can find the full release notes on my blog: http://leafo.net/posts/moonscript_v023.html
Changes
- For loops when used as expressions will no longer discard nil values when accumulating into an array table. This is a backwards incompatible change. Instead you should use the
continuekeyword to filter out iterations you don't want to keep. Read more here. - The
moonscriptmodule no longer sets a global value formoonscriptand instead returns it. You should update your code:
moonscript = require "moonscript"New Things
- Lua 5.2 Support. The compiler can now run in either Lua 5.2 and 5.1
- A switch
whenclause can take multiple values, comma separated. - Added destructuring assignment.
- Added
local *(andlocal ^) for hoisting variable declarations in the current scope - List comprehensions and line decorators now support numeric loop syntax
Bug Fixes
- Numbers that start with a dot, like
.03, are correctly parsed - Fixed typo in
foldlibrary function - Fix declaration hoisting inside of class body, works the same as
local *now
Other Stuff
MoonScript has made its way into GitHub. .moon files should start to be recognized in the near future.
Web
I've started a couple interesting projects for MoonScript as a web programming language.
- Lapis -- A MoonScript friendly web framework. Includes application routing, a HTML construction MoonScript DSL, and a basic ORM.
cloud_storage-- A MoonScript/Lua module for interacting with Google Cloud Storage.
Using the following I've created a community powered Lua rock hosting website called MoonRocks:
http://rocks.moonscript.org. (source)
Compiled MoonScript runs inside of the nginx distribution OpenResty. I created a created a Lua rock for running OpenResty on Heroku in conjunction with my Heroku Lua buildpack.
Games
Ludum Dare happened again, two games were created in
MoonScript:
- X-Moon
- Event Horizon -- by SelectricSimian
Additionally, Michael F has created a game engine, BoxEngine, which natively supports MoonScript.
Thanks
Thanks to everyone who provided feedback for this release. See you next time.
MoonScript v0.2.2
Today marks MoonScript version 0.2.2, the CoffeeScript inspired language that compiles to Lua. It's been approximately 11 months since the last release, and I'd like to apologize for the long gap. Hopefully we'll see more frequent updates in the future.
You can follow me on twitter for updates or complaints. Also if you're
using MoonScript I'd love to hear about it: leafot@gmail.com.
You can find the full release notes on my blog: http://leafo.net/posts/moonscript_v022.html
Changes
- Compiled files will now implicitly return their last statement. Be careful, this might change what
requirereturns.
New Things
The Language
- Added
continuekeyword for skipping the current iteration in a loop. - Added string interpolation.
- Added
doexpression and block. - Added
unlessas a block and line decorator. Is the inverse ofif. - Assignment can be used in an
ifstatement's expression. - Added
or=andand=operators. @@can be prefixed in front of a name to access that name withinself.__class@and@@can be used as values to referenceselfandself.__class.- In class declarations it's possible to assign to the class object instead of the instance metatable by prefixing the key with
@. - Class methods can access locals defined within the body of the class declaration.
- Super classes are notified when they are extended from with an
__inheritedcallback. - Classes can now implicitly return and be expressions.
localkeyword returns, can be used for forward declaration or shadowing a variable.- String literals can be used as keys in table literals.
- Call methods on string literals without wrapping in parentheses:
"hello"\upper! - Table comprehensions can return a single value that is unpacked into the key and value.
- The expression in a
withstatement can now be an assignment, to give a name to the expression that is being operated on.
The API
- The
loadfunctions can take an optional last argument of options.
The Tools
- The online compiler now runs through a web service instead of emscripten, should work reliably on any computer now.
- Windows binaries have been updated.
Bug Fixes
- Significantly improved the line number rewriter. It should now accurately report all line numbers.
- Generic
forloops correctly parse for multiple values as defined in Lua. - Update expressions don't fail with certain combinations of precedence.
- All statements/expressions are allowed in a class body, not just some.
x = "hello" if somethingwill extract the declaration ofxif it's not in scope yet. Preventing an impossible to access variable from being created.- varargs,
..., correctly bubble up through automatically generated anonymous functions. - Compiler doesn't crash if you try to assign something that isn't assignable.
- Numerous other small fixes. See commit log.
Other Stuff
Since the past release I've written quite a bit of MoonScript. I wrote four games, feel free to check out the source code:
I've written a tutorial for installing MoonScript on the three main platforms, Windows, OSX, and Linux.
I've written a script and guide for running Lua on Heroku. Which lets us also run MoonScript. This opens up quite a few opportunities, more on that later.
Bitbucket now highlights MoonScript files. If you'd like to see MoonScript on GitHub say something here: github-linguist/linguist#246.
Thanks
That's all for this release. Thanks to everyone who submitted bugs and patches and provided feedback on GitHub. See you next release.