def value_erdev(ins): """ ERDEV$: device error string; not implemented. """ logging.warning("ERDEV or ERDEV$ function not implemented.") if util.skip_white_read_if(ins, ('$',)): return vartypes.null('$') else: return vartypes.null('%')
def value_erdev(ins): """ ERDEV$: device error string; not implemented. """ logging.warning("ERDEV or ERDEV$ function not implemented.") if util.skip_white_read_if(ins, ('$', )): return vartypes.null('$') else: return vartypes.null('%')
def get_scalar(name): """ Retrieve the value of a scalar variable. """ name = vartypes.complete_name(name) try: return (name[-1], state.basic_state.variables[name]) except KeyError: return vartypes.null(name[-1])
def get_scalar(name): """ Retrieve the value of a scalar variable. """ name = vartypes.complete_name(name) try: return (name[-1], state.basic_state.variables[name]) except KeyError: return vartypes.null(name[-1])
def read_var(self, name): """ Read the value for a variable from a file (INPUT#). """ typechar = name[0][-1] value, sep = self._input_entry(typechar, allow_past_end=False) if value is None: value = vartypes.null(typechar) return value, sep
def set_scalar(name, value=None): """ Assign a value to a variable. """ name = vartypes.complete_name(name) type_char = name[-1] if value is not None: value = vartypes.pass_type(type_char, value) # update memory model # check if garbage needs collecting before allocating memory if name not in state.basic_state.var_memory: # don't add string length, string already stored size = (max(3, len(name)) + 1 + vartypes.byte_size[type_char]) check_free_memory(size, error.OUT_OF_MEMORY) # first two bytes: chars of name or 0 if name is one byte long name_ptr = state.basic_state.var_current # byte_size first_letter second_letter_or_nul remaining_length_or_nul var_ptr = name_ptr + max(3, len(name)) + 1 state.basic_state.var_current += max(3, len(name)) + 1 + vartypes.byte_size[name[-1]] state.basic_state.var_memory[name] = (name_ptr, var_ptr) # don't change the value if just checking allocation if value is None: if name in state.basic_state.variables: return else: value = vartypes.null(type_char) # copy buffers try: # in-place copy is crucial for FOR state.basic_state.variables[name][:] = value[1][:] except KeyError: # copy into new buffer if not existing state.basic_state.variables[name] = value[1][:]
def value_point(ins): """ POINT: get pixel attribute at screen location. """ util.require_read(ins, ('(',)) arg0 = parse_expression(ins) screen = state.console_state.screen if util.skip_white_read_if(ins, (',',)): # two-argument mode arg1 = parse_expression(ins) util.require_read(ins, (')',)) if screen.mode.is_text_mode: raise error.RunError(error.IFC) return vartypes.int_to_integer_signed(screen.drawing.point( (fp.unpack(vartypes.pass_single(arg0)), fp.unpack(vartypes.pass_single(arg1)), False))) else: # single-argument mode util.require_read(ins, (')',)) try: x, y = screen.drawing.last_point fn = vartypes.pass_int_unpack(arg0) if fn == 0: return vartypes.int_to_integer_signed(x) elif fn == 1: return vartypes.int_to_integer_signed(y) elif fn == 2: fx, _ = screen.drawing.get_window_logical(x, y) return fp.pack(fx) elif fn == 3: _, fy = screen.drawing.get_window_logical(x, y) return fp.pack(fy) except AttributeError: return vartypes.null('%')
def value_pmap(ins): """ PMAP: convert between logical and physical coordinates. """ util.require_read(ins, ('(', )) coord = parse_expression(ins) util.require_read(ins, (',', )) mode = vartypes.pass_int_unpack(parse_expression(ins)) util.require_read(ins, (')', )) util.range_check(0, 3, mode) screen = state.console_state.screen if screen.mode.is_text_mode: return vartypes.null('%') if mode == 0: value, _ = screen.drawing.get_window_physical( fp.unpack(vartypes.pass_single(coord)), fp.Single.zero) return vartypes.int_to_integer_signed(value) elif mode == 1: _, value = screen.drawing.get_window_physical( fp.Single.zero, fp.unpack(vartypes.pass_single(coord))) return vartypes.int_to_integer_signed(value) elif mode == 2: value, _ = screen.drawing.get_window_logical( vartypes.pass_int_unpack(coord), 0) return fp.pack(value) elif mode == 3: _, value = screen.drawing.get_window_logical( 0, vartypes.pass_int_unpack(coord)) return fp.pack(value)
def value_point(ins): """ POINT: get pixel attribute at screen location. """ util.require_read(ins, ('(', )) arg0 = parse_expression(ins) screen = state.console_state.screen if util.skip_white_read_if(ins, (',', )): # two-argument mode arg1 = parse_expression(ins) util.require_read(ins, (')', )) if screen.mode.is_text_mode: raise error.RunError(error.IFC) return vartypes.int_to_integer_signed( screen.drawing.point( (fp.unpack(vartypes.pass_single(arg0)), fp.unpack(vartypes.pass_single(arg1)), False))) else: # single-argument mode util.require_read(ins, (')', )) try: x, y = screen.drawing.last_point fn = vartypes.pass_int_unpack(arg0) if fn == 0: return vartypes.int_to_integer_signed(x) elif fn == 1: return vartypes.int_to_integer_signed(y) elif fn == 2: fx, _ = screen.drawing.get_window_logical(x, y) return fp.pack(fx) elif fn == 3: _, fy = screen.drawing.get_window_logical(x, y) return fp.pack(fy) except AttributeError: return vartypes.null('%')
def set_scalar(name, value=None): """ Assign a value to a variable. """ name = vartypes.complete_name(name) type_char = name[-1] if value is not None: value = vartypes.pass_type(type_char, value) # update memory model # check if garbage needs collecting before allocating memory if name not in state.basic_state.var_memory: # don't add string length, string already stored size = (max(3, len(name)) + 1 + vartypes.byte_size[type_char]) check_free_memory(size, error.OUT_OF_MEMORY) # first two bytes: chars of name or 0 if name is one byte long name_ptr = state.basic_state.var_current # byte_size first_letter second_letter_or_nul remaining_length_or_nul var_ptr = name_ptr + max(3, len(name)) + 1 state.basic_state.var_current += max(3, len(name)) + 1 + vartypes.byte_size[name[-1]] state.basic_state.var_memory[name] = (name_ptr, var_ptr) # don't change the value if just checking allocation if value is None: if name in state.basic_state.variables: return else: value = vartypes.null(type_char) # copy buffers try: # in-place copy is crucial for FOR state.basic_state.variables[name][:] = value[1][:] except KeyError: # copy into new buffer if not existing state.basic_state.variables[name] = value[1][:]
def read_var(self, name): """ Read the value for a variable from a file (INPUT#). """ typechar = name[0][-1] value, sep = self._input_entry(typechar, allow_past_end=False) if value is None: value = vartypes.null(typechar) return value, sep
def value_eof(ins): """ EOF: get end-of-file. """ util.skip_white(ins) num = vartypes.pass_int_unpack(parse_bracket(ins), maxint=0xffff) if num == 0: return vartypes.null('%') util.range_check(0, 255, num) the_file = devices.get_file(num, 'IR') return vartypes.bool_to_integer(the_file.eof())
def value_eof(ins): """ EOF: get end-of-file. """ util.skip_white(ins) num = vartypes.pass_int_unpack(parse_bracket(ins), maxint=0xffff) if num == 0: return vartypes.null('%') util.range_check(0, 255, num) the_file = devices.get_file(num, 'IR') return vartypes.bool_to_integer(the_file.eof())
def value_right(ins): """ RIGHT$: get substring at the end of string. """ util.require_read(ins, ('(', )) s = var.copy_str(vartypes.pass_string(parse_expression(ins))) util.require_read(ins, (',', )) stop = vartypes.pass_int_unpack(parse_expression(ins)) util.require_read(ins, (')', )) util.range_check(0, 255, stop) if stop == 0: return vartypes.null('$') stop = min(stop, len(s)) return state.basic_state.strings.store(s[-stop:])
def value_right(ins): """ RIGHT$: get substring at the end of string. """ util.require_read(ins, ('(',)) s = var.copy_str(vartypes.pass_string(parse_expression(ins))) util.require_read(ins, (',',)) stop = vartypes.pass_int_unpack(parse_expression(ins)) util.require_read(ins, (')',)) util.range_check(0, 255, stop) if stop == 0: return vartypes.null('$') stop = min(stop, len(s)) return state.basic_state.strings.store(s[-stop:])
def str_to_number(strval, allow_nonnum=True): """ Convert Python str to BASIC value. """ ins = StringIO(strval) outs = StringIO() # skip spaces and line feeds (but not NUL). util.skip(ins, (' ', '\n')) tokenise_number(ins, outs) outs.seek(0) value = parse_value(outs) if not allow_nonnum and util.skip_white(ins) != '': # not everything has been parsed - error return None if not value: return vartypes.null('%') return value
def value_instr(ins): """ INSTR: find substring in string. """ util.require_read(ins, ('(', )) big, small, n = '', '', 1 # followed by coma so empty will raise STX s = parse_expression(ins) if s[0] != '$': n = vartypes.pass_int_unpack(s) util.range_check(1, 255, n) util.require_read(ins, (',', )) big = vartypes.pass_string(parse_expression(ins, allow_empty=True)) else: big = vartypes.pass_string(s) util.require_read(ins, (',', )) small = vartypes.pass_string(parse_expression(ins, allow_empty=True)) util.require_read(ins, (')', )) big, small = var.copy_str(big), var.copy_str(small) if big == '' or n > len(big): return vartypes.null('%') # BASIC counts string positions from 1 find = big[n - 1:].find(small) if find == -1: return vartypes.null('%') return vartypes.int_to_integer_signed(n + find)
def value_instr(ins): """ INSTR: find substring in string. """ util.require_read(ins, ('(',)) big, small, n = '', '', 1 # followed by coma so empty will raise STX s = parse_expression(ins) if s[0] != '$': n = vartypes.pass_int_unpack(s) util.range_check(1, 255, n) util.require_read(ins, (',',)) big = vartypes.pass_string(parse_expression(ins, allow_empty=True)) else: big = vartypes.pass_string(s) util.require_read(ins, (',',)) small = vartypes.pass_string(parse_expression(ins, allow_empty=True)) util.require_read(ins, (')',)) big, small = var.copy_str(big), var.copy_str(small) if big == '' or n > len(big): return vartypes.null('%') # BASIC counts string positions from 1 find = big[n-1:].find(small) if find == -1: return vartypes.null('%') return vartypes.int_to_integer_signed(n + find)
def str_to_number(strval, allow_nonnum=True): """ Convert Python str to BASIC value. """ ins = StringIO(strval) outs = StringIO() # skip spaces and line feeds (but not NUL). util.skip(ins, (' ', '\n')) tokenise_number(ins, outs) outs.seek(0) value = parse_value(outs) if not allow_nonnum and util.skip_white(ins) != '': # not everything has been parsed - error return None if not value: return vartypes.null('%') return value
def value_mid(ins): """ MID$: get substring. """ util.require_read(ins, ('(', )) s = var.copy_str(vartypes.pass_string(parse_expression(ins))) util.require_read(ins, (',', )) start = vartypes.pass_int_unpack(parse_expression(ins)) if util.skip_white_read_if(ins, (',', )): num = vartypes.pass_int_unpack(parse_expression(ins)) else: num = len(s) util.require_read(ins, (')', )) util.range_check(1, 255, start) util.range_check(0, 255, num) if num == 0 or start > len(s): return vartypes.null('$') start -= 1 stop = start + num stop = min(stop, len(s)) return state.basic_state.strings.store(s[start:stop])
def value_mid(ins): """ MID$: get substring. """ util.require_read(ins, ('(',)) s = var.copy_str(vartypes.pass_string(parse_expression(ins))) util.require_read(ins, (',',)) start = vartypes.pass_int_unpack(parse_expression(ins)) if util.skip_white_read_if(ins, (',',)): num = vartypes.pass_int_unpack(parse_expression(ins)) else: num = len(s) util.require_read(ins, (')',)) util.range_check(1, 255, start) util.range_check(0, 255, num) if num == 0 or start > len(s): return vartypes.null('$') start -= 1 stop = start + num stop = min(stop, len(s)) return state.basic_state.strings.store(s[start:stop])
def value_screen(ins): """ SCREEN: get char or attribute at a location. """ util.require_read(ins, ('(',)) row = vartypes.pass_int_unpack(parse_expression(ins)) util.require_read(ins, (',',), err=error.IFC) col = vartypes.pass_int_unpack(parse_expression(ins)) z = 0 if util.skip_white_read_if(ins, (',',)): z = vartypes.pass_int_unpack(parse_expression(ins)) cmode = state.console_state.screen.mode util.range_check(1, cmode.height, row) if state.console_state.view_set: util.range_check(state.console_state.view_start, state.console_state.scroll_height, row) util.range_check(1, cmode.width, col) util.range_check(0, 255, z) util.require_read(ins, (')',)) if z and not cmode.is_text_mode: return vartypes.null('%') else: return vartypes.int_to_integer_signed(state.console_state.screen.apage.get_char_attr(row, col, z!=0))
def value_screen(ins): """ SCREEN: get char or attribute at a location. """ util.require_read(ins, ('(', )) row = vartypes.pass_int_unpack(parse_expression(ins)) util.require_read(ins, (',', ), err=error.IFC) col = vartypes.pass_int_unpack(parse_expression(ins)) z = 0 if util.skip_white_read_if(ins, (',', )): z = vartypes.pass_int_unpack(parse_expression(ins)) cmode = state.console_state.screen.mode util.range_check(1, cmode.height, row) if state.console_state.view_set: util.range_check(state.console_state.view_start, state.console_state.scroll_height, row) util.range_check(1, cmode.width, col) util.range_check(0, 255, z) util.require_read(ins, (')', )) if z and not cmode.is_text_mode: return vartypes.null('%') else: return vartypes.int_to_integer_signed( state.console_state.screen.apage.get_char_attr(row, col, z != 0))
def value_pmap(ins): """ PMAP: convert between logical and physical coordinates. """ util.require_read(ins, ('(',)) coord = parse_expression(ins) util.require_read(ins, (',',)) mode = vartypes.pass_int_unpack(parse_expression(ins)) util.require_read(ins, (')',)) util.range_check(0, 3, mode) screen = state.console_state.screen if screen.mode.is_text_mode: return vartypes.null('%') if mode == 0: value, _ = screen.drawing.get_window_physical(fp.unpack(vartypes.pass_single(coord)), fp.Single.zero) return vartypes.int_to_integer_signed(value) elif mode == 1: _, value = screen.drawing.get_window_physical(fp.Single.zero, fp.unpack(vartypes.pass_single(coord))) return vartypes.int_to_integer_signed(value) elif mode == 2: value, _ = screen.drawing.get_window_logical(vartypes.pass_int_unpack(coord), 0) return fp.pack(value) elif mode == 3: _, value = screen.drawing.get_window_logical(0, vartypes.pass_int_unpack(coord)) return fp.pack(value)
def value_exterr(ins): """ EXTERR: device error information; not implemented. """ x = vartypes.pass_int_unpack(parse_bracket(ins)) util.range_check(0, 3, x) logging.warning("EXTERR() function not implemented.") return vartypes.null('%')
def value_usr(ins): """ USR: get value of machine-code function; not implemented. """ util.require_read(ins, tk.digit) parse_bracket(ins) logging.warning("USR() function not implemented.") return vartypes.null('%')
def value_usr(ins): """ USR: get value of machine-code function; not implemented. """ util.require_read(ins, tk.digit) parse_bracket(ins) logging.warning("USR() function not implemented.") return vartypes.null('%')
def value_exterr(ins): """ EXTERR: device error information; not implemented. """ x = vartypes.pass_int_unpack(parse_bracket(ins)) util.range_check(0, 3, x) logging.warning("EXTERR() function not implemented.") return vartypes.null('%')