File: api.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Umu#8
  module: Api#10
has properties
function: setup_interpreter / 1 #203
function: va_context / 1 #210
function: eval_decls / 3 #217
function: eval_expr / 3 #226
  class: Interpreter#12
inherits from
  Object ( Builtin-Module )
has properties
class method: setup / 1 #13
attribute: env [R] #26
attribute: parser [R] #26
method: initialize / 1 #28
method: eval_decls / 2 #36
method: eval_expr / 2 #71
method: __parse_option__ / 1 #111
method: __lex_source__ / 4 #143

Class Hierarchy

Object ( Builtin-Module )
  Interpreter ( Umu::Api ) #12

Code

   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