Search code examples
f#tuplesgrammarrecordfsyacc

Using record types in FSYACC


In FSYACC it is common to have terminals that result in tuples. However, for convenience I want to use a record type instead. For example, if I have the following in my Abstract Syntax Tree (AbstractSyntaxTree.fsl):

namespace FS
module AbstractSyntaxTree =

 type B = { x : int; y : int }

 type Either = 
      | Record of B
      | Tuple of int * string

 type A =
     | Int of int
     | String of string
     | IntTuple of Either

I'm not clear on the correct syntax in FSYACC (parser.fsy), because if I use:

%start a
%token <string> STRING
%token <System.Int32> INT
%token ATOMTOKEN TUPLETOKEN EOF
%type < A > a

%%

a:
    | atomS { $1 }
    | atomI { $1 }
    | either { $1 }

atomI:
    | ATOMTOKEN INT   { Int($2) }

atomS:
    | ATOMTOKEN STRING { String($2)  }

either:
    | TUPLETOKEN INT INT { Record {x=$2;y=$3} } // !!!
    | TUPLETOKEN TUPLETOKEN INT STRING { Tuple( $3, $4) } // !!!

I would expect the type B and the Tuple to be inferred. However, FSYACC gives the error for both of the lines marked with "!!!":

This expression was expected to have type  A but here has type Either

What is the correct syntax to for the "either" production on the last two lines?


Solution

  • Don't you mean IntTuple($2, $3) as opposed to B($2, $3)? I'd try IntTuple{x=$2; y=$3}

    EDIT: this works:

    module Ast
    
    type B = { x : int; y : int }
    type A =
        | Int of int
        | String of string
        | IntTuple of B
    

    and

    %{
    
    open Ast
    
    %}
    
    %start a
    %token <string> STRING
    %token <System.Int32> INT
    %token ATOMTOKEN TUPLETOKEN 
    %type < Ast.A > a
    
    
    %%
    
    a:
        | atom { $1 }
        | tuple { $1 }
    
    atom:
        | ATOMTOKEN INT   { Int($2) }
        | ATOMTOKEN STRING { String($2) }
    
    tuple:
        | TUPLETOKEN INT INT { IntTuple {x = $2; y = $3} }
    

    EDIT 2: Take good care, that the line %type < Ast.A > a requires your non-terminal a to be of type Ast.A. So therefore, since you are using the non-terminal tuple directly, tuple needs to be of type Ast.A. As such, you have to wrap the record in IntTuple, so the syntax is IntTuple {x = $2; y = $3} as opposed to just {x = $2; y = $3}.