Articles on luthfan's Bloghttps://blogs.python-gsoc.orgUpdates on different articles published on luthfan's BlogenThu, 08 Sep 2022 14:45:40 +0000Generic function support for LPython - Reporthttps://blogs.python-gsoc.org/en/luthfans-blog/generic-function-support-for-lpython-report/<h2><span style="">Overview</span></h2> <p><span style="">Project: Generic function support for LPython (</span><a href="https://github.com/lcompilers/lpython">https://github.com/lcompilers/lpython</a><span style="">)<br> Organization: Python Software Foundation (LPython)</span><br> <span style="">Mentors: Ondřej Čertík, Gagandeep Singh, Rohit Goswami</span><br> <span style="">Contributor: Luthfan Anshar Lubis</span></p> <h2><span style="">Project Summary</span></h2> <p><span style="">Generics is a common functionality found in statically-typed programming languages to allow easier maintenance of programs with identical implementations but different type signatures. LPython, a statically-typed Python compiler does not yet support this. In this project, we introduce generic functions as functions with type variables; these variables are statically type-checked and made concrete when lower-level code is generated. To allow type checks for generic function calls, restrictions (similar to <em>traits</em> in Rust) are provided to ensure safety of type parameters.</span></p> <h2><span style="">Background</span></h2> <p><span style="">Programs in LPython are statically-typed, requiring type annotations by users. They are first compiled into Abstract Semantic Representation (ASR), an intermediate representation that carries all the syntactic and semantic (including typing) information of the programs. From this IR, the programs are further compiled to lower level languages such as C and LLVM.</span></p> <p><span style="">Another important feature of LPython is ensuring that programs for LPython can also be run in CPython.</span></p> <h2><span style="">Implementation</span></h2> <p><span style="">The project will be explained through several phases:</span></p> <h3><span style="">1. Introducing type variables</span></h3> <p><span style="">The first phase of the implementation was adding syntax support for type variable declarations. On the Python level, we rely on <code>TypeVar</code> provided by Python 3. On the ASR level, I added a new kind of type for expression called <code>TypeParameter</code>. This allows the declaration of the following function:</span></p> <pre><code class="language-python">T = TypeVar('T') def add(x: T, y: T) -&gt; T: return x + y </code></pre> <p><span style="">The arguments and return value of the function <code>add</code> are typed with a <code>TypeParameter</code> on the ASR level.</span></p> <p><span style="">Simple checks on the type variable declarations are also implemented. First, ensuring that a type variable declaration is unique. Second, ensuring that a function can only be typed with an already declared type variable.</span></p> <p><span style=""><em>Related PR:</em></span></p> <p><span style=""><a href="https://github.com/lcompilers/lpython/pull/831">https://github.com/lcompilers/lpython/pull/625<br> https://github.com/lcompilers/lpython/pull/831</a></span></p> <p><span style=""><em>Related blog posts:</em></span></p> <p><span style="">Adding type variable support to LPython, link: <a href="https://blogs.python-gsoc.org/en/luthfans-blog/adding-type-variable-support-to-lpython-1st-week/">https://blogs.python-gsoc.org/en/luthfans-blog/adding-type-variable-support-to-lpython-1st-week/</a><br> Dealing with conflict and ASR, link: <a href="https://blogs.python-gsoc.org/en/luthfans-blog/dealing-with-conflict-and-asr-2nd-week/">https://blogs.python-gsoc.org/en/luthfans-blog/dealing-with-conflict-and-asr-2nd-week/</a></span></p> <h3><span style="">2. Implementing generic function instantiation</span></h3> <p><span style="">A big leap from the first phase, I implemented a working generic function instantiation that can be compiled to LLVM and can be run, but still without type checks.</span></p> <p><span style="">Using the example from the previous phase, it is now possible to have the following code:</span></p> <pre><code class="language-python">T = TypeVar('T') def add(x: T, y: T) -&gt; T: return x + y print(add(1,2)) print(add('a','b')) </code></pre> <p><span style="">The two function calls <code>add(1,2)</code> and <code>add('a','b')</code> instantiate the function <code>add</code> into two different functions on the ASR level, each with different type signatures. If we were to express it with Python syntax, we would have:</span></p> <pre><code class="language-python">def __lpython_generic_add_0(x: i32, y: i32) -&gt; i32: ... def __lpython_generic_add_1(x: str, y: str) -&gt; str: ... </code></pre> <p><span style="">Here, <code>i32</code> represents 32-bit integer and <code>str</code> represents string.</span></p> <p><span style="">At the same time, the function calls themselves are correspondingly renamed into:</span></p> <pre><code class="language-python">print(__lpython_generic_add_0(1,2)) print(__lpython_generic_add_1('a','b')) </code></pre> <p><span style="">At the function call site, the consistence of the type substitution between the arguments types (<code>i32</code> or <code>str</code>) with the type variables (<code>T</code>) is also checked. The function call <code>add(1,'a')</code> is rejected.</span></p> <p><span style="">To allow compilation to LLVM, the generic function (<code>add</code>) is ignored while the instantiated functions (<code>__lpython_generic_add_0, __lpython_generic_add_1</code>) and renamed functions calls are compiled normally with the existing compilation.</span></p> <p><span style="">This step particularly took a long time due to several reasons. First, the lack of familiarity with the already existing tools within LPython that can be utilized for function instantiations. Originally I started with a function instantiator that I personally defined, although later on finding out from one of the mentors about an ASR duplicator. Second, we did not start with a concrete design for the ASR grammar. This resulted in a couple iterations on the grammar for generic functions.</span></p> <p><span style=""><em>Related PR:</em></span></p> <p><span style=""><a href="https://github.com/lcompilers/lpython/pull/831">https://github.com/lcompilers/lpython/pull/625<br> https://github.com/lcompilers/lpython/pull/831</a></span><br> <span style=""><a href="https://github.com/lcompilers/lpython/pull/903">https://github.com/lcompilers/lpython/pull/903</a></span></p> <p><span style=""><em>Related blog posts:</em></span></p> <p><span style="">Instantiating generic functions Into valid functions in ASR, link: <a href="https://blogs.python-gsoc.org/en/luthfans-blog/instantiating-generic-functions-into-valid-functions-in-asr-3rd-week/">https://blogs.python-gsoc.org/en/luthfans-blog/instantiating-generic-functions-into-valid-functions-in-asr-3rd-week/</a><br> Revisiting function generation, link: <a href="https://blogs.python-gsoc.org/en/luthfans-blog/revisiting-function-generation-4th-week/">https://blogs.python-gsoc.org/en/luthfans-blog/revisiting-function-generation-4th-week/</a></span><br> <span style="">Getting the generated ASR, link: <a href="https://blogs.python-gsoc.org/en/luthfans-blog/getting-the-generated-asr-for-generic-functions-5th-week/">https://blogs.python-gsoc.org/en/luthfans-blog/getting-the-generated-asr-for-generic-functions-5th-week/</a></span><br> <span style="">Completing the generics early prototype, link: <a href="https://blogs.python-gsoc.org/en/luthfans-blog/completing-the-generics-early-prototype-6th-week/">https://blogs.python-gsoc.org/en/luthfans-blog/completing-the-generics-early-prototype-6th-week/</a></span></p> <h3><span style="">3. Adding necessary functionalities and handling ASR changes</span></h3> <p><span style="">I added support for <code>Array</code> and <code>List</code> types, along with corresponding examples where these types are used.</span></p> <p><span style="">I also added support for generic <code>Subfunction</code> (functions without return values). However, during the implementation, the main branch of LPython made a change and combined both <code>Function</code> and <code>Subfunction</code>, requiring modifications on the generic functions support.</span></p> <p><span style=""><em>Related PR:</em></span></p> <p><span style=""><a href="https://github.com/lcompilers/lpython/pull/989">https://github.com/lcompilers/lpython/pull/907<br> https://github.com/lcompilers/lpython/pull/989</a></span></p> <p><span style=""><em>Related blog posts:</em></span></p> <p><span style="">Adding more generic examples, link: <a href="https://blogs.python-gsoc.org/en/luthfans-blog/adding-more-generic-examples-7th-week/">https://blogs.python-gsoc.org/en/luthfans-blog/adding-more-generic-examples-7th-week/</a></span></p> <h3><span style="">4. Adding hard-coded restrictions for type variables</span></h3> <p><span style="">The next step is adding a mechanism to type check generic function calls and operations involving values with type variables. Consider again the <code>add</code> program, there was no check on the operation <code>x+y</code> against the arguments with type <code>T</code>. There was also no type check on <code>add(1,2)</code> to make sure that the arguments <code>1</code> and <code>2</code> can handle the operation inside <code>add</code>.</span></p> <p><span style="">As the first approach to this, I added restrictions on the type variable declarations. The restrictions I added were <code>SupportsPlus</code>, <code>SupportsZero</code>, and <code>Divisible</code>. These restrictions are hard-coded in the way that they are hard-coded into the compiler to be associated with specific computations. With restrictions, type variables declarations become:</span></p> <pre><code class="language-python">T = TypeVar('T', bound=SupportsPlus) </code></pre> <p><span style="">The restriction <code>SupportsPlus</code> is associated with addition between integer, real, and string. However, it only supports addition between same typed arguments.</span></p> <p><span style="">With these restrictions, it is possible to check whether the generic operation <code>x+y</code> is safe by checking the restrictions on the type variables associated with both arguments. It is also possible to check whether <code>add(1,2)</code> is safe by checking that <code>1</code> and <code>2</code> are typed as integers which does support addition.</span></p> <p><span style=""><em>Related PR:</em></span></p> <p><span style=""><a href="https://github.com/lcompilers/lpython/pull/1007">https://github.com/lcompilers/lpython/pull/1007</a></span></p> <p><span style=""><em>Related blog posts:</em></span></p> <p><span style="">Next step, adding restriction, link: <a href="https://blogs.python-gsoc.org/en/luthfans-blog/next-step-adding-restriction-8th-week/">https://blogs.python-gsoc.org/en/luthfans-blog/next-step-adding-restriction-8th-week/</a><br> Working further on restriction type check, link: <a href="https://blogs.python-gsoc.org/en/luthfans-blog/working-further-on-restriction-type-check-9th-week/">https://blogs.python-gsoc.org/en/luthfans-blog/working-further-on-restriction-type-check-9th-week/</a></span><br> <span style="">Extending restriction and handling ASR changes, link: <a href="https://blogs.python-gsoc.org/en/luthfans-blog/extending-restriction-and-handling-asr-changes-10th-week/">https://blogs.python-gsoc.org/en/luthfans-blog/extending-restriction-and-handling-asr-changes-10th-week/</a></span></p> <h3><span style="">5. Designing and implementing user-defined restrictions</span></h3> <p><span style="">The above approach to restrictions does handle type check on operations, but limit them to only those hard-coded into the compilers. We require a mechanism that can allow users to freely define restrictions according to need.</span></p> <p><span style="">To illustrate this, let us consider a different generic function <code>mean</code>that takes a list of <code>T</code> as arguments and calculate the mean value of the elements in the list:</span></p> <pre><code class="language-python">def mean(x: list[T]) -&gt; f64: k: i32 = len(x) if k == 0: return 0.0 res: T res = 0.0 i: i32 for i in range(k): res = res + x[i] return res/k </code></pre> <p><span style="">Several computations are made on the variable <code>res</code> with type <code>T</code>. A zero assignment, an addition, and a division. To type check the body of <code>mean</code>, we can abstract the computations as restrictions, expressed as body-less functions.</span></p> <pre><code class="language-python">@restriction def zero(x: T) -&gt; T: pass @restriction def add(x: T, y: T) -&gt; T: pass @restriction def div(x: T, k: i32) -&gt; f64: pass def mean(x: list[T], **kwargs) -&gt; f64: k: i32 = len(x) if k == 0: return 0.0 res: T res = zero(x[0]) i: i32 for i in range(k): res = plus(res, x[i]) return div(res/k) </code></pre> <p><span style="">Then, the function calls can assign specific functions that will take over the place of these restrictions (<code>add</code>, <code>zero</code>, <code>div</code>).</span></p> <pre><code class="language-python">print(mean([1,2], zero=int.__zero__, add=int.__add__, div=int.__div__)) print(mean([1.0,2.0], zero=real.__zero__, add=real.__add__, div=real.__div__)) </code></pre> <p><span style="">The assignment between a restriction (eg. <code>zero</code>) and a function (eg. <code>int.__zero__</code>) is also checked by making sure if the type substitution remains consistent or not.</span></p> <p><span style=""><em>Related PR:</em></span></p> <p><span style=""><a href="https://github.com/lcompilers/lpython/pull/1048">https://github.com/lcompilers/lpython/pull/1048</a> (still open)</span></p> <p><span style=""><em>Related blog posts:</em></span></p> <p><span style="">Designing user-defined restrictions, link: <a href="https://blogs.python-gsoc.org/en/luthfans-blog/designing-user-defined-restrictions-11th-week/">https://blogs.python-gsoc.org/en/luthfans-blog/designing-user-defined-restrictions-11th-week/</a></span></p> <h2><span style="">Result</span></h2> <p><span style="">I have completed a prototype implementation for LPython. The implementation is strongly type-checked (strong concept) by using restrictions to define computations on type variables. Type-checked generic function calls are compiled into ASR then LLVM.</span></p> <h2><span style="">Future Work</span></h2> <p><span style="">- More complicated generic functions, such as recursive generic functions and nested generic function calls will require some modifications on both type checks and function instantiations</span><br> - Designs can be further simplified to avoid defining similar restrictions</p>luthfanlubis@gmail.com (luthfan)Thu, 08 Sep 2022 14:45:40 +0000https://blogs.python-gsoc.org/en/luthfans-blog/generic-function-support-for-lpython-report/Designing user-defined restrictions (11th week)https://blogs.python-gsoc.org/en/luthfans-blog/designing-user-defined-restrictions-11th-week/<p>My apologies for posting this very late.</p> <p><strong>What I did this week</strong></p> <p>1. Merged the hard-coded restrictions</p> <p>After making some fixes on the implementation, I had the hard-coded restriction that I explained in the previous post merged.</p> <p>2. Designed user-defined restrictions</p> <p>Ultimately, the restrictions on type parameters that we want for LPython is one that users can freely defined according to need. While the hard-coded restrictions can support generics to a certain degree, it cannot handle the various functions that users may define.</p> <p>Take the <span style="">mean</span> example from the previous week. With user-defined restrictions, it turns into:</p> <pre><code class="language-python">T = TypeVar('T') @restriction def zero(x: T) -&gt; T: pass @restriction def plus(x: T, y: T) -&gt; T: pass @restriction def div(x: T, k: i32) -&gt; f64: pass def mean(x: list[T]) -&gt; f64: k: i32 = len(x) if k == 0: return 0.0 res: T res = zero(x[0]) i: i32 for i in range(k): res = plus(res, x[i]) return div(res, k)</code></pre> <p>With the hard-coded restrictions, the <span style="">mean</span> function is limited to handling numbers. However, with user-defined restrictions, it would be possible to pass arguments of any types as long as they have the restriction functions <span style="">plus</span>, <span style="">zero</span>, and <span style="">div</span> provided.</p> <p><strong>What is coming up next week</strong></p> <p>I have to conduct a meeting with my mentor and evaluate the current design for user-defined restrictions. Then iterate again on the designs based on the meeting.</p> <p><strong>Did I get stuck anywhere</strong></p> <p>I did not have any issue this week as I was freely designing the grammar for the restrictions.</p>luthfanlubis@gmail.com (luthfan)Mon, 29 Aug 2022 18:29:44 +0000https://blogs.python-gsoc.org/en/luthfans-blog/designing-user-defined-restrictions-11th-week/Extending restriction and handling ASR changes (10th week)https://blogs.python-gsoc.org/en/luthfans-blog/extending-restriction-and-handling-asr-changes-10th-week/<p><strong>What I did this week</strong></p> <p>1. Adding more types of hard-coded restrictions</p> <p>Again, continuing from last week's work, I added more types of restrictions for type parameters.</p> <p>Currently there are four restrictions: <span style="">SupportsZero</span>, <span style="">SupportsPlus</span>, <span style="">Divisible</span>, <span style="">Any</span>. These restrictions are hard-coded into the compiler's frontend, meaning that each restriction is essentially associated with specific basic types available in LPython. For example, a type parameter restricted to <span style="">SupportsZero</span> has to be of type <span style="">Integer</span> or Real.</p> <p>With these restrictions, it is possible to have the following generic function:</p> <pre><code class="language-python">T = TypeVar('T', bound=SupportsPlus|SupportsZero|Divisible) def mean(x: list[T]) -&gt; f64: k: i32 = len(x) if k == 0: return 0.0 sum: T sum = 0 i: i32 for i in range(k): sum = sum + x[i] return sum/k print(mean([1,2,3])) print(mean([1.0,2.0,3.0]))</code></pre> <p>Given the restrictions, any function instantiation is only required to check against the generic function's signature.</p> <p>2. Handling ASR changes</p> <p>The ASR design was recently changed so that <span style="">Subroutine </span>(function without return values) is merged into <span style="">Function</span>. Therefore I had to make modifications when adding generic functions and subroutines into the symbol table. This was done in PR <a href="https://github.com/lcompilers/lpython/pull/957">#957</a> and has been subsequently merged.</p> <p><strong>What is coming up next week</strong></p> <p>1. Finalize the current hard-coded restrictions and have it merged<br> 2. I did not have the time to handle arrays last week, so hopefully I can work on adding more support for generic arrays next week</p> <p><strong>Did I get stuck anywhere</strong></p> <p>This week was smooth sailing, although it took some iterations to have a clean pull request for supporting generic subroutines.</p>luthfanlubis@gmail.com (luthfan)Sun, 21 Aug 2022 05:26:15 +0000https://blogs.python-gsoc.org/en/luthfans-blog/extending-restriction-and-handling-asr-changes-10th-week/Working further on restriction type check (9th week)https://blogs.python-gsoc.org/en/luthfans-blog/working-further-on-restriction-type-check-9th-week/<p><strong>What I did this week</strong></p> <p>Continuing on the restriction's work from last week, I implemented more support for restriction check on both generic function definition and generic function call. So let's say we have the following function:</p> <pre><code class="language-python">T = TypeVar('T', bound=SupportsZero) def f(x: T) -&gt; T print(x) x = 0 return x f(1) f('a')</code></pre> <p>For the function definition, the assignment <span style="font-family: Courier New,Courier,monospace;">x = 0</span> would check whether the type of <span style="font-family: Courier New,Courier,monospace;">x</span> supports zero assignment (<span style="font-family: Courier New,Courier,monospace;">SupportsZero</span>) or not. In this case, it does, so it passes the type check.</p> <p>For the first function call, because <span style="font-family: Courier New,Courier,monospace;">1</span> is an integer, it is possible to reassign it with zero. But in the second function call, the character <span style="font-family: Courier New,Courier,monospace;">a</span> cannot be reassigned with the number zero. The type check considers this and reject the second function call.</p> <p><strong>What is coming up next week</strong></p> <p>1. Access the current restriction design on ASR level<br> 2. Provide more flexible support for generic array</p> <p><strong>Did I get stuck anywhere</strong></p> <p>I'm currently a bit confused on how to make a decision for the restriction design on the ASR level. My mentor has provided some high-level design that we want to realize in LPython, but I have not grasped the concrete design yet. I will consult on this matter with my mentor ASAP.</p>luthfanlubis@gmail.com (luthfan)Sat, 13 Aug 2022 11:26:49 +0000https://blogs.python-gsoc.org/en/luthfans-blog/working-further-on-restriction-type-check-9th-week/Next step, adding restriction (8th week)https://blogs.python-gsoc.org/en/luthfans-blog/next-step-adding-restriction-8th-week/<p><strong>What I did this week</strong></p> <p style="">1. Merged the generic function implementation</p> <p style=""><span style=""><span style=""><span style="">After drafting it for quite sometimes and solving the conflicts with the main branch, we finally have the prototype implementation for generic function merged into LPython (<a href="https://github.com/lcompilers/lpython/pull/900">PR #900</a>).</span></span></span></p> <p style=""><span style=""><span style=""><span style="">The array support that I mentioned in a previous post was also merged into LPython (<a href="https://github.com/lcompilers/lpython/pull/900">PR #907</a>). Unfortunately, although generic arrays work in LLVM, it does not yet work with CPython due to incompatible usage of </span></span></span><span style=""><span style=""><span style="">TypeVar</span></span></span><span style=""><span style=""><span style="">.</span></span></span></p> <p style=""><span style=""><span style=""><span style="">2. Worked on restrictions for type variables</span></span></span></p> <p style=""><span style=""><span style=""><span style="">The prototype implementation mentioned above would type check every function instantiated by a generic function call, which would slow down the compilation time. Ideally, we want a generics type system that only requires checks on the function call arguments.</span></span></span></p> <p style=""><span style=""><span style=""><span style="">To do so, I worked on adding <i>restriction</i> for type variables. An example we have right now is as follows:</span></span></span></p> <pre><code class="language-python">from ltypes import TypeVar, SupportsPlus T = TypeVar('T', bound=SupportsPlus) def f(x: T, y: T) -&gt; T: return x + y print(f(1,2)) print(f("a","b")) </code></pre> <p><span style=""><span style=""><span style="">Where </span></span></span><span style=""><span style=""><span style="">SupportsPlus </span></span></span><span style=""><span style=""><span style="">is a restriction. This denotes that the any argument that will substitute the type variable </span></span></span><span style=""><span style=""><span style="">T </span></span></span><span style=""><span style=""><span style="">must support the plus operation.</span></span></span></p> <p><span style=""><span style=""><span style="">The type check is executed in the following two steps:</span></span></span></p> <p><span style=""><span style=""><span style="">1. Check the function definition. If a generic parameter </span></span></span><span style=""><span style=""><span style="">(x: T)</span></span></span><span style=""><span style=""><span style=""> is used for a certain operation </span></span></span><span style=""><span style=""><span style="">O</span></span></span><span style=""><span style=""><span style="">, then we have to check if the restriction </span></span></span><span style=""><span style=""><span style="">R</span></span></span><span style=""><span style=""><span style=""> on </span></span></span><span style=""><span style=""><span style="">T </span></span></span><span style=""><span style=""><span style="">satisfies operation </span></span></span><span style=""><span style=""><span style="">O</span></span></span><span style=""><span style=""><span style="">.<br> 2. Check the function call. If the argument substitutes a parameter with type </span></span></span><span style=""><span style=""><span style="">T</span></span></span><span style=""><span style=""><span style=""> and restriction </span></span></span><span style=""><span style=""><span style="">R</span></span></span><span style=""><span style=""><span style="">, we have to check if the actual type of the argument satisfies that restriction.</span></span></span></p> <p><span style=""><strong>What is coming up next week</strong></span></p> <p style=""><span style=""><span style=""><span style="">Continue working on restriction. Currently I have had only implemented a very simple type check on the generic function definition with restriction. Next would be implement type check on the generic function calls.</span></span></span></p> <p><span style=""><strong>Did I get stuck anywhere</strong></span></p> <p><span style=""><span style=""><span style="">There were some conflicts with the main branch that I personally could not solve. These conflicts kept my PR from being merged. It turned out to be a section that I changed without properly cross-checking with the main branch. Thankfully, with the help of both my mentors it was solved right away.</span></span></span></p>luthfanlubis@gmail.com (luthfan)Tue, 09 Aug 2022 07:06:49 +0000https://blogs.python-gsoc.org/en/luthfans-blog/next-step-adding-restriction-8th-week/Adding more generic examples (7th week)https://blogs.python-gsoc.org/en/luthfans-blog/adding-more-generic-examples-7th-week/<p><strong>What I did this week</strong></p> <p>- Generic array types</p> <p>I added support for generic array types. In the following simple example, <span style="font-family: Courier New,Courier,monospace;">T[:]</span> signifies the type of one-dimensional array <span style="font-family: Courier New,Courier,monospace;">T</span>.</p> <pre><code class="language-python">T = TypeVar('T') def f(lst: T[:], i: T) -&gt; T: lst[0] = i return lst[0]</code></pre> <p>It is then possible to have different function calls involving different types of arrays:</p> <pre><code class="language-python">f([1],2) f([1.0],2.0)</code></pre> <p>To implement this, the type substitution checks between the formal parameter <span style="font-family: Courier New,Courier,monospace;">lst: T[:]</span> and the argument <span style="font-family: Courier New,Courier,monospace;">[1]</span> (<span style="font-family: Courier New,Courier,monospace;">i32[:]</span>) match the type parameter <span style="font-family: Courier New,Courier,monospace;">T</span> with <span style="font-family: Courier New,Courier,monospace;">i32</span> and to also check that the dimensions are equal.</p> <p>- Merging TemplateFunction with Function</p> <p>To distinguish generic functions from functions, I added a new syntactic construct TemplateFunction into LPython's intermediate representation ASR. However, this construct appears to be unnecessary and can be handled by the original Function construct by adding another field where type parameters are stored.</p> <p>On a separate <a href="https://github.com/lcompilers/lpython/pull/831">PR</a>, I removed TemplateFunction from the grammar and modified the definition for Function.</p> <p><strong>What is coming up next week</strong></p> <p>There are tests that the compiler does not yet pass. So I will have to solve those first.</p> <p><strong>Did I get stuck anywhere</strong></p> <p>There was no issue specifically this week.</p>luthfanlubis@gmail.com (luthfan)Sun, 31 Jul 2022 04:38:17 +0000https://blogs.python-gsoc.org/en/luthfans-blog/adding-more-generic-examples-7th-week/Completing the generics early prototype (6th week)https://blogs.python-gsoc.org/en/luthfans-blog/completing-the-generics-early-prototype-6th-week/<p><strong>What I did this week</strong></p> <p>I completed an early prototype of generic function support in LPython. Given the following simple generic function and its function calls:</p> <pre><code class="language-python">T = TypeVar('T') def f(x: T, y: T) -&gt; T: return x + y f(1,2) f('a','b')</code></pre> <p>The compiler can correspondingly instantiate two functions each for the integer call <span style="font-family: Courier New,Courier,monospace;">f(1,2)</span> and character call <span style="font-family: Courier New,Courier,monospace;">f('a','b')</span>. The function body is properly generated for the instantiated functions.</p> <p>Further, the program can also be compiled into LLVM. This is done simply by ignoring the type parameter declaration <span style="font-family: Courier New,Courier,monospace;">T = TypeVar('T')</span> as well as the functions involving type parameters.</p> <p>For reference, all my progress is still kept as an <a href="https://github.com/lcompilers/lpython/pull/625">open pull request</a>. This will be merged once we finalize the overall design of generic functions.</p> <p><strong>What is coming up next week</strong></p> <p>1. Making decisions on the design for generic functions.<br> 2. Making other examples and adding support for other statements and expressions for generic functions.</p> <p><strong>Did I get stuck anywhere</strong></p> <p>While rebuilding the body of the instantiated functions from the generic function, I met more problems with the ASR (LPython's intermediate representation) verification. One particular issue was that it was impossible to understand the problem simply by looking at the structure of the generated ASR. I solved this issue by looking at the other existing visitor classes that also build function bodies and try to mimic their process.</p>luthfanlubis@gmail.com (luthfan)Sat, 23 Jul 2022 11:26:08 +0000https://blogs.python-gsoc.org/en/luthfans-blog/completing-the-generics-early-prototype-6th-week/Getting the generated ASR for generic functions (5th week)https://blogs.python-gsoc.org/en/luthfans-blog/getting-the-generated-asr-for-generic-functions-5th-week/<p><strong>What I did this week</strong></p> <p>Following on the suggestion from my mentor, I reimplemented the generic function instantiation to use the already existing visitors within LPython compiler. My mentor also helped with some issues with the ASR verification which we solved by adding verification support for the constructs I added into the ASR.</p> <p>This week I also worked on including another important missing piece of the instantiated generic functions, the function body.</p> <p><strong>What is coming up next week</strong></p> <p>1. Finishing up the function body of instantiated generic functions.<br> 2. Work on LLVM compilation support for the generic functions.</p> <p><strong>Did I get stuck anywhere</strong></p> <p>I was not aware of the verification step for the ASR during the compilation and my mentor explained and helped with the implementation.</p>luthfanlubis@gmail.com (luthfan)Fri, 15 Jul 2022 15:17:33 +0000https://blogs.python-gsoc.org/en/luthfans-blog/getting-the-generated-asr-for-generic-functions-5th-week/Revisiting function generation (4th week)https://blogs.python-gsoc.org/en/luthfans-blog/revisiting-function-generation-4th-week/<p><strong>What I did this week</strong></p> <p>I'm afraid there is not much progress this week because I've been visiting relatives. I've improved the function generation implemented last week.</p> <p><strong>What is coming up next week</strong></p> <p>Finishing up the initial example case for generics. This means getting an ASR without triggering any errors.</p> <p><strong>Did I gets stuck anywhere</strong></p> <p>I had a personal meeting with my mentor to discuss the progress far and I found a simpler way to implement the work than what I am doing right now.</p> <p> </p>luthfanlubis@gmail.com (luthfan)Mon, 11 Jul 2022 01:57:40 +0000https://blogs.python-gsoc.org/en/luthfans-blog/revisiting-function-generation-4th-week/Instantiating generic functions into valid functions in ASR (3rd week)https://blogs.python-gsoc.org/en/luthfans-blog/instantiating-generic-functions-into-valid-functions-in-asr-3rd-week/<p>I made some good progress this week in handling generic functions on LPython's ASR level.</p> <p><strong>What I did this week</strong></p> <p>I managed to get the type parameters in the generic functions to be instantiated by different function calls. Currently, I'm working with a very simple function <span style="font-family: Courier New,Courier,monospace;">f</span> that can take two values <span style="font-family: Courier New,Courier,monospace;">x</span> and <span style="font-family: Courier New,Courier,monospace;">y</span> of type <span style="font-family: Courier New,Courier,monospace;">T</span> and returns a value of type <span style="font-family: Courier New,Courier,monospace;">T</span>.</p> <pre><code class="language-python">T = TypeVar('T') def f(x: T, y: T) -&gt; T: return x + y</code></pre> <p>This function is called in two different places with different types. First with integers, second with floats.</p> <pre><code class="language-python">print(f(1,2)) print(f(1.0,1.0))</code></pre> <p>This week I managed to have each function call generates a new overloaded function for <span style="font-family: Courier New,Courier,monospace;">f</span>. It also checks the consistencies of the assigned types and the type parameters.</p> <p><strong>What is coming up next week</strong></p> <p>Next I have to also handle the function calls themselves, because they technically are calling overloaded functions. LPython actually have already supported function overloading, so what I need to do is to learn the compiler and apply that overloading to these generic function calls.</p> <p><strong>Did I get stuck anywhere</strong></p> <p>Nowhere especially for this week.</p>luthfanlubis@gmail.com (luthfan)Fri, 01 Jul 2022 07:42:00 +0000https://blogs.python-gsoc.org/en/luthfans-blog/instantiating-generic-functions-into-valid-functions-in-asr-3rd-week/Dealing with conflict and ASR (2nd week)https://blogs.python-gsoc.org/en/luthfans-blog/dealing-with-conflict-and-asr-2nd-week/<p>Hello again, here's a quick update on my second week with LPython!</p> <p><strong>What I did this week</strong></p> <p>It turned out that there were conflicts between my last week's work and the project's upstream, so the first thing I did this week was resolving that conflict. I also found another issue with existing integration tests, so some changes had to be made to make it possible for my work from last week to be submitted.</p> <p>I also spent time to understand the differences between two AST visitors that build the ASR: a visitor that builds the symbol table and a visitor that transforms the statements.</p> <p><strong>What is coming up next week</strong></p> <p>I want to start implementing support to allow the following function declaration with type parameters:</p> <pre><code class="language-python">def fun(x: T, y: T) -&gt; T: return x+y</code></pre> <p><strong>Did I get stuck anywhere</strong></p> <p>I didn't exactly understand the cause of the conflict at the beginning, but consulting with my mentor solved that issue.</p>luthfanlubis@gmail.com (luthfan)Fri, 24 Jun 2022 14:07:56 +0000https://blogs.python-gsoc.org/en/luthfans-blog/dealing-with-conflict-and-asr-2nd-week/Adding type variable support to LPython (1st week)https://blogs.python-gsoc.org/en/luthfans-blog/adding-type-variable-support-to-lpython-1st-week/<p>Hello, here is a quick update of my first week with LPython project!</p> <p><strong>What I did this week</strong></p> <p>Unfortunately due to a personal issue, I had a very late start. I could not start until Thursday. Spent the day to reintroduce myself to the project and finally started making progress on Friday.</p> <p>As planned, the first week was to give support for Python's type variable declaration <span style="font-family: Courier New,Courier,monospace;">T = TypeVar('T')</span>. The syntax was already extended, so that's <em>a okay</em>. What I had to do then was to support the type variable in the underlying ASR (Abstract Semantic Representation) into which the Python AST will be translated. By the way, ASR is an IR from which we compile the program into lower languages like LLVM.</p> <p>To do so, what I did was adding a new kind of type to the underlying ASR, the type variable. Then, while scanning through the AST, the type variable declaration <span style="font-family: Courier New,Courier,monospace;">T = TypeVar('T')</span> is converted into a variable that is typed with an ASR type variable and then placed into the symbol table of the program, so that later on functions can identify these variables as type variables.</p> <p>Slight note though, since I'm messing around with the ASR, the code generation for these type variables have to also be added later on.</p> <p><strong>What is coming up next week</strong></p> <p>Next week I will have to handle functions with type parameters. One important issue would be how to handle the type check on these functions, because they can't be type checked as usual where the base types are all present.</p> <p><strong>Did I get stuck anywhere</strong></p> <p>I was confused on whether to approach the issue by tinkering with the AST or going straight to ASR. However, since the ASR has many utilities for handling symbol table, I decided to go straight with ASR.</p>luthfanlubis@gmail.com (luthfan)Sat, 18 Jun 2022 13:58:22 +0000https://blogs.python-gsoc.org/en/luthfans-blog/adding-type-variable-support-to-lpython-1st-week/