Class: Nydp::InterpretedFunction

Inherits:
Object
  • Object
show all
Extended by:
Helper
Includes:
Helper
Defined in:
lib/nydp/interpreted_function.rb

Constant Summary collapse

NIL =
nil

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helper

cons, list, literal?, pair?, sig, sym, sym?

Methods included from Converter

#n2r, #r2n, #rubify

Instance Attribute Details

#arg_namesObject

Returns the value of attribute arg_names.



40
41
42
# File 'lib/nydp/interpreted_function.rb', line 40

def arg_names
  @arg_names
end

#bodyObject

Returns the value of attribute body.



40
41
42
# File 'lib/nydp/interpreted_function.rb', line 40

def body
  @body
end

#context_builderObject

Returns the value of attribute context_builder.



40
41
42
# File 'lib/nydp/interpreted_function.rb', line 40

def context_builder
  @context_builder
end

Class Method Details

.build(arg_list, body, bindings, ns) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/nydp/interpreted_function.rb', line 99

def self.build arg_list, body, bindings, ns
  my_params = { }
  index_parameters arg_list, my_params
  body = compile_body body, cons(my_params, bindings), [], ns
  reach = body.map { |b| b.lexical_reach(-1)  }.max

  ifn_klass     = reach >= 0 ? InterpretedFunctionWithClosure : InterpretedFunctionWithoutClosure
  ifn           = ifn_klass.new
  ifn.arg_names = arg_list
  ifn.body      = body

  ifn.extend Nydp::LexicalContextBuilder.select arg_list
  ifn
end

.compile_body(body_forms, bindings, instructions, ns) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/nydp/interpreted_function.rb', line 114

def self.compile_body body_forms, bindings, instructions, ns
  instructions << Nydp::Compiler.compile(body_forms.car, bindings, ns)

  rest = body_forms.cdr
  if !rest
    return Pair.from_list(instructions)
  else
    # PopArg is necessary because each expression pushes an arg onto the arg stack.
    # we only need to keep the arg pushed by the last expression in a function
    # so we need the following line in order to remove unwanted args from the stack.
    # Each expression at some executes vm.push_arg(thing)
    # TODO find a more intelligent way to do this, eg change the meaning of vm or of push_arg in the expression vm.push_arg(thing)
    # instructions << PopArg
    compile_body rest, bindings, instructions, ns
  end
end

.index_parameters(arg_list, hsh) ⇒ Object



131
132
133
134
135
136
137
138
# File 'lib/nydp/interpreted_function.rb', line 131

def self.index_parameters arg_list, hsh
  if pair? arg_list
    index_parameters arg_list.car, hsh
    index_parameters arg_list.cdr, hsh
  elsif NIL != arg_list
    hsh[arg_list] = hsh.size
  end
end

Instance Method Details

#can_do?Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/nydp/interpreted_function.rb', line 46

def can_do?
  arg_names == nil
end

#compile_do_expr_to_ruby(indent, srcs) ⇒ Object



50
51
52
53
54
55
56
57
58
# File 'lib/nydp/interpreted_function.rb', line 50

def compile_do_expr_to_ruby indent, srcs
  body.
    map { |expr| expr.compile_to_ruby("  ", srcs, cando: true) }.
    to_a.
    join("\n").
    split(/\n/). # need join-split to separate out embedded newlines (TODO worry about newlines within literal strings?)
    map { |e| "#{indent}  #{e}" }.
    join("\n")
end

#compile_to_ruby(indent, srcs, opts = {}) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/nydp/interpreted_function.rb', line 60

def compile_to_ruby indent, srcs, opts={}
  an        = arg_names
  rubyargs  = []
  src_index = srcs.length

  srcs << to_s

  while (pair? an)
    rubyargs << "_arg_#{an.car.to_s._nydp_name_to_rb_name}=nil"
    an = an.cdr
  end

  if an
    rest_arg = "_arg_#{an.to_s._nydp_name_to_rb_name}"
    rubyargs << "*#{rest_arg}"
  end

  if rubyargs == []
    rubyargs = ""
  else
    rubyargs = "|#{rubyargs.join ","}|"
    # rubyargs = "(#{rubyargs.join ","})"
  end

  # code = "#{indent}(Nydp::Fn.new(@@src_#{src_index}) {#{rubyargs}\n"
  code = "#{indent}##> (fn #{arg_names._nydp_inspect} #{body.to_a.map(&:_nydp_inspect).join(" ").gsub(/\n/, '\n')})\n"
  code << "#{indent}(Nydp::Fn.new {#{rubyargs}\n"
  # code << "#{indent}(Proc.new {#{rubyargs}\n"
  # code = "(->#{rubyargs} {\n"
  if rest_arg
    code << "#{indent}  #{rest_arg} = #{rest_arg}._nydp_wrapper\n"
  end
  bodycode = body.map { |expr| expr.compile_to_ruby("  ", srcs, cando: true) }.to_a

  bodycode.push "#{bodycode.pop}._nydp_wrapper"
  code << bodycode.join("\n").split(/\n/).map { |e| "#{indent}  #{e}" }.join("\n")
  code << "\n#{indent}})"
end

#inspectObject



141
# File 'lib/nydp/interpreted_function.rb', line 141

def inspect   ; to_s ; end

#lexical_reach(n) ⇒ Object



42
43
44
# File 'lib/nydp/interpreted_function.rb', line 42

def lexical_reach n
  body.map { |b| b.lexical_reach(n - 1)  }.max
end

#nydp_typeObject



140
# File 'lib/nydp/interpreted_function.rb', line 140

def nydp_type ; "fn" ; end

#run_body(vm) ⇒ Object



146
147
148
149
150
# File 'lib/nydp/interpreted_function.rb', line 146

def run_body vm
  res = nil
  self.body.each { |x| res = x.execute(vm) }
  res
end

#to_sObject



142
143
144
# File 'lib/nydp/interpreted_function.rb', line 142

def to_s
  "(fn #{arg_names._nydp_inspect} #{body.map { |b| b._nydp_inspect}.join('\n')})"
end