Skip to content
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

add: Fortran Playground Code links #184

Merged
merged 13 commits into from
Aug 13, 2023
93 changes: 93 additions & 0 deletions extensions/fortran_playground.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from sphinx.directives.code import CodeBlock, parselinenos, dedent_lines, container_wrapper, logger
import urllib.parse
import requests
from requests.structures import CaseInsensitiveDict
from docutils import nodes

url = "https://play-api.fortran-lang.org/run"

headers = CaseInsensitiveDict()
headers["Accept"] = "application/json"
headers["Content-Type"] = "application/json"
data = """{"code":"%s","programInput":"","libs":[]}"""
comp_error = [b"<ERROR>",b"Error",b"app/main.f90",b"<h1>Bad Request</h1>"]


class PlayCodeBlock(CodeBlock):

def run(self):
document = self.state.document
code = '\n'.join(self.content)
location = self.state_machine.get_source_and_line(self.lineno)
linespec = self.options.get('emphasize-lines')
if linespec:
try:
nlines = len(self.content)
hl_lines = parselinenos(linespec, nlines)
if any(i >= nlines for i in hl_lines):
logger.warning(__('line number spec is out of range(1-%d): %r') %
(nlines, self.options['emphasize-lines']),
location=location)

hl_lines = [x + 1 for x in hl_lines if x < nlines]
except ValueError as err:
return [document.reporter.warning(err, line=self.lineno)]
else:
hl_lines = None

if 'dedent' in self.options:
location = self.state_machine.get_source_and_line(self.lineno)
lines = code.splitlines(True)
lines = dedent_lines(lines, self.options['dedent'], location=location)
code = ''.join(lines)

literal: Element = nodes.literal_block(code, code)
if 'linenos' in self.options or 'lineno-start' in self.options:
literal['linenos'] = True
literal['classes'] += self.options.get('class', [])
literal['force'] = 'force' in self.options
if self.arguments:
# highlight language specified
literal['language'] = self.arguments[0]
else:
# no highlight language specified. Then this directive refers the current
# highlight setting via ``highlight`` directive or ``highlight_language``
# configuration.
literal['language'] = self.env.temp_data.get('highlight_language',
self.config.highlight_language)
extra_args = literal['highlight_args'] = {}
if hl_lines is not None:
extra_args['hl_lines'] = hl_lines
if 'lineno-start' in self.options:
extra_args['linenostart'] = self.options['lineno-start']
self.set_source_info(literal)
caption = f"<a href='https://play.fortran-lang.org/?code={urllib.parse.quote(code)}' target='_blank'>Fortran Playground</a>"
try:
literal = container_wrapper(self, literal, caption)
except ValueError as exc:
return [document.reporter.warning(exc, line=self.lineno)]
resp = requests.post(url, headers=headers, data=data%clean(code))
print(resp.content)
#print([i in resp.content for i in comp_error])
if any(i in resp.content for i in comp_error):
#print("original")
return [*super().run()]
else:
#print("with link")
return [literal]



def setup(app):
app.add_directive('play-code-block', PlayCodeBlock)

return {
'version': '0.1',
'parallel_read_safe': True,
'parallel_write_safe': True,
}

def clean(s):
s = s.replace("\t", "\\t")
s = s.replace("\n", "\\n")
return s
henilp105 marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 3 additions & 0 deletions source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
"intrinsics": pathlib.Path(root, "data", "intrinsics.yml"),
}

sys.path.insert(0, str(root / "extensions"))

if not all(data.exists() for data in data_files.values()):
sys.path.insert(0, str(root.absolute()))
# pylint: disable=import-error, unused-import
Expand Down Expand Up @@ -68,6 +70,7 @@
"sphinx_copybutton",
"sphinx.ext.intersphinx",
"sphinx_jinja",
"fortran_playground",
]

myst_enable_extensions = [
Expand Down
12 changes: 6 additions & 6 deletions source/learn/quickstart/arrays_strings.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ using the `dimension` attribute or by appending the array dimensions in parenthe

**Example:** static array declaration

```fortran
```{play-code-block} fortran
program arrays
implicit none

Expand All @@ -43,7 +43,7 @@ we can perform operations on all or part of an array using array _slicing_ notat

**Example:** array slicing

```fortran
```{play-code-block} fortran
program array_slice
implicit none

Expand Down Expand Up @@ -80,7 +80,7 @@ These are _allocated_ while the program is running once we know how big the arra

**Example:** allocatable arrays

```fortran
```{play-code-block} fortran
program allocatable
implicit none

Expand All @@ -105,7 +105,7 @@ when they go out of scope.

**Example:** static character string

```fortran
```{play-code-block} fortran
program string
implicit none

Expand All @@ -126,7 +126,7 @@ end program string

**Example:** allocatable character string

```fortran
```{play-code-block} fortran
program allocatable_string
implicit none

Expand Down Expand Up @@ -155,7 +155,7 @@ Finally, we use the intrinsic function `trim` to remove any excess spaces when p

**Example:** string array

```fortran
```{play-code-block} fortran
program string_array
implicit none
character(len=10), dimension(2) :: keys, vals
Expand Down
22 changes: 11 additions & 11 deletions source/learn/quickstart/derived_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ As discussed previously in [Variables](variables), there are five built-in data

Here's an example of a basic derived type:

```fortran
```{play-code-block} fortran
type :: t_pair
integer :: i
real :: x
Expand All @@ -15,7 +15,7 @@ end type

The syntax to create a variable of type `t_pair` and access its members is:

```fortran
```{play-code-block} fortran
! Declare
type(t_pair) :: pair
! Initialize
Expand All @@ -30,15 +30,15 @@ You can also initialize derived type members by invoking the derived type constr

Example using the derived type constructor:

```fortran
```{play-code-block} fortran
pair = t_pair(1, 0.5) ! Initialize with positional arguments
pair = t_pair(i=1, x=0.5) ! Initialize with keyword arguments
pair = t_pair(x=0.5, i=1) ! Keyword arguments can go in any order
```

Example with default initialization:

```fortran
```{play-code-block} fortran
type :: t_pair
integer :: i = 1
real :: x = 0.5
Expand Down Expand Up @@ -79,7 +79,7 @@ The `sequence` attribute may be used only to declare that the following members

Example with `sequence`:

```fortran
```{play-code-block} fortran
type :: t_pair
sequence
integer :: i
Expand All @@ -98,7 +98,7 @@ The attribute `bind(c)` is used to achieve compatibility between Fortran's deriv

Example with `bind(c)`:

```fortran
```{play-code-block} fortran
module f_to_c
use iso_c_bindings, only: c_int
implicit none
Expand All @@ -124,7 +124,7 @@ struct c_struct {

Example of a derived type with `parameterized-declaration-list` and with the attribute `public`:

```fortran
```{play-code-block} fortran
module m_matrix
implicit none
private
Expand Down Expand Up @@ -154,7 +154,7 @@ The attribute `extends` was added in the F2003 standard and introduces an import

Example with the attribute `extends`:

```fortran
```{play-code-block} fortran
module m_employee
implicit none
private
Expand Down Expand Up @@ -229,7 +229,7 @@ end program test_employee

Examples of common cases:

```fortran
```{play-code-block} fortran
type :: t_example
! 1st case: simple built-in type with access attribute and [init]
integer, private :: i = 0
Expand Down Expand Up @@ -259,7 +259,7 @@ A derived type can contain functions or subroutines that are _bound_ to it. We'l

Here's an example of a derived type with a basic type-bound procedure:

```fortran
```{play-code-block} fortran
module m_shapes
implicit none
private
Expand Down Expand Up @@ -308,7 +308,7 @@ What is new:

In the above example, the type-bound procedure `area` is defined as a function and can be invoked only in an expression, for example `x = sq%area()` or `print *, sq%area()`. If you define it instead as a subroutine, you can invoke it from its own `call` statement:

```fortran
```{play-code-block} fortran
! Change within module
contains
subroutine area(self, x)
Expand Down
2 changes: 1 addition & 1 deletion source/learn/quickstart/hello_world.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Once you have set up your compiler, open a new file in your favourite code editor and enter the following:

```fortran
```{play-code-block} fortran
program hello
! This is a comment line; it is ignored by the compiler
print *, 'Hello, World!'
Expand Down
20 changes: 10 additions & 10 deletions source/learn/quickstart/operators_control_flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ message to describe the nature of the `angle` variable:

**Example:** single branch `if`

```fortran
```{play-code-block} fortran
if (angle < 90.0) then
print *, 'Angle is acute'
end if
Expand All @@ -65,7 +65,7 @@ We can add an alternative branch to the construct using the `else` keyword:

**Example:** two-branch `if`-`else`

```fortran
```{play-code-block} fortran
if (angle < 90.0) then
print *, 'Angle is acute'
else
Expand All @@ -80,7 +80,7 @@ We can actually add any number of branches using `else if` to specify more condi

**Example:** multi-branch `if`-`else if`-`else`

```fortran
```{play-code-block} fortran
if (angle < 90.0) then
print *, 'Angle is acute'
else if (angle < 180.0) then
Expand All @@ -105,7 +105,7 @@ to specify the start value and final value of our counting variable.

**Example:** `do` loop

```fortran
```{play-code-block} fortran
integer :: i

do i = 1, 10
Expand All @@ -115,7 +115,7 @@ end do

**Example:** `do` loop with skip

```fortran
```{play-code-block} fortran
integer :: i

do i = 1, 10, 2
Expand All @@ -130,7 +130,7 @@ in `while()` evaluates to `.true.`.

**Example:** `do while()` loop

```fortran
```{play-code-block} fortran
integer :: i

i = 1
Expand All @@ -150,7 +150,7 @@ with such cases.

**Example:** loop with `exit`

```fortran
```{play-code-block} fortran
integer :: i

do i = 1, 100
Expand All @@ -166,7 +166,7 @@ On the other hand, `cycle` skips whatever is left of the loop and goes into the

**Example:** loop with `cycle`

```fortran
```{play-code-block} fortran
integer :: i

do i = 1, 10
Expand All @@ -190,7 +190,7 @@ A recurring case in any programming language is the use of nested loops. Nested

**Example:** tagged nested loops

```fortran
```{play-code-block} fortran
integer :: i, j

outer_loop: do i = 1, 10
Expand All @@ -217,7 +217,7 @@ These requirements place restrictions on what can be placed within the loop body

**Example:** `do concurrent()` loop

```fortran
```{play-code-block} fortran
real, parameter :: pi = 3.14159265
integer, parameter :: n = 10
real :: result_sin(n)
Expand Down
Loading