Tulip Formal Syntax
1 Datums and Operators
2 Expressions
2.1 Lambdas
3 Definitions
4 Whole Programs

Tulip Formal Syntax

This provides a formal syntax for Tulip written in an extended BNF.

1 Datums and Operators

 

identifier

 ::= 

identifier start identifier body*

 

identifier start

 ::= 

letter

 

identifier body

 ::= 

letter  |  digit  |  -

 

tag word

 ::= 

. identifier

 

flag word

 ::= 

- identifier

 

number

 ::= 

digit+ [.]

 

  |  

digit* . digit+

 

letter

 ::= 

a  |  b  |  c  |  ...  |  z

 

  |  

A  |  B  |  C  |  ...  |  Z

 

digit

 ::= 

0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9

 

sequence delimiter

 ::= 

;  |  newline

2 Expressions

 

expression

 ::= 

group

 

  |  

block

 

  |  

chain

 

  |  

application

 

  |  

identifier

 

  |  

tag word

 

  |  

flag pair

 

  |  

lambda

 

  |  

block lambda

 

  |  

$

 

group

 ::= 

( expression )

 

block

 ::= 

{ expression {sequence delimiter expression}* }

 

chain

 ::= 

expression > expression

 

application

 ::= 

expression+

 

  |  

expression !

 

flag pair

 ::= 

flag word : expression

Note that $ is only allowed as an expression while parsing an auto lambda.

2.1 Lambdas

 

lambda

 ::= 

[ lambda body ]

 

block lambda

 ::= 

{ lambda body }

 

lambda body

 ::= 

full lambda  |  auto lambda

 

full lambda

 ::= 

lambda clause {sequence delimiter lambda clause}*

 

lambda clause

 ::= 

lambda formals => expression

 

lambda formals

 ::= 

pattern+

 

  |  

!

 

auto lambda

 ::= 

expression

 

pattern

 ::= 

grouped pattern

 

  |  

conjunct pattern

 

  |  

condition pattern

 

  |  

tag pattern

 

  |  

identifier

 

  |  

number

 

  |  

_

 

grouped pattern

 ::= 

( pattern )

 

conjunct pattern

 ::= 

pattern : pattern

 

condition pattern

 ::= 

pattern ? expression

 

tag pattern

 ::= 

tag word pattern*

The above grammar is slightly ambiguous when applied to the following syntax:

[ .foo bar baz => ... ]

Specifically, either of the following forms would be reasonable interpretations:

[ (.foo) bar baz => ... ]

[ (.foo bar baz) => ... ]

To disambiguate, a special rule is considered when parsing the pattern for the first argument of a lambda. If the pattern is a tag pattern, then the lambda is parsed as accepting a single argument, the tag. If the pattern is anything else, then all patterns at root level of the lambda formals are treated as patterns for individual arguments.

[ .foo bar baz => ... ]   # parses as [ (.foo bar baz) => ... ]

[ (.foo) bar baz => ... ] # parses as [ (.foo) bar baz => ... ]

[ foo .bar baz => ... ]   # parses as [ foo (.bar) baz => ... ]

3 Definitions

 

definition

 ::= 

declaration = expression

 

declaration

 ::= 

binding declaration

 

  |  

function declaration

 

binding declaration

 ::= 

identifier

 

function declaration

 ::= 

identifier lambda formals

Function definitions do not use the custom pattern parsing rule described in Lambdas, so patterns are always interpreted as separate arguments when possible.

foo .bar baz = ... # parses like [ (.bar) baz => ... ]

4 Whole Programs

 

program

 ::= 

top-level form {sequence delimiter top-level form}*

 

top-level form

 ::= 

expression

 

  |  

definition