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

Add support for injectable function parameters in DML #293

Closed
EvanKirshenbaum opened this issue Jan 30, 2024 · 2 comments
Closed

Add support for injectable function parameters in DML #293

EvanKirshenbaum opened this issue Jan 30, 2024 · 2 comments
Labels
4 imporant Important issue in: DML issues related to the macro language is: feature Issue proposes a new feature

Comments

@EvanKirshenbaum
Copy link

I had intended that this would be implemented as part of adding support for general overloaded functions (#288), but that's turning out to be trickier than I had thought (partially due to COVID brain), and the OSU folks are going to want this sooner rather than later, so I think I'm going to try a somewhat kludgier approach for the short term.

When mocking up a macro for them, since there isn't support for general paths yet (#282), I found myself writing

define walk_circle(injectable drop, direction hdir)
{
   repeat for mix_time
   {
     drop : down 2
          : 4 in direction hdir
          : north 4
          : 4 in direction hdir turned around
          : south 2;
   }
}

The notion is that we have a two-argument function walk_circle(), but we want to be able to say

d : walk_circle(north);

By marking the drop parameter as injectable, when the compiler sees walk_circle(north), instead of complaining that an incorrect number of arguments have been supplied, it would remember the arguments passed in and return a new function that took one argument, spliced it into the correct position in the list, and then called the function.

I think that I should be able to do this pretty straightforwardly by adding the injectable positions to CallableType.

Note, that, unlike the approach I have been taking with #288, this would not result in walk_circle being treated as dir -> (drop -> no_val), although I guess I could probably make it work in CallableType._find_conversion_to().

Migrated from internal repository. Originally created by @EvanKirshenbaum on Aug 02, 2023 at 12:13 PM PDT. Closed on Aug 02, 2023 at 4:22 PM PDT.
@EvanKirshenbaum EvanKirshenbaum added 4 imporant Important issue in: DML issues related to the macro language is: feature Issue proposes a new feature labels Jan 30, 2024
@EvanKirshenbaum
Copy link
Author

This issue was referenced by the following commit before migration:

@EvanKirshenbaum
Copy link
Author

Okay, a bit of a kludge, but it appears to work, although it only supports a single injectable position.

CallableType now has

injectable_pos: Final[Optional[int]]
as_injection: Final[Optional[CallableType]]

injectable_pos tells the system where to put the delayed parameter, and as_injection is the resulting type signature.

In order to make this work, I also had to munge things so that as_injection's with_self_sig has the full type, not the resulting type. So, __init__() and find() take an optional as_self parameter. Note that this means that when computing as_injection, we don't call find(), because we don't want the munged type being returned in the future. I also changed the way the find() cache works. It now keys on both the Signature and the optional injectable position.

The actual value that's created is a new subclass of CallableValue that remembers the bound arguments, the injection point, and the full CallableValue:

lass BoundInjectionValue(CallableValue):
    bound_args: Final[tuple[Any, ...]]
    full_callable: Final[CallableValue]
    injection_pos: Final[int]

    def __init__(self, full_type: CallableType, full: CallableValue,
                 *args: Any) -> None:
        as_injection = not_None(full_type.as_injection)
        super().__init__(as_injection.sig)
        self.bound_args = args
        self.full_callable = full
        self.injection_pos = not_None(full_type.injectable_pos)
        
    def __str__(self) -> str:
        return f"({self.full_callable})({', '.join(str(a) for a in self.bound_args)})"
    
    def apply(self, args:Sequence[Any]) -> Delayed[Any]:
        assert len(args)==1
        full_args = list(self.bound_args)
        full_args.insert(self.injection_pos, args[0])
        return self.full_callable.apply(full_args)
Migrated from internal repository. Originally created by @EvanKirshenbaum on Aug 02, 2023 at 4:22 PM PDT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
4 imporant Important issue in: DML issues related to the macro language is: feature Issue proposes a new feature
Projects
None yet
Development

No branches or pull requests

1 participant