Skip to content

About

a toy functional language

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

Husky

  • a simple functional language

Syntax example

-- facc n computes n!
facc x | x == 0 = 1
       | x > 0 = x * facc (x - 1);
  • comments are single-line only and must be prefixed with --
  • guards can also be omitted entirely
  • n-ary functions already take n-tuples f (a1, ..., an) (so f x = f (x))
  • ; must separate each definition; from a design standpoint this is there so that we can easily ignore any whitespace character
  • infix operators are always left-associative; where has the lowest priority, then +, -, or, then *, /, and, and not and unary minus (e.g. -5) have the highest priority. Both boolean and functional expressions can be parenthesized as needed, after which the priorities are clear.
  • all arithmetic operations are evaluated over ints (except /, which is integer division).

Notes

For simplicity, there are several things that Husky does not guarantee:

  • function order does not matter
  • inside where blocks, you can only refer to the formal parameters of the "parent" function
  • you cannot nest multiple where blocks (i.e. use where blocks inside where blocks)
  • guards must be "mutually exclusive", because the order in which they are evaluated is not guaranteed!
  • if a function is non-total, i.e. there is a case for a formal parameter that isn't covered by any of the guards, then Husky does not guarantee correctness or that an error will be thrown — 0 is returned instead
  • since output happens only via the exit code, the sign is unfortunately lost on output — this doesn't mean, however, that it isn't handled internally
  • where blocks should not override any other local definition; they may only override global definitions (shadowing works)

Optimizations

Husky code is not optimized and relies on LLVM optimizations, i.e.:

  • even without guards, a jump is inserted, which is trivially true and jumps into the if branch
  • the same instructions are inserted into different unnamed variables; LLVM can largely eliminate this

Areas for improvement

  • replace String with ByteString everywhere (including in the lexer, where a wrapper bytestring-monad is needed)
  • rework local definitions to use AddrSpace
  • improve the AST types, and especially the traversal in the emitter, so that it isn't done via recursion but via catamorphisms
  • replace arrays with maps, especially in NameTable, etc.
  • get rid of unnecessary duplicate computation of the same thing — in several places something is done twice (mainly in the emitter)

About

a toy functional language

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Contributors

Languages