Skip to content

enh : Refactor print#4696

Merged
certik merged 10 commits intolfortran:mainfrom
assem2002:refactor-print-for-real
Sep 23, 2024
Merged

enh : Refactor print#4696
certik merged 10 commits intolfortran:mainfrom
assem2002:refactor-print-for-real

Conversation

@assem2002
Copy link
Copy Markdown
Contributor

@assem2002 assem2002 commented Aug 28, 2024

towards #2543


Concerns

  • Naming of print_t only member to be 'text', is that a good choice?
  • Now, with print only supporting single argument of character type only. Should we throw an error when we encounter a text member that isn't of type character or should we only assert or to not even care about that?
  • Is removing end and sep from print gonna affect lPython?
  • Should We use make_print_t_util() that creates a print node with stringformat wrapped in it if necessary, or should build such a thing on our own each time we want print bunch of arguments.
  • replace_symbolic pass visits print and sees if it has some ready compile time values (In the old print node definition, not the one in this PR), then it replaces the argument with value (as I understand) ; Do we benefit from this visitor?, if so we would need to add values member into print structure

@assem2002 assem2002 added the refactor Issue or pull request to refactor existing code label Aug 28, 2024
@assem2002
Copy link
Copy Markdown
Contributor Author

I'm aware of all of the failing tests. They're compilation error details, it worked on my Ubuntu machine, but it's failing here. That's normal. I'll solve them.

@assem2002 assem2002 force-pushed the refactor-print-for-real branch 2 times, most recently from 5e4e9bb to 615f09e Compare August 29, 2024 01:34
@assem2002 assem2002 marked this pull request as ready for review August 29, 2024 01:45
@certik
Copy link
Copy Markdown
Contributor

certik commented Aug 29, 2024

Concerns

* [ ]  Naming of `print_t` only member to be 'text', is that a good choice?

I think so.

* [ ]  Now, with `print` only supporting single argument of character type only. Should we throw an error when we encounter a `text` member that isn't of type `character` or should we only assert or to not even care about that?

The verify pass should have a check for this.

* [ ]  Is removing `end` and `sep` from `print` gonna affect lPython?

Yes. LPython will need to use StringFormat also. We can write a utility function that does it automatically for LPython.

* [ ]  Should We use `make_print_t_util()` that creates a print node with stringformat wrapped in it if necessary, or should build such a thing on our own each time we want print bunch of arguments.

I think so.

* [ ]  `replace_symbolic` pass visits `print` and sees if it has some ready compile time values (In the old `print` node definition, not the one in this PR), then it replaces the argument with value (as I understand) ; Do we benefit from this visitor?, if so we would need to add `values` member into `print` structure.

Print is a statement, so it doesn't have an evaluation. But StringFormat is an expr so it should have value that we will eventually fill if the formatting can be done at compile time.

Comment thread src/libasr/codegen/asr_to_llvm.cpp
@certik
Copy link
Copy Markdown
Contributor

certik commented Aug 29, 2024

The replace symbolic is for symbolic (SymPy like) expressions. The Print replacement allowed printing the expressions. Those should be now handled in StringFormat. @anutosh491 can help with this later. For now it's fine, we can even disable this pass in LFortran if needed. We should add Fortran tests for symbolics also, to ensure things work. This is all unrelated.

Copy link
Copy Markdown
Contributor

@certik certik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this is fine. Thanks for finishing this.

@Pranavchiku can you please also review this if you see any big problems? Small issues can be fixed after we merge.

@Pranavchiku
Copy link
Copy Markdown
Member

I'll review this by tonight.

Comment thread src/lfortran/semantics/ast_body_visitor.cpp
Comment thread src/lfortran/semantics/ast_body_visitor.cpp Outdated
Comment thread src/libasr/pass/replace_symbolic.cpp
Comment thread tests/reference/asr-interface_10-e9eb6ea.stdout
Copy link
Copy Markdown
Member

@Pranavchiku Pranavchiku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a few comments above, please address those changes before merging. Reviewed references, looks good to me, except one which needs to be looked by Assem. Thanks for doing this!

@certik certik marked this pull request as draft September 15, 2024 16:30
@certik
Copy link
Copy Markdown
Contributor

certik commented Sep 15, 2024

@assem2002 let's finish this, I think it is almost done.

@assem2002 assem2002 force-pushed the refactor-print-for-real branch from 615f09e to 480add4 Compare September 21, 2024 07:07
@assem2002 assem2002 marked this pull request as ready for review September 21, 2024 08:02
@assem2002
Copy link
Copy Markdown
Contributor Author

assem2002 commented Sep 21, 2024

It should be ready now.

Comment thread src/libasr/codegen/asr_to_wasm.cpp
@certik
Copy link
Copy Markdown
Contributor

certik commented Sep 21, 2024

Thank you. I think this is great! Can you please resolve the conflicts?

To summarize, this PR makes the Print node accept just the text as a required argument. Much simpler!

@Pranavchiku, @gxyd can you please also review this PR if you see any issues?

@assem2002 assem2002 force-pushed the refactor-print-for-real branch from 480add4 to 1cb7524 Compare September 21, 2024 16:23
Comment thread src/libasr/codegen/asr_to_llvm.cpp Outdated
bool global_sep_space = true;
end = builder->CreateGlobalStringPtr("\n");
sep = builder->CreateGlobalStringPtr(" ");
if constexpr (x.class_type == ASR::stmtType::FileWrite){ // Remove after write node refactor.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can this be constexpr if x is runtime?

Copy link
Copy Markdown
Contributor Author

@assem2002 assem2002 Sep 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as I know, x should be either filewrite or print. CPP should evaluate that if condition at compile time which gives me the ability to use filewrite members freely without compile time errors as this function is generic.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a question. Will we have similar refactors for filewrite node as we are doing now with print?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, x is compile time here. Clever!

Yes, we should refactor FileWrite in a similar way later.

nullptr, nullptr, args.p, args.size(), nullptr, empty_string, nullptr);
}
return ASR::make_FileWrite_t(al, loc, 0, nullptr, nullptr,
nullptr, nullptr, args.p, args.size(), nullptr, empty_string, nullptr);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine as long as the leading space still works for print, by adding the space using StringFormat or some other way.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can test it like this:

$ lfortran examples/expr2.f90
25
$ lfortran --print-leading-space examples/expr2.f90
 25
$

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it prints the same. We have test for this case btw (reference test print3.f90).

Copy link
Copy Markdown
Contributor Author

@assem2002 assem2002 Sep 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to use print_t but I couldn't tell the backend to use lfortran_printf() with no \n character as now print_t doesn't have end member (the standard way if no end is provided is to use \n character).
If you can suggest better approach, it would be super helpful.

Copy link
Copy Markdown
Contributor

@certik certik Sep 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So lfortran --print-leading-space examples/expr2.f90 does not print the lead space now?

If so, then in AST->ASR you need to check for this flag, and if present, use StringFormat and concatenate " " and the other expression.

Regarding no end, that has to be implemented by having \n in the string itself. Print should not append \n. As a temporary solution you can reintroduce "end" into Print, to either append or not append \n. But this has to be done by the frontend to decide if \n is needed, and if so, append it via StringFormat. So unfortunately for now print("Hello") will turn into Print(StringFormat(["Hello", "\n"])). But later, we'll add compile time evaluation of StringFormat, that would provide a value "Hello\n" for this case, and in the backend you would use this value (if present), so in the end, the LLVM generated code would just print a simple string "Hello\n", which is the optimal way. If you can get this PR to work with having the backend to just append \n, that would be the easiest, and then once this is in, we can further refactor this based on this paragraph.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actullay that's much better to embed the " " in the stringformat args. it should work for both filewrite and print.
I think with your suggestion we won't need end member to help us with the leading space issue.
In the backend we print \n after each use of lfortran_printf() or lfortran_string_write() unless we set end in filewrite to something else.

I'll embed the " " character if leading space flag is true.

Copy link
Copy Markdown
Contributor

@certik certik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed every commit, it looks good. I have just one concern:

#4696 (comment)

As long as that works, then we can merge.

Copy link
Copy Markdown
Member

@Pranavchiku Pranavchiku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good to me, references are good too.

@anutosh491
Copy link
Copy Markdown
Contributor

Looks good. I shall address this TODO commit here (3782c7a) once this goes in

@certik
Copy link
Copy Markdown
Contributor

certik commented Sep 22, 2024

We need to print the empty space for lfortran --print-leading-space examples/expr2.f90 (one way or the other), then we can merge.

@assem2002
Copy link
Copy Markdown
Contributor Author

assem2002 commented Sep 23, 2024

--print-leading-space works as intended. examples/expr2.f90 works fine with flag --print-leading-space.
The resulting ASR of lfortran examples/expr2.f90 --print-leading-space is now like this :

          (FileWrite
              0
              ()
              ()
              ()
              ()
              [(StringConstant
                  " "
                  (Character 1 1 () PointerString)
              )]
              ()
              (StringConstant
                  ""
                  (Character 1 0 () PointerString)
              )
              ()
          )
          (Print
              (StringFormat
                  ()
                  [(Var 2 x)]
                  FormatFortran
                  (Character -1 0 () PointerString)
                  ()
              )
          )]
      )

With the suggestion you made here #4696 (comment) about adding just an arg into the stringFormat node instead of creating a whole write statment node, We can transfer the resulting ASR to look something like this :

(Print
            (StringFormat
                ()
                [(StringConstant
                    " "
                    (Character 1 1 () PointerString)
                )
                (Var 2 x)]
                FormatFortran
                (Character -1 0 () PointerString)
                ()
            )
        )]
    )

but the final print would be --> ' ' + four-default-spacing(set by the backend) + var x, so spacing won't be just 1 single empty space it would be 5 empty spaces.

Let me know what you think is better to use.

- The refactor cleans up some uses of the removed members of the old node.
- Handles generic function that operate on 'write' + 'print'
- Created 'make_print_t_util()' to build a print node with stringformat as the text to hold the arguments to be printed
by not using a generic function for both and just handle string format or handle the single character in each one's standalone visitor
…his is the only node that supports 'advance=no' feature

now, print doesn't support 'end' of value none, so we had to use FileWrite node
@assem2002 assem2002 force-pushed the refactor-print-for-real branch from 1cb7524 to 83cefd6 Compare September 23, 2024 06:07
Copy link
Copy Markdown
Contributor

@certik certik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I think this is fine to merge. The rest we can improve upon later, such as using StringFormat for everything, including FileWrite, and handle leading spaces and \n in StringFormat.

This is a huge step forward, now Print is clean. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Issue or pull request to refactor existing code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants