Peculiar Ocamllex error

I made this repository to reproduce the error in only 111 lines of code.

This is the error

File "lexer.mll", line 33, characters 25-33:
Error: This variant expression is expected to have type unit
       There is no constructor CONSTANT within type unit
make: *** [Makefile:39: lexer.cmo] Error 2

My first assumption was that it had to do with the fact that the type of the CONSTANT token is %token <Ast.constant> CONSTANT. However, when I change it to something else like %token <string> CONSTANT, it returns the same error. So I believe this has something to do with the Ocamllex.
This is the parser simplified.

let int = '-'? digit+  (* regex for integers *)
let whitespace = [' ' '\t']+
let newline = '\r' | '\n' | "\r\n"

rule read_token = parse
  | whitespace         { read_token lexbuf }
  | newline            { next_line lexbuf; }
  | int as i           { CONSTANT (CONST_INT i) }
  | "+"                 { ADD }
  | "-"                 { SUB }
  | "*"                 { MULT }
  | "/"                 { DIV }

I decided to make it more explicit, so I replaced { CONSTANT (CONST_INT i) } with
{ Parser.CONSTANT (CONST_INT i) }, which gave me a more informative error

File "lexer.mll", line 33, characters 25-40:
 Error: The constructor Parser.CONSTANT belongs to the variant type
          Parser.token
       but a constructor was expected belonging to the variant type unit
make: *** [Makefile:39: lexer.cmo] Error 2

The same thing happens with the other tokens like ADD and SUB. So I decided to try and fix this error by changing %token <Ast.constant> CONSTANT to %token <unit> CONSTANT, however, that still gave me the same exact error.

So just as a guess, I changed { CONSTANT (CONST_INT i) } to { Ast.CONSTANT ( CONST_INT i) }, which obviously did not work

The first question to ask is, why is does the type-checker expect the expression to have type unit? There must be something in read_token which returns that type.

From looking at the full code in the repository, it seems like the next_line function returns type unit. So now we can see the type error more clearly here:

You likely need to write { next_line lexbuf; read_token lexbuf }.

1 Like

Thanks, now that seems really obvious

1 Like