0001import types
0002from cStringIO import StringIO
0003from builtins import _join, logo_soft_repr
0004import interpreter
0005from common import *
0006
0007class Writer(object):
0008
0009 def __init__(self, output):
0010 self._output = output
0011
0012 @logofunc(aliases=['print'], arity=-1)
0013 def pr(self, *args):
0014 trans = []
0015 for arg in args:
0016 if isinstance(arg, list):
0017 trans.append(_join(map(logo_soft_repr, arg)))
0018 else:
0019 trans.append(logo_soft_repr(arg))
0020 self._output.write(' '.join(trans))
0021 self._output.write('\n')
0022
0023 @logofunc(name='type', arity=-1)
0024 def logo_type(self, *args):
0025 trans = []
0026 for arg in args:
0027 if isinstance(arg, list):
0028 trans.append(_join(map(logo_soft_repr, arg)))
0029 else:
0030 trans.append(logo_soft_repr(arg))
0031 self._output.write(' '.join(trans))
0032
0033 def show(self, *args):
0034 self._output.write(' '.join(map(repr(args))))
0035 self._output.write('\n')
0036
0037 def writer(self):
0038 return self
0039
0040 def setwritepos(self, charpos):
0041 """
0042 SETWRITEPOS charpos
0043
0044 command. Sets the file pointer of the write stream file so
0045 that the next PRINT, etc., will begin writing at the
0046 ``charpos`` character in the file, counting from 0. (That is,
0047 SETWRITEPOS 0 will start writing from the beginning of the
0048 file.) Meaningless if the write stream is the terminal.
0049 """
0050 self.output.seek(charpos)
0051
0052 def writepos(self):
0053 """
0054 WRITEPOS
0055
0056 outputs the file position of the current write stream file.
0057 """
0058 return self.output.tell()
0059
0060
0061class Reader(object):
0062
0063 def __init__(self, input):
0064 self.input = input
0065
0066 def reader(self):
0067 return self
0068
0069 def setreadpos(self, charpos):
0070 """
0071 SETREADPOS charpos
0072
0073 command. Sets the file pointer of the read stream file so
0074 that the next READLIST, etc., will begin reading at the
0075 ``charpos`` character in the file, counting from 0. (That is,
0076 SETREADPOS 0 will start reading from the beginning of the
0077 file.) Meaningless if the read stream is the terminal.
0078 """
0079 self.input.seek(charpos)
0080
0081 def readpos(self):
0082 """
0083 READPOS
0084
0085 outputs the file position of the current read stream file.
0086 """
0087 return self.input.tell()
0088
0089 @logofunc(aliases=["eof?"])
0090 def eofp(self):
0091 """
0092 EOFP
0093 EOF?
0094
0095 predicate, outputs TRUE if there are no more characters to be
0096 read in the read stream file, FALSE otherwise.
0097 """
0098 fn = self.input.name
0099 size = os.stat(fn).st_size
0100 return self.input.tell() >= size
0101
0102class CaptureWriter(Writer):
0103
0104 logo_class = True
0105
0106 def __init__(self):
0107 super(CaptureWriter, self).__init__(StringIO())
0108
0109 def writervalue(self):
0110 return self._output.getvalue()
0111
0112@logofunc(aware=True, name='create')
0113def logo_create(interp, superclass, name, block):
0114 frame = interp.new()
0115 methods = {}
0116 def set_function(name, func):
0117 methods[name] = func
0118 def get_function(name):
0119 if name in methods:
0120 return methods[name]
0121 else:
0122 return frame.__class__.get_function(frame, name)
0123 frame.set_function = set_function
0124 frame.get_function = get_function
0125 frame.eval(block)
0126 frame.vars.update(methods)
0127 if hasattr(superclass, '__logo_create__'):
0128 new = superclass.__logo_create__(name, frame.vars)
0129 elif not isinstance(superclass, (types.ClassType, type)):
0130 new = superclass.__class__()
0131 new.__dict__.update(superclass.__dict__)
0132 for a_name, a_value in frame.vars.items():
0133 if isinstance(a_value, interpreter.UserFunction):
0134 a_value = interpreter.BoundUserFunction(a_value, new)
0135 setattr(new, a_name, a_value)
0136 else:
0137 new = type(superclass)(name, (superclass,), frame.vars)
0138 new.logo_class = True
0139 interp.set_variable(name, new)
0140 interp.set_function(name, new)
0141 return new
0142
0143@logofunc(aware=True)
0144def actor(interp, the_actor):
0145 """
0146 ACTOR object
0147
0148 Adds the actor to the top of the actor list, so that commands will
0149 be passed to the actor first.
0150 """
0151 interp.push_actor(the_actor)
0152
0153@logofunc(aware=True)
0154def actors(interp):
0155 """
0156 ACTORS
0157
0158 outputs all the actors; the first object in the list is the
0159 topmost actor that gets first chance at commands.
0160 """
0161 return interp.actors
0162
0163@logofunc(aware=True, arity=1)
0164def removeactor(interp, the_actor=None):
0165 """
0166 REMOVEACTOR object
0167
0168 Remove the actor from the actor list. If the actor does not
0169 appear on the list, it will be an error. If the actor is None or
0170 [] then the most recent actor added with ACTOR will be removed.
0171 """
0172 if the_actor is None or the_actor == []:
0173 interp.pop_actor()
0174 else:
0175 interp.pop_actor(the_actor)
0176
0177def oobuiltins_main(interp):
0178 interp.set_variable('object', object)
0179
0180
0181
0182
0183
0184
0185
0186_filename_prefix = None
0187
0188@logofunc()
0189def setprefix(prefix):
0190 """
0191 SETPREFIX string
0192
0193 command. Sets a prefix that will be used as the implicit
0194 beginning of filenames in OPENREAD, OPENWRITE, OPENAPPEND,
0195 OPENUPDATE, LOAD, and SAVE commands. Logo will put the
0196 appropriate separator character (slash for Unix, backslash for
0197 DOS/Windows, colon for MacOS) between the prefix and the filename
0198 entered by the user. The input to SETPREFIX must be a word,
0199 unless it is the empty list, to indicate that there should be no
0200 prefix.
0201
0202 @@ Note: LOAD and SAVE don't use this
0203 """
0204 global _filename_prefix
0205
0206 if not prefix:
0207 _filename_prefix = None
0208 else:
0209 _filename_prefix = prefix
0210
0211@logofunc()
0212def prefix():
0213 """
0214 PREFIX
0215
0216 outputs the current file prefix, or None if there is no prefix.
0217 See SETPREFIX.
0218
0219 @@ Note: None instead of [] like in ucblogo
0220 """
0221 return _filename_prefix
0222
0223@logofunc(hide=True)
0224def _filename(filename):
0225 if _filename_prefix is not None:
0226 filename = os.path.join(_filename_prefix, filename)
0227 return filename
0228
0229@logofunc()
0230def openread(filename):
0231 """
0232 OPENREAD filename
0233
0234 command. Opens the named file for reading. The read position is
0235 initially at the beginning of the file.
0236
0237 Use ``ACTOR OPENREAD filename`` to take all input from the given
0238 file.
0239 """
0240 f = open(_filename(filename))
0241 return Reader(f)
0242
0243@logofunc()
0244def openwrite(filename):
0245 """
0246 OPENWRITE filename
0247
0248 command. Opens the named file for writing. If the file already
0249 existed, the old version is deleted and a new, empty file created.
0250
0251 Use ``ACTOR OPENWRITE filename`` to put all output to the given
0252 file.
0253 """
0254 f = open(_filename(filename), 'w')
0255 return Writer(f)
0256
0257@logofunc()
0258def openappend(filename):
0259 """
0260 OPENAPPEND filename
0261
0262 command. Opens the named file for writing. If the file already
0263 exists, the write position is initially set to the end of the old
0264 file, so that newly written data will be appended to it.
0265
0266 Use ``ACTOR OPENAPPEND filename`` to put all output to the given
0267 file.
0268 """
0269 f = open(_filename(filename), 'a')
0270 return Writer(f)
0271
0272
0273
0274@logofunc(aware=True)
0275def close(interp, filename):
0276 """
0277 CLOSE filename
0278
0279 command. Closes the named file, or file object.
0280 """
0281 if isinstance(filename, basestring):
0282 filename = _filename(filename)
0283 for actor in interp.actors:
0284 if isinstance(actor, Reader):
0285 f = actor.input
0286 if getattr(f, 'name', None) == filename:
0287 break
0288 elif isinstance(actor, Writer):
0289 f = actor.output
0290 if getattr(f, 'name', None) == filename:
0291 break
0292 else:
0293 raise ValueError(
0294 "No file with the name %r found in the actor list"
0295 % filename)
0296 else:
0297 f = filename
0298 if isinstance(f, Reader):
0299 f.input.close()
0300 else:
0301 f.output.close()
0302 if f in interp.actors:
0303 interp.actors.remove(f)
0304
0305@logofunc(aware=True)
0306def allopen(interp):
0307 """
0308 ALLOPEN
0309
0310 outputs a list whose members are the file objects currently open.
0311 This list does not include the dribble file, if any.
0312 """
0313 result = []
0314 for actor in actors:
0315 if isinstance(actor, (Reader, Writer)):
0316 result.append(actor)
0317 return result
0318
0319@logofunc(aware=True)
0320def closeall(interp):
0321 """
0322 CLOSEALL
0323
0324 command. Closes all open files. Abbreviates
0325 FOREACH ALLOPEN [CLOSE ?]
0326 """
0327 for f in allopen(interp):
0328 close(interp, f)
0329
0330@logofunc(aliases=['erf'])
0331def erasefile(filename):
0332 """
0333 ERASEFILE filename
0334 ERF filename
0335
0336 command. Erases (deletes, removes) the named file, which should not
0337 currently be open.
0338 """
0339 os.unlink(_filename(filename))
0340
0341
0342
0343
0344
0345@logofunc(aliases=["file?"])
0346def filep(filename):
0347 """
0348 FILEP filename
0349 FILE? filename
0350
0351 predicate, outputs TRUE if a file of the specified name exists
0352 and can be read, FALSE otherwise.
0353 """
0354 return os.path.exists(_filename(filename))