1 # coding: utf-8
2 # frozen_string_literal: true
3
4 require 'pp'
5
6
7
8 module Umu
9
10 module Api
11
12 class Interpreter
13 def self.setup(opts)
14 ASSERT.kind_of opts, ::Array
15
16 env, file_names = Umu::Commander.setup opts
17
18 unless file_names.empty?
19 raise X::CommandError.new('Does not exists input files')
20 end
21
22 Interpreter.new(env).freeze
23 end
24
25
26 attr_reader :env, :parser
27
28 def initialize(env)
29 ASSERT.kind_of env, E::Entry
30
31 @env = env
32 @parser = CS::Parser.new
33 end
34
35
36 def eval_decls(source, opts)
37 ASSERT.kind_of source, ::String
38 ASSERT.kind_of opts, ::Hash
39
40 file_name, init_line_num, bindings = __parse_option__ opts
41
42 tokens, lexed_env = __lex_source__(
43 source, file_name, self.env, init_line_num
44 )
45
46 csyn_stmts = self.parser.parse tokens
47
48 new_env = lexed_env.va_extend_values bindings
49
50 final_env = csyn_stmts.inject(new_env) { |env, csyn_stmt|
51 ASSERT.kind_of env, E::Entry
52 ASSERT.kind_of csyn_stmt, CS::Abstract
53
54 result = Umu::Commander.execute(csyn_stmt, env)
55 ASSERT.kind_of result, ASR::Abstract
56
57 case result
58 when ASR::Value
59 env
60 when ASR::Environment
61 result.env
62 else
63 ASSERT.abort result.inspect
64 end
65 }
66
67 Interpreter.new(final_env).freeze
68 end
69
70
71 def eval_expr(source, opts)
72 ASSERT.kind_of source, ::String
73 ASSERT.kind_of opts, ::Hash
74
75 file_name, init_line_num, bindings = __parse_option__ opts
76
77 tokens, lexed_env = __lex_source__(
78 source, file_name, self.env, init_line_num
79 )
80
81 csyn_stmts = self.parser.parse tokens
82
83 new_env = lexed_env.va_extend_values bindings
84
85 opt_value, _ = csyn_stmts.inject(
86 [nil, new_env]
87 ) { |(opt_val, env ), csyn_stmt|
88 ASSERT.opt_kind_of opt_val, VC::Top
89 ASSERT.kind_of env, E::Entry
90 ASSERT.kind_of csyn_stmt, CS::Abstract
91
92 result = Umu::Commander.execute(csyn_stmt, env)
93 ASSERT.kind_of result, ASR::Abstract
94
95 case result
96 when ASR::Value
97 [result.value, env]
98 when ASR::Environment
99 [opt_val, result.env]
100 else
101 ASSERT.abort result.inspect
102 end
103 }
104
105 ASSERT.opt_kind_of opt_value, VC::Top
106 end
107
108
109 private
110
111 def __parse_option__(opts)
112 ASSERT.kind_of opts, ::Hash
113
114 triple = opts.inject(
115 ['<_>', 0, {}]
116 ) { |(name, num, bs), (key, val)|
117 ASSERT.kind_of key, ::Symbol
118
119 case key
120 when :_file_name
121 ASSERT.kind_of val, ::String
122
123 [val, num, bs]
124 when :_line_num
125 ASSERT.kind_of val, ::Integer
126
127 [name, val, bs]
128 else
129 ASSERT.kind_of val, VC::Top
130
131 new_bs = bs.merge(key => val) {
132 ASSERT.abort "Duplicated key: '%s'", key.to_s
133 }
134
135 [name, num, new_bs]
136 end
137 }
138
139 ASSERT.tuple_of triple, [::String, ::Integer, ::Hash]
140 end
141
142
143 def __lex_source__(
144 source, file_name, env, init_line_num = 0
145 )
146 ASSERT.kind_of source, ::String
147 ASSERT.kind_of file_name, ::String
148 ASSERT.kind_of env, E::Entry
149 ASSERT.kind_of init_line_num, ::Integer
150
151 pref = env.pref
152
153 if pref.dump_mode?
154 STDERR.puts
155 STDERR.printf "________ Source: '%s' ________\n", file_name
156 source.each_line.with_index do |line, index|
157 STDERR.printf "%04d: %s", index + 1, line
158 end
159 end
160
161 if pref.dump_mode?
162 STDERR.puts
163 STDERR.printf "________ Tokens: '%s' ________", file_name
164 end
165
166 init_tokens = []
167 init_lexer = LL.make_initial_lexer file_name, init_line_num
168 scanner = ::StringScanner.new source
169 tokens, _lexer = LL.lex(
170 init_tokens, init_lexer, scanner, pref
171 ) do |_event, _matched, output_tokens, _lexer, before_line_num|
172
173 if pref.dump_mode?
174 output_tokens.each do |token|
175 tk_line_num = token.loc.line_num
176
177 if tk_line_num != before_line_num
178 STDERR.printf "\n%04d: ", tk_line_num + 1
179 end
180
181 unless token && token.separator?
182 STDERR.printf "%s ", token.to_s
183 STDERR.flush
184 end
185 end
186 end
187 end
188
189 if pref.dump_mode?
190 STDERR.puts
191 end
192
193 [
194 tokens,
195 env.update_source(file_name, source, init_line_num)
196 ]
197 end
198 end
199
200
201 module_function
202
203 def setup_interpreter(*opts)
204 ASSERT.kind_of opts, ::Array
205
206 Interpreter.setup opts
207 end
208
209
210 def va_context(interp)
211 ASSERT.kind_of interp, Interpreter
212
213 interp.env.va_context
214 end
215
216
217 def eval_decls(interp, source, opts = {})
218 ASSERT.kind_of interp, Interpreter
219 ASSERT.kind_of source, ::String
220 ASSERT.kind_of opts, ::Hash
221
222 interp.eval_decls source, opts
223 end
224
225
226 def eval_expr(interp, source, opts = {})
227 ASSERT.kind_of interp, Interpreter
228 ASSERT.kind_of source, ::String
229 ASSERT.kind_of opts, ::Hash
230
231 interp.eval_expr source, opts
232 end
233
234 end # Umu::Api
235
236 end # Umu