Constant Default Parameter Support #98
No reviewers
Labels
No Milestone
No Assignees
3 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: M-Labs/nac3#98
Loading…
Reference in New Issue
No description provided.
Delete Branch "default_parameter"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Add support for constant default parameter
@ -344,0 +354,4 @@
if let Ok(v) = v.try_into() {
Ok(SymbolValue::I32(v))
} else {
Ok(SymbolValue::I64(v.try_into().unwrap()))
Should we just accept int32? int64 is handled in the call part, e.g.
int64(1234)
.this is handled in the new commit below
LGTM, but we should probably add tests to nac3artiq/nac3standalone later.
Yes, some demo python files related to this will be added later.
@ -344,0 +355,4 @@
Ok(SymbolValue::I32(v))
} else {
Err(format!(
"int64 default parameter should be specified explicitly by `int64()` at {}",
Isn't that an internal compiler error if this code is executed, not a problem with the user code?
Using
unreachable!()
sounds more appropriate here.@ -344,0 +355,4 @@
Ok(SymbolValue::I32(v))
} else {
Err(format!(
"int64 default parameter should be specified explicitly by `int64()` at {}",
Isn't that an internal compiler error if this code is executed, not a problem with the user code?
Using
unreachable!()
sounds more appropriate here.No I don't think so? It is possible for users to specify some default value outside the range of int64. I think a more appropriate error message would be value out of range and only say
int64
if the value is really an int64?OK, yes.
Thanks, this error message is updated in the new commit
@ -344,0 +390,4 @@
.iter()
.map(|x| Self::parse_parameter_default_value(x))
.collect::<Result<Vec<_>, _>>()?
)),
We also want to support globals defined in the module, e.g.:
See the ARTIQ drivers, this is used in many places.
In fact, why not just compile the expression like any other?
Things like
def foo(x=[i*2 for i in range(3)])
are also valid Python.The expression should be immutable and primitive types/tuples. I think we can
eval()
the expression and set the default value if its type can be accepted.eval
is slow and not available in nac3standalone.Regarding performance issue, I think we can optimize it later if it is really that slow. For nac3standalone, I think we can support simple cases first and leave this later, I don't think this is of high priority?
Well the only thing we really need is module globals. If that can be done then something like the current code seems fine.
Ok I will add module globals support on top of the current constant support
Sorry, still one thing not very clear about this...
To handle complex expressions(calling
eval
for now? Also, expressions likeModule.T
which refers to things defined in another module imported) as default value, should we add a function in symbol resolver, which accepts aast::Expr
and return aSymbolValue
?Let's not call
eval
and let's keep the more restricted approach. Keep the current mechanism and simply add support for being able to use globals e.g.:I have added the basic module primitive/tuple global default parameter in the new commit.
No
eval
is used, only simple variable name is supported, but still involve some changes in symbol resolver(adding a function in symbol resolver which accepts aast::Expr
and return aSymbolValue
). If I do not miss anything, I do not think there is another way to workaround this without changing symbol resolver... since in nac3artiq the core compiler does not know anything about the module globals if symbol resolver does not provide any information to it. Please have a review, thanks!LGTM
@ -344,0 +386,4 @@
Err(format!("only allow constant integer here at {}", default.location))
}
}
ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple(elts
Lists should also be supported (also if they are a module global, see comment below).
Lists are not immutable, I think we discussed this previously?
M-Labs/nac3-spec#6
Indeed, and that's a well-known pitfall in CPython as well.
ARTIQ drivers do use lists with default parameter. AFAICT this can be changed to tuple, so far...
Well we can start with tuples only for now and see if that causes any serious problems.
@ -344,0 +372,4 @@
ast::ExprKind::Constant { value, .. } => handle_constant(value, &default.location),
ast::ExprKind::Call { func, args, .. } if {
match &func.node {
ast::ExprKind::Name { id, .. } => *id == "int64".into(),
Aren't we matching on
id(numpy.int64)
elsewhere?https://git.m-labs.hk/M-Labs/nac3/src/branch/master/nac3artiq/src/lib.rs#L270-L306
I'm fine with string matches since they're simpler and potentially faster, but we should do things consistently.
I think here we are handling default parameters in nac3core so we do not really know the
id(numpy.int64)
?In type inference module we also do things using strings matches here and here. So I think it is ok to use strings? Or did I miss anything?
That is matching on the value type, not about functions.
What's the difference? There isn't one in CPython.
Also this can cause issues e.g. if the user types
from numpy import int64 as i64
. CPython and nac3artiq will expecti64
, whereas nac3core will expectint64
.If that's the simplest thing to do, I'm fine having restrictions such as "numpy types must be imported as their reserved NAC3 keywords int64/int32/..." but they should be documented and enforced by the compiler.
Anyway this isn't the most pressing issue at the moment and we can do this inconsistent string/id match for now. Let's continue this discussion in #105
599aeb7bb3
toe75ec35687
@ -1322,0 +1350,4 @@
default_value: match default {
None => None,
Some(default) => {
if name == "self".into() {
Technically CPython lets you name
self
whatever you want, it's only a convention.So this test should be "the function is a method and we are looking at its first parameter".
Would it be acceptable that in nac3, we just enforce and document that the
self
should always beself
and should not be named arbitrarily? As I think this would not cause very big problems and our existing nac3 codebase is already doing this (e.g., here, here, and here)It is acceptable but not super clean - is it difficult to use the condition I proposed instead?
https://github.com/m-labs/artiq/blob/nac3/artiq/language/core.py#L56 is unavoidable without a lot of code (AFAICT) because CPython does not tell you if something is a method until it is bound, but inside NAC3 we have more information.
59bdb1be50
toee7c1eb11d
@ -69,0 +74,4 @@
internal_resolver.add_module_global(*id, value);
}
} else {
unimplemented!("only single assign supported now")
Come on. It's not more code to iterate on
targets
, is it?Oh sure, now the symbol resolver change is ok, I will add this support now.
This is supported in the latest commit, as well as a better type check for default parameter, please have a review, thanks!
5097e9e15a
to03cdca606d
Thanks. @ychenfo please add tests