Skip to content

Commit

Permalink
Added the LFortran tutorial
Browse files Browse the repository at this point in the history
  • Loading branch information
kmr-srbh authored Feb 22, 2024
1 parent 5a98b0c commit 7315c19
Showing 1 changed file with 177 additions and 3 deletions.
180 changes: 177 additions & 3 deletions doc/src/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing

Hey! Thanks for showing interest in LPython!
Thanks for your interest in LPython!

We welcome contributions from anyone, even if you are new to compilers or open source in general.
It might sound daunting at first to contribute to a compiler, but do not worry, it is not that complicated.
Expand Down Expand Up @@ -49,13 +49,187 @@ All contributions to a public repository on GitHub require the contributor to op
![image](https://github.com/kmr-srbh/lpython/assets/151380951/3f2245df-42f4-44e5-9c20-d6d7789ac894)
- Once you are done, select the <kbd>Create Pull Request</kbd> button to open a new PR.

Congratulations! You just made your first contribution!
Congratulations! You just made your first contribution! 🎉

### What next?
Sit back and relax or go on a bug hunt.

We too have day jobs and reviewing a Pull Request (PR) may take some time. We request you to patiently wait for any feedback or action on your PR. If you are asked to make changes, push commits to the same branch to automatically include them in the open PR.
Reviewing a PR may take some time. We request you to patiently wait for any feedback or action on your PR. If you are asked to make changes, push commits to the same branch to automatically include them in the open PR.

# Add New Features

LPython shares it's architectural design with LFortran. The example below shows the steps it would take to create a caret binary operator (**^**) in LFortran. The caret binary operator computes the average value of the two operands.
- ### Create New Token(s)
We extend the *tokenizer.re* as well as *parser.yy* to add the new token **^**.
We also tell LFortran how to print the new token in *parser.cpp*.
*src/lfortran/parser/tokenizer.re*
```
// "^" { RET(TK_CARET) }
```
*src/lfortran/parser/parser.yy*
```
%token TK_CARET "^"
```
*src/lfortran/parser/parser.cpp*
```
std:string token2text(const int token)
{
switch (token) {
T(TK_CARET, "^")
}
}
```
The added code is tested with `lfortran --show-tokens examples2/expr2.f90`
- ### Parse the New Token
Now we have to parse the new operator. We add it to the AST by extending the BinOp with a caret operator and modifying the *AST.asdl* file. Then we add it in *parse.yy* to properly parse and generate the new AST in *semantics.h*.Finally we extend *pickle.cpp* so that the new operator can print itself.
*grammar/AST.asdl*
```
operator = Add | Sub | Mul | Div | Pow | Caret
```
*src/lfortran/parser/parser.yy*
```
%left "^"
expr
: id { $$=$1; }
| expr "^" expr { $$ = CARET($1, $3, @$); }
```
*src/lfortran/parser/semantics.h*
```
#define CARET(x,y,l) make_BinOp_t(p.m_a, l, EXPR(x), operatorType::Caret, EXPR(y))
```
*src/lfortran/pickle.cpp*
```
std::string op2str(const operatorType type)
{
switch (type) {
case (operatorType::Caret) : return "^";
} // now the caret operator can print itself
}
```
The section is tested with `lfortran --show-ast examples/expr2.f90`
- ### Implement the Semantics of the New Token
We first extend the ASR in *ASR.asdl* and add ^ as a BinOp operator option.
*src/libasr/ASR.asdl*
```
binop = Add | Sub | Mul | Div | Pow | Caret
```
*src/lfortran/semantics/ast_common_visitor.h*
```
namespace LFortran {
class CommonVisitorMethods {
public:
inline static void visit_BinOp(Allocator &al, const AST::BinOp_t &x,
ASR::expr_t *&left, ASR::expr_t *&right,
ASR::asr_t *&asr) {
ASR::binopType op;
switch (x.m_op) {
case (AST::Caret):
op = ASR::Caret;
break;
}
if (LFortran::ASRUtils::expr_value(left) != nullptr &&
LFortran::ASRUtils::expr_value(right) != nullptr) {
if (ASR::is_a<LFortran::ASR::Integer_t>(*dest_type)) {
int64_t left_value = ASR::down_cast<ASR::ConstantInteger_t>(
LFortran::ASRUtils::expr_value(left))
->m_n;
int64_t right_value = ASR::down_cast<ASR::ConstantInteger_t>(
LFortran::ASRUtils::expr_value(right))
->m_n;
int64_t result;
switch (op) {
case (ASR::Caret):
result = (left_value + right_value)/2;
break;
}
}
}
}
}
}
```
Then we transform it from AST to ASR by extending *src/lfortran/semantics/ast_common_visitor.h*.
We also add it into compile time evaluation triggered by expressions such as `e = (2+3)^5` which is evaluated at compile time. An expression such as `e = x^5` is evaluated at run time only.
The section is tested with `lfortran --show-asr examples/expr2.f90`
### Implement the New Token in LLVM
To implement in LLVM, we extend the BinOp translation by handling the new operator. We first add the two numbers then divide by two.
*src/lfortran/codegen/asr_to_llvm.cpp*
```
void visit_BinOp(const ASR::BinOp_t &x) {
if (x.m_value) {
this->visit_expr_wrapper(x.m_value, true);
return;
}
this->visit_expr_wrapper(x.m_left, true);
llvm::Value *left_val = tmp;
this->visit_expr_wrapper(x.m_right, true);
llvm::Value *right_val = tmp;
if (x.m_type->type == ASR::ttypeType::Integer ||
x.m_type->type == ASR::ttypeType::IntegerPointer) {
switch (x.m_op) {
case ASR::binopType::Caret: {
tmp = builder->CreateAdd(left_val, right_val);
llvm::Value *two = llvm::ConstantInt::get(context,
llvm::APInt(32, 2, true));
tmp = builder->CreateUDiv(tmp, two);
break;
};
}
}
}
```
The section is tested with `lfortran --show-llvm examples/expr2.f90`
Now when LLVM works, we can test the final executable by:
```
lfortran examples/expr2.f90
./a.out
```
And it should print 6.
It also works interactively:
```
$ lfortran
Interactive Fortran. Experimental prototype, not ready for end users.
* Use Ctrl-D to exit
* Use Enter to submit
* Use Alt-Enter or Ctrl-N to make a new line
- Editing (Keys: Left, Right, Home, End, Backspace, Delete)
- History (Keys: Up, Down)
>>> 4^8 1,4 ]
6
>>> integer :: x 1,13 ]
>>> x = 4 1,6 ]
>>> x^8 1,4 ]
6
```
## Reach Out
If you have any questions or need help, please ask as on our [mailinglist](https://groups.io/g/lfortran) or headover to [Zulip Chat](https://lfortran.zulipchat.com/).
Expand Down

0 comments on commit 7315c19

Please sign in to comment.