Releases: dcutting/Song
Unicode string support
Standard Library
Some useful functions are now available as part of a standard library, including:
> "abc".length
3
> [1,2,3].reverse
[3,2,1]
> [1,2,3].map(|x| x*2)
[2,4,6]
> [4,6,1,2,2].sort
[1,2,2,4,6]
> 5.cubed
125
> "hello there world".split
["hello", "there", "world"]
> ["a", "b", "c"].join(":")
"a:b:c"
Fix lexical scoping
Song is supposed to be lexically scoped, but a bug meant that in many cases it was actually dynamically scoped leading to lots of confusion.
E.g. the following was surprisingly returning 2
rather than throwing an error:
foo() = n
bar(n) = foo()
bar(2)
This release tightens up the lexical scoping rules to behave as you would expect in most functional and C-style languages.
Tail call optimisation
Function calls in the tail position of a function declaration are now trampolined to prevent stack overflows.
This means you can now loop effectively infinitely with a recursive call, which is important because Song does not have imperative loops.
E.g.:
loop() = Do
"n? ".in.number.fib.out
loop()
End
Warn user if script looks incomplete
Warn user if script finishes parsing but looks incomplete, rather than silently failing.
Input!
Song can now read input from stdin
!
name = in("What is your name? ")
out("Hello", name)
You can also print to stderr
using the err()
built-in function (as well as stdout
with out()
).
Also fixed is a bug that prevented some command-line arguments beginning with hyphens (such as negative numbers) from being passed to Song scripts.
Function call bug fixes
Fix some edge cases for wrapped arguments in function calls.
Restrict lambdas from matching literals apart from lists and list constructors.
Bugfix for function parameter shadowing
Fix serious bug that meant parameters in functions that shadowed existing declarations would require pattern equality.
Improved function calls
Massive improvements to function call parsing. You should now be able to mix free/subject/lambdas in function calls in almost any way you can imagine. Closes #68. E.g.:
1.foo(3)(4)
(|x|x).foo(1)
1.(|x|x)
foo().bar
lessThan(5)(4)
foo(|x|x.foo(bar()())(),1)
Also:
Repeated variables in patterns now need to be equal. Closes #38.
Bail in script mode when an error is hit, rather than trying to carry on. Closes #76.
Truncate floats to ints; clean up bugs with functions; change scope semantics
Permit scopes to appear as terms in expressions.
Permit anonymous functions as the subject of function calls.
Built-in truncate
function converts floats to ints. Other conversion functions are built on top of this. Closes #77.
Properly support unary - and + operators for arbitrary expressions, not just numerical literals. Closes #79.
Move subfunction pattern matching logic into closure expressions, which means you can pass named functions as arguments to functions that expect a lambda. Closes #61.
Change scope semantics such that if a new named function is declared that shadows the same name outside the scope, the one outside is completely ignored during evaluation of the scope.