Map literals in ASH (potential feature)

Veracity

Developer
Staff member
Actually needs two little patches:

- One when you have just defined an aggregate
- One when you have a multiple layer map and are parsing an aggregate literal.

With revision 17658:

Code:
record rec1 { int a; string b; };

rec1 [int,int] rmap {4: {4: new rec1( 10, "abc" ) }, 10: {40: new rec1( 100, "xyz" ) } };

foreach key1, key2, val in rmap {
    print( "[ " + key1 + ", " + key2 + " ] -> ( " + val.a + ", " + val.b + " )" );
}
yields

Code:
[color=green]> test-map2[/color]

[ 4, 4 ] -> ( 10, abc )
[ 10, 40 ] -> ( 100, xyz )
I like it.
 

Veracity

Developer
Staff member
For Reference, I tried something I imagined would work, but didn't. I have this code:

Code:
// Far Future rewards
static item RIKER = $item[ Riker's Search History ];		// combat item: 900-1000 sleaze damage
static item KARDASHIAN = $item[ Shot of Kardashian Gin ];	// EPIC 1 drunk booze, +3 PVP fights
static item POINTY_EARS = $item[ Unstable Pointy Ears ];	// accessory disappears at rollover, +3 stats
static item MEMORY_DISK = $item[ Memory Disk, Alpha ];		// usable, allows access to The Far Future
static item EARL_GREY = $item[ Tea, Earl Grey, Hot ];		// EPIC 1 full food, 1000 MP and 1000 HP

// Keyword for Exandora's FarFuture script to replicate each item
static string [item] FAR_FUTURE_OPTION;
static
{
    FAR_FUTURE_OPTION[ RIKER ] = "riker";
    FAR_FUTURE_OPTION[ KARDASHIAN ] = "booze";
    FAR_FUTURE_OPTION[ POINTY_EARS ] = "ears";
    FAR_FUTURE_OPTION[ MEMORY_DISK ] = "memory";
    FAR_FUTURE_OPTION[ EARL_GREY ] = "food";
}
I tried to initialize using a map literal: { RIKER: "riker", ...} but it didn't work.
That's because although RIKER is (correctly) of type "item", it is not a constant. It is a Variable Reference. And, unfortunately, since static initialization happens at run time, not compile time, we can't even evaluate it at compile time.

The map literal however does happen at compile time. If we generated code to initialize the map at runtime, we'd presumably evaluate the lhs and rhs.

That is not how this works, though, so we should presumably require them to actually be constants and disallow variable references.
 

heeheehee

Developer
Staff member
It doesn't work even if you remove static, if I'm not mistaken.

I agree that the two reasonable approaches are either to make the literal resolve during runtime, or to require keys to be const. I personally would prefer the former because it's less surprising to me, especially since values resolve as expected.
 

heeheehee

Developer
Staff member
Looking back at r17654 -- we clearly evaluate the value.
Code:
 entry.setValue( entry.getValue().execute( interpreter ) );

I wonder if this would be as simple as just evaluating the key, as well.
 

heeheehee

Developer
Staff member
Apparently setKey doesn't exist, so you'd have to construct a whole separate map. I guess you could cache that with an "isEvaluated" boolean private property.
 

heeheehee

Developer
Staff member
On the other hand, if you wanted to require keys to be const, you could just throw an exception in Parser.parseAggregateLiteral if the lhs is a VariableReference.
 

Veracity

Developer
Staff member
Test program:

Code:
// Far Future rewards
static item RIKER = $item[ Riker's Search History ];		// combat item: 900-1000 sleaze damage
static item KARDASHIAN = $item[ Shot of Kardashian Gin ];	// EPIC 1 drunk booze, +3 PVP fights
static item POINTY_EARS = $item[ Unstable Pointy Ears ];	// accessory disappears at rollover, +3 stats
static item MEMORY_DISK = $item[ Memory Disk, Alpha ];		// usable, allows access to The Far Future
static item EARL_GREY = $item[ Tea, Earl Grey, Hot ];		// EPIC 1 full food, 1000 MP and 1000 HP

// Keyword to ask Exandora's FarFuture script to replicate each item
static string [item] FAR_FUTURE_OPTION;
static
{
    FAR_FUTURE_OPTION[ RIKER ] = "riker";
    FAR_FUTURE_OPTION[ KARDASHIAN ] = "booze";
    FAR_FUTURE_OPTION[ POINTY_EARS ] = "ears";
    FAR_FUTURE_OPTION[ MEMORY_DISK ] = "memory";
    FAR_FUTURE_OPTION[ EARL_GREY ] = "food";
}

foreach key, value in FAR_FUTURE_OPTION {
    print( key + " (" + key.to_int() + ") -> " + value );
}
yields:

Code:
Riker's Search History (9118) -> riker
Shot of Kardashian Gin (9119) -> booze
Unstable Pointy Ears (9120) -> ears
Memory Disk, Alpha (9121) -> memory
Tea, Earl Grey, Hot (9122) -> food
With literals, test program:

Code:
// Far Future rewards
static item RIKER = $item[ Riker's Search History ];		// combat item: 900-1000 sleaze damage
static item KARDASHIAN = $item[ Shot of Kardashian Gin ];	// EPIC 1 drunk booze, +3 PVP fights
static item POINTY_EARS = $item[ Unstable Pointy Ears ];	// accessory disappears at rollover, +3 stats
static item MEMORY_DISK = $item[ Memory Disk, Alpha ];		// usable, allows access to The Far Future
static item EARL_GREY = $item[ Tea, Earl Grey, Hot ];		// EPIC 1 full food, 1000 MP and 1000 HP

// Keyword to ask Exandora's FarFuture script to replicate each item
static string [item] FAR_FUTURE_OPTION {
     RIKER : "riker",
     KARDASHIAN : "booze",
     POINTY_EARS : "ears",
     MEMORY_DISK : "memory",
     EARL_GREY : "food"
};

foreach key, value in FAR_FUTURE_OPTION {
    print( key + " (" + key.to_int() + ") -> " + value );
}
yields:

Code:
EARL_GREY (0) -> food
KARDASHIAN (0) -> booze
MEMORY_DISK (0) -> memory
POINTY_EARS (0) -> ears
RIKER (0) -> riker
We cannot evaluate the key at compile time since, although it looks like a constant, it doesn't actually get initialized until run time.

I'll make the aggregate literal into something that evaluates at runtime. How hard can it be? :)
 

Veracity

Developer
Staff member
With revision 17878,

Code:
// Far Future rewards
static item RIKER = $item[ Riker's Search History ];		// combat item: 900-1000 sleaze damage
static item KARDASHIAN = $item[ Shot of Kardashian Gin ];	// EPIC 1 drunk booze, +3 PVP fights
static item POINTY_EARS = $item[ Unstable Pointy Ears ];	// accessory disappears at rollover, +3 stats
static item MEMORY_DISK = $item[ Memory Disk, Alpha ];		// usable, allows access to The Far Future
static item EARL_GREY = $item[ Tea, Earl Grey, Hot ];		// EPIC 1 full food, 1000 MP and 1000 HP

// Keyword to ask Exandora's FarFuture script to replicate each item
static string [item] FAR_FUTURE_OPTION {
     RIKER : "riker",
     KARDASHIAN : "booze",
     POINTY_EARS : "ears",
     MEMORY_DISK : "memory",
     EARL_GREY : "food"
};

foreach key, value in FAR_FUTURE_OPTION {
    print( key + " (" + key.to_int() + ") -> " + value );
}
yields:

Code:
Riker's Search History (9118) -> riker
Shot of Kardashian Gin (9119) -> booze
Unstable Pointy Ears (9120) -> ears
Memory Disk, Alpha (9121) -> memory
Tea, Earl Grey, Hot (9122) -> food
 

heeheehee

Developer
Staff member
Certainly a different approach than I would have taken, but hey, works just as well (and probably a bit more efficient, too).
 

Veracity

Developer
Staff member
We probably no longer need the MapValue.execute override, correct?
Let me think about that. When we call initialValue() on an AggregateType(), we get back either a MapValue or an ArrayValue (each of which is an AggregateValue).

AggregateLiteral also is-a AggregateValue.

So, when do we call the execute() method of an AggregateValue? I'm not sure.

For an AggregateLiteral, it creates and fills in the MapValue or ArrayValue and subsequent calls to execute() will get the same thing.

For a MapValue, it calls execute to evaluate and bind the values of every key.
Ditto for an ArrayValue.

I am not sure why. I'm going to have to figure out/relearn when we call execute on these objects...
 

Veracity

Developer
Staff member
When we assign the AggregateLiteral to a Map, it calls the execute method and generates the MapValue.
I have been unable to find where/how the execute method of a MapValue or ArrayValue is called.
Looking at Assignment, you'd think that might do it, but no; if you have a map in one variable and copy it to another, the rhs is a VariableReference.
 

Veracity

Developer
Staff member
Except my experimentation has not yet found a case where we actually call execute on an AggregateValue, except for the new AggregateLiteral. So, yes - "we call it" because of what you said - but how can I trigger it?
 

heeheehee

Developer
Staff member
IIRC, it's called when we try to access the value. I thought those changes were originally needed to handle nested literals?
 

Veracity

Developer
Staff member
Huh. You are right. Revision 17654.

I'll see if I can figure out what the issue was and determine if it is still necessary.
 

Veracity

Developer
Staff member
Ah. test-map2.ash. I still have that. And it still works after removing the execute functions from MapValue and ArrayValue.
 
Top