Foxy
Foxy

Reputation: 1099

Parsing the calling of a function without an argument in the parameters of a function - FParsec

I'm trying to implement an analyzer via a monadic parser combination using FParsec. I also use an indentation module, but it is not important for the current problem.

So I'm trying to parse this branch of my little AST:

type Identifier = string

type Expression =
    ...
    | Call of Identifier * Expression list
    ...
type Program = Program of Expression list

I have this implementation:

// Identifier parser
let private identifier =
    many1Satisfy2L isLetter
        (fun c -> isLetter c || isDigit c) "identifier"

// Monadic parser
let call = parse {
        let! id = identifier
        let! parameters = sepBy parameter spaces1
        return Call(id, parameters)
    }

and expression =
    ... // <|>
    attempt call // <|>
    ...

parameter represents all acceptable expressions in a function call as a parameter:

// All possible parameter
let parameter =
    attempt pint32 <|> // A number, for example.
    attempt (identifier |>> fun callid -> Call(callid, [])) <|>
    attempt (between (pstring "(") (pstring ")") call)

As you can see, there are two elements of the parser that use the "C/call". They correspond to this, in order and for example:

add x 1  // Call the function `add` and passing it another call (`x`) and the simple literal `1`
add (add 8 2) 10 // Call the function `add` and passing it another call (`add 8 2`) and the simple literal `10`

And of course, these elements can also be intertwined:

add (add x 1) 7

The problem, which I obviously can't solve otherwise I won't ask the question, is that the generated tree doesn't look like what is expected:

add x 1 gives:

Success: Program [Call ("add",[Call ("x",[]); Literal (Int 1)])]

In other words, the parser seems to identify the following x as the arguments of x.

However, the second way works. add (add 8 2) 10 gives:

Success: Program
  [Call
     ("add",[Call ("add",[Literal (Int 8); Literal (Int 2)]); Literal (Int 10)])]

Could you put me on track?

Upvotes: 1

Views: 49

Answers (1)

To me it looks like the following line matches x:

attempt (identifier |>> fun callid -> Call(callid, [])) <|>

A single identifier is seen as a call.

It therefore doesn't suprise that you get: [Call ("add",[Call ("x",[]); Literal (Int 1)])

As you think this is wrong what is the expected results for you? I would have expected this to be an identifer dereference expression.

Also a tip, you seem to have opted for the OCaml style of invoking functions like so: f x y

Perhaps you should also go for the OCaml style that a function always takes a single argument and returns a single value.

add x 1 would then be parsed into something like: Apply (Apply (Identifier "add", Identifier "x"), Literal 1)

Upvotes: 1

Related Questions