Create more objects of the same type - xtext

I have a DSL with some constant and variable declarations, like:
const c1 : Int
const c2 : Int
vars
v1 : Int
v2 : Int
b : Bool
But I would like to have something like this:
const c1, c2 : Int
vars
v1, v2 : Int
b : Bool
I couldn't find a way from the grammar to have that...What would be the solution?

you can achive this my do a model 2 model transformation using IDerivedStateComputer
see http://xtextcasts.org/episodes/18-model-optimization for an example

Related

CXXRecordDecl with child VarDecl?

Let's say I have a CXXRecordDecl with only static members, all raised to external linkage:
struct S {
static constexpr int x = 10;
static constexpr int y = 20;
static void foo() {...}
};
The AST is as follow:
TranslatioUnitDecl
...
CXXRecordDecl struct S definition
-CXXRecordDecl implicit struct S
-VarDecl x
-IntegralLiteral 10
-VarDecl y
-IntegralLiteral 20
-CXXMethodDecl foo
...
I think due to the "static" data member, there is no FieldDecl in the CXXRecordDecl, there are 2 VarDecl instead. So how do I access the 2 VarDecl from CXXRecordDecl? There is no API function in CXXRecordDecl for that.
The only way I can think of is to use a RecursiveASTVisitor class and visit all decls. A VarDecl has boolean API functions isStaticDataMember() and isConstexpr() to help, great! But how do I know what is the parent class for these static VarDecl?
Any suggestion will be appreciated profoundly!
I think I found my own answer. There is a base class DeclContext for many block decls, including RecordDecl. This class has public member functions to iterate all the decls within the struct, look at decls_begin() and decls_end().

f# static member constraint with multiple tupled arguments

From f# I'm trying to call a function on a C# defined object using a member constraint. Since the c# member function take multiple arguments the f# compiler treats it as a tuple but when applying the generic member constraint I get an error that the function takes 4 arguments but I've only supplied one.
I've tried forming the tuple from the arguments or just taking the pre-tupled set of arguments but both give the same error. I think I must be defining my member constraint incorrectly but there aren't a lot of examples of member constraints with multiple arguments.
let inline wrapForDecode (buffer:DirectBuffer) (offset:int) (blockLen:uint16) (version:uint16) : ^a =
let msg = new ^a()
(^a : (member WrapForDecode : (DirectBuffer*int*int*int)->unit) msg, (buffer, offset, (int blockLen), (int version)))
msg
let inline wrapForDecode2 (args :DirectBuffer*int*int*int) : ^a =
let msg = new ^a()
(^a : (member WrapForDecode : (DirectBuffer*int*int*int)->unit) (msg, args))
msg
The original WrapForDecode member function is defined in c# like:
public void WrapForDecode(DirectBuffer buffer, int offset, int actingBlockLength, int actingVersion) {...}
When I try to call the function I get the following error for either wrapForDecode or wrapForDecode2.
The member or object constructor 'WrapForDecode' takes 4 argument(s) but is here given 1. The required signature is 'MDInstrumentDefinitionFuture27.WrapForDecode(buffer: DirectBuffer, offset: int, actingBlockLength: int, actingVersion: int) : unit'.
If you change the type of WrapForDecode's argument from (DirectBuffer*int*int*int) to DirectBuffer*int*int*int the first inline method will compile:
let inline wrapForDecode (buffer:string)
(offset:int)
(blockLen:uint16)
(version:uint16)
: ^a =
let msg = new ^a()
(^a : (member WrapForDecode : string * int * int * int -> unit)
msg,
buffer,
offset,
(int blockLen),
(int version))
msg
type foo () =
member this.WrapForDecode (a : string, b: int, c: int, d:int) =
()
let x : foo = wrapForDecode "asd" 1 2us 3us
In ordinary F# code, the two signatures would be equivalent - all methods take a single argument, and to write a function with arity > 1 it must either be curried or take a tupled argument.
However, that is not how the CLI works - in C#/VB.Net land, foo1(x : bar, y : baz) has a different signature from foo2(xy : Tuple<bar, baz>).
Normally the F# compiler automatically translates between the two styles, and so when accessing non-F# .NET code from F# you will see both methods as taking a tupled argument.
But statically-resolved member constraints are a complicated and relatively fringe feature of F#, so it appears that this automatic translation isn't or cannot be performed when invoking methods this way.
(thanks to #ildjarn for pointing out the source of this difference)

Duplicate definition of type or module when defining a type and a module with the same name

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.

No argument names in abstract declaration?

This is the typical declaration of an abstract member in F#:
abstract member createEmployee : string -> string -> Employee
You define the argument types but not their names. Without names, how do you tell what each parameter is when you implement the interface? In other words, how do you know if the interface expects to be implemented as 1- or 2-?
1- member this.createEmployee firstName lastName = ...
2- member this.createEmployee lastName firstName = ...
Am I looking the problem from a wrong perspective (being used to C#)?
What about:
abstract member createEmployee : firstName:string -> lastName:string -> Employee
?
The syntax for this is super fiddly IMO. I wanted to do this with the parameters as a tuple (like a C# method) and only through trial and error did I find this to work:
abstract member PutChar : x:int * y:int * c:char * flag:Background -> unit
And this uglier variant also works:
abstract member PutChar : x : int * y : int * c : char * flag : Background -> unit
Below are things that all felt reasonable but failed with the same error - Unexpected symbol ':' in member definition.:
// ALL BAD vvv
abstract member PutChar : (x:int * y:int * c:char * flag:Background) -> unit
abstract member PutChar : (x:int, y:int, c:char, flag:Background) -> unit
abstract member PutChar : (x:int) * (y:int) * (c:char) * (flag:Background) -> unit
// ALL BAD ^^^

Static Member Indexed Properties

Is it possible to create static member indexed properties in F#? MSDN show them only for instance members, however, I'm able to define the following class:
type ObjWithStaticProperty =
static member StaticProperty
with get () = 3
and set (value:int) = ()
static member StaticPropertyIndexed1
with get (x:int) = 3
and set (x:int) (value:int) = ()
static member StaticPropertyIndexed2
with get (x:int,y:int) = 3
and set (x:int,y:int) (value:int) = ()
//Type signature given by FSI:
type ObjWithStaticProperty =
class
static member StaticProperty : int
static member StaticPropertyIndexed1 : x:int -> int with get
static member StaticPropertyIndexed2 : x:int * y:int -> int with get
static member StaticProperty : int with set
static member StaticPropertyIndexed1 : x:int -> int with set
static member StaticPropertyIndexed2 : x:int * y:int -> int with set
end
But when I try to use one, I get an error:
> ObjWithStaticProperty.StaticPropertyIndexed2.[1,2] <- 3;;
ObjWithStaticProperty.StaticPropertyIndexed2.[1,2] <- 3;;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error FS1187: An indexer property must be given at least one argument
I tried a few different syntax variations and none worked. Also weird is that when I hover over set in VS2010 for one of the definitions in the type, I get info about ExtraTopLevelOperators.set.
If you wanted to recover the Type.Prop.[args] notation, then you can define a simple object to represent an indexable property with the Item property:
type IndexedProperty<'I, 'T>(getter, setter) =
member x.Item
with get (a:'I) : 'T = getter a
and set (a:'I) (v:'T) : unit = setter a v
type ObjWithStaticProperty =
static member StaticPropertyIndexed1 =
IndexedProperty((fun x -> 3), (fun x v -> ()))
ObjWithStaticProperty.StaticPropertyIndexed1.[0]
This returns a new instance of IndexedProperty every time, so it may be better to cache it. Anyway, I think this is quite nice trick and you can encapsulate some additional behavior into the property type.
A digression: I think that an elegant extension to F# would be to have first-class properties just like it has first-class events. (You could for example create properties that automatically support INotifyPropertyChange with just one line of code)
I believe that you call indexed properties using a different syntax (whether instance or static):
ObjWithStaticProperty.StaticPropertyIndexed2(1,2) <- 3
The only semi-exception to this is that an Item property on an instance x can be called via x.[...] (that is, Item is omitted and brackets are used around the arguments).

Resources