开源软件名称(OpenSource Name):richardhundt/shine开源软件地址(OpenSource Url):https://github.com/richardhundt/shine开源编程语言(OpenSource Language):Lua 88.3%开源软件介绍(OpenSource Introduction):-- taken from a real world web app which talks to elasticsearch
import JSON from "codec.json"
import Presenter from "swarm.app"
import HTTPStatic from "swarm.static"
import ESClient, ESIndex from "app.es.client"
-- this presenter is a singleton, so we use `module` here
module Features include Presenter
local client = ESClient('localhost', 9200)
local storage = ESIndex(client, 'features')
local static = HTTPStatic("./public/admin")
@self.route('GET', '/admin')
admin(req, path, query)
if #path == 0 then
path[#path + 1] = 'index.html'
end
return static.handler(req, path, query)
end
@self.route('GET', '/features/feature/:id')
fetch(req, args, query)
resp = storage.lookup('feature', args['id'])
hdrs = { }
hdrs['Content-Type'] = 'application/json'
if resp.exists then
return { 200, hdrs, { JSON.encode(resp) } }
else
return { 404, hdrs, { JSON.encode(resp) } }
end
end
end Shine ReferenceThis document aims to be a fairly concise, but broad reference. To help get you started, though, have a look at the wiki which has a growing collection of tutorials.
IntroductionShine is a general purpose, dynamic, multi-paradigm programming language which is based on, and extends, Lua with features geared more to programming in the large. For maximum performance it uses a modified version of the LuaJIT virtual machine, which is known for its small footprint and impressive performance which rivals that of C. Most of the language features are those of the underlying LuaJIT VM, and the extensions are implemented in terms of lower level constructs already present in LuaJIT, so anyone familiar with Lua and LuaJIT should quickly feel right at home with Shine. Moreover, vanilla Lua libraries can be loaded and run unmodified, and although compilation of Lua code is slower than with LuaJIT or PuC Lua, there is no additional runtime penalty, and since they share the same bytecode, this means that Shine users can leverage all of the existing Lua libraries out there without writing wrappers or additional bindings. You can, of course, call seamlessly into Shine code from Lua too, as long as Lua is running within the Shine runtime. Another goal of Shine, is that the standard libraries which are included are focused on providing CSP style concurrency, so although the language itself has no concurrency primitives, the fibers, channels, threads, pipes and I/O libraries are all centered around building highly scalable, low-footprint, network oriented concurrent applications. PhilosophyShine strives for a pragmatic balance between safety and syntactic and semantic flexibility. Summary of safety features:
Summary of flexibility features:
Additionally, all constructs can be nested. Classes can be declared inside other classes and even inside functions, which allows for run-time construction of classes, modules and grammars. Other notable extensions to Lua:
Getting StartedShine ships with all its dependencies, so simply clone the git
repository and run
Standard
This will install two executables
The main executable and runtime is
The Shine has been tested on Linux and Mac OS X, and support for Windows is in progress. Language BasicsShine is a line-oriented language. Statements are generally seperated
by a line terminator. If several statements appear on the same line, they
must be may be separated by a semicolon Long expressions with infix operators may be wrapped with the operator leading after the line break, however for function and method calls, the argument list must start on the same line as the callee:
A bare word by itself is parsed as a function call:
CommentsComments come in 3 forms:
The last form is designed to allow Shine sources to be annotated for processing by external tools such as documentation generators:
IdentifiersIdentifiers must start with
ScopingShine scoping rules are similar to Lua's with the addition of the concept
of a default storage if The default storage for variables is always
Declarations can always be lexically scoped by declaring them as In short, what this means is that most of the time you can simply leave out
the There are cases where a Builtin TypesShine includes all of LuaJIT's builtin types:
All other extensions are built primarily using These include: Primitive meta types:
Additional builtins:
Nominal meta types:
Pattern matching meta types:
The meta meta type:
BooleansThe constants NumbersThe Shine parser recognizes LuaJIT The following are represented as Lua
These are LuaJIT extensions enabled by default in Shine:
|
Operator | Precedence | Associativity | Comment |
---|---|---|---|
..._ |
1 | right | unpack |
or |
1 | left | logical or |
and |
2 | left | logical and |
== |
3 | left | equality |
!= |
3 | left | inequality |
~~ |
3 | left | matches |
!~ |
3 | left | does not match |
is |
4 | left | type equality |
as |
4 | left | type coercion |
>= |
5 | left | greater than or equal to |
<= |
5 | left | less than or equal to |
> |
5 | left | greater than |
< |
5 | left | less than |
| | 6 | left | bitwise or |
^ |
7 | left | bitwise exclusive or |
& |
8 | left | bitwise and |
<< |
9 | left | bitwise left shift |
>> |
9 | left | bitwise right shift |
>>> |
9 | left | bitwise arithmetic right shift |
~ |
10 | left | concatenation |
+ |
10 | left | addition |
- |
10 | left | subtraction |
.. |
10 | right | range |
* |
11 | left | multiplication |
/ |
11 | left | division |
% |
11 | left | remainder (modulo) |
~_ |
12 | right | bitwise not |
!_ |
12 | right | logical not |
not_ |
12 | right | logical not |
** |
13 | right | exponentiation |
#_ |
14 | right | length of |
Many infix operators are also available in update, or assigment, form:
Operator | Comment |
---|---|
+= |
add assign |
-= |
subtract assign |
~= |
concatenate assign |
*= |
multiply assign |
/= |
divide assign |
%= |
modulo assign |
**= |
exponentiation assign |
and= |
logical and assign |
or= |
logical or assign |
&= |
bitwise and assign |
|= | bitwise or assign |
^= |
bitwise xor assign |
<<= |
bitwise left shift assign |
>>= |
bitwise right shift assign |
>>>= |
bitwise arithmetic right shift assign |
The following operators are used in patterns:
Operator | Precedence | Associativity | Comment |
---|---|---|---|
~> |
1 | left | fold capture |
-> |
1 | left | production capture |
+> |
1 | left | match-time capture |
| | 2 | left | ordered choice |
&_ |
3 | right | lookahead assertion |
!_ |
3 | right | negative lookahead assertion |
+ |
3 | left | one or more repetitions |
* |
3 | left | zero or more repetitions |
? |
3 | left | zero or one |
^+ |
4 | right | at least N repetitions |
^- |
4 | right | at most N repetitions |
Not listed above are the common (
and )
for grouping, and
postcircumfix ()
and []
operators for function/method calls and
subscripting respectively.
In addition to the built-in operators, Shine exposes a full suite of user-definable operators, which share precedence with their built-in counterparts, but have no intrinsic meaning to the language.
Shine will simply try to call the corresponding meta-method as with the built-in operators. The full listing is:
Operator | Precedence | Associativity | Meta-Method |
---|---|---|---|
:! |
3 | left | __ubang |
:? |
3 | left | __uques |
:= |
5 | left | __ueq |
:> |
5 | left | __ugt |
:< |
5 | left | __ult |
:| | 6 | left | __upipe |
:^ |
7 | left | __ucar |
:& |
8 | left | __uamp |
:~ |
10 | left | __utilde |
:+ |
10 | left | __uadd |
:- |
10 | left | __usub |
:* |
11 | left | __umul |
:/ |
11 | left | __udiv |
:% |
11 | left | __umod |
When calling a function, method, or other callable, parenthesis may be omitted provided there is either at least one argument. The following are all valid:
fido.bark(loudness)
fido.move x, y -- fido.move(x, y)
As a special case, if the callee is a single word as a statement on its own, then no parentheses or arguments are required:
yield -- OK yield()
fido.greet -- BAD (not a word)
print yield -- BAD (yield not a statement)
Member expressions have three lexical forms:
Shine deviates from Lua in that the .
operator when followed by
a call expression is a method call, whereas Lua uses :
. To call
a property without passing an implicit receiver, use ::
instead:
s.format(...) -- method call (self is implicit)
string::format(s, ...) -- property call
For property access, either ::
or .
may be used with identical
semantics. By convention, one may prefer ::
for indicating namespace
access such as async::io::StreamReader
, whereas .
may be used to
access instance members.
Assignment expressions are based on Lua allowing multiple left and right hand sides. If an identifier on the left is previously undefined, then a new local variable is automatically introduced the fist time it is assigned. This prevents global namespace pollution. Examples:
a, b = 1, 2 -- implicit locals a, b
o.x, y = y, o.x -- implicit local y
local o, p = f() -- explicit
a[42] = 'answer'
Shine also supports destructuring of tables, arrays and application patterns. This can be used during assignment as well as pattern matching in given statements.
For tables and arrays, Shine knows how to extract values for you:
a = ['foo', { bar = 42 }, 'baz']
[x, { bar = y }, z] = a
print x, y, z -- prints: foo 42 baz
However, with objects you have to implement an __unapply
hook to make
it work. The hook is expected to return an iterator which would be valid
for use in a generic for loop. Here's an example:
class Point
self(x = 0, y = 0)
self.x = x
self.y = y
end
function self.__unapply(o)
return ipairs{ o.x, o.y }
end
end
p = Point(42, 69)
Point(x, y) = p
print x, y -- prints: 42 69
Patterns already implement the relevant hooks, so the following works as expected:
Split2 = / { [a-z]+ } %s+ { [a-z]+ } /
str = "two words"
Split2(a, b) = str
assert a == 'two' and b == 'words'
Comprehensions are an experimental feature only implemented for arrays currently. They are also not lazy generators. They should look familiar to Python programmers. Here are two examples:
a1 = [ i * 2 for i in 1..10 if i % 2 == 0 ]
a2 = [ i * j for i in 1..5 for j in 1..5 ]
Shine has a syntactic short-hand form for creating functions:
(<param_list>)? => <func_body> <end>
The parameter list is optional.
-- these two are identical
f1 = (x) =>
return x * 2
end
function f1(x)
return x * 2
end
Additionally, if the function body contains a single expression
and appears on one line, then an implicit return
is inserted
and the end
token is omitted:
b = a.map((x) => x * 2)
-- shorter still
b = a.map (x) => x * 2
Means:
b = a.map((x) =>
return x * 2
end)
do <chunk> end
Same as in Lua.
if <expr> then <chunk> (elseif <expr> then <chunk>)* (else <chunk>)? end
Same as in Lua.