Skip to content

szensk/wul

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

wul

Wul is another unnecessary language developed for fun. The simple syntax is borrowed from Lisp but the language isn't much of a lisp. It is more influenced by Lua: function arity is flexible, functions often return multiple values rather than lists and a value's metatype defines its behavior with standard operators (akin to Lua's metatables). Too few arguments is equivalent to passing nil to all the remaining arguments. Extra arguments not specified as a formal parameter of the function become accessible via a list named $args. Variable arguments are supported with .... Named parameters are also supported: (add y: 6 x: 5) and (add 5 6) are equivalent. Finally, lists rarely need to be quoted: (1 2 3) constructs a new list without needing (list 1 2 3) or '(1 2 3).

Types

There are seven basic types: Bool, Number, String, List, Map, Range, Function. Strings come in two varieties, interpolated (e.g. "hello {world}.") and regular (e.g. 'this will appear exactly {as seen here}'). There are also two types of functions. Regular functions operate as you expect but macro functions are passed unevaluated syntax nodes instead of value arguments and can return quoted syntax. These syntax nodes may be evaluated using the eval function. This makes it easy to implementing short circuit operators or control flow (see while.wul). Ranges are enumerators of a sequence of values (e.g. [0 10 2] enumerates all values from 0 to 10 by increments of 2). Beside generating sequences, ranges can be used to index lists (e.g. ([0] (1 2 3)) grabs the first element of the list and ([2 0] (1 2 3)) returns the list reversed).

MetaTypes

A metatype contains methods that define how a value interacts with existing functions. All values, except the value nil, have a metatype. By default, values are constructed with their type's metatype. You can define new or override existing functions on a metatype at either the value or type level. Since all simple values have a default invoke metamethod that builds lists, it is not necessary to use the list method to construct a list. (1 2 3) will suffice. As an example of user metamethods, you can define the invoke metamethod on a map value. The map itself may be used like a function and accessed in metamethods as the variable self (see invoke.wul and unpack.wul). Furthermore, an unnamed function may be accessed as the variable self and called recursively (e.g. invoking (lambda (arg) (self arg)) would result in infinite recursion).

.NET Interoperability

The :: function invokes static .NET methods (e.g. (:: System.IO.Directory.SetCurrentDirectory 'someDirectory')). The ::new function constructs new .NET objects. These objects can be bound to name or stored in a list for later use. Fields and properties of an object can be accessed with (at obj PropertyName) and set with (set obj PropertyName 5). Methods on objects may be invoked by using the value like a function, for example (obj Join 'argument1').

Examples

(defn fact (a) 
  (if (< a 2) 
    (then 1)
    (else (* a (fact (- a 1))))
  )
)

(print "10! is {(fact 10)}.") ; prints '10! is 3628800.'
(defn ltr (a b) (print 'ltr'))
(defmacro rtl (a b) (`do (print 'rtl') b a))

;arguments are evaluated before being passed to functions
(ltr (print "1") (print "2")) ; prints 1, 2, ltr 
;but arguments are not evaluated before being passed to macros
(rtl (print "1") (print "2")) ; prints rtl, 2, 1 
; functions may return multiple values
(defn n-and-its-square (n) (return n (* n n)))
(print (n-and-its-square 5)) ; prints 5, 25 
(+ (n-and-its-square 7)) ; returns 56

See the examples directory for more.

About

some lispy language

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages