Skip to content

Commit 8368246

Browse files
author
Damian Rouson
authored
Merge pull request #50 from sourceryinstitute/fix-47
Fix Construction From JSON
2 parents 73e223b + a16e11a commit 8368246

File tree

5 files changed

+96
-84
lines changed

5 files changed

+96
-84
lines changed

.github/workflows/CI.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ jobs:
2727

2828
- name: Install GFortran, OpenCoarrays,and fpm
2929
run: |
30-
sudo apt install -y gfortran-10 graphviz
31-
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 \
32-
--slave /usr/bin/gfortran gfortran /usr/bin/gfortran-10 \
33-
--slave /usr/bingcov gcov /usr/bin/gcov-10
30+
sudo apt install -y gfortran-11 graphviz
31+
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 100 \
32+
--slave /usr/bin/gfortran gfortran /usr/bin/gfortran-11 \
33+
--slave /usr/bingcov gcov /usr/bin/gcov-11
3434
if [ ! -d OpenCoarrays-2.9.2 ] ; then wget -P . https://github.com/sourceryinstitute/OpenCoarrays/releases/download/2.9.2/OpenCoarrays-2.9.2.tar.gz && tar -xf OpenCoarrays-2.9.2.tar.gz && cd OpenCoarrays-2.9.2 && TERM=xterm ./install.sh -y; fi
3535
wget https://github.com/fortran-lang/fpm/releases/download/v0.1.3/fpm-0.1.3-linux-x86_64 && sudo cp fpm-0.1.3-linux-x86_64 /usr/local/bin/fpm && sudo chmod a+x /usr/local/bin/fpm
3636

src/dag_s.f90

Lines changed: 19 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ recursive subroutine depth_first_search(v, d, s, o)
5555
integer, intent(in) :: v, d(:)
5656
integer, intent(out), allocatable :: s(:)
5757
integer, intent(inout), allocatable :: o(:)
58-
58+
5959
call assert(.not. any(v == d), "depth_first_search: cycle detected", intrinsic_array_t([v,d]))
60-
60+
6161
block
6262
integer, allocatable :: dependencies(:), s_local(:), d_local(:)
6363
integer w
@@ -73,29 +73,29 @@ recursive subroutine depth_first_search(v, d, s, o)
7373
s_local = d_local
7474
end if
7575
end do
76-
76+
7777
if (.not. any(v == o)) o = [v, o]
7878
s = [v, s_local]
7979
end block
8080

8181
end subroutine
8282

8383
end function toposort
84-
84+
8585
module procedure is_sorted_and_acyclic
86-
86+
8787
if (.not. allocated(self%order)) then
8888
is_sorted_and_acyclic = .false.
8989
return
9090
end if
91-
91+
9292
associate(num_vertices => size(self%vertices), order_size => size(self%order))
9393
call assert(order_size == num_vertices, "dag_t%is_sorted_and_acyclic: size(self%vertices) == size(self%order)", &
9494
intrinsic_array_t([order_size, num_vertices]))
95-
95+
9696
block
9797
integer i, j
98-
98+
9999
do i = 1, num_vertices
100100
associate(edges => self%vertices(self%order(i))%get_edges())
101101
do j = 1, size(edges)
@@ -106,55 +106,30 @@ end function toposort
106106
end do
107107
end associate
108108
end do
109-
109+
110110
is_sorted_and_acyclic = .true.
111111
end block
112-
112+
113113
end associate
114-
114+
115115
end procedure
116116

117117
module procedure construct_from_json
118118
type(fallible_json_value_t) :: maybe_vertices
119119

120+
maybe_vertices = json_object%get_element("vertices")
120121
associate(errors => maybe_vertices%errors())
121122
call assert(.not. errors%has_any(), "dag_s construct_from_json: .not. errors%has_any()", char(errors%to_string()))
122123
end associate
123124

124125
select type (vertices => maybe_vertices%value_())
125126
type is (json_array_t)
126-
127-
associate(nvertices => vertices%length())
128-
allocate(dag%vertices(nvertices))
129-
block
130-
integer i
131-
call dag%vertices%set_vertex_id( [(i,i=1,nvertices)] )
132-
end block
133-
end associate
134-
135-
block
136-
integer i
137-
do i = 1, vertices%length()
138-
associate(maybe_vertex => vertices%get_element(i))
139-
associate(errors => maybe_vertex%errors())
140-
call assert(.not. errors%has_any(), "dag_s construct_from_json: .not. errors%has_any()", char(errors%to_string()))
141-
end associate
142-
143-
select type (vertex_json => maybe_vertex%value_())
144-
class default
145-
call assert(.false., "dag_s construct_from_json: vertex was not an object", char(vertex_json%to_compact_string()))
146-
type is (json_object_t)
147-
associate(dag_vertex => vertex_t(vertex_json))
148-
call dag%vertices(i)%set_edges(dag_vertex%edges)
149-
end associate
150-
end select
151-
end associate
152-
end do
153-
end block
127+
dag%vertices = vertex_t(vertices%get_elements())
154128

155129
class default
156130
call assert(.false., "dag%from_json: vertices was not an array", char(vertices%to_compact_string()))
157131
end select
132+
dag%order = toposort(dag)
158133
end procedure
159134

160135
module procedure to_json
@@ -168,7 +143,7 @@ end function toposort
168143
block
169144
type(json_array_t) vertices_value
170145

171-
vertices_value = json_array_t(json_element_t(self%vertices%to_json()))
146+
vertices_value = json_array_t(json_element_t(self%vertices%to_json()))
172147

173148
associate(vertices_key => maybe_key%string())
174149
json_object = json_object_t([vertices_key], [json_element_t(vertices_value)])
@@ -190,7 +165,7 @@ end function toposort
190165

191166
allocate(dependencies(0))
192167

193-
block
168+
block
194169
integer v
195170

196171
do v = 1, size(self%vertices)
@@ -222,11 +197,11 @@ function generate_digraph(self,rankdir,dpi) result(str)
222197
!! - Result is the string to write out to a *.dot file. (Called by save_digraph())
223198
implicit none
224199
class(dag_t),intent(in) :: self
225-
character(len=:),allocatable :: str
200+
character(len=:),allocatable :: str
226201
character(len=*),intent(in),optional :: rankdir
227202
!! - Rank Direction which are applicable inputs to the -rankdir option on the digraph command
228-
integer,intent(in),optional :: dpi
229-
!! - dots per inch
203+
integer,intent(in),optional :: dpi
204+
!! - dots per inch
230205

231206
integer :: i,j
232207
integer :: n_edges

src/vertex_m.f90

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module vertex_m
33
!! version: v1.0
44
!! date: 2020-Nov-30
55
!! license: Copyright (c) 2020-2021, Sourcery Institute, BSD 3-clause license Copyright (c) 2018 Jacob Williams
6-
use jsonff, only : json_object_t
6+
use jsonff, only : json_element_t, json_object_t, json_value_t
77
use iso_varying_string, only : varying_string, len
88

99
implicit none
@@ -38,13 +38,19 @@ module vertex_m
3838
end type vertex_t
3939

4040
interface vertex_t
41-
42-
module function from_json(json_object) result(vertex)
41+
42+
impure elemental module function from_json_element(json_element) result(vertex)
43+
implicit none
44+
type(json_element_t), intent(in) :: json_element
45+
type(vertex_t) :: vertex
46+
end function
47+
48+
module function from_json_value(json_value) result(vertex)
4349
implicit none
44-
type(json_object_t), intent(in) :: json_object
50+
class(json_value_t), intent(in) :: json_value
4551
type(vertex_t) :: vertex
4652
end function
47-
53+
4854
pure module function construct_from_components(identifier, edges, label, attributes) result(vertex)
4955
implicit none
5056
integer, intent(in) :: identifier
@@ -53,11 +59,17 @@ pure module function construct_from_components(identifier, edges, label, attribu
5359
type(varying_string), intent(in), optional :: attributes
5460
type(vertex_t) vertex
5561
end function
56-
62+
5763
end interface
5864

5965
interface
6066

67+
module function from_json_object(json_object) result(vertex)
68+
implicit none
69+
type(json_object_t), intent(in) :: json_object
70+
type(vertex_t) :: vertex
71+
end function
72+
6173
module subroutine set_edge_vector(self,edges)
6274
!! Define the vertices on which this vertex depends on
6375
implicit none

src/vertex_s.f90

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
fallible_json_string_t, &
44
fallible_json_value_t, &
55
json_array_t, &
6-
json_element_t, &
76
json_number_t, &
87
json_string_t, &
98
json_integer_t
@@ -27,25 +26,25 @@
2726
errors = maybe_key%errors()
2827
call assert(.not. errors%has_any(), "vertex%to_json (edges key): .not. errors%has_any()", char(errors%to_string()))
2928
edges_key = maybe_key%string()
30-
29+
3130
if (allocated(self%edges)) then
3231
do i = lbound(self%edges, 1), ubound(self%edges, 1)
3332
call edges_value%append(json_integer_t(self%edges(i)))
3433
end do
3534
end if
36-
35+
3736
maybe_key = fallible_json_string_t("label")
3837
errors = maybe_key%errors()
3938
call assert(.not. errors%has_any(), "vertex%to_json (label key): .not. errors%has_any()", char(errors%to_string()))
4039
label_key = maybe_key%string()
41-
40+
4241
maybe_value = fallible_json_string_t(self%get_label())
4342
errors = maybe_value%errors()
4443
call assert(.not. errors%has_any(), "vertex%to_json (label value): .not. errors%has_any()", char(errors%to_string()))
4544
label_value = maybe_value%string()
4645

47-
48-
json_object = json_object_t([label_key, edges_key], [json_element_t(label_value), json_element_t(edges_value)])
46+
47+
json_object = json_object_t([label_key, edges_key], [json_element_t(label_value), json_element_t(edges_value)])
4948

5049
end procedure
5150

@@ -69,7 +68,20 @@
6968
vertex%defined_ = .true.
7069
end procedure
7170

72-
module procedure from_json
71+
module procedure from_json_element
72+
vertex = vertex_t(json_element%value_())
73+
end procedure
74+
75+
module procedure from_json_value
76+
select type (json_value)
77+
type is (json_object_t)
78+
vertex = from_json_object(json_value)
79+
class default
80+
call assert(.false., "vertex%from_json_value: vertex was not an object", char(json_value%to_compact_string()))
81+
end select
82+
end procedure
83+
84+
module procedure from_json_object
7385
type(error_list_t) :: errors
7486
type(fallible_json_value_t) :: maybe_edge
7587
type(fallible_json_value_t) :: maybe_edges
@@ -88,6 +100,8 @@
88100
select type (edge => maybe_edge%value_())
89101
type is (json_number_t)
90102
vertex%edges(i) = int(edge%get_value())
103+
type is (json_integer_t)
104+
vertex%edges(i) = edge%get_value()
91105
class default
92106
call assert(.false., "vertex%from_json: edge was not a number", char(edge%to_compact_string()))
93107
end select

test/dag_test.f90

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
module dag_test
22
use dag_m, only: dag_t
3+
use erloff, only: error_list_t
34
use vertex_m, only: vertex_t
45
use vegetables, only: &
5-
result_t, test_item_t, assert_equals, describe, it, assert_that
6+
result_t, test_item_t, assert_equals, describe, it, assert_that, fail
67
use iso_varying_string, only : varying_string, var_str, assignment(=), char
7-
use jsonff, only: json_object_t
8+
use jsonff, only: fallible_json_value_t, json_object_t, parse_json
89
!! Test DAG construction, input, and output.
910
implicit none
1011
private
@@ -16,31 +17,31 @@ function test_dag_construction() result(tests)
1617
type(test_item_t) :: tests
1718

1819
tests = describe("dag's module dependency graph", &
19-
[it("can be constructed, output to .dot file, and converted to a PDF", construct_dag_and_write_pdf) &
20-
,it("can be constructed and converted to a JSON object", construct_dag_and_json_object) &
21-
,it("is topologically sorted when constructed from components", component_constructor_sorts) &
20+
[ it("can be constructed, output to .dot file, and converted to a PDF", construct_dag_and_write_pdf) &
21+
, it("can be constructed and converted to a JSON object", construct_dag_and_json_object) &
22+
, it("is topologically sorted when constructed from components", component_constructor_sorts) &
23+
, it("is topologically sorted when constructed from a JSON object", json_constructor_sorts) &
2224
])
23-
!,it("is topologically sorted when constructed from a JSON object", json_constructor_sorts)])
2425

2526
end function
2627

2728
function module_tree_from_components() result(dag_modules)
2829
type(dag_t) dag_modules
29-
30+
3031
enum, bind(C)
31-
enumerator :: assert_m=1, vertex_s, vertex_m, dag_m, dag_s
32+
enumerator :: assert_m=1, vertex_s, vertex_m, dag_m, dag_s
3233
end enum
33-
34+
3435
integer, parameter :: module_id(*) = [assert_m, vertex_s, vertex_m, dag_m, dag_s]
3536
type(varying_string) :: names(size(module_id))
36-
37+
3738
names(assert_m) = "assert_m"
3839
names(vertex_m) = "vertex_m"
39-
names(vertex_s) = "vertex_s"
40+
names(vertex_s) = "vertex_s"
4041
names(dag_m) = "dag_m"
4142
names(dag_s) = "dag_s"
4243

43-
block
44+
block
4445
character(len=*), parameter :: &
4546
branch = 'shape=square, fillcolor="SlateGray1", style=filled' &
4647
,external_ = 'shape=square, fillcolor="green", style=filled' &
@@ -69,7 +70,7 @@ function construct_dag_and_write_pdf() result(result_)
6970
associate(modules => module_tree_from_components())
7071
call modules%save_digraph(dot_file_name, 'RL', 300)
7172
call execute_command_line(command, wait=.true., exitstat=exit_status, cmdstat=command_status)
72-
result_ = assert_equals(success, exit_status) .and. assert_equals(success, command_status)
73+
result_ = assert_equals(success, exit_status) .and. assert_equals(success, command_status)
7374
end associate
7475

7576
end function
@@ -94,28 +95,38 @@ function construct_dag_and_json_object() result(result_)
9495

9596
function component_constructor_sorts() result(result_)
9697
type(result_t) result_
97-
98+
9899
associate(dag => module_tree_from_components())
99100
result_ = assert_that(dag%is_sorted_and_acyclic())
100101
end associate
101-
end function
102+
end function
102103

103104
function json_constructor_sorts() result(result_)
104105
type(result_t) result_
105-
type(dag_t) dag
106-
character(len=*), parameter :: dag_library_module_dependencies= &
106+
type(dag_t) dag
107+
type(error_list_t) :: errors
108+
type(fallible_json_value_t) :: maybe_json
109+
character(len=*), parameter :: json_string = &
107110
'{"vertices":[' // &
108111
'{"label":"assert_m","edges":[]},' // &
109112
'{"label":"vertex_s","edges":[3,1]},' // &
110113
'{"label":"vertex_m","edges":[]},' // &
111114
'{"label":"dag_m","edges":[3]},' // &
112115
'{"label":"dag_s","edges":[4,1]}]}'
113-
character(len=len(dag_library_module_dependencies)) json
114-
115-
json = dag_library_module_dependencies
116-
117-
read(json,*) dag
118-
result_ = assert_that(dag%is_sorted_and_acyclic())
116+
117+
maybe_json = parse_json(json_string)
118+
if (.not.maybe_json%failed()) then
119+
select type (json => maybe_json%value_())
120+
type is (json_object_t)
121+
dag = dag_t(json)
122+
result_ = assert_that(dag%is_sorted_and_acyclic())
123+
class default
124+
result_ = fail("json wasn't an object")
125+
end select
126+
else
127+
errors = maybe_json%errors()
128+
result_ = fail(errors%to_string())
129+
end if
119130
end function
120131

121132
end module dag_test

0 commit comments

Comments
 (0)