@@ -22,7 +22,7 @@ defmodule Apix.Schema.Extensions.Core.TypeGraph do
2222
2323 @ doc """
2424 Runs all the `#{ inspect __MODULE__ } ` functions that are intended to be run
25- after compilation if compilation is finished to avoid corrupting `#{ inspect __MODULE__ } ` state.
25+ after compilation is finished to avoid corrupting `#{ inspect __MODULE__ } ` state.
2626
2727 - `prune!/0`
2828 - `validate!/0`
@@ -157,14 +157,23 @@ defmodule Apix.Schema.Extensions.Core.TypeGraph do
157157 - Known and unknown types are not subtypes.
158158 - `t:Ast.t/0` and `t:Context.t/0` referencing same schema are subtypes.
159159 """
160- def is_subtype? ( subtype , supertype ) when ( is_struct ( subtype , Context ) or is_struct ( subtype , Ast ) ) and ( is_struct ( supertype , Context ) or is_struct ( supertype , Ast ) ) do
161- subtype = Apix.Schema . get_schema ( subtype ) || subtype
162- supertype = Apix.Schema . get_schema ( supertype ) || supertype
163-
164- subtype_vertex = Apix.Schema . hash ( subtype )
165- supertype_vertex = Apix.Schema . hash ( supertype )
160+ def is_subtype? ( _subtype , % Context { module: Any , schema: :t , params: [ ] } ) , do: true
161+ def is_subtype? ( _subtype , % Ast { module: Any , schema: :t , args: [ ] } ) , do: true
166162
167- ! ! Graph . edge ( { subtype_vertex , supertype_vertex , :subtype } )
163+ def is_subtype? ( subtype , supertype ) when ( is_struct ( subtype , Context ) or is_struct ( subtype , Ast ) ) and ( is_struct ( supertype , Context ) or is_struct ( supertype , Ast ) ) do
164+ subtype =
165+ subtype
166+ |> Apix.Schema . get_schema ( )
167+ |> Kernel . || ( subtype )
168+ |> Apix.Schema . hash ( )
169+
170+ supertype =
171+ supertype
172+ |> Apix.Schema . get_schema ( )
173+ |> Kernel . || ( supertype )
174+ |> Apix.Schema . hash ( )
175+
176+ ! ! Graph . get_path_by ( supertype , subtype , & ( & 1 == :subtype ) )
168177 end
169178
170179 @ doc """
@@ -174,57 +183,71 @@ defmodule Apix.Schema.Extensions.Core.TypeGraph do
174183 - Known and unknown types are not supertypes.
175184 - `t:Ast.t/0` and `t:Context.t/0` referencing same schema are supertypes.
176185 """
177- def is_supertype? ( supertype , subtype ) when ( is_struct ( supertype , Context ) or is_struct ( supertype , Ast ) ) and ( is_struct ( subtype , Context ) or is_struct ( subtype , Ast ) ) do
178- supertype = Apix.Schema . get_schema ( supertype ) || supertype
179- subtype = Apix.Schema . get_schema ( subtype ) || subtype
180-
181- supertype_vertex = Apix.Schema . hash ( supertype )
182- subtype_vertex = Apix.Schema . hash ( subtype )
186+ def is_supertype? ( % Context { module: Any , schema: :t , params: [ ] } , _subtype ) , do: true
187+ def is_supertype? ( % Ast { module: Any , schema: :t , args: [ ] } , _subtype ) , do: true
183188
184- ! ! Graph . edge ( { supertype_vertex , subtype_vertex , :supertype } )
189+ def is_supertype? ( supertype , subtype ) when ( is_struct ( supertype , Context ) or is_struct ( supertype , Ast ) ) and ( is_struct ( subtype , Context ) or is_struct ( subtype , Ast ) ) do
190+ supertype =
191+ supertype
192+ |> Apix.Schema . get_schema ( )
193+ |> Kernel . || ( supertype )
194+ |> Apix.Schema . hash ( )
195+
196+ subtype =
197+ subtype
198+ |> Apix.Schema . get_schema ( )
199+ |> Kernel . || ( subtype )
200+ |> Apix.Schema . hash ( )
201+
202+ ! ! Graph . get_path_by ( subtype , supertype , & ( & 1 == :supertype ) )
185203 end
186204
187- defp build_type_relations! ( % Context { } = context ) do
188- context . ast
189- |> normalize ( )
190- |> Ast . prewalk ( [ { context , context } ] , fn
191- % Ast { module: m , schema: :t , args: [ _ , _ ] } = ast , [ { parent_ast , parent_ast } | _rest ] = acc when m in [ And , Or ] ->
192- {
193- ast ,
194- [ { m , ast . args } | acc ]
195- }
196-
197- % Ast { module: m , schema: :t , args: [ _ , _ ] } = ast , [ { m , args } | _rest ] = acc when m in [ And , Or ] ->
198- {
199- ast ,
200- [ { m , ast . args ++ args } | acc ]
201- }
205+ def build_type_relations! ( context_or_ast ) do
206+ context_or_ast
207+ |> case do
208+ % Context { } = context ->
209+ context . ast
202210
203- % Ast { } = ast , [ { parent_ast , parent_ast } | _rest ] = acc ->
211+ % Ast { } = ast ->
212+ ast
213+ end
214+ |> normalize ( )
215+ |> Ast . prewalk ( { context_or_ast , [ ] } , fn
216+ ast , { % Ast { module: And , schema: :t , args: [ _ , _ ] } = last , relations } ->
204217 {
205218 ast ,
206- [ { ast , parent_ast } | acc ]
219+ { last , [ { ast , last } | relations ] }
207220 }
208221
209- ast , [ { Or , args } , { parent_ast , parent_ast } | rest ] ->
210- {
211- ast ,
212- Enum . map ( args , & { parent_ast , & 1 } ) ++ [ { parent_ast , parent_ast } | rest ]
213- }
222+ ast , { % Ast { module: Or , schema: :t , args: [ _ , _ ] } = last , relations } ->
223+ { ast , { last , [ { last , ast } | relations ] } }
214224
215- ast , [ { And , args } , { parent_ast , parent_ast } | rest ] ->
216- {
217- ast ,
218- Enum . map ( args , & { & 1 , parent_ast } ) ++ [ { parent_ast , parent_ast } | rest ]
219- }
225+ ast , { last , [ ] } ->
226+ { ast , { ast , [ { last , ast } ] } }
220227
221228 ast , acc ->
222229 { ast , acc }
223230 end )
224231 |> elem ( 1 )
232+ |> elem ( 1 )
225233 |> Enum . each ( fn { sup , sub } ->
226- sup = Apix.Schema . get_schema ( sup ) || sup
227- sub = Apix.Schema . get_schema ( sub ) || sub
234+ sup =
235+ case sup do
236+ % { module: m } when m in [ And , Or ] ->
237+ sup
238+
239+ _ ->
240+ Apix.Schema . get_schema ( sup ) || sup
241+ end
242+
243+ sub =
244+ case sub do
245+ % { module: m } when m in [ And , Or ] ->
246+ sub
247+
248+ _ ->
249+ Apix.Schema . get_schema ( sub ) || sub
250+ end
228251
229252 sup_vertex = Apix.Schema . hash ( sup )
230253 sub_vertex = Apix.Schema . hash ( sub )
@@ -250,31 +273,38 @@ defmodule Apix.Schema.Extensions.Core.TypeGraph do
250273 defp normalize_not ( % Ast { module: Not , schema: :t , args: [ % Ast { module: None , schema: :t , args: [ ] } = ast ] } ) , do: struct ( ast , module: Any , schema: :t , args: [ ] )
251274
252275 defp normalize_not ( % Ast { module: Not , schema: :t , args: [ % Ast { module: And , schema: :t , args: args } ] } = ast ) do
253- args
254- |> Enum . sort_by ( & Apix.Schema . msa / 1 )
255- |> Enum . map ( & struct ( ast , module: Not , schema: :t , args: [ & 1 ] ) )
276+ args =
277+ args
278+ |> Enum . sort_by ( & Apix.Schema . msa / 1 )
279+ |> Enum . map ( & struct ( ast , module: Not , schema: :t , args: [ & 1 ] ) )
256280
257281 struct ( ast , module: Or , schema: :t , args: args )
258282 end
259283
260- defp normalize_not ( % Ast { module: Not , schema: :t , args: [ % Ast { module: Or , schema: :t , args: args } ] } = ast ) do
261- args
262- |> Enum . sort_by ( & Apix.Schema . msa / 1 )
263- |> Enum . map ( & struct ( ast , module: Not , schema: :t , args: [ & 1 ] ) )
264-
265- struct ( ast , module: And , schema: :t , args: args )
266- end
267-
268284 defp normalize_not ( % Ast { module: Not , schema: :t , args: [ arg ] } = ast ) do
269- reject = [
270- Apix.Schema . msa ( arg ) ,
271- { And , :t , 2 } ,
272- { Or , :t , 2 } ,
273- { Not , :t , 1 } ,
274- { Const , :t , 1 } ,
275- { Any , :t , 0 } ,
276- { None , :t , 0 }
277- ]
285+ reject =
286+ arg
287+ |> Ast . postwalk ( [ ] , fn
288+ % Ast { module: Or , schema: :t , args: args } = ast , acc ->
289+ msa =
290+ args
291+ |> Enum . map ( & Apix.Schema . msa / 1 )
292+ |> Enum . reject ( & ( & 1 == { Or , :t , 2 } ) )
293+
294+ { ast , msa ++ acc }
295+
296+ ast , acc ->
297+ { ast , acc }
298+ end )
299+ |> elem ( 1 )
300+ |> Kernel . ++ ( [
301+ { And , :t , 2 } ,
302+ { Or , :t , 2 } ,
303+ { Not , :t , 1 } ,
304+ { Const , :t , 1 } ,
305+ { Any , :t , 0 } ,
306+ { None , :t , 0 }
307+ ] )
278308
279309 Graph . vertices ( )
280310 |> Enum . map ( fn hash ->
@@ -284,6 +314,7 @@ defmodule Apix.Schema.Extensions.Core.TypeGraph do
284314 end )
285315 |> Enum . reject ( & ( Apix.Schema . msa ( & 1 ) in reject ) )
286316 |> Enum . sort_by ( & Apix.Schema . msa / 1 )
317+ |> Enum . uniq ( )
287318 |> case do
288319 [ ] ->
289320 struct ( ast , module: None , schema: :t , args: [ ] )
@@ -292,8 +323,8 @@ defmodule Apix.Schema.Extensions.Core.TypeGraph do
292323 context . ast
293324
294325 [ first | rest ] ->
295- Enum . reduce ( rest , first . ast , fn current , acc ->
296- struct ( ast , module: And , schema: :t , args: [ current . ast , acc ] )
326+ Enum . reduce ( rest , % Ast { module: first . module , schema: first . schema , args: Enum . map ( first . params , fn _ -> false end ) } , fn current , acc ->
327+ struct ( ast , module: Or , schema: :t , args: [ % Ast { module: current . module , schema: current . schema , args: Enum . map ( current . params , fn _ -> false end ) } , acc ] )
297328 end )
298329 end
299330 end
0 commit comments