You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Having spent some time thinking about this (see #1 and #2), my conclusion is that we need a mapping to Java which produces something as close to "normal" Java as possible. My proposed mapping is thus:
Primitives.
bool as JVM boolean. byte as JVM byte.
u8 and i8 as JVM byte. For u8, this requires jiggery pokery using & 0xFF in places.
u16 as JVM char, i16 as JVM short. This works since JVM char is unsigned 16-bit.
u32 as JVM long, i32 as JVM int. Potentially could try to map u32 to JVM int with jiggery pokery.
u64 unmapped, i64 as JVM long. Here, u64 is just treated as int.
int mapped to JVM BigInteger.
Arrays.T[] mapped to JVM array T[]. This works, though requires external method for array generators [v;n].
Records mapped to JVM classes of same name. These classes are implemented as structs, but include obvious methods: equals(), hashCode(), clone().
Unions, Intersections and Negations mapped to Object. An interesting question is whether or not we want tags of some kind. Also, a union of the form T|null can be mapped to reference type for T (e.g. i32|null maps to Integer).
References.
Function / Methods.
This is a pretty decent mapping in general, and should make interoperation with Java relatively easy. In particular, mapping records to Java classes means that external code can create and use them. However, there remain a number of questions:
Representation. The used of specific representations (particularly for integer primitives) means that appropriate casts must be introduced. The following example illustrates:
u16 x = 1
u32 y = x // need to cast here.
u32 z = x+y
In addition, there are complications arising from the typing of arithmetic. For example, in x+y above, the calculated return type will be int. We need to back propagate from z to determine the appropriate type for the expression and its arguments.
Anonymous Records. For example, the following is difficult to translate efficiently as its unclear what type to construct for {x: 1, y:2}?
Point p = {x: 1, y: 2}
We can resolve this in two ways. Firstly, anonymous records can be represented using e.g. HashMap<String,Object>, or a type from the Whiley Runtime. Secondly, we can use type inference to back propagate the type Point into the expression {x: 1, y: 2}. This does get tricky though, as it's not always clear what the right type is. For example, null|Point p = {x: 1, y: 2}, well we need to figure out the intended type to construct is Point. Another possibility here would be to introduced named record construction, to allow Point p = Point{x: 1, y: 2}. This syntax is similar to Rust, and I don't believe it would cause any ambiguity in the grammar.
Ownership. Here, we will avoid reference counting. The reason being simply that we cannot retro-fit reference counting onto Java array types. Therefore, a live variables analysis will be used to determine when a variable must be copied, versus when it must be moved. For copying of non-primitive types, we employ clone(). However, care must be taken to minimise this as much as possible. For example, in the expression x == y, we do not need to clone either x or y (even if they are still live). This is somehow similar to Rust's notion of "reference lvals".
Runtime Type Tests. The current JVM backend uses the Whiley runtime to handle runtime type tests. Specifically, traversing their structure to exhaustively determine what they are. This is not exactly idea. An alternative solution would be to translate union types using a specialised Union object which contains the necessary type tag. This makes the FFI harder though, since the user needs to then manually specify tags.
Whiley Runtime. A small runtime library is almost certainly required here. In particular, for implementing array generators, and also presumably for runtime type tests.
The text was updated successfully, but these errors were encountered:
DavePearce
changed the title
Generating Java Source Code
Mapping Whiley to Java
Jan 18, 2017
Having spent some time thinking about this (see #1 and #2), my conclusion is that we need a mapping to Java which produces something as close to "normal" Java as possible. My proposed mapping is thus:
bool
as JVMboolean
.byte
as JVMbyte
.u8
andi8
as JVMbyte
. Foru8
, this requires jiggery pokery using& 0xFF
in places.u16
as JVMchar
,i16
as JVMshort
. This works since JVMchar
is unsigned 16-bit.u32
as JVMlong
,i32
as JVMint
. Potentially could try to map u32 to JVMint
with jiggery pokery.u64
unmapped,i64
as JVMlong
. Here,u64
is just treated asint
.int
mapped to JVMBigInteger
.T[]
mapped to JVM arrayT[]
. This works, though requires external method for array generators[v;n]
.equals()
,hashCode()
,clone()
.Object
. An interesting question is whether or not we want tags of some kind. Also, a union of the formT|null
can be mapped to reference type forT
(e.g.i32|null
maps toInteger
).This is a pretty decent mapping in general, and should make interoperation with Java relatively easy. In particular, mapping records to Java classes means that external code can create and use them. However, there remain a number of questions:
x+y
above, the calculated return type will beint
. We need to back propagate fromz
to determine the appropriate type for the expression and its arguments.{x: 1, y:2}
? We can resolve this in two ways. Firstly, anonymous records can be represented using e.g.HashMap<String,Object>
, or a type from the Whiley Runtime. Secondly, we can use type inference to back propagate the typePoint
into the expression{x: 1, y: 2}
. This does get tricky though, as it's not always clear what the right type is. For example,null|Point p = {x: 1, y: 2}
, well we need to figure out the intended type to construct isPoint
. Another possibility here would be to introduced named record construction, to allowPoint p = Point{x: 1, y: 2}
. This syntax is similar to Rust, and I don't believe it would cause any ambiguity in the grammar.clone()
. However, care must be taken to minimise this as much as possible. For example, in the expressionx == y
, we do not need to clone eitherx
ory
(even if they are still live). This is somehow similar to Rust's notion of "reference lvals".Union
object which contains the necessary type tag. This makes the FFI harder though, since the user needs to then manually specify tags.The text was updated successfully, but these errors were encountered: