1
0
Fork 0
mirror of https://github.com/Reuh/candran.git synced 2025-10-27 17:59:30 +00:00

Added safe operators, if/while with assignement, method stubs

This commit is contained in:
Étienne Fildadut 2019-08-27 17:07:33 +02:00
parent 6be81267d2
commit 851e9f89d6
11 changed files with 3688 additions and 2845 deletions

100
README.md
View file

@ -20,6 +20,8 @@ end
let a = {
hey = true,
child = nil,
method = :(foo, thing) -- short function declaration, with self
@hey = thing(foo) -- @ as an alias for self
end,
@ -33,6 +35,13 @@ a:method(42, (foo)
return "something " .. foo
end)
local fn = a:method -- bundles an object and method in a function
fn(42, (foo)
return "something" .. foo
end)
a.child?:method?() -- safe navigation operator
local odd = [ -- table comprehension
for i=1, 10 do
if i%2 == 0 then
@ -48,6 +57,12 @@ local a = if condition then "one" else "two" end -- statement as expressions
print("Hello %s":format("world")) -- methods calls on strings (and tables) litterals without enclosing parentheses
if f, err = io.open("data") then -- if condition with assignements
thing.process(f)
else
error("can't open data: "..err)
end
````
**Current status**: Candran is heavily used in several of my personal projects and works as expected.
@ -97,7 +112,7 @@ All theses operators can also be put right of the assigment operator, in which c
Right and left operator can be used at the same time.
**Please note** that the Lua code `a=-1` will be compiled into `a = 1 - a` and not `a = -1`! Write spaced code: `a = -1` works as expected.
**Please note** that the code `a=-1` will be compiled into `a = -1` and not `a = a - 1`, like in pure Lua. If you want the latter, spacing is required between the `=-` and the expression: `a=- 1`. Yes, this is also valid Lua code, but as far as I'm aware, nobody write code like this; people who really like spacing would write `a= - 1` or `a = - 1`, and Candran will read both of those as it is expected in pure Lua. This is the only incompatibility between Candran and pure Lua.
##### Default function parameters
```lua
@ -230,6 +245,68 @@ Values returned by the function will be inserted in the generated table in the o
The table generation function also have access to the `self` variable (and its alias `@`), which is the table which is being created, so you can set any of the table's field.
##### Safe navigation operators
```lua
a = nil
print(a?.b) -- nil
a = {b=true}
print(a?.b) -- true
-- So instead of typing
if object and object.child and object.child.isGreen then
-- stuff
end
-- you can type
if object?.child?.isGreen then
-- stuff
end
-- The ?. operator does not break the whole chain; make sure to use the operator on each index.
print(a?.undefined.field) -- a?.undefined returns nil, so this throws a "attempt to index a nil value"
-- Other safe navigator operators behave similarly:
print(a:method) -- nil if a is nil, other normal behaviour
print(a["key"]) -- nil if a is nil, other normal behaviour
print(a?()) -- nil if a is nil, other normal behaviour
```
Some operators can be prefixed by a `?` to turn into a safe version of the operator: if the base value if `nil`, the normal behaviour of the operator will be skipped and nil will be returned; otherwise, the operator run as usual. Is available safe dot index `?.`, safe array index `?[...]`, safe method stub `?:` and safe function call `?(...)`.
##### If and while with assignement in the condition
```lua
if f, err = io.open("somefile") then -- condition if verified if f is a truthy value (not nil or false)
-- do something with f
f:close()
elseif f2, err2 = io.open("anotherfile") then -- same behaviour on elseif
print("could not open somefile:", err) -- f and err stay in scope for the rest of the if-elseif-else block
-- do something with f2
f2:close()
else
print("could not open somefile:", err)
print("could not open anotherfile:", err2)
end
-- f, err, f2 and err2 are now out of scope
if (value = list[index = 2]) and yes = true then -- several assignements can be performed, anywhere in the expression; index is defined before value, yes is defined after these two. The condition is verified if both value and yes are thruthy.
print(index, value)
end
-- When used in a while, the expression is evaluated at each iteration.
while line = io.read() do
print(line)
end
-- The assignement have the same priority as regular assignements, i.e., the lowest.
if a = 1 and 2 then -- will be read as a = (1 and 2)
elseif (a = 1) and 2 then -- will be read as (a = 1) and 2
end
```
Assignements can be used in the condition of if, elseif and while statements. Several variables can be assigned; only the first will be tested in the condition, for each assignement. The assigned variables will be in scope the duration of the block; for if statements, they will also be in scope for the following elseif(s) and else.
For while statements, the assigned expression will be reevaluated at each iteration.
##### Suffixable string and table litterals
```lua
"some text":upper() -- "SOME TEXT". Same as ("some text"):upper() in Lua.
@ -246,6 +323,27 @@ String litterals, table litterals, and comprehensions can be suffixed with `:` m
**Please note**, that "normal" functions calls have priority over this syntax, in order to maintain Lua compatibility.
##### Method stubs
```lua
object = {
value = 25,
method = function(self, str)
print(str, self.value)
end
}
stub = object:method
object.method = error -- stub stores the method as it was when stub was defined
object = nil -- also stores the object
print(stub("hello")) -- hello 25
```
Create a closure function which bundles the variable and its method; when called it will call the method on the variable, without requiring to pass the variable as a first argument.
The closure stores the value of the variable and method when created.
##### Statement expressions
```lua
a = if false then