Skip to content

__emit as a function parameter #570

Open
@Y-Less

Description

@Y-Less

It would be good if using __emit as a function parameter maybe bypassed some checks, for example:

Func(const arr[])
{
	printf("%s", arr);
}

main()
{
	new string[] = "hello";
	new a = ref(string);
	Func(__emit(load.s.pri a));
}

That currently gives a type mismatch error, but maybe it shouldn't? If you're using __emit you're clearly not worrying about the normal language limitations, and so you should be able to pass addresses around quite easily.

I was trying to think about how this would look, and how it would work most efficiently. As I understand __emit, it basically uses pri as the return value and therefore operates on that as if it were a normal function return. Thus using it as a function parameter there is equivalent to load.s.pri a, push.pri. That then begs the question - why not just use push.s a? There's no way to here, because of how __emit works, but maybe we as the assembly writers know there is a better way.

So I came up with an idea. I don't know if it will work or is compatible with existing code, but have some separation between __emit() and __emit{} in semantics. () will mirror normal expression syntax - so the code above remains exactly as it is and gives an error. {}, which mirrors existing statement syntax is a little more clever. It DOESN'T treat pri as a return value, so the following becomes invalid:

new var = __emit { lctrl 5 };

(this might be a breaking change, but I don't think it will affect many people yet, as this feature isn't even properly documented outside several PRs). Instead, it asserts that we know what we are doing and we are taking responsibility for ensuring that the state is correct after we are done. So, as a function parameter we can do:

	Func(__emit { push.s a });

And this will disable all standard code and checks for that parameter - no push is generated for us, no type checks, nothing. the compiler still knows there should be a parameter there, for the purposes of pushing the parameter byte count, but does nothing else. I'm not quite sure how to marry the semantics of "this is fine as a parameter, but not as an allocation" - it seems like they should always be the same thing, but there is still a way to do the allocation using () instead, or you could just use a {} block after the new and use stor.s var if you really want to use {}.

I thought about a few ways to somewhat keep existing sane return syntax, which will be wanted a lot of the time, but also allow for more efficient and controlled pushes. This was the best I could come up with, but there may be better ways. I've finally gotten around to using __emit in YSI, hence the increase in issues/suggestions related to it.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions