Class: Lisp::PrimIo

Inherits:
Object show all
Defined in:
lib/rubylisp/prim_io.rb

Class Method Summary collapse

Class Method Details

.close_port_impl(args, env) ⇒ Object



56
57
58
59
60
61
# File 'lib/rubylisp/prim_io.rb', line 56

def self.close_port_impl(args, env)
  p = args.car
  return Lisp::Debug.process_error("'close-port' requires a port argument.", env) unless p.port?
  p.value.close
  Lisp::String.with_value("OK")
end

.eof_objectp_impl(args, env) ⇒ Object



128
129
130
# File 'lib/rubylisp/prim_io.rb', line 128

def self.eof_objectp_impl(args, env)
  Boolean.with_value(args.car.eof_object?)
end

.format_impl(args, env) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/rubylisp/prim_io.rb', line 133

def self.format_impl(args, env)
  destination = args.car
  return Lisp::Debug.process_error("'format' requires a port or boolean as it's first argument.", env) unless destination.port? || destination.boolean?

  control_string_obj = args.cadr
  return Lisp::Debug.process_error("'format' requires a string as it's second argument.", env) unless control_string_obj.string?
  control_string = control_string_obj.value

  arguments = args.cddr

  number_of_substitutions = control_string.count('~')
  parts = []
  start = 0
  i = 0
  numeric_arg = 0
  at_modifier = false
  
  while i < control_string.length
    numeric_arg = 0
    at_modifier = false

    if control_string[i] == '~'
      parts << control_string[start...i]
      i += 1
      start = i
      i += 1 while '0123456789'.include?(control_string[i])
      if i == start
        if control_string[i] == '#'
          numeric_arg = arguments.length
          i += 1
        elsif 'vV'.include?(control_string[i])
          if arguments.car.number?
            numeric_arg = arguments.car.value
            arguments = arguments.cdr
          else
            return Lisp::Debug.process_error("'format' encountered a size argument mismatch at index #{i}.", env)
          end
          i += 1
        else
          numeric_arg = 0
        end
      else
        numeric_arg = control_string[start...i].to_i
      end
      if control_string[i] == '@'
        at_modifier = true
        i += 1
      end

      case control_string[i]
      when 'A', 'a', 'S', 's'
        substitution = ('Aa'.include?(control_string[i])) ? arguments.car.print_string : arguments.car.to_s
        padding = substitution.length < numeric_arg ? (" " * (numeric_arg - substitution.length)) : ""
        parts << padding if at_modifier
        parts << substitution
        parts << padding unless at_modifier
        arguments = arguments.cdr
        start = i + 1
      when '%'
        parts << ((numeric_arg > 0) ? ("\n" * numeric_arg) : "\n")
        start = i + 1
      when '~'
        parts << ((numeric_arg > 0) ? ("~" * numeric_arg) : "~")
        start = i + 1
      when "\n"
        while control_string[i] =~ /[[:space:]]/
          i += 1
        end
        parts << "\n" if at_modifier
        start = i
        i -= 1
      else
        return Lisp::Debug.process_error("'format' encountered an unsupported substitution at index #{i}.", env)
      end
    end
    i += 1
  end
  parts << control_string[start..i] if start < control_string.length
  return Lisp::Debug.process_error("'format' found a mismatch in the number of substitutions and arguments.", env) if i < control_string.length || !arguments.nil?

  combined_string = parts.join

  if destination.port?
    destination.value.write(combined_string)
    Lisp::String.with_value("OK")
  elsif destination.value
    self.output_to_stdout(combined_string)
    Lisp::String.with_value("OK")
  else
    return Lisp::String.with_value(combined_string)
  end

end

.list_directory_impl(args, env) ⇒ Object



119
120
121
122
123
124
125
# File 'lib/rubylisp/prim_io.rb', line 119

def self.list_directory_impl(args, env)
  return Lisp::Debug.process_error("'list-directory' requires a string as it's first argument.", env) unless args.car.string?
  dir = args.car.value
  fpart = (args.length == 2) ? args.cadr.value : "*"
  filenames = Dir.glob(File.join(dir, fpart))
  Lisp::ConsCell.array_to_list(filenames.map {|f| Lisp::String.with_value(f)})
end

.load_impl(args, env) ⇒ Object



30
31
32
33
34
35
36
# File 'lib/rubylisp/prim_io.rb', line 30

def self.load_impl(args, env)
  fname = args.car
  return Lisp::Debug.process_error("'load' requires a string argument.", env) unless fname.string?
  filename = fname.value.end_with?(".lsp") ? fname.value : "#{fname.value}.lsp"
  Lisp::Parser.new.process_file(filename)
  Lisp::String.with_value("OK")
end

.newline_impl(args, env) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
# File 'lib/rubylisp/prim_io.rb', line 80

def self.newline_impl(args, env)
  if args.length == 1
    p = args.car
    return Lisp::Debug.process_error("'newline' requires a port as it's argument.", env) unless p.port?
    port = p.value
    port.write("\n")
  else
    self.output_to_stdout("\n")
  end
  Lisp::String.with_value("OK")
end

.open_input_file_impl(args, env) ⇒ Object



39
40
41
42
43
44
# File 'lib/rubylisp/prim_io.rb', line 39

def self.open_input_file_impl(args, env)
  fname = args.car
  return Lisp::Debug.process_error("'open-input-file' requires a string argument.", env) unless fname.string?
  f = File.open(fname.value, "r")
  f ? Lisp::Port.with_value(f) : nil
end

.open_output_file_impl(args, env) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/rubylisp/prim_io.rb', line 47

def self.open_output_file_impl(args, env)
  fname = args.car
  return Lisp::Debug.process_error("'load' requires a string argument.", env) unless fname.string?
  mode = (args.length == 2 && args.cadr.true?) ? "a" : "w"
  f = File.open(fname.value, mode)
  f ? Lisp::Port.with_value(f) : nil
end

.output_to_stdout(to_output) ⇒ Object



25
26
27
# File 'lib/rubylisp/prim_io.rb', line 25

def self.output_to_stdout(to_output)
  $stdout.write(to_output)
end

.read_impl(args, env) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
# File 'lib/rubylisp/prim_io.rb', line 106

def self.read_impl(args, env)
  if args.length == 1
    p = args.car
    return Lisp::Debug.process_error("'read' requires a port as it's argument.", env) unless p.port?
    port = p.value
  else
    port = $stdin
  end

  Lisp::Parser.new.parse_object_from_file(port)
end

.registerObject



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/rubylisp/prim_io.rb', line 5

def self.register
   Primitive.register("load", "1")         {|args, env| Lisp::PrimIo::load_impl(args, env) }
   Primitive.register("open-input-file", "1") {|args, env| Lisp::PrimIo::open_input_file_impl(args, env) }
   Primitive.register("open-output-file", "1|2") {|args, env| Lisp::PrimIo::open_output_file_impl(args, env) }
   Primitive.register("close-port", "1") {|args, env| Lisp::PrimIo::close_port_impl(args, env) }
   Primitive.register("write-string", "1|2") {|args, env| Lisp::PrimIo::write_string_impl(args, env) }
   Primitive.register("newline", "0|1") {|args, env| Lisp::PrimIo::newline_impl(args, env) }
   Primitive.register("write", "1|2") {|args, env| Lisp::PrimIo::write_impl(args, env) }
   Primitive.register("read", "0|1") {|args, env| Lisp::PrimIo::read_impl(args, env) }
   Primitive.register("list-directory", "1|2") {|args, env| Lisp::PrimIo::list_directory_impl(args, env) }
   Primitive.register("eof-object?", "1") {|args, env| Lisp::PrimIo::eof_objectp_impl(args, env) }
   Primitive.register("format", ">=2") {|args, env| Lisp::PrimIo::format_impl(args, env) }
   # Primitive.register("load-library", "1") {|args, env| Lisp::PrimIo::load_library_impl(args, env) }
   # Primitive.register("load-project", "1") {|args, env| Lisp::PrimIo::load_project_impl(args, env) }
   Primitive.register("trace", "*")        {|args, env| puts "Trace: #{(args.to_a.map {|a| a.value.to_s}).join(' ')}"; nil} 
   Primitive.register("error", "*")        {|args, env| App.alert((args.to_a.map {|a| a.value.to_s}).join(' '))}
   Primitive.register("alert", "*")        {|args, env| App.alert((args.to_a.map {|a| a.value.to_s}).join(' '))}
end

.write_impl(args, env) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
# File 'lib/rubylisp/prim_io.rb', line 93

def self.write_impl(args, env)
  if args.length == 2
    p = args.cadr
    return Lisp::Debug.process_error("'write' requires a port as it's second argument.", env) unless p.port?
    port = p.value
    port.write(args.car.print_string)
  else
    self.output_to_stdout(args.car.print_string)
  end
  Lisp::String.with_value("OK")
end

.write_string_impl(args, env) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/rubylisp/prim_io.rb', line 64

def self.write_string_impl(args, env)
  s = args.car
  return Lisp::Debug.process_error("'write-string' requires a string first argument.", env) unless s.string?

  if args.length == 2
    p = args.cadr
    return Lisp::Debug.process_error("'write-string' requires a port as it's second argument.", env) unless p.port?
    port = p.value
    port.write(s.value)
  else
    self.output_to_stdout(s.value)
  end
  Lisp::String.with_value("OK")
end