mirror of
https://github.com/leafo/moonscript.git
synced 2024-11-22 02:44:23 +00:00
documentation
This commit is contained in:
parent
632262b323
commit
10d134a369
127
README.md
127
README.md
@ -1 +1,126 @@
|
||||
# moonscript
|
||||
# MoonScript
|
||||
|
||||
MoonScript is a programmer friendly language that compiles into
|
||||
[Lua](http://ww.lua.org/). It gives you the power of the fastest scripting
|
||||
language combined with a rich set of features:
|
||||
|
||||
- Provides a clean syntax using significant whitespace that avoids all the
|
||||
keyword noise typically seen in a Lua script.
|
||||
|
||||
- Adds table comprehensions, implicit return on functions, classes,
|
||||
inheritance, scope management statements `import` & `export`, and a
|
||||
convenient object creation statement called `with`.
|
||||
|
||||
- Can be loaded directly from a Lua script without an intermediate compile
|
||||
step. It even knows how to tell you where errors occurred in the original
|
||||
file when they happen.
|
||||
|
||||
Creating an instance of a instance of a class and calling a method:
|
||||
|
||||
class Thing
|
||||
name: "unknown"
|
||||
|
||||
class Person extends Thing
|
||||
say_name: -> print "Hello, I am", @name
|
||||
|
||||
with Person!
|
||||
.name = "Moonscript"
|
||||
\say_name!
|
||||
|
||||
MoonScript can either be compiled into Lua and run at a later time, or it
|
||||
can be dynamically compiled and run using the *moonloader*. It's as simple
|
||||
`require "moon"` in order to have Lua understand how to load and run any
|
||||
MoonScript file.
|
||||
|
||||
The command line tools also let you run MoonScript directly from the
|
||||
command line, like any first-class scripting language.
|
||||
|
||||
## Installation
|
||||
|
||||
## Installing with LuaRocks
|
||||
|
||||
The easiest way to install is to use Lua rocks and the provide rockspec.
|
||||
|
||||
LuaRocks can be obtained [here](http://www.luarocks.org/) or from your package
|
||||
manager.
|
||||
|
||||
After it is installed, run the following in a terminal:
|
||||
|
||||
~> wget https://raw.github.com/leafo/moonscript/master/moonscript-dev-1.rockspec
|
||||
~> luarocks install moonscript-dev-1.rockspec
|
||||
|
||||
This will provide the `moon` and `moonc` binaries along with the `moonscript`
|
||||
Lua module.
|
||||
|
||||
### Optional
|
||||
|
||||
If you are on Linux and want to run *watch* mode, which compiles `moon` files to
|
||||
`lua` files as they are changed, you can install
|
||||
[linotify](https://github.com/hoelzro/linotify).
|
||||
|
||||
|
||||
# Learning
|
||||
|
||||
Read the [reference manual](docs/index.md).
|
||||
|
||||
## Overview of Differences & Highlights
|
||||
|
||||
A more detailed overview of the syntax can be found in the
|
||||
[documentation](docs/index.md).
|
||||
|
||||
* Whitespace sensitive blocks defined by indenting
|
||||
* All variable declarations are local by default
|
||||
* `export` keyword to declare global variables, `import` keyword to make local
|
||||
copies of values from a table
|
||||
* Parentheses are optional for function calls, similar to Ruby
|
||||
* Fat arrow, `=>`, can be used to create a function with a self argument
|
||||
* `@` can be prefixed in front of a name to refer to that name in `self`
|
||||
* `!` operator can be used to call a function with no arguments
|
||||
* Implicit return on functions based on the type of last statement
|
||||
* ':' is used to separate key and value in table literals instead of `=`
|
||||
* Newlines can be used as table literal entry delimiters in addition to `,`
|
||||
* `\` is used to call a method on an object instead of `:`
|
||||
* `+=`, `-=`, `/=`, `*=`, `%=` operators
|
||||
* `!=` is an alias for `~=`
|
||||
* Table comprehensions, with convenient slicing and iterator syntax
|
||||
* Lines can be decorated with for loops and if statements at the end of the line
|
||||
* If statements can be used as expressions
|
||||
* Class system with inheritance based on metatable's `__index` property
|
||||
* Constructor arguments can begin with `@` to cause them to automatically be
|
||||
assigned to the object
|
||||
* Magic `super` function which maps to super class method of same name in a
|
||||
class method
|
||||
* `with` statement lets you access anonymous object with short syntax
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
The following are used in MoonScript:
|
||||
|
||||
* [Lua 5.1](http://lua.org)
|
||||
* [LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/lpeg.html)
|
||||
* [LuaFileSystem](http://keplerproject.github.com/luafilesystem/)
|
||||
* [alt-getopt](http://luaforge.net/projects/alt-getopt/)
|
||||
* and optionally on Linux [linotify](https://github.com/hoelzro/linotify)
|
||||
|
||||
## License (MIT)
|
||||
|
||||
Copyright (C) 2011 by Leaf Corcoran
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
411
docs/index.md
411
docs/index.md
@ -2,14 +2,374 @@
|
||||
|
||||
MoonScript compiles to Lua
|
||||
|
||||
## Assignment
|
||||
|
||||
Unlike Lua, there is no local keyword. All assignments to names that are not
|
||||
already defined will be declared as local to the scope of that declaration. If
|
||||
you wish to create a global variable it must be done using the `export`
|
||||
keyword.
|
||||
|
||||
hello = "world"
|
||||
a,b,c = 1, 2, 3
|
||||
|
||||
|
||||
## Update Assignment
|
||||
|
||||
`+=`, `-=`, `/=`, `*=`, `%=` operators have been added for updating a value by
|
||||
a certain amount have been added. They are aliases for their expanded
|
||||
equivalents.
|
||||
|
||||
x += 10
|
||||
|
||||
Is the same as:
|
||||
|
||||
x = x + 10
|
||||
|
||||
## Comments
|
||||
|
||||
Like Lua, comments start with `--` and continue to the end of the line.
|
||||
|
||||
## Literals & Operators
|
||||
|
||||
MoonScript supports all the same primitive literals as Lua and uses the same
|
||||
syntax. This applies to numbers, strings, booleans, and `nil`.
|
||||
|
||||
MoonScript also supports all the same binary and unary operators. `!=` is also
|
||||
added as an alias of `~=`.
|
||||
|
||||
## Function Literals
|
||||
|
||||
All functions are created using a function expression. A simple function is
|
||||
denoted using the arrow: `->`
|
||||
|
||||
my_function = ->
|
||||
my_function() -- does nothing
|
||||
|
||||
|
||||
The body of the function can either by one statement placed directly after the
|
||||
arrow, or it can be a series of statements indented on the following line:
|
||||
|
||||
func_a = -> print "hello world"
|
||||
|
||||
func_b = ->
|
||||
value = 100
|
||||
print "The value:", value
|
||||
|
||||
If a function has no arguments, it can be called using the `!` operator,
|
||||
instead of empty parentheses.
|
||||
|
||||
We can call the two functions above like so:
|
||||
|
||||
func_a! -- equivalent to `func_a()`
|
||||
func_b!
|
||||
|
||||
Functions with arguments can be created by preceding the arrow with a list of
|
||||
argument names in parentheses:
|
||||
|
||||
sum = (x, y) -> print "sum", x + y
|
||||
|
||||
Functions can be called by listing the values of the arguments after the name
|
||||
of the variable where the function is stored:
|
||||
|
||||
sum 10, 20
|
||||
|
||||
Functions will coerce the last statement in their body into a return statement,
|
||||
giving you implicit return:
|
||||
|
||||
sum = (x, y) -> x + y
|
||||
print "The sum is ", sum 10, 20
|
||||
|
||||
Of course if you wanted to explicitly return, you can use the `return` keyword.
|
||||
|
||||
sum = (x, y) -> return x + y
|
||||
|
||||
In order to avoid ambiguity in when calling functions, parentheses can be used
|
||||
to surround the arguments. This is required here in order to make sure the
|
||||
right arguments get sent to the right functions.
|
||||
|
||||
print "sum 1:", sum(10, 20), "sum 1:", sum(30, 40)
|
||||
|
||||
|
||||
The following are equivalent:
|
||||
|
||||
print "the value is", sum 10, get_number "decimal", "1 thousand"
|
||||
|
||||
print("the value is", sum(10, get_number("decimal", "1 thousand")))
|
||||
|
||||
### Fat Arrows
|
||||
|
||||
Because it is an idiom in Lua to send the object as the first argument when
|
||||
calling a method, a special syntax is provided for functions which
|
||||
automatically includes this `self` argument.
|
||||
|
||||
func = (num) => self.value + num
|
||||
|
||||
Is the same as:
|
||||
|
||||
func = (self, num) -> self.value + num
|
||||
|
||||
## Table Literals
|
||||
|
||||
Like in Lua, tables are delimited in curly braces.
|
||||
|
||||
some_values = { 1, 2, 3, 4 }
|
||||
|
||||
Unlike Lua, assigning a value to a key in a table is done with `:` (instead of
|
||||
`=`).
|
||||
|
||||
some_values = {
|
||||
name: "Bill",
|
||||
age: 200,
|
||||
["favorite food"]: "rice"
|
||||
}
|
||||
|
||||
The curly braces can be left off if a single table is being assigned.
|
||||
|
||||
profile =
|
||||
height: "4 feet",
|
||||
shoe_size: 13,
|
||||
favorite_foods: {"ice cream", "donuts"}
|
||||
|
||||
Newlines can be used to delimit values instead of a comma (or both):
|
||||
|
||||
values = {
|
||||
1,2,3,4
|
||||
5,6,7,8
|
||||
name: "superman"
|
||||
occupation: "crime fighting"
|
||||
}
|
||||
|
||||
## Table Comprehensions
|
||||
|
||||
Table comprehensions provide a quick way to iterate over a table's values while
|
||||
applying a statement and accumulating the result.
|
||||
|
||||
The following creates a copy of the `items` table but with all the values
|
||||
doubled.
|
||||
|
||||
items = { 1, 2, 3, 4 5}
|
||||
doubled = [item * 2 for i, item in ipairs items]
|
||||
|
||||
The items included in the new table can be restricted with a `when` clause:
|
||||
|
||||
slice = [item in i, item in ipairs items when i > 1 and i < 3]
|
||||
|
||||
Because it is common to iterate over the values of a numerically indexed table,
|
||||
an `*` operator is introduced. The doubled example can be rewritten as:
|
||||
|
||||
doubled = [item for item in *items]
|
||||
|
||||
The `for` and `when` clauses can be chained as much as desired. The only
|
||||
requirement on a comprehension is that there is at least one `for` clause.
|
||||
|
||||
Using multiple `for` clauses is the same as using nested loops:
|
||||
|
||||
x_coords = {4, 5, 6, 7}
|
||||
y_coords = {9, 2, 3}
|
||||
|
||||
pairs = [{x,y} for x in *x_coords for y in *y_coords]
|
||||
|
||||
|
||||
## For Loop
|
||||
|
||||
There are two for loop forms, just line in Lua. A numeric one and a generic one:
|
||||
|
||||
for i = 10, 20
|
||||
print i
|
||||
|
||||
for k = 1,15,2 -- an optional step provided
|
||||
print k
|
||||
|
||||
for key, value in pairs object
|
||||
print key, value
|
||||
|
||||
The slicing and `*` operators can be used, just like with table comprehensions:
|
||||
|
||||
for item in *items[2:4]
|
||||
print item
|
||||
|
||||
A shorter syntax is also available for all variations when the body is only a
|
||||
single line:
|
||||
|
||||
for item in *items do print item
|
||||
|
||||
for j = 1,10,3 do print j
|
||||
|
||||
## While Loop
|
||||
|
||||
The while loop also comes in two variations:
|
||||
|
||||
i = 10
|
||||
while i > 0
|
||||
print i
|
||||
i -= 1
|
||||
|
||||
while running == true do my_function!
|
||||
|
||||
## Conditionals
|
||||
|
||||
have_coins = false
|
||||
if have_coins
|
||||
print "I have coins"
|
||||
else
|
||||
print "I don't have coins"
|
||||
|
||||
A short syntax for single statements can also be used:
|
||||
|
||||
have_coins = false
|
||||
if have_coins then print "I have coins" else print "I don't have coins"
|
||||
|
||||
|
||||
Because if statements can be used as expressions, this can able be written as:
|
||||
|
||||
have_coins = false
|
||||
print if have_coins then "I have coins" else "I don't have coints"
|
||||
|
||||
Conditionals can also be used in return statements and assignments:
|
||||
|
||||
is_tall = (name) ->
|
||||
if name == "Rob"
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
message = if is_tall "Rob"
|
||||
"I am very tall"
|
||||
else
|
||||
"I am not so tall"
|
||||
|
||||
print message -- prints: I am very tall
|
||||
|
||||
|
||||
## Line Decorators
|
||||
|
||||
For convenience, the for loop and if statement can be applied to single
|
||||
statements at the end of the line:
|
||||
|
||||
print "hello world" if name == "Rob"
|
||||
|
||||
This is equivalent to:
|
||||
|
||||
if name == "rob"
|
||||
print "hello world"
|
||||
|
||||
And with basic loops:
|
||||
|
||||
print "item: ", item for item in *items
|
||||
|
||||
## Object Oriented Programming
|
||||
|
||||
A simple class:
|
||||
|
||||
class Inventory
|
||||
new: =>
|
||||
@items = {}
|
||||
|
||||
add_item: (name) =>
|
||||
if @items[name]
|
||||
@items[name] += 1
|
||||
else
|
||||
@items[name] = 1
|
||||
|
||||
A class is declared with a `class` statement followed by a table-like
|
||||
declaration where all of the methods and properties are listed.
|
||||
|
||||
The `new` property is special in that it will become the constructor.
|
||||
|
||||
Notice how all the methods in the class use the fat arrow function syntax. When
|
||||
calling methods on a instance, the instance itself is sent in as the first
|
||||
argument. The fat arrow handles the creation of a `self` variable.
|
||||
|
||||
The `@` prefix on a variable name is shorthand for `self.`. `@items` becomes
|
||||
`self.items`.
|
||||
|
||||
Creating an instance of the class is done by calling the name of the class as a
|
||||
function.
|
||||
|
||||
inv = Inventory!
|
||||
inv\add_item "t-shirt"
|
||||
inv\add_item "pants"
|
||||
|
||||
Because the instance of the class needs to be sent to the methods when they are
|
||||
called, the '\' operator is used.
|
||||
|
||||
All properties of a class are shared among the instances. This is fine for
|
||||
functions, but for other types of objects, undesired results may occur:
|
||||
|
||||
class Person
|
||||
clothes: {}
|
||||
give_item: (name) =>
|
||||
table.insert @clothes, name
|
||||
|
||||
a = Person!
|
||||
b = Person!
|
||||
|
||||
a\give_item "pants"
|
||||
b\give_item "shirt"
|
||||
|
||||
print item for item in *a.clothes -- will print both pants and shirt
|
||||
|
||||
### Inheritance
|
||||
|
||||
The `extends` keyword can be used in a class declaration to inherit the
|
||||
properties and methods from another class.
|
||||
|
||||
class BackPack extends Inventory
|
||||
size: 10
|
||||
add_item: (name) =>
|
||||
if #@items > size then error "backpack is full"
|
||||
super name
|
||||
|
||||
Here we extend our Inventory class, and limit the amount of items it can carry.
|
||||
The `super` keyword can be called as a function to call the function of the
|
||||
same name in the super class. It can also be accessed like an object in order
|
||||
to retrieve values in the parent class that might have been shadowed by the
|
||||
child class.
|
||||
|
||||
### Types
|
||||
|
||||
Every instance of a class carries its type with it. This is stored in the
|
||||
special `__class` property. This property holds the class object. The class
|
||||
object is what we call to build a new instance. We can also index the class
|
||||
object to retrieve class methods and properties.
|
||||
|
||||
|
||||
b = BackPack!
|
||||
assert b.__class == BackPack
|
||||
|
||||
print BackPack.size -- prints 10
|
||||
|
||||
|
||||
## Export Statement
|
||||
|
||||
Because, by default, all assignments to variables that are not lexically visible will
|
||||
be declared as local, special syntax is required to declare a variable globally.
|
||||
|
||||
The export keyword makes it so any following assignments to the specified names
|
||||
will not be assigned locally.
|
||||
|
||||
export var-name [, var-name2, ...]
|
||||
|
||||
This is especially useful when declaring what will be externally visible in a
|
||||
module:
|
||||
|
||||
-- my_module.moon
|
||||
module "my_module", package.seeall
|
||||
export print_result
|
||||
|
||||
length = (x, y) -> math.sqrt x*x + y*y
|
||||
|
||||
print_result = (x, y) ->
|
||||
print "Length is ", length x, y
|
||||
|
||||
-- main.moon
|
||||
require "my_module"
|
||||
|
||||
my_module.print_result 4, 5 -- prints the result
|
||||
|
||||
print my_module.length 6, 7 -- errors, `length` not visible
|
||||
|
||||
|
||||
## Import Statement
|
||||
|
||||
Often you want to bring some values from a table into the current scope as
|
||||
@ -22,7 +382,7 @@ The multiple names can be given, each separated by a comma:
|
||||
import C, Ct, Cmt from lpeg
|
||||
|
||||
Sometimes a function requires that the table be sent in as the first argument
|
||||
(when using the `:` syntax). As a shortcut, we can prefix the name with a `:`
|
||||
(when using the `\` syntax). As a shortcut, we can prefix the name with a `\`
|
||||
to bind it to that table:
|
||||
|
||||
-- some object
|
||||
@ -31,12 +391,59 @@ to bind it to that table:
|
||||
add: (value) =>
|
||||
self.state + value
|
||||
|
||||
import :add from my_module
|
||||
import \add from my_module
|
||||
|
||||
print add(22) -- equivalent to calling my_module:get(22)
|
||||
|
||||
## With Statement
|
||||
|
||||
A common pattern involving the creation of an object is calling a series of
|
||||
functions and setting a series of properties immediately after creating it.
|
||||
|
||||
This results in repeating the name of the object multiple times in code, adding
|
||||
unnecessary noise. A common solution to this is to pass a table in as an
|
||||
argument which contains a collection of keys and values to overwrite. The
|
||||
downside to this is that the constructor of this object must support this form.
|
||||
|
||||
The `with` block helps to alleviate this. It lets us use a bare function and
|
||||
index syntax in order to work with the object:
|
||||
|
||||
with Person!
|
||||
.name = "Oswald"
|
||||
\add_relative my_dad
|
||||
\save!
|
||||
print .name
|
||||
|
||||
Is equivalent to:
|
||||
|
||||
_person = Person!
|
||||
_person.name = "Oswald"
|
||||
_person\add_relative my_dad
|
||||
_person\save!
|
||||
print _person.name
|
||||
|
||||
This is more expressive than trying to create multiple constructors to handle
|
||||
unique instances of initializing an object.
|
||||
|
||||
The `with` statement can also be used as an expression which returns the newly
|
||||
created object.
|
||||
|
||||
file = with File "favorite_foods.txt"
|
||||
\set_encoding "utf8"
|
||||
|
||||
Or...
|
||||
|
||||
create_person = (name, relatives) ->
|
||||
with Person!
|
||||
.name = name
|
||||
\add_relative for relative in *relatives
|
||||
|
||||
me = create_person "Leaf", {dad, mother, sister}
|
||||
|
||||
## The Using Clause; Controlling Destructive Assignment
|
||||
|
||||
*This isn't implemented yet*
|
||||
|
||||
While lexical scoping can be a great help in reducing the complexity of the
|
||||
code we write, things can get unwieldy as the code size increases. Consider
|
||||
the following snippet:
|
||||
|
Loading…
Reference in New Issue
Block a user