fork download
  1. module TMZ
  2.  
  3. module Commander
  4.  
  5. unless ::Object.new.respond_to?(:yield_self) # Ruby 2.5 or after
  6. class ::Object
  7. def yield_self
  8. yield self
  9. end
  10. end
  11. end
  12.  
  13.  
  14. module_function
  15.  
  16. begin
  17. require 'reline' # Ruby 2.7 or after
  18.  
  19. def input(prompt)
  20. Reline.readline(prompt, true)
  21. end
  22.  
  23. rescue ::LoadError
  24. begin
  25. require 'readline' # Ruby 2.6 or before
  26.  
  27. def input(prompt)
  28. Readline.readline(prompt, true)
  29. end
  30.  
  31. rescue ::LoadError
  32. def input(prompt)
  33. STDERR.print prompt; STDERR.flush
  34.  
  35. STDIN.gets
  36. end
  37. end
  38. end
  39.  
  40.  
  41. STDIN_FILE_NAME = '<stdin>'
  42.  
  43. PARSER = SC::Parser.new
  44.  
  45.  
  46. def main(args)
  47. ASSERT.kind_of args, ::Array
  48.  
  49. exit_code = begin
  50. prelude_env = Commander.process_file(
  51. PRELUDE,
  52. '<prelude>',
  53. E.setup(E::INITIAL_PREFERENCE)
  54. )
  55. pref, file_names = Commander.parse_option args, prelude_env.pref
  56. init_env = prelude_env.update_preference pref
  57.  
  58. if pref.interactive_mode?
  59. env = unless file_names.empty?
  60. Commander.process_files file_names, init_env
  61. else
  62. init_env
  63. end
  64.  
  65. Commander.interact env
  66. else
  67. if file_names.empty?
  68. raise X::CommandError.new('No input files')
  69. end
  70.  
  71. Commander.process_files file_names, init_env
  72. end
  73.  
  74. 0
  75. rescue X::Abstraction::RuntimeError => e
  76. e.print_backtrace
  77. STDERR.puts
  78. STDERR.puts e.to_s
  79.  
  80. 1
  81. rescue X::Abstraction::Expected, ::SystemCallError => e
  82. STDERR.puts
  83. STDERR.puts e.to_s
  84.  
  85. 1
  86. rescue ::Interrupt
  87. 1
  88. end
  89.  
  90. ASSERT.kind_of exit_code, ::Integer
  91. end
  92.  
  93.  
  94. def interact(init_env)
  95. ASSERT.kind_of init_env, E::Entry
  96.  
  97. init_tokens = []
  98. init_lexer = L::Lexer.make_initial_lexer STDIN_FILE_NAME, 1
  99. final_env = loop.inject(
  100. [1, init_tokens, init_lexer, init_env]
  101. ) { |(line_num, tokens, lexer, env ), _|
  102. ASSERT.kind_of line_num, ::Integer
  103. ASSERT.kind_of tokens, ::Array
  104. ASSERT.kind_of lexer, L::Lexer::Abstract
  105. ASSERT.kind_of env, E::Entry
  106.  
  107. prompt = format(
  108. "%04d%s%s%s ",
  109.  
  110. line_num,
  111.  
  112. if lexer.in_braket?
  113. format(":%s:%d",
  114. lexer.braket_stack.reverse.map { |bb|
  115. format("%-2s", bb)
  116. }.join('.'),
  117. lexer.braket_stack.length
  118. )
  119. else
  120. ''
  121. end,
  122.  
  123. if lexer.in_comment?
  124. format(":%s:%d",
  125. '(*' * lexer.comment_depth,
  126. lexer.comment_depth
  127. )
  128. else
  129. ''
  130. end,
  131.  
  132. if lexer.in_comment?
  133. '*'
  134. elsif lexer.in_braket?
  135. '|'
  136. else
  137. '>'
  138. end
  139. )
  140. opt_line = Commander.input prompt
  141.  
  142. break env if opt_line.nil?
  143. line = opt_line
  144.  
  145. next_tokens, next_lexer, next_env = begin
  146. if lexer.between_braket? && /^:/ =~ line
  147. [
  148. [],
  149. init_lexer,
  150. Commander.subcommand(line, line_num, env)
  151. ]
  152. else
  153. Commander.process_line(
  154. line + "\n",
  155. line_num,
  156. tokens,
  157. lexer,
  158. env.update_line(STDIN_FILE_NAME, line_num, line)
  159. )
  160. end
  161. rescue X::Abstraction::RuntimeError => e
  162. e.print_backtrace
  163. STDERR.puts
  164. STDERR.puts e.to_s
  165.  
  166. [[], init_lexer, env]
  167. rescue X::Abstraction::Expected, ::SystemCallError => e
  168. STDERR.puts
  169. STDERR.puts e.to_s
  170.  
  171. [[], init_lexer, env]
  172. rescue ::Interrupt
  173. STDERR.puts
  174. STDERR.puts 'Interrupt!!'
  175.  
  176. [[], init_lexer, env]
  177. end
  178.  
  179. [line_num + 1, next_tokens, next_lexer, next_env]
  180. }
  181.  
  182. ASSERT.kind_of final_env, E::Entry
  183. end
  184.  
  185.  
  186. def process_line(line, line_num, tokens, lexer, env)
  187. ASSERT.kind_of line, ::String
  188. ASSERT.kind_of line_num, ::Integer
  189. ASSERT.kind_of tokens, ::Array
  190. ASSERT.kind_of lexer, L::Lexer::Abstract
  191. ASSERT.kind_of env, E::Entry
  192.  
  193. pref = env.pref
  194. file_name = STDIN_FILE_NAME
  195.  
  196. if pref.trace_mode?
  197. STDERR.puts
  198. STDERR.printf "________ Source: '%s' ________\n", file_name
  199. STDERR.printf "%04d: %s", line_num, line
  200. end
  201.  
  202. if pref.trace_mode?
  203. STDERR.puts
  204. STDERR.printf "________ Tokens: '%s' ________", file_name
  205. end
  206.  
  207. scanner = ::StringScanner.new line
  208. next_tokens, next_lexer = L::Lexer.lex(
  209. tokens, lexer, 0, scanner, pref
  210. ) do |token, before_line_num|
  211.  
  212. if pref.trace_mode?
  213. line_num = token.pos.line_num
  214.  
  215. if line_num != before_line_num
  216. STDERR.printf "\n%04d: ", line_num
  217. end
  218.  
  219. unless token && token.separator?
  220. STDERR.printf "%s ", token.to_s
  221. STDERR.flush
  222. end
  223. end
  224. end
  225.  
  226. if pref.trace_mode?
  227. STDERR.puts
  228. end
  229.  
  230. if next_lexer.between_braket?
  231. [
  232. [],
  233. next_lexer,
  234. Commander.execute(next_tokens, env)
  235. ]
  236. else
  237. [
  238. next_tokens,
  239. next_lexer,
  240. env
  241. ]
  242. end
  243. end
  244.  
  245.  
  246. def process_files(file_names, init_env)
  247. ASSERT.kind_of file_names, ::Array
  248. ASSERT.kind_of init_env, E::Entry
  249.  
  250. final_env = file_names.inject(init_env) { |env, file_name|
  251. ASSERT.kind_of env, E::Entry
  252. ASSERT.kind_of file_name, ::String
  253.  
  254. source = ::File.open(file_name) { |io| io.read }
  255.  
  256. Commander.process_file(
  257. source,
  258. file_name,
  259. env.update_source(file_name, source)
  260. )
  261. }
  262.  
  263. ASSERT.kind_of final_env, E::Entry
  264. end
  265.  
  266.  
  267. def process_file(source, file_name, env)
  268. ASSERT.kind_of source, ::String
  269. ASSERT.kind_of file_name, ::String
  270. ASSERT.kind_of env, E::Entry
  271.  
  272. pref = env.pref
  273.  
  274. if pref.trace_mode?
  275. STDERR.puts
  276. STDERR.printf "________ Source: '%s' ________\n", file_name
  277. source.each_line.with_index do |line, index|
  278. STDERR.printf "%04d: %s", index + 1, line
  279. end
  280. end
  281.  
  282. if pref.trace_mode?
  283. STDERR.puts
  284. STDERR.printf "________ Tokens: '%s' ________", file_name
  285. end
  286.  
  287. init_tokens = []
  288. init_lexer = L::Lexer.make_initial_lexer file_name, 1
  289. scanner = ::StringScanner.new source
  290. tokens, _lexer = L::Lexer.lex(
  291. init_tokens, init_lexer, 0, scanner, pref
  292. ) do |token, before_line_num|
  293.  
  294. if pref.trace_mode?
  295. line_num = token.pos.line_num
  296.  
  297. if line_num != before_line_num
  298. STDERR.printf "\n%04d: ", line_num
  299. end
  300.  
  301. unless token && token.separator?
  302. STDERR.printf "%s ", token.to_s
  303. STDERR.flush
  304. end
  305. end
  306. end
  307.  
  308. if pref.trace_mode?
  309. STDERR.puts
  310. end
  311.  
  312. Commander.execute(tokens, env)
  313. end
  314.  
  315.  
  316. def execute(tokens, init_env)
  317. ASSERT.kind_of tokens, ::Array
  318. ASSERT.kind_of init_env, E::Entry
  319.  
  320. con_syntaxes = PARSER.parse tokens
  321.  
  322. final_env = con_syntaxes.inject(init_env) { |env, con_syntax|
  323. ASSERT.kind_of env, E::Entry
  324. ASSERT.kind_of con_syntax, SC::Abstract
  325.  
  326. pref = env.pref
  327.  
  328. con_syntax.tap { |csyn|
  329. ASSERT.kind_of csyn, SC::Abstract
  330.  
  331. if pref.trace_mode?
  332. STDERR.puts
  333. STDERR.printf(
  334. "________ Concrete Syntax: #%d in '%s' ________\n",
  335. csyn.pos.line_num,
  336. csyn.pos.file_name
  337. )
  338. STDERR.puts csyn.to_s
  339. end
  340. }.desugar.tap { |asyn|
  341. ASSERT.kind_of asyn, SA::Abstract
  342.  
  343. if pref.trace_mode?
  344. STDERR.puts
  345. STDERR.printf(
  346. "________ Abstract Syntax: #%d in '%s' ________\n",
  347. asyn.pos.line_num,
  348. asyn.pos.file_name
  349. )
  350. STDERR.puts asyn.to_s
  351. end
  352.  
  353. if pref.trace_mode?
  354. STDERR.puts
  355. STDERR.puts "________ Evaluator Trace ________"
  356. end
  357. }.evaluate(env).yield_self { |result|
  358. ASSERT.kind_of result, SAR::Abstract
  359.  
  360. case result
  361. when SAR::Value
  362. value = result.value
  363.  
  364. STDERR.puts
  365. STDERR.printf("-> %s : %s\n",
  366. value.to_s,
  367. value.type_sym.to_s
  368. )
  369.  
  370. env
  371. when SAR::Environment
  372. result.env
  373. else
  374. ASSERT.abort result.inspect
  375. end
  376. }
  377. }
  378.  
  379. ASSERT.kind_of final_env, E::Entry
  380. end
  381.  
  382. end # TMZ::Commander
  383.  
  384. end # TMZ
  385.  
Runtime error #stdin #stdout #stderr 0.01s 7016KB
stdin
Standard input is empty
stdout
Standard output is empty
stderr
prog.rb:43:in `<module:Commander>': uninitialized constant TMZ::Commander::SC (NameError)
	from prog.rb:3:in `<module:TMZ>'
	from prog.rb:1:in `<main>'