-
Notifications
You must be signed in to change notification settings - Fork 164
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
Function Default Arguments #2618
Function Default Arguments #2618
Conversation
The errors arises from converting the lpython code into "c code" as c doesn't provide default arguments. |
If the solution seems to be doing the job correctly. I would start handling the syntax error to make the solution complete without any flaws. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shared couple comments. Rest looks good. Let's add some integration tests and check if the implementation works as expected.
You can start another PR to support the semantic error. I suspect that the implementation might require updates in the parser. |
Please mark it as "Ready for review" when ready. |
I think we can handle such a thing on the parser level as you mentioned. |
Go ahead and submit a PR with your approach and I will take a look. |
I suggest implementing the semantic error in a separate PR. |
I'll do right after handling this PR |
I faced a test case which I can't say whether it's a valid test case or not def default_func(x : str ="Hello" ,y : str = " ", z : str = "World") ->str:
return x + y + z
default_func(z="lpython") It results in the following error: semantic error: default_func() got multiple values for argument 'z'
--> ../../integration_tests/def_func_01.py:49:20
|
49 | test_06 :str = default_func(z="lpython")
| ^^^^^^^^^^^^^^^^^^^^^^^^^
should I handle this in the parsing phase to prevent user form passing keyword arguments for the last parameters ?, instead the user should pass keyword arguments only if he filled some sequence in the beginning of the parameter list like that: default_func(y = "///",x="Hi") # result => "Hi///World" This prevention still fits the convention that most programming languages use, which states that whenever you pass an argument to a default argument function,you can't pass it arbitrarily but you should follow the following pattern : and not -> |
If the test case runs in cpython then its a valid test case. |
Actually it passes this testcase. I will try to find a way to handle it. |
@Shaikh-Ubaid def default_func(x : str ="Hello" ,y : str = " ", z : str = "World") ->str:
return x + y + z
test_09 :str = default_func(y = "++",z = "LPython")
print("test_09 is =>",test_09)
assert test_09 == "Hello++LPython"
test_10 :str = default_func("Welcome",z = "LPython")
print("test_10 is =>",test_10)
assert test_10 == "Welcome LPython" Solution Flow
|
Thanks! To implement default arguments, the following must be done:
The alternative design is to not even insert them and sort it out inside the function, but I would not do this, since it is not explicit. I would always insert them at the call site. |
@assem2002 could you please test for this case? from lpython import i32
def fn(defarg1: str="default", arg: i32, defarg2: str="default") -> i32:
return 1
fn() This should throw an error. |
Yeah it should, but unfortunately it doesn't |
Does that mean the AST of a call to a function with default arguments will include the default arguments passed even if they weren't provided by user? If so, isn't the whole AST is built then ASR? Or what you mean is to edit the call to 'make_call_helper()' to include the default arguments? |
The approach that Ondrej shared comprises of the following two steps: Step 1For default function arguments, their default value should be inserted in the functions symbol table inside the Variable declaration. Precisely, the default value should be inserted in the variable's Step 2For each function call, whenever we need to use the default argument value we can simply lookup the symbol table of the called function, access the Please let me know if this makes it clear. |
I got the first step. (for size_t i = index_start_def_arguments; i < func-> n_args; i++){
ASR::var_t* var = ASR::down_cast<ASR::Var_t>(func->m_args[i]);
std::string symbol_name = ASRUtils::symbol_name(arg_Var->m_v);
ASR::symbol_t* sym = func->m_symtab->getsymbol(symbol_name);
//then accessing the value, and pushing in call_args vector.
} |
Co-authored-by: Shaikh Ubaid <[email protected]>
Co-authored-by: Ondřej Čertík <[email protected]>
Co-authored-by: Ondřej Čertík <[email protected]>
Co-authored-by: Shaikh Ubaid <[email protected]>
Co-authored-by: Saurabh Kumar <[email protected]>
04a94e8
to
2549f0b
Compare
fixes #2509
fixes #2109
completed the implementation of default arguments in functions.
Code Flow
AST::functiondef
hasarguments
object as one of its members, this object hasm_defaults
andn_defaults
which preserve the number of default arguments andAST::expr_t
of the default constants.visit_functiondef( )
, we start pushing the ASR::expr_t of the defaults as a value for the variable when we reach the difference ofn_args
andn_defaults
.n_pos_args
is less thanfunc.n_args
, if so, we start pushing the data from varibles in ASR::function_t toVec<ASR::call_arg_t>
,starting from the index n_pos_args.The code handles keyword arguments.
serious issue to handle
The solution is build upon the idea of starting to make variable for the last number of parameters. If the user writes a code like this
as the lpython would be matched with the last parameter.
This should arise a syntax error like how Cpython does.