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

Cause syntax error when assigning to 'var #39

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

wonkodv
Copy link

@wonkodv wonkodv commented Apr 3, 2021

You can cause a Syntaxerror for assignments to rust variables by expanding them to ((lambda:_RUST_var)())

Since the SyntaxError has a very confusing message, the likely cause is appended:

error: python: cannot assign to function call. LIKELY CAUSE: you cannot assign to RUST-Variables, see Context::get_global() instead
 --> examples/readonly.rs:6:9
  |
6 |         'x = 42;
  |         ^^^^^^^^

error: aborting due to previous error

The Error message could be improved by inspecting the code it is raised for, but I don't know how to do it reliably.

@de-vri-es
Copy link
Contributor

de-vri-es commented Apr 3, 2021

Hey, thanks for the PR. It's an interesting idea.

I think it would be nicer to make the Rust globals an object with read-only properties. One downside for that is that it gives a runtime error when trying to assign, rather than syntax errors. But it's python, so I think people will forgive that. The advantage is that the error message will make more sense, and there's no need to intercept and adjust error messages then.

@wonkodv
Copy link
Author

wonkodv commented Apr 3, 2021

My first Idea was to use a new type as locals argument to exec, it does not have to be a dict. Globals have to be a dict. This is how it could look in python:

class ReadOnlyRustVariables:
    def __init__(self, dict):
        self.dict = dict
    def __getitem__(self, key):
        return self.dict[key]

    def __setitem__(self, key, val):
        if key.startswith("__rust_var_"):
            k = key[len("__rust_var_"):]
            raise TypeError(f"You can not modify the rust-variable '{k} use Context::get_global()")
        self.dict[key] = val

locals_ = ReadOnlyRustVariables({"__rust_var_x":42})
globals_ = vars(__import__("builtins"))


exec("y = __rust_var_x * 2", globals_, locals_)
assert locals_["y"] == 84, locals_

exec("__rust_var_x = __rust_var_x * 2", globals_, locals_)
# TypeError: You can not modify the rust-variable 'x use Context::get_global()

I didn't try this one.

another Idea was to replace 'var with _RUST_IMMUT_VARS['var'] (and maybe #var with _RUST_MUT_VARS['var']).
The two objects could be created in Context::try_new() using inline_python::python! to initialize the python environment like so:

class RustVars:                                                                                      
	__slots__ = ("_dict", "_mutable")                                                                
	def __init__(self, mutable:bool):                                                                
		self._dict = dict()                                                                          
		self._mutable = mutable                                                                      
                                                                                                     
	def __setitem__(self, key, value):                                                               
		if self._mutable:                                                                            
			self._dict[key] = value                                                                  
		else:                                                                                        
			raise TypeError("You are trying to write to "+'\''+key+" which is read-only. Try #"+key) 
                                                                                                     
	def __getitem__(self, key):                                                                      
		return self._dict[key]                                                                       
                                                                                                     
_RUST_MUT_VARS = RustVars(True)                                                                      
_RUST_IMMUT_VARS = RustVars(False)                                                                   

del RustVars
from builtins import *

I tried implementing the second in rust and failed to run python code when initializing the context.
It's a mess: wonkodv@1a6a51f

When I thought of the lambda trick and found it easy to implement I liked the compile time errors better than runtime errors, even if the Error Message is not perfect.

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

Successfully merging this pull request may close these issues.

None yet

2 participants