1 # coding: utf-8
2 # frozen_string_literal: true
3
4
5
6 module Umu
7
8 module ConcreteSyntax
9
10 module Core
11
12 module Declaration
13
14 class Recursive < Declaration::Abstract
15 attr_reader :functions
16
17
18 def initialize(loc, functions)
19 ASSERT.kind_of functions, ::Array
20
21 super(loc)
22
23 @functions = functions
24 end
25
26
27 def to_s
28 format("%%FUN %%REC %s",
29 self.functions.map(&:to_s).join(' %%AND ')
30 )
31 end
32
33
34 def pretty_print(q)
35 q.text '%FUN %REC '
36
37 fst_func, *not_fst_funcs = self.functions
38 q.pp fst_func
39
40 not_fst_funcs.each do |func|
41 q.breakable
42
43 q.text '%AND'
44
45 q.breakable
46
47 PRT.group q do
48 q.pp func
49 end
50 end
51 end
52
53
54 def exported_vars
55 self.functions.inject([]) { |array, function|
56 ASSERT.kind_of array, ::Array
57 ASSERT.kind_of function, Function::Abstract
58
59 array + function.exported_vars
60 }.freeze
61 end
62
63
64 private
65
66 def __desugar__(env, event)
67 new_env = env.enter event
68
69 case self.functions.size
70 when 0
71 ASSERT.abort self.inspect
72 when 1
73 function = self.functions[0]
74 ASSERT.kind_of function, Function::Abstract
75
76 ASCD.make_recursive(
77 function.loc,
78 function.lam_expr.sym,
79 function.lam_expr.desugar(new_env)
80 )
81 else
82 functions = self.functions.inject({}) {
83 |hash, function|
84 ASSERT.kind_of hash, ::Hash
85 ASSERT.kind_of function, Function::Abstract
86
87 hash.merge(
88 function.lam_expr.sym => ECV.make_recursive_target(
89 function.lam_expr.desugar(new_env)
90 )
91 ) {
92 raise X::SyntaxError.new(
93 function.loc,
94 "In mutual recursion, duplicated variable: '%s'",
95 function.lam_expr.sym.to_s
96 )
97 }
98 }
99
100 ASCD.make_mutual_recursive self.loc, functions
101 end
102 end
103 end
104
105
106
107 module_function
108
109 def make_recursive(loc, functions)
110 ASSERT.kind_of loc, LOC::Entry
111 ASSERT.kind_of functions, ::Array
112
113 Recursive.new(loc, functions.freeze).freeze
114 end
115
116 end # Umu::ConcreteSyntax::Core::Declaration
117
118 end # Umu::ConcreteSyntax::Core
119
120 end # Umu::ConcreteSyntax
121
122 end # Umu