def ml_parse_value(gmls, default=None): """ Parse a value in a macro-language string. """ c = util.skip(gmls, ml_whitepace) sgn = -1 if c == '-' else 1 if not c: raise error.RunError(error.IFC) if c in ('+', '-'): gmls.read(1) c = util.peek(gmls) # don't allow default if sign is given default = None if c == '=': gmls.read(1) c = util.peek(gmls) if len(c) == 0: raise error.RunError(error.IFC) elif ord(c) > 8: name = util.get_var_name(gmls) indices = ml_parse_indices(gmls) step = var.get_var_or_array(name, indices) util.require_read(gmls, (';',), err=error.IFC) else: # varptr$ step = get_value_for_varptrstr(gmls.read(3)) elif c in representation.ascii_digits: step = ml_parse_const(gmls) elif default is not None: step = default else: raise error.RunError(error.IFC) if sgn == -1: step = vartypes.number_neg(step) return step
def ml_parse_value(gmls, default=None): """ Parse a value in a macro-language string. """ c = util.skip(gmls, ml_whitepace) sgn = -1 if c == '-' else 1 if c in ('+', '-'): gmls.read(1) c = util.peek(gmls) # don't allow default if sign is given default = None if c == '=': gmls.read(1) c = util.peek(gmls) if len(c) == 0: raise error.RunError(error.IFC) elif ord(c) > 8: name = util.get_var_name(gmls) indices = ml_parse_indices(gmls) step = var.get_var_or_array(name, indices) util.require_read(gmls, (';',), err=error.IFC) else: # varptr$ step = get_value_for_varptrstr(gmls.read(3)) elif c and c in string.digits: step = ml_parse_const(gmls) elif default is not None: step = default else: raise error.RunError(error.IFC) if sgn == -1: step = vartypes.number_neg(step) return step
def parse_bracket(ins): """ Compute the value of the bracketed expression. """ util.require_read(ins, ('(',)) # we need a Syntax error, not a Missing operand val = parse_expression(ins, empty_err=error.STX) util.require_read(ins, (')',)) return val
def parse_bracket(ins): """ Compute the value of the bracketed expression. """ util.require_read(ins, ('(', )) # we need a Syntax error, not a Missing operand val = parse_expression(ins, empty_err=error.STX) util.require_read(ins, (')', )) return val
def value_point(ins): """ POINT: get pixel attribute at screen location. """ util.require_read(ins, ('(',)) lst = parse_expr_list(ins, 2, err=error.STX) util.require_read(ins, (')',)) if not lst[0]: raise error.RunError(error.STX) screen = state.console_state.screen if not lst[1]: # single-argument version try: x, y = screen.drawing.last_point fn = vartypes.pass_int_unpack(lst[0]) if fn == 0: return vartypes.pack_int(x) elif fn == 1: return vartypes.pack_int(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['%'] else: # two-argument mode if screen.mode.is_text_mode: raise error.RunError(error.IFC) return vartypes.pack_int(screen.drawing.point( (fp.unpack(vartypes.pass_single_keep(lst[0])), fp.unpack(vartypes.pass_single_keep(lst[1])), False)))
def value_fn(ins): """ FN: get value of user-defined function. """ fnname = util.get_var_name(ins) try: varnames, fncode = state.basic_state.functions[fnname] except KeyError: raise error.RunError(error.UNDEFINED_USER_FUNCTION) # save existing vars varsave = {} for name in varnames: if name in state.basic_state.variables: # copy the *value* - set_var is in-place it's safe for FOR loops varsave[name] = state.basic_state.variables[name][:] # read variables if util.skip_white_read_if(ins, ('(',)): exprs = parse_expr_list(ins, len(varnames), err=error.STX) if None in exprs: raise error.RunError(error.STX) for i in range(len(varnames)): var.set_var(varnames[i], exprs[i]) util.require_read(ins, (')',)) # execute the code fns = StringIO(fncode) fns.seek(0) value = parse_expression(fns) # restore existing vars for name in varsave: # re-assign the stored value state.basic_state.variables[name][:] = varsave[name] return value
def parse_bracket(ins): """ Compute the value of the bracketed expression. """ util.require_read(ins, ('(', )) # we'll get a Syntax error, not a Missing operand, if we close with ) val = parse_expression(ins) util.require_read(ins, (')', )) return val
def parse_bracket(ins): """ Compute the value of the bracketed expression. """ util.require_read(ins, ('(',)) # we'll get a Syntax error, not a Missing operand, if we close with ) val = parse_expression(ins) util.require_read(ins, (')',)) return val
def value_point(ins): """ POINT: get pixel attribute at screen location. """ util.require_read(ins, ('(', )) lst = parse_expr_list(ins, 2, err=error.STX) util.require_read(ins, (')', )) if not lst[0]: raise error.RunError(error.STX) screen = state.console_state.screen if not lst[1]: # single-argument version try: x, y = screen.drawing.last_point fn = vartypes.pass_int_unpack(lst[0]) if fn == 0: return vartypes.pack_int(x) elif fn == 1: return vartypes.pack_int(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['%'] else: # two-argument mode if screen.mode.is_text_mode: raise error.RunError(error.IFC) return vartypes.pack_int( screen.drawing.point( (fp.unpack(vartypes.pass_single_keep(lst[0])), fp.unpack(vartypes.pass_single_keep(lst[1])), False)))
def value_fn(ins): """ FN: get value of user-defined function. """ fnname = util.get_var_name(ins) try: varnames, fncode = state.basic_state.functions[fnname] except KeyError: raise error.RunError(error.UNDEFINED_USER_FUNCTION) # save existing vars varsave = {} for name in varnames: if name in state.basic_state.variables: # copy the *value* - set_var is in-place it's safe for FOR loops varsave[name] = state.basic_state.variables[name][:] # read variables if util.skip_white_read_if(ins, ('(', )): exprs = parse_expr_list(ins, len(varnames), err=error.STX) if None in exprs: raise error.RunError(error.STX) for i in range(len(varnames)): var.set_var(varnames[i], exprs[i]) util.require_read(ins, (')', )) # execute the code fns = StringIO(fncode) fns.seek(0) value = parse_expression(fns) # restore existing vars for name in varsave: # re-assign the stored value state.basic_state.variables[name][:] = varsave[name] return value
def parse_file_number(ins, file_mode='IOAR'): """ Helper function: parse a file number and retrieve the file object. """ screen = None if util.skip_white_read_if(ins, ('#', )): number = vartypes.pass_int_unpack(parse_expression(ins)) util.range_check(0, 255, number) screen = devices.get_file(number, file_mode) util.require_read(ins, (',', )) return screen
def parse_file_number(ins, file_mode='IOAR'): """ Helper function: parse a file number and retrieve the file object. """ screen = None if util.skip_white_read_if(ins, ('#',)): number = vartypes.pass_int_unpack(parse_expression(ins)) util.range_check(0, 255, number) screen = devices.get_file(number, file_mode) util.require_read(ins, (',',)) return screen
def value_environ(ins): """ ENVIRON$: get environment string. """ util.require_read(ins, ('$',)) expr = parse_bracket(ins) if expr[0] == '$': return state.basic_state.strings.store(shell.get_env(var.copy_str(expr))) else: expr = vartypes.pass_int_unpack(expr) util.range_check(1, 255, expr) return state.basic_state.strings.store(shell.get_env_entry(expr))
def value_environ(ins): """ ENVIRON$: get environment string. """ util.require_read(ins, ('$', )) expr = parse_bracket(ins) if expr[0] == '$': return state.basic_state.strings.store( shell.get_env(var.copy_str(expr))) else: expr = vartypes.pass_int_unpack(expr) util.range_check(1, 255, expr) return state.basic_state.strings.store(shell.get_env_entry(expr))
def parse_variable(ins): """ Helper function: parse a variable or array element. """ name = util.parse_scalar(ins) indices = [] if util.skip_white_read_if(ins, ('[', '(')): # it's an array, read indices while True: indices.append(vartypes.pass_int_unpack(parse_expression(ins))) if not util.skip_white_read_if(ins, (',',)): break util.require_read(ins, (']', ')')) return name, indices
def parse_variable(ins): """ Helper function: parse a variable or array element. """ name = util.parse_scalar(ins) indices = [] if util.skip_white_read_if(ins, ('[', '(')): # it's an array, read indices while True: indices.append(vartypes.pass_int_unpack(parse_expression(ins))) if not util.skip_white_read_if(ins, (',', )): break util.require_read(ins, (']', ')')) return name, indices
def get_var_or_array_name(ins): """ Helper function: parse a variable or array name. """ name = util.get_var_name(ins) indices = [] if util.skip_white_read_if(ins, ('[', '(')): # it's an array, read indices indices = parse_int_list(ins, 255, 9) # subscript out of range while len(indices) > 0 and indices[-1] is None: indices = indices[:-1] if None in indices: raise error.RunError(error.STX) util.require_read(ins, (']', ')')) return name, indices
def get_var_or_array_name(ins): """ Helper function: parse a variable or array name. """ name = util.get_var_name(ins) indices = [] if util.skip_white_read_if(ins, ('[', '(')): # it's an array, read indices indices = parse_int_list(ins, 255, 9) # subscript out of range while len(indices) > 0 and indices[-1] is None: indices = indices[:-1] if None in indices: raise error.RunError(error.STX) util.require_read(ins, (']', ')')) return name, indices
def ml_parse_string(gmls): """ Parse a string value in a macro-language string. """ c = util.skip(gmls, ml_whitepace) if len(c) == 0: raise error.RunError(error.IFC) elif ord(c) > 8: name = util.get_var_name(gmls, err=error.IFC) indices = ml_parse_indices(gmls) sub = var.get_var_or_array(name, indices) util.require_read(gmls, (';',), err=error.IFC) return vartypes.pass_string_unpack(sub, err=error.IFC) else: # varptr$ return vartypes.pass_string_unpack(get_value_for_varptrstr(gmls.read(3)))
def ml_parse_string(gmls): """ Parse a string value in a macro-language string. """ c = util.skip(gmls, ml_whitepace) if len(c) == 0: raise error.RunError(error.IFC) elif ord(c) > 8: name = util.get_var_name(gmls) indices = ml_parse_indices(gmls) sub = var.get_var_or_array(name, indices) util.require_read(gmls, (';',), err=error.IFC) return vartypes.pass_string_unpack(sub, err=error.IFC) else: # varptr$ return vartypes.pass_string_unpack(get_value_for_varptrstr(gmls.read(3)))
def ml_parse_indices(gmls): """ Parse constant array indices. """ indices = [] c = util.skip(gmls, ml_whitepace) if c in ('[', '('): gmls.read(1) while True: indices.append(ml_parse_const_int(gmls)) c = util.skip(gmls, ml_whitepace) if c == ',': gmls.read(1) else: break util.require_read(gmls, (']', ')')) return indices
def value_string(ins): """ STRING$: repeat characters. """ util.require_read(ins, ('(',)) n, j = parse_expr_list(ins, 2) n = vartypes.pass_int_unpack(n) util.range_check(0, 255, n) if j[0] == '$': j = vartypes.unpack_string(j) util.range_check(1, 255, len(j)) j = j[0] else: j = vartypes.pass_int_unpack(j) util.range_check(0, 255, j) util.require_read(ins, (')',)) return vartypes.pack_string(bytearray(chr(j)*n))
def ml_parse_indices(gmls): """ Parse constant array indices. """ indices = [] c = util.skip(gmls, ml_whitepace) if c in ('[', '('): gmls.read(1) while True: indices.append(ml_parse_const_int(gmls)) c = util.skip(gmls, ml_whitepace) if c == ',': gmls.read(1) else: break util.require_read(gmls, (']', ')')) return indices
def value_string(ins): """ STRING$: repeat characters. """ util.require_read(ins, ('(', )) n, j = parse_expr_list(ins, 2) n = vartypes.pass_int_unpack(n) util.range_check(0, 255, n) if j[0] == '$': j = vartypes.unpack_string(j) util.range_check(1, 255, len(j)) j = j[0] else: j = vartypes.pass_int_unpack(j) util.range_check(0, 255, j) util.require_read(ins, (')', )) return vartypes.pack_string(bytearray(chr(j) * n))
def value_varptr(ins): """ VARPTR, VARPTR$: get memory address for variable or FCB. """ dollar = util.skip_white_read_if(ins, ('$',)) util.require_read(ins, ('(',)) if (not dollar) and util.skip_white(ins) == '#': filenum = parse_file_number_opthash(ins) var_ptr = machine.varptr_file(filenum) else: name, indices = get_var_or_array_name(ins) var_ptr = machine.varptr(name, indices) util.require_read(ins, (')',)) if var_ptr < 0: raise error.RunError(error.IFC) if dollar: return vartypes.pack_string(bytearray(chr(var.byte_size[name[-1]])) + vartypes.value_to_uint(var_ptr)) else: return vartypes.pack_int(var_ptr)
def value_varptr(ins): """ VARPTR, VARPTR$: get memory address for variable or FCB. """ dollar = util.skip_white_read_if(ins, ('$',)) util.require_read(ins, ('(',)) if (not dollar) and util.skip_white(ins) == '#': filenum = parse_file_number_opthash(ins) var_ptr = machine.varptr_file(filenum) else: name, indices = parse_variable(ins) var_ptr = machine.varptr(name, indices) util.require_read(ins, (')',)) if var_ptr < 0: raise error.RunError(error.IFC) var_ptr = vartypes.int_to_integer_unsigned(var_ptr) if dollar: return state.basic_state.strings.store(chr(vartypes.byte_size[name[-1]]) + vartypes.integer_to_bytes(var_ptr)) else: return var_ptr
def value_screen(ins): """ SCREEN: get char or attribute at a location. """ util.require_read(ins, ('(',)) row, col, z = parse_int_list(ins, 3, 5) if row is None or col is None: raise error.RunError(error.IFC) if z is None: z = 0 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.pack_int(state.console_state.screen.apage.get_char_attr(row, col, z!=0))
def value_varptr(ins): """ VARPTR, VARPTR$: get memory address for variable or FCB. """ dollar = util.skip_white_read_if(ins, ('$', )) util.require_read(ins, ('(', )) if (not dollar) and util.skip_white(ins) == '#': filenum = parse_file_number_opthash(ins) var_ptr = machine.varptr_file(filenum) else: name, indices = get_var_or_array_name(ins) var_ptr = machine.varptr(name, indices) util.require_read(ins, (')', )) if var_ptr < 0: raise error.RunError(error.IFC) if dollar: return vartypes.pack_string( bytearray(chr(var.byte_size[name[-1]])) + vartypes.value_to_uint(var_ptr)) else: return vartypes.pack_int(var_ptr)
def value_varptr(ins): """ VARPTR, VARPTR$: get memory address for variable or FCB. """ dollar = util.skip_white_read_if(ins, ('$', )) util.require_read(ins, ('(', )) if (not dollar) and util.skip_white(ins) == '#': filenum = parse_file_number_opthash(ins) var_ptr = machine.varptr_file(filenum) else: name, indices = parse_variable(ins) var_ptr = machine.varptr(name, indices) util.require_read(ins, (')', )) if var_ptr < 0: raise error.RunError(error.IFC) var_ptr = vartypes.int_to_integer_unsigned(var_ptr) if dollar: return state.basic_state.strings.store( chr(vartypes.byte_size[name[-1]]) + vartypes.integer_to_bytes(var_ptr)) else: return var_ptr
def value_screen(ins): """ SCREEN: get char or attribute at a location. """ util.require_read(ins, ('(', )) row, col, z = parse_int_list(ins, 3, 5) if row is None or col is None: raise error.RunError(error.IFC) if z is None: z = 0 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.pack_int( state.console_state.screen.apage.get_char_attr(row, col, z != 0))
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 value_fn(ins): """ FN: get value of user-defined function. """ fnname = util.parse_scalar(ins) # recursion is not allowed as there's no way to terminate it if fnname in state.basic_state.user_function_parsing: raise error.RunError(error.OUT_OF_MEMORY) state.basic_state.user_function_parsing.add(fnname) try: varnames, fncode = state.basic_state.functions[fnname] except KeyError: raise error.RunError(error.UNDEFINED_USER_FUNCTION) # save existing vars varsave = {} for name in varnames: if name in state.basic_state.variables: # copy the *value* - set_var is in-place it's safe for FOR loops varsave[name] = state.basic_state.variables[name][:] # read variables if util.skip_white_read_if(ins, ('(',)): exprs = [] while True: exprs.append(parse_expression(ins)) if not util.skip_white_read_if(ins, (',',)): break if len(exprs) != len(varnames): raise error.RunError(error.STX) for name, value in zip(varnames, exprs): var.set_scalar(name, value) util.require_read(ins, (')',)) # execute the code fns = StringIO(fncode) fns.seek(0) value = parse_expression(fns) # restore existing vars for name in varsave: # re-assign the stored value state.basic_state.variables[name][:] = varsave[name] state.basic_state.user_function_parsing.remove(fnname) return vartypes.pass_type(fnname[-1], value)
def value_fn(ins): """ FN: get value of user-defined function. """ fnname = util.parse_scalar(ins) # recursion is not allowed as there's no way to terminate it if fnname in state.basic_state.user_function_parsing: raise error.RunError(error.OUT_OF_MEMORY) state.basic_state.user_function_parsing.add(fnname) try: varnames, fncode = state.basic_state.functions[fnname] except KeyError: raise error.RunError(error.UNDEFINED_USER_FUNCTION) # save existing vars varsave = {} for name in varnames: if name in state.basic_state.variables: # copy the *value* - set_var is in-place it's safe for FOR loops varsave[name] = state.basic_state.variables[name][:] # read variables if util.skip_white_read_if(ins, ('(', )): exprs = [] while True: exprs.append(parse_expression(ins)) if not util.skip_white_read_if(ins, (',', )): break if len(exprs) != len(varnames): raise error.RunError(error.STX) for name, value in zip(varnames, exprs): var.set_scalar(name, value) util.require_read(ins, (')', )) # execute the code fns = StringIO(fncode) fns.seek(0) value = parse_expression(fns) # restore existing vars for name in varsave: # re-assign the stored value state.basic_state.variables[name][:] = varsave[name] state.basic_state.user_function_parsing.remove(fnname) return value
def value_instr(ins): """ INSTR: find substring in string. """ util.require_read(ins, ('(',)) big, small, n = '', '', 1 s = parse_expression(ins, empty_err=error.STX) if s[0] != '$': n = vartypes.pass_int_unpack(s) util.range_check(1, 255, n) util.require_read(ins, (',',)) big = vartypes.pass_string_unpack(parse_expression(ins, allow_empty=True)) else: big = vartypes.pass_string_unpack(s) util.require_read(ins, (',',)) small = vartypes.pass_string_unpack(parse_expression(ins, allow_empty=True)) util.require_read(ins, (')',)) return vartypes.str_instr(big, small, n)
def value_ioctl(ins): """ IOCTL$: read device control string response; not implemented. """ util.require_read(ins, ('$', )) util.require_read(ins, ('(', )) num = parse_file_number_opthash(ins) util.require_read(ins, (')', )) devices.get_file(num) logging.warning("IOCTL$() function not implemented.") raise error.RunError(error.IFC)
def value_ioctl(ins): """ IOCTL$: read device control string response; not implemented. """ util.require_read(ins, ('$',)) util.require_read(ins, ('(',)) num = parse_file_number_opthash(ins) util.require_read(ins, (')',)) devices.get_file(num) logging.warning("IOCTL$() function not implemented.") raise error.RunError(error.IFC)
def value_instr(ins): """ INSTR: find substring in string. """ util.require_read(ins, ('(', )) big, small, n = '', '', 1 s = parse_expression(ins, empty_err=error.STX) if s[0] != '$': n = vartypes.pass_int_unpack(s) util.range_check(1, 255, n) util.require_read(ins, (',', )) big = vartypes.pass_string_unpack( parse_expression(ins, allow_empty=True)) else: big = vartypes.pass_string_unpack(s) util.require_read(ins, (',', )) small = vartypes.pass_string_unpack(parse_expression(ins, allow_empty=True)) util.require_read(ins, (')', )) return vartypes.str_instr(big, small, n)
def value_left(ins): """ LEFT$: get substring at the start of string. """ util.require_read(ins, ('(', )) s = vartypes.pass_string_unpack(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 vartypes.pack_string(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 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_left(ins): """ LEFT$: get substring at the start of string. """ util.require_read(ins, ('(',)) s = vartypes.pass_string_unpack(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 vartypes.pack_string(s[:stop])
def value_input(ins): """ INPUT$: get characters from the keyboard or a file. """ util.require_read(ins, ('$',)) util.require_read(ins, ('(',)) num = vartypes.pass_int_unpack(parse_expression(ins)) util.range_check(1, 255, num) infile = state.io_state.kybd_file if util.skip_white_read_if(ins, (',',)): infile = devices.get_file(parse_file_number_opthash(ins)) util.require_read(ins, (')',)) word = bytearray(infile.read_raw(num)) if len(word) < num: # input past end raise error.RunError(error.INPUT_PAST_END) return state.basic_state.strings.store(word)
def value_input(ins): """ INPUT$: get characters from the keyboard or a file. """ util.require_read(ins, ('$',)) util.require_read(ins, ('(',)) num = vartypes.pass_int_unpack(parse_expression(ins)) util.range_check(1, 255, num) infile = backend.kybd_file if util.skip_white_read_if(ins, (',',)): infile = iolayer.get_file(parse_file_number_opthash(ins)) util.require_read(ins, (')',)) word = vartypes.pack_string(bytearray(infile.read_raw(num))) if len(word) < num: # input past end raise error.RunError(62) return word
def value_input(ins): """ INPUT$: get characters from the keyboard or a file. """ util.require_read(ins, ('$', )) util.require_read(ins, ('(', )) num = vartypes.pass_int_unpack(parse_expression(ins)) util.range_check(1, 255, num) infile = state.io_state.kybd_file if util.skip_white_read_if(ins, (',', )): infile = devices.get_file(parse_file_number_opthash(ins)) util.require_read(ins, (')', )) word = bytearray(infile.read_raw(num)) if len(word) < num: # input past end raise error.RunError(error.INPUT_PAST_END) return state.basic_state.strings.store(word)
def value_string(ins): """ STRING$: repeat characters. """ util.require_read(ins, ('(', )) n = vartypes.pass_int_unpack(parse_expression(ins)) util.range_check(0, 255, n) util.require_read(ins, (',', )) j = parse_expression(ins) if j[0] == '$': j = var.copy_str(j) util.range_check(1, 255, len(j)) j = ord(j[0]) else: j = vartypes.pass_int_unpack(j) util.range_check(0, 255, j) util.require_read(ins, (')', )) return state.basic_state.strings.store(chr(j) * n)
def value_string(ins): """ STRING$: repeat characters. """ util.require_read(ins, ('(',)) n = vartypes.pass_int_unpack(parse_expression(ins)) util.range_check(0, 255, n) util.require_read(ins, (',',)) j = parse_expression(ins) if j[0] == '$': j = var.copy_str(j) util.range_check(1, 255, len(j)) j = ord(j[0]) else: j = vartypes.pass_int_unpack(j) util.range_check(0, 255, j) util.require_read(ins, (')',)) return state.basic_state.strings.store(chr(j)*n)
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 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_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('%')