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

Idents in Meta #23

Open
ExpHP opened this issue Apr 9, 2021 · 2 comments
Open

Idents in Meta #23

ExpHP opened this issue Apr 9, 2021 · 2 comments
Labels
internals This is about internal APIs or code style

Comments

@ExpHP
Copy link
Owner

ExpHP commented Apr 9, 2021

The basic problem

I want meta for MSG to look something like this:

meta {
    scripts: {
        0: {script: someScriptIdent},
        1: {script: anotherIdent, flags: 0xbc},
    },
}

where someScriptIdent and anotherIdent are names of scripts. The thing is, we can't really do this the same way we've been doing sprite IDs; they can't just be treated as consts because they are offsets that we can't evaluate until we're almost done writing a binary file!

@ExpHP ExpHP added the internals This is about internal APIs or code style label Apr 9, 2021
@ExpHP
Copy link
Owner Author

ExpHP commented Apr 9, 2021

The solution I tried

Personally speaking, I am also bothered by the fact that ANM sprite IDs currently get special treatment; they are type-checked and evaluated in a completely different manner from all other expressions in meta. So I came up with a solution intended to tackle that problem as well:

  • Visitors like the const simplifier should not recurse into meta.
  • Instead, when parsing meta, it could be done in two stages:
    • Let's say you want to parse to f32. First it would broadly check the kind of meta (array, object, expr) and give an error upfront if not an expr.
    • It would then schedule a deferred type check for float type,
    • and return an object that could after const evaluation be used to obtain this f32 value.

In other words, the sort of type-check/const-eval deferral mechanisms that are currently used by sprite ids would now be used by ALL expressions in meta. This would solve the identifier problem by simply choosing not to schedule const evaluation on things we want to parse as identifiers.

Now that all types had to go through this two stage process, I had to bake it into the FromMeta trait. So at some point I had stuff like this:

pub type FromMetaOutput<'ctx, T> = Box<dyn Fn(ConstEvalProof) -> T + 'ctx>;
pub type FromMetaResult<'ctx, T> = Result<FromMetaOutput<'ctx, T>, FromMetaError>;

impl FromMeta for ast::Expr {
    fn from_meta<'ctx>(meta: &Sp<Meta>, ctx: &'_ CompilerContext<'ctx>) -> FromMetaResult<'ctx, Self> {
        match &meta.value {
            Meta::Scalar(expr) => {
                let expr = expr.clone();
                Ok(Box::new(move |_| expr.value.clone()))
            },
            _ => Err(FromMetaError::expected("an expr", meta)),
        }
    }
}

impl<T: FromMeta> FromMeta for Vec<T> {
    fn from_meta<'ctx>(meta: &Sp<Meta>, ctx: &'_ CompilerContext<'ctx>) -> FromMetaResult<'ctx, Self>
    // where T: 'ctx,  // ideal bound, but https://github.com/rust-lang/rust/issues/84021
    where T: 'static,
    {
        match &meta.value {
            Meta::Array(xs) => {
                let funcs = xs.into_iter().map(|x| x.parse(ctx)).collect::<Result<Vec<_>, _>>()?;
                Ok(Box::new(move |proof| funcs.iter().map(move |f| f(proof)).collect()))
            },
            _ => Err(FromMetaError::expected("an array", meta)),
        }
    }
}

// etc.

So, uh...... there was one problem with this.

The whole time I was writing this I was thinking: dear god these FromMeta impls are so gigabrain, how did this get so complicated, oh my god what is this type error, HOW IS THIS TYPE ERROR, what is life even, whywhywhywhy

(in particular it's worth noting that impls of this trait cannot always reuse each other. While Result<Fn() -> T> is a functor, it is not a monad)

...

So, yeah. Given that basically nobody else in the Touhou community is coming from functional languages, I kinda got the feeling that if this stuff ever made it into main it would basically scare away all other potential contributors, assuming it didn't kill me first.

@ExpHP
Copy link
Owner Author

ExpHP commented Apr 9, 2021

The thing is, we can't really do this the same way we've been doing sprite IDs; they can't just be treated as consts because they are offsets that we can't evaluate until we're almost done writing a binary file!

Actually I guess this is false. I could add some weird intrinsic kind of ScalarType for these things. But that's like... ugly?

...anyways, would probably be easier...

Edit: Or have them evaluate to strings containing the identifier text? Feels a bit roundabout, but...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
internals This is about internal APIs or code style
Projects
None yet
Development

No branches or pull requests

1 participant