I try to parse the call of a function, here are the variants:
add 8 2
add x y
add (inc x) (dec y)
funcWithoutArgs
Depending on how I distribute my analyzers in the code, and perhaps also how they are coded, I get errors, as well as successful but unwanted analyses. For example, this:
add 4 7
returns the following AST:
[Call ("foo",[Number 4]);
Number 7]
He therefore only takes the first parameter.
When I do that:
foo x y
He sends me back this AST:
[Call ("foo",[Call ("x",[Call ("y",[])])])]
And that's not what I want, since here, each parameter calls the next one as a parameter.
Another example, when I do this:
foo x y
inc x
I get:
[Call ("foo",[Call ("x",[Call ("y",[Call ("inc",[Call ("x",[])])])])])]
It does the same as above, but also calls the code that follows the line. When I ask my analyzer for a new line (see code), it sends me this:
[Call ("foo",[]); Call ("x",[]); Call ("y",[]); Call ("inc",[]); Call ("x",[])]
Even in brackets it doesn't work:
foo (x) (y)
Give:
[Call ("foo",[]); Call ("x",[]); Call ("y",[])]
And:
add (inc x) (dec y)
Give:
Error in Ln: 1 Col: 1
Note: The error occurred on an empty line.
The parser backtracked after:
Error in Ln: 2 Col: 5
add (inc x) (dec y)
^
Expecting: end of input or integer number (32-bit, signed)
The parser backtracked after:
Error in Ln: 2 Col: 10
add (inc x) (dec y)
^
Expecting: ')'
[]
In short, my function call analyzer does not work properly. Every time I change something, like a new line, an attempt, or a different hierarchy, something doesn't work... Do you have any idea how to solve this very annoying problem?
Here is the minimum functional code that was used:
open FParsec
// Ast
type Expression =
| Number of int
| Call of string * Expression list
type Program = Expression list
// Tools
let private bws p =
spaces >>? p .>>? spaces
let private suiteOf p =
sepEndBy p spaces1
let inline private betweenParentheses p label =
between (pstring "(") (pstring ")") p
<?> (label + " between parentheses")
let private identifier =
many1Satisfy2 isLetter (fun c -> isLetter c)
// Expressions
let rec private call = parse {
let! call = pipe2 (spaces >>? identifier) (spaces >>? parameters)
(fun id parameters -> Call(id, parameters)) // .>>? newline
return call
}
and private parameters = suiteOf expression
and private callFuncWithoutArgs =
identifier |>> fun id -> Call(id, [])
and private number = pint32 |>> Number
and private betweenParenthesesExpression =
parse { let! ex = betweenParentheses expression "expression"
return ex }
and private expression =
bws (attempt betweenParenthesesExpression <|>
attempt number <|>
attempt call <|>
callFuncWithoutArgs)
// -------------------------------
let parse code =
let parser = many expression .>>? eof
match run parser code with
| Success(result, _, _) -> result
| Failure(msg, _, _) ->
printfn "%s" msg
[]
System.Console.Clear()
parse @"
add 4 7
foo x y
inc x
foo (x) (y)
add (inc x) (dec y)
" |> printfn "%A"
funcWithoutArgsto be parsed as a function call rather than as an identifier? In every language I'm aware of, calling a function requires different syntax than referring to it: e.g.,func()is a function call, whilefuncis simply a reference to the function. I think part (though not all) of your problem may be stemming from the fact thatfuncWithoutArgsis parsing as a function call. - rmunn[Call ("foo",[Call ("x",[Call ("y",[])])])]is not what you wantfoo x yto parse to, but I can't tell from the types in your example what you would wantfoo x yto parse to. I would assume you would want it to parse to something like[Call ("foo", [Identifier "x"; Identifier "y"])], but there's noIdentifierin the DU in your pared-down example. So what do you wantfoo x yto actually parse to? What's your actually desired result? - rmunnfuncWithoutArgsis, as its name suggests, supposed to be a function call, without arguments, which can be seen as a simple identifier, in fact. For example, in OCaml, Haskell or even F#, there is, as far as I know, no distinction, since the variables/data are simply data that can be applied. That's what I've been trying to replicate. What would you have suggested? Maybe to create a newVariablenode? - Foxyfoo x yshould be analyzed as follows:[call ("foo",[Call ("x", []); call ("y", []))]. According to what I said above. - Foxy