1
votes

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?

1
ok, i got fsyacc now, can you post your fsy?Daniel Fabian
Thanks for the help Daniel. I've taken the working solution you gave and made it resemble more closely my own code. The discriminated union with a record type is one level deeper, the lines I've commented with exclamation marks are the ones for which I can't work out the syntax.Flakker
Oh, that's easy... You still need to return an A, so all you need to do IntTuple(Record{ x = $2; y = $3 } and IntTuple(Tuple( $3, $4))Daniel Fabian
Yes that works perfectly, without adding an extra level. Thanks! Now I need to tidy up the above mess... Do you want to add that to your answer ?Flakker
I extended my answer with an EDIT 2. If this works for you, please be as kind as marking it as answered. And don't hesitate to ask further questions, if you need more help.Daniel Fabian

1 Answers

2
votes

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}.