I have been trying to figure out how to fix some shift reduce conflicts I have. I have looked around and found different topics on fixing it but it seems like no matter what I do I just can't seem to find a way to fix these issues.
I am trying to write a grammar class for Angel Script a popular scripting engine
I got the BNF grammar from the parser class.
You can find the language reference here
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_script.html
And within my class for each rule I addde a comment of the BNF grammar Im trying to copy. At the moment I don't actually use the keywords I define. I will go back and try and clean it up once I can get it working without conflicts.
Here is my class
http://pastebin.com/FydCTqmU
You should be able to just create a Dll and run that with the grammar explorer and you'll see all the errors. It seems like most of the errors all come from the same issue so I think maybe once I can get that fixed it will fix almost everything.
EDIT: Here is the main issue. That is the main script state, I know its broken up into a lot of different rules but I did that so I could try and fix the issue which I still havent had luck with.
EDIT: I tried condensing my code to hopefully get passed the reduce-reduce errors but it seems to stay exactly the same but only looking way more cluttered. If anyone can help me get it right i'll be more then happy to send them a few hundred dollars via paypal. I'm at the point of just giving up its been over a week I've been on this. My email is Anth0ny229#live.com.
State S0 (Inadequate)
Reduce-reduce conflicts on inputs: const identifier void int8 int16 int32 int64 int uint8 uint16 uint32 uint64 uint float double bool ? auto ::
Shift items:
script' -> ·script EOF
script -> ·script_0_list
script_0_list -> ·script_0+
script_0+ -> ·script_0+ script_0
script_0+ -> ·script_0
script_0 -> ·import
import -> ·import type import_0_opt identifier paramlist from string ;
script_0 -> ·enum
enum -> ·enum_0_opt enum identifier { identifier enum_1_opt enum_2_list }
enum_0_opt -> ·shared
script_0 -> ·typedef
typedef -> ·typedef primtype identifier ;
script_0 -> ·class
class -> ·class_0_list class identifier class_1_opt { class_2_list }
class_0_list -> ·class_0+
class_0+ -> ·class_0+ class_0
class_0+ -> ·class_0
class_0 -> ·shared
class_0 -> ·abstract
class_0 -> ·final
script_0 -> ·mixin
mixin -> ·mixin class
script_0 -> ·interface
interface -> ·interface_0_opt interface identifier interface_1_opt { interface_2_list }
interface_0_opt -> ·shared
script_0 -> ·funcdef
funcdef -> ·funcdef type funcdef_0_opt identifier paramlist ;
script_0 -> ·virtprop
virtprop -> ·virtprop_0_opt type virtprop_1_opt identifier { virtprop_2_list }
virtprop_0_opt -> ·private
virtprop_0_opt -> ·protected
script_0 -> ·func
func -> ·func_0_opt func_1_opt identifier paramlist func_2_opt func_3_list statblock
func_0_opt -> ·private
func_0_opt -> ·protected
func_0_opt -> ·shared
script_0 -> ·var
var -> ·var_0_opt type identifier var_1_opt var_2_list ;
var_0_opt -> ·private
var_0_opt -> ·protected
script_0 -> ·namespace
namespace -> ·namespace identifier { script }
script_0 -> ·;
Reduce items:
script_0_list -> · [EOF]
enum_0_opt -> · [enum]
class_0_list -> · [class]
interface_0_opt -> · [interface]
virtprop_0_opt -> · [const identifier void int8 int16 int32 int64 int uint8 uint16 uint32 uint64 uint float double bool ? auto ::]
func_0_opt -> · [const ~ identifier void int8 int16 int32 int64 int uint8 uint16 uint32 uint64 uint float double bool ? auto ::]
var_0_opt -> · [const identifier void int8 int16 int32 int64 int uint8 uint16 uint32 uint64 uint float double bool ? auto ::]
Transitions:
script->S1, script_0_list->S2, script_0+->S3, script_0->S4, import->S5, import->S6, enum->S7, enum_0_opt->S8, shared->S9, typedef->S10, typedef->S11, class->S12, class_0_list->S13, class_0+->S14, class_0->S15, abstract->S16, final->S17, mixin->S18, mixin->S19, interface->S20, interface_0_opt->S21, funcdef->S22, funcdef->S23, virtprop->S24, virtprop_0_opt->S25, private->S26, protected->S27, func->S28, func_0_opt->S29, var->S30, var_0_opt->S31, namespace->S32, namespace->S33, ;->S34
Related
I want to create custom comparison operators for my type (<, >, <=, >=, etc). I have tried:
type MyType() =
static member (>) (left: MyType, right: int) = true
let foo = new MyType();
let bar = foo > 12;
and receive the error:
The type 'MyType' does not support the 'comparison' constraint. For example, it does not support the 'System.IComparable' interface
(Why would a language feature like operator overloading depend on an interface IComparable that comes from a framework? shouldn't the language and the frameworks it use be independent?) So I try:
type MyType() =
interface IComparable
member self.CompareTo yobj = true
interface IComparable<int>
member self.CompareTo yobj = true
static member (>) (left: MyType, right: int) = true
and I get:
This expression was expected to have type 'MyType' but here has type 'int'
How can I get the expected behavior?
The Reason Why You Get Such An Error
I don't know why F# doesn't allow me to write such codes like C#.
public class MyType
{
public int Value {get;set;}
public static bool operator >(MyType left, int right)
{
return left.Value > right;
}
public static bool operator <(MyType left, int right)
{
return left.Value < right;
}
}
Even if this type doesn't implement the IComparable interface, I could compare it with an int as below:
t > 2
t < 6
It seems that F# treat the (>) as a T' -> T' -> bool:
val ( > ):
x: 'T (requires comparison )->
y: 'T (requires comparison )
-> bool
This indicates :
The left and right parameters are the same Type.
The T' requires comparison (IComparable)
If I understand it correctly, this is the reason why you get an error like:
This expression was expected to have type 'MyType' but here has type 'int'
Even if you has implemented the IComparable interface, the standard (>) requires that the left and the right parameters belong to the same Type.
A Walkaround
One walk around is to create a custom function (>) that accepts a left MyType and a right int parameters directly:
type MyType(info) =
member x.Info : int = info
let inline (>) (left: MyType) (right: int) =
left.Info > right
let inline (<) (left: MyType) (right: int) =
left.Info < right
// see https://stackoverflow.com/questions/19682432/global-operator-overloading-in-f
let inline (>) (left) (right) =
match (box left, box right) with
| (:? MyType as l, :? int as r ) ->
l.Info > int right
| (:? IComparable as left', :? IComparable )->
let r = left'.CompareTo right
r > 0
| _ -> failwith "not support type "
let inline (<) (left) (right) =
match (box left, box right) with
| (:? MyType as l, :? int as r ) ->
l.Info < int right
| (:? IComparable as left', :? IComparable )->
let r = left'.CompareTo right
r < 0
| _ -> failwith "not support type "
Note that there is also a warning emitted at the declaration of >:
The name '(>)' should not be used as a member name. To define comparison semantics for a type, implement the 'System.IComparable' interface. If defining a static member for use from other CLI languages then use the name 'op_GreaterThan' instead.
As itminus' answer shows, this is because > is defined on two 'Ts that satisfy the comparable constraint.
There is no operator overloading in F# like you can do in C#. This is because operators are functions, and functions cannot be overloaded.
So your choices are either to (a) implement System.IComparable as the warning suggests, or (b) apply a workaround with inline functions as itminus proposes.
In F#, I can write a function (fun x -> x * x) and confirm it has type int->int because the following code compiles:
let typeCheck<'T> (x:'T) = ()
typeCheck<int->int> (fun x -> x*x)
On the other hand, GetType for this function doesn't agree with typeof<int->int>:
> (fun x -> x*x).GetType() = typeof<int -> int>
val it : bool = false
If not GetType() and typeof, what functions can I call to mimic the type-checking done by the compiler?
The reason why GetType of a specific lambda function is not the same as typeof<int -> int> is that the F# compiler generates a new class for the function which inherits from int -> int. In other words, the types are not the same, but the type you get via GetType inherits from int -> int.
You can check for this easily using IsAssignableFrom. The following is true:
typeof<int -> int>.IsAssignableFrom((fun x -> x*x).GetType())
You can use the :? operator to check based on type. I boxed it because (int -> int) is a sealed type.
F# Why can't I use the :? operator in F# interactive?
> let f = box (fun x -> x*x);;
val f : obj
> f :? (int -> int);;
val it : bool = true
If you wanted to build your typecheck function you could use this. A 'T and a thing of type 'T, they would always have the same type so I made x an object here, and you can box it before looking at it. However you probably don't need to do this, so if you're new to F# you may be working harder than you need to.
let typeCheck<'T> (x: obj) =
x :? 'T
//which is the same as
x :? (int -> int)
//so you probably don't need to define your own :)
I've distilled these sample types from my design:
type SomeType = T1 of int | T2 of string
type Condition = Int | String
Now, for unit testing purposes and other reasons that were distilled from here(design can't be changed), I must create SomeType values based on Condition tag.
However, my first attempt didn't compile:
let inline createSomeType' (someTypeVal : ^T, cond) =
match cond with
| Int -> T1 someTypeVal // warning FS0064: 'T restricted to "int"
| String -> T2 someTypeVal // error FS0001: expected "string" got "int"
Changing function signature to createSomeType'< ^T > didn't help either:
error FS0001: expected "int" got 'T
error FS0001: expected "string" got 'T
Then I tried overloading:
type detail =
static member inline dispatch (someTypeVal : int) = T1 someTypeVal
static member inline dispatch (someTypeVal : string) = T2 someTypeVal
let inline createSomeType' (someTypeVal : ^T, cond) =
match cond with
| Int -> detail.dispatch someTypeVal // error FS0041: ambiguous overload
| String -> detail.dispatch someTypeVal // error FS0041: ambiguous overload
Let's disambigue, right? No, adding type annotations restricts someTypeVal to int and we're back where we started.
From C++ point of view, all that means that F# compiler doesn't support SFINAE on union cases in pattern matching.
We could use quotations or dynamic checking like this:
A)
let inline createSomeType ((someTypeVal : obj), cond) =
match box someTypeVal with
| :? int when cond = Int -> T1(someTypeVal :?> int)
| :? string when cond = String -> T2(someTypeVal :?> string)
| _ -> failwith "something happened:("
B)
type Condition = Int = 0 | String = 1
type detail =
static member inline dispatch ((someTypeVal : int), (c : int)) =
if Condition.Int = enum<Condition>(c) then
T1 someTypeVal
else
failwith "something happened:("
static member inline dispatch ((someTypeVal : string), (c : int)) =
if Condition.String = enum<Condition>(c) then
T2 someTypeVal
else
failwith "something happened:("
detail.dispatch(123, int Condition.Int) // usage
However, that's not concise and throws exceptions.
How should I implement createSomeType function so it does everything at compile-time?
P.S. The question is intentionally detailed because I couldn't find much info on this subject in one place, so someone googling will save time not repeating my errors.
EDIT:
Basically, I needed a single convenient function which uses both cond and someTypeVal with a signature like ^TVal -> Condition -> SomeType and compile time type resolution.
As #Gustavo says, IIUC, it's not possible without writing N * M overloads:
you can't expect the compiler to check for the cases contained in
cond, since those cases are values.
As stated in the comments it is not clear for me what do you want to achieve.
What's deciding? The VALUE of cont or the TYPE of SomeType?
All errors you're getting make totally sense to me. In the first attempt, the first case of the match assumes you receive an integer, so it unifies with integer. Otherwise the value should come boxed, like this:
let createSomeType' (someTypeVal : obj, cond) =
match cond with
| Int -> T1 (someTypeVal :?> int )
| String -> T2 (someTypeVal :?> string)
In the second attempt the problem is that overloading in F# doesn't work like that. It tries to resolve at the call site, unless the overload involves static constraints, which in this case doesn't.
This code will work:
type SomeType = T1 of int | T2 of string
type Condition = Int | String
type Detail = Detail with
static member ($) (Detail, someTypeVal : int) = T1 someTypeVal
static member ($) (Detail, someTypeVal : string) = failwith "something went wrong"; T2 someTypeVal
static member (%) (Detail, someTypeVal : string) = T2 someTypeVal
static member (%) (Detail, someTypeVal : int) = failwith "something went wrong"; T1 someTypeVal
let inline createSomeType' (someTypeVal : ^T, cond) =
match cond with
| Int -> Detail $ someTypeVal
| String -> Detail % someTypeVal
You can expect the compiler to check on the type of someTypeVal because it's a type and it will be checked at compile-time, but you can't expect the compiler to check for the cases contained in cond, since those cases are values.
A common misconception is that cases of a Discriminated Union represent types, in fact they represent different values on a single type.
If you will rely on types you don't need cond at all. Then your code will be:
type SomeType = T1 of int | T2 of string
type Detail = Detail with
static member ($) (Detail, someTypeVal : int) = T1 someTypeVal
static member ($) (Detail, someTypeVal : string) = T2 someTypeVal
let inline createSomeType' (someTypeVal : ^T) = Detail $ someTypeVal
I used operators instead of named methods because they infer the signature with the static constraints automatically, but you can use named methods as well.
In the following code:
type ParseResult<'a> =
{
Result : Option<'a>;
Rest : string
}
type Parser<'a> = string -> ParseResult<'a>
let ThenBind p (f : Option<'a> -> Parser<'b>) : Parser<'b> =
fun input ->
let r = p input
match r.Result with
| None -> { Result = None; Rest = input }
| _ -> (f r.Result) r.Rest
With the type annotation for f, the type for ThenBind is:
p:(string -> ParseResult<'a>) ->
f:(Option<'a> -> Parser<'b>) ->
input:string -> ParseResult<'b>
But without the annotation, it's:
p:(string -> ParseResult<'a>) ->
f:(Option<'a> -> string -> ParseResult<'b>) ->
input:string -> ParseResult<'b>
Why?
You don't need a type annotation. The two types are identical.
Parser<'a> is just an alias string -> ParseResult<'a>, so it makes no difference whether the result type of f is declared as Parser<'b> or string -> ParseResult<'b>. They're the exact same type.
So as far as I understand, the convention is to define your type, and then define a module with the same name after it with the functions that operate on the type.
I'm trying to do that so I have this code
namespace Rand
type ImmutableRandom
module ImmutableRandom =
open System
val fromSeed : int -> ImmutableRandom
val int : ImmutableRandom -> int
val intInRange : ImmutableRandom -> int -> int -> int
val double : ImmutableRandom -> double
val next : ImmutableRandom -> ImmutableRandom
I'm getting the error that ImmutableRandom (the name of the module is underlined) is redefining a type or a module.
In the very same project, the identical setup works for a different type, with the only difference being that that type has a generic parameter, while ImmutableRandom doesn't.
What am I doing wrong?
Use the CompilationRepresentation attribute on your module so that it has the same name in source, but not in IL:
namespace Rand
type ImmutableRandom
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module ImmutableRandom =
open System
val fromSeed : int -> ImmutableRandom
val int : ImmutableRandom -> int
val intInRange : ImmutableRandom -> int -> int -> int
val double : ImmutableRandom -> double
val next : ImmutableRandom -> ImmutableRandom
This will cause the module to be named ImmutableRandomModule in IL (and consequently from languages other than F#). This has a few advantages over static members, which are well summarized in this answer: F# code organization: types & modules
This works if the type is generic. Otherwise, there is ambiguity that the compiler cannot resolve on its own.
If you really feel the need to do this with a non-generic type, define all the functions as static members on the type. A bit less elegant, but you get the same surface API.