diprism / perpl

The PERPL Compiler
MIT License
10 stars 5 forks source link

case of let #28

Closed davidweichiang closed 2 years ago

davidweichiang commented 2 years ago

An expression like case e of Unit -> let x = e in e currently can't parse. The error message is very clear (it says to add parentheses) but would it be better to make it parseable?

colin-mcd commented 2 years ago

I think the crux of this issue was that there is no way to know if we should parse

case e₁ of Unit -> case e₂ of False -> e₃ | True -> e₄ as case e₁ of Unit -> (case e₂ of False -> e₃ | True -> e₄) or case e₁ of Unit -> (case e₂ of False -> e₃) | True -> e₄

So with our current syntax, we can't nest case-ofs without parentheses. Similarly, we can't parse any term that could end with a case-of inside a case (e.g. case e₁ of Unit -> let x = e₂ in case e₃ of False -> e₄ | True -> e₅). The same goes for lambda-terms and if-then-else-terms too.

—————

In general though, I think I could really iron out some parsing precedence details. Currently, we have the following precedence levels:

TERM1 :=
  | case TERM1 of VAR VAR* -> TERM2 \| ...
  | if TERM1 then TERM1 else TERM1
  | \ VAR : TYPE1. TERM1
  | let (VAR, ...) = TERM1 in TERM1
  | let VAR = TERM1 in TERM1
  | TERM2

TERM2 :=
  | sample DIST : TYPE1
  | amb TERM5*
  | TERM3

TERM3 :=
  | TERM4 . NUM    (* e.2 *)
  | TERM4

TERM4 :=
  | TERM5 == TERM5 == ...
  | TERM5 TERM5*    (* application *)
  | TERM5

TERM5 :=
  | VAR
  | (TERM1)
  | <TERM1, ...>
  | error

TYPE1 :=
  | TYPE2 -> TYPE1
  | TYPE2

TYPE2 :=
  | TYPE3 * TYPE3 * ...
  | TYPE3 & TYPE3 & ...
  | TYPE3

TYPE3 :=
  | VAR
  | (TYPE1)
  | error
davidweichiang commented 2 years ago

Do ML and Haskell make the same decision for these cases, and can we do the same?

colin-mcd commented 2 years ago

I know in Haskell you must either do case e₁ of { False -> e₂; True -> e₃ } or

case e₁ of
  False -> e₂
  True -> e₃

For the latter syntax, I think that indentation does matter.

I haven't really used ML much, but at least in Standard ML it looks like you must use parentheses to nest case-ofs (source)

davidweichiang commented 2 years ago

It seems like OCaml is the opposite of SML, so this parses:

match true with
    true -> true
  | false -> match [] with
                [] -> true
              | x::xs -> false

and

match true with
    true -> true
  | false ->
      let y = 0 in
        match [] with
            [] -> true
          | x::xs -> false
ccshan commented 2 years ago

Haskell (and SML as well?) "attempt to maximally consume potential clauses", like OCaml (and also like C with if...then if...then...else). Basically this is favoring shift over reduce when there's a shift/reduce conflict. I'm ok with that but I'm also ok with requiring disambiguating parentheses.