Skip to content

Releases: dcutting/Song

Unicode string support

07 Apr 16:12
Compare
Choose a tag to compare

You can now process real unicode strings:

> text = "I like cafés! 😀"
> text.reverse
"😀 !séfac ekil I"

Also added support for literal newlines and tabs using \n, \r, and \t escape sequences.

Standard Library

03 Apr 23:23
Compare
Choose a tag to compare

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

03 Apr 00:21
Compare
Choose a tag to compare

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

31 Mar 21:09
Compare
Choose a tag to compare

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

09 Mar 15:44
Compare
Choose a tag to compare

Warn user if script finishes parsing but looks incomplete, rather than silently failing.

Input!

09 Mar 11:56
Compare
Choose a tag to compare

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

08 Mar 21:25
Compare
Choose a tag to compare

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

07 Mar 17:42
Compare
Choose a tag to compare

Fix serious bug that meant parameters in functions that shadowed existing declarations would require pattern equality.

Improved function calls

07 Mar 11:56
Compare
Choose a tag to compare

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

04 Mar 23:52
Compare
Choose a tag to compare

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.