Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

let expressions error #147

Open
est77 opened this issue Feb 25, 2023 · 2 comments
Open

let expressions error #147

est77 opened this issue Feb 25, 2023 · 2 comments

Comments

@est77
Copy link

est77 commented Feb 25, 2023

After updating wiz recently, one of my projects now fails to build with a let expression error.

Minimal repro:

in ram
{

var g_entity_data_0 : [u16 ; 16];

}; // ram.

let g_player_action = g_entity_data_0[0];

in prg
{

#[mem16, idx16]
func test()
{
aa = g_player_action;

// error: `g_player_action` is a `let` expression, so it cannot accept a run-time expression

}

} // prg

@MikeDX
Copy link

MikeDX commented Mar 14, 2023

I am also getting this problem

https://github.com/MikeDX/pitfall-wiz

My pitfall wiz seems to be broken now. Apparently I can't assign something like

let INTIM = vcs.timer.value;

where vcs.timer.value is from:

namespace vcs {
  namespace timer {
    var value @ 0x284 : u8;
  }
}

Am I missing something? Did "let" change, or can i define a macro like this so that INTIM resolves to vcs.timer.value in this way

error: `INTIM` is a `let` expression, so it cannot accept a run-time expression

@Bananattack
Copy link
Collaborator

Bananattack commented Mar 22, 2023

Sorry for the delay on responding here. Things are currently on hiatus while I work to rewrite Wiz.

There was a change more recently to make let only be able to bind to compile-time constant expressions. There was a long-standing defect in the language that would allow any expression to be bound with let even if those expressions had side-effects. This would mean any time that those values were substituted, those effects would be evaluated. I could have added a compatibility option here, but long-term this wouldn't be supported and shouldn't have been possible to do in the language.

There's a few alternative solutions that should work:

Option 1: You can put an explicit address @ addr after the variable name to specify the exact address where it should be located. By passing taking another variable's address with & and using that as the explicit address, you can force these variables to alias another variable's address:

var g_player_action @ &g_entity_data_0 : u16;

Option 2: You can write T in expr as the variable's type, to create a typed view* of another variable or register, so long as it matches in size (eg. you can give another name to the same value with the same type, but you can also make a i8 view of a u8, a pointer view of a u16, etc). Prefer method 1 if you need different sized things at the same address, or using more complicated types that aren't compatible with each other. Prefer method 2 if you want to easily bind to either a register or var, without needing an address (since registers don't have addresses), or wanting to use things as function arguments.

* (also called "designated storage" in some parts of the compiler, but this name is a bit confusing and I want to retire it eventually)

var g_player_action : u16 in g_entity_data[0];

Option 3: You can use a union with all the stuff you want to share an address.

struct PlayerData {
    action: u16,
}

union EntityData {
    words: [u16; 16],
    player_data: PlayerData,
}

var g_entity_data : EntityData;

Future Option (Not implemented): On the roadmap for the in-progress Wiz rewrite, I want to introduce a ref keyword. This will be able to bind to arbitrary l-value terms at compile-time. Also, inline functions will be able to take ref parameters so that each call is inlined with knowledge of the exact l-value operands it's acting on, without having to make duplicate versions of inline functions.

ref g_player_action = g_entity_data_0[0];

inline func add(ref left: u8, ref right : u8) {
    left += right;
}
add(hl, bc);

Note that due to a current quirk with var declarations in the language, the options 1 + 2 must defined in code within an in block such as in my_bank { ... } block, even though they don't actually reserve any new bank storage.

However, option 1 can be used for extern vars like those used for registers, you can write them anywhere.

extern var foo @ &myothervar : u8;

Options 1 + 2 can also be used to make convenient local names for static vars and registers. Finally, option 2 works for parameters + return values in function signatures.

Hope that helps! Let me know if you have further questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants