def number_add(left, right): """ Add two numbers. """ left, right = pass_most_precise_keep(left, right) if left[0] in ('#', '!'): return fp.pack(fp.unpack(left).iadd(fp.unpack(right))) else: return pack_int(unpack_int(left) + unpack_int(right))
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_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_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_to_str_keep(inp, screen=False, write=False, allow_empty_expression=False): """ Convert BASIC number to BASIC string. """ # screen=False means in a program listing # screen=True is used for screen, str$ and sequential files if not inp: if allow_empty_expression: return ('$', '') else: raise error.RunError(error.STX) typechar = inp[0] if typechar == '$': return ('$', inp[1]) elif typechar == '%': if screen and not write and vartypes.unpack_int(inp) >= 0: return ('$', ' ' + str(vartypes.unpack_int(inp))) else: return ('$', str(vartypes.unpack_int(inp))) elif typechar == '!': return ('$', float_to_str(fp.unpack(inp), screen, write)) elif typechar == '#': return ('$', float_to_str(fp.unpack(inp), screen, write)) else: raise error.RunError(error.STX)
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_operator(op, left, right): """ Get value of binary operator expression. """ if op == tk.O_CARET: return vcaret(left, right) elif op == tk.O_TIMES: return vtimes(left, right) elif op == tk.O_DIV: return vdiv(left, right) elif op == tk.O_INTDIV: return fp.pack( fp.div( fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack(vartypes.pass_single_keep( right)).ifloor()).apply_carry().ifloor()) elif op == tk.MOD: numerator = vartypes.pass_int_unpack(right) if numerator == 0: # simulate division by zero return fp.pack( fp.div( fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack( vartypes.pass_single_keep(right)).ifloor()).ifloor()) return vartypes.pack_int(vartypes.pass_int_unpack(left) % numerator) elif op == tk.O_PLUS: return vplus(left, right) elif op == tk.O_MINUS: return vartypes.number_add(left, vartypes.number_neg(right)) elif op == tk.O_GT: return vartypes.bool_to_int_keep(vartypes.gt(left, right)) elif op == tk.O_EQ: return vartypes.bool_to_int_keep(vartypes.equals(left, right)) elif op == tk.O_LT: return vartypes.bool_to_int_keep(not ( vartypes.gt(left, right) or vartypes.equals(left, right))) elif op == tk.O_GT + tk.O_EQ: return vartypes.bool_to_int_keep( vartypes.gt(left, right) or vartypes.equals(left, right)) elif op == tk.O_LT + tk.O_EQ: return vartypes.bool_to_int_keep(not vartypes.gt(left, right)) elif op == tk.O_LT + tk.O_GT: return vartypes.bool_to_int_keep(not vartypes.equals(left, right)) elif op == tk.AND: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) & vartypes.pass_twoscomp(right)) elif op == tk.OR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) | vartypes.pass_twoscomp(right)) elif op == tk.XOR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right)) elif op == tk.EQV: return vartypes.twoscomp_to_int(~(vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right))) elif op == tk.IMP: return vartypes.twoscomp_to_int((~vartypes.pass_twoscomp(left)) | vartypes.pass_twoscomp(right)) else: raise error.RunError(error.STX)
def number_power(left, right): """ Left^right. """ if (left[0] == '#' or right[0] == '#') and vartypes.option_double: return fp.pack( fp.power(fp.unpack(vartypes.pass_double(left)), fp.unpack(vartypes.pass_double(right))) ) else: if right[0] == '%': return fp.pack( fp.unpack(vartypes.pass_single(left)).ipow_int(vartypes.integer_to_int_signed(right)) ) else: return fp.pack( fp.power(fp.unpack(vartypes.pass_single(left)), fp.unpack(vartypes.pass_single(right))) )
def vcaret(left, right): """ Left^right. """ if (left[0] == '#' or right[0] == '#') and option_double: return fp.pack( fp.power(fp.unpack(vartypes.pass_double_keep(left)), fp.unpack(vartypes.pass_double_keep(right))) ) else: if right[0] == '%': return fp.pack( fp.unpack(vartypes.pass_single_keep(left)).ipow_int(vartypes.unpack_int(right)) ) else: return fp.pack( fp.power(fp.unpack(vartypes.pass_single_keep(left)), fp.unpack(vartypes.pass_single_keep(right))) )
def number_add(left, right): """ Add two numbers. """ left, right = vartypes.pass_most_precise(left, right) if left[0] in ('#', '!'): return fp.pack(fp.unpack(left).iadd(fp.unpack(right))) else: # return Single to avoid wrapping on integer overflow return fp.pack(fp.Single.from_int(vartypes.integer_to_int_signed(left) + vartypes.integer_to_int_signed(right)))
def value_fix(ins): """ FIX: round towards zero. """ inp = vartypes.pass_number(parse_bracket(ins)) if inp[0] == '%': return inp elif inp[0] == '!': # needs to be a float to avoid overflow return fp.pack(fp.Single.from_int(fp.unpack(inp).trunc_to_int())) elif inp[0] == '#': return fp.pack(fp.Double.from_int(fp.unpack(inp).trunc_to_int()))
def vtimes(left, right): """ Left*right. """ if left[0] == '#' or right[0] == '#': return fp.pack( fp.unpack(vartypes.pass_double_keep(left)).imul( fp.unpack(vartypes.pass_double_keep(right)))) else: return fp.pack( fp.unpack(vartypes.pass_single_keep(left)).imul( fp.unpack(vartypes.pass_single_keep(right))))
def vdiv(left, right): """ Left/right. """ if left[0] == '#' or right[0] == '#': return fp.pack( fp.div(fp.unpack(vartypes.pass_double_keep(left)), fp.unpack(vartypes.pass_double_keep(right)))) else: return fp.pack( fp.div(fp.unpack(vartypes.pass_single_keep(left)), fp.unpack(vartypes.pass_single_keep(right))))
def equals(left,right): """ Return whether two numbers are equal. """ if left[0] == '$': return pass_string_unpack(left) == pass_string_unpack(right) else: left, right = pass_most_precise_keep(left, right) if left[0] in ('#', '!'): return fp.unpack(left).equals(fp.unpack(right)) else: return unpack_int(left)==unpack_int(right)
def gt(left, right): """ Number ordering: return whether left > right. """ if left[0] == '$': return str_gt(pass_string_unpack(left), pass_string_unpack(right)) else: left, right = pass_most_precise_keep(left, right) if left[0] in ('#', '!'): return fp.unpack(left).gt(fp.unpack(right)) else: return unpack_int(left) > unpack_int(right)
def _bool_eq(left, right): """ Return true if left == right, false otherwise. """ if left[0] == '$': return var.copy_str(vartypes.pass_string(left)) == var.copy_str(vartypes.pass_string(right)) else: left, right = vartypes.pass_most_precise(left, right) if left[0] in ('#', '!'): return fp.unpack(left).equals(fp.unpack(right)) else: return vartypes.integer_to_int_signed(left) == vartypes.integer_to_int_signed(right)
def circle(self, lcoord, r, start, stop, c, aspect): """ Draw a circle, ellipse, arc or sector (CIRCLE). """ x0, y0 = self.view_coords(*self.get_window_physical(*lcoord)) c = self.get_attr_index(c) if aspect == None: aspect = fp.div( fp.Single.from_int(self.screen.mode.pixel_aspect[0]), fp.Single.from_int(self.screen.mode.pixel_aspect[1]), ) if aspect.equals(aspect.one): rx, _ = self.get_window_scale(r, fp.Single.zero) ry = rx elif aspect.gt(aspect.one): _, ry = self.get_window_scale(fp.Single.zero, r) rx = fp.div(r, aspect).round_to_int() else: rx, _ = self.get_window_scale(r, fp.Single.zero) ry = fp.mul(r, aspect).round_to_int() start_octant, start_coord, start_line = -1, -1, False if start: start = fp.unpack(vartypes.pass_single_keep(start)) start_octant, start_coord, start_line = get_octant(start, rx, ry) stop_octant, stop_coord, stop_line = -1, -1, False if stop: stop = fp.unpack(vartypes.pass_single_keep(stop)) stop_octant, stop_coord, stop_line = get_octant(stop, rx, ry) if aspect.equals(aspect.one): self.draw_circle(x0, y0, rx, c, start_octant, start_coord, start_line, stop_octant, stop_coord, stop_line) else: startx, starty, stopx, stopy = -1, -1, -1, -1 if start != None: startx = abs(fp.mul(fp.Single.from_int(rx), fp.cos(start)).round_to_int()) starty = abs(fp.mul(fp.Single.from_int(ry), fp.sin(start)).round_to_int()) if stop != None: stopx = abs(fp.mul(fp.Single.from_int(rx), fp.cos(stop)).round_to_int()) stopy = abs(fp.mul(fp.Single.from_int(ry), fp.sin(stop)).round_to_int()) self.draw_ellipse( x0, y0, rx, ry, c, start_octant / 2, startx, starty, start_line, stop_octant / 2, stopx, stopy, stop_line, ) self.last_attr = c self.last_point = x0, y0
def circle(self, lcoord, r, start, stop, c, aspect): """ Draw a circle, ellipse, arc or sector (CIRCLE). """ x0, y0 = self.view_coords(*self.get_window_physical(*lcoord)) c = self.get_attr_index(c) if aspect is None: aspect = fp.div( fp.Single.from_int(self.screen.mode.pixel_aspect[0]), fp.Single.from_int(self.screen.mode.pixel_aspect[1])) if aspect.equals(aspect.one): rx, _ = self.get_window_scale(r, fp.Single.zero) ry = rx elif aspect.gt(aspect.one): _, ry = self.get_window_scale(fp.Single.zero, r) rx = fp.div(r, aspect).round_to_int() else: rx, _ = self.get_window_scale(r, fp.Single.zero) ry = fp.mul(r, aspect).round_to_int() start_octant, start_coord, start_line = -1, -1, False if start: start = fp.unpack(vartypes.pass_single_keep(start)) start_octant, start_coord, start_line = get_octant(start, rx, ry) stop_octant, stop_coord, stop_line = -1, -1, False if stop: stop = fp.unpack(vartypes.pass_single_keep(stop)) stop_octant, stop_coord, stop_line = get_octant(stop, rx, ry) if aspect.equals(aspect.one): self.draw_circle(x0, y0, rx, c, start_octant, start_coord, start_line, stop_octant, stop_coord, stop_line) else: startx, starty, stopx, stopy = -1, -1, -1, -1 if start is not None: startx = abs( fp.mul(fp.Single.from_int(rx), fp.cos(start)).round_to_int()) starty = abs( fp.mul(fp.Single.from_int(ry), fp.sin(start)).round_to_int()) if stop is not None: stopx = abs( fp.mul(fp.Single.from_int(rx), fp.cos(stop)).round_to_int()) stopy = abs( fp.mul(fp.Single.from_int(ry), fp.sin(stop)).round_to_int()) self.draw_ellipse(x0, y0, rx, ry, c, start_octant / 2, startx, starty, start_line, stop_octant / 2, stopx, stopy, stop_line) self.last_attr = c self.last_point = x0, y0
def vcaret(left, right): """ Left^right. """ if (left[0] == '#' or right[0] == '#') and option_double: return fp.pack( fp.power(fp.unpack(vartypes.pass_double_keep(left)), fp.unpack(vartypes.pass_double_keep(right)))) else: if right[0] == '%': return fp.pack( fp.unpack(vartypes.pass_single_keep(left)).ipow_int( vartypes.unpack_int(right))) else: return fp.pack( fp.power(fp.unpack(vartypes.pass_single_keep(left)), fp.unpack(vartypes.pass_single_keep(right))))
def value_rnd(ins): """ RND: get pseudorandom value. """ if util.skip_white(ins) == '(': return rnd.get_random( fp.unpack(vartypes.pass_single(parse_bracket(ins)))) else: return rnd.get_random_int(1)
def value_func(ins, fn): """ Return value of unary math function. """ return fp.pack( fn( fp.unpack( vartypes.pass_float(parse_bracket(ins), vartypes.option_double))))
def value_operator(op, left, right): """ Get value of binary operator expression. """ if op == tk.O_CARET: return vcaret(left, right) elif op == tk.O_TIMES: return vtimes(left, right) elif op == tk.O_DIV: return vdiv(left, right) elif op == tk.O_INTDIV: return fp.pack(fp.div(fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack(vartypes.pass_single_keep(right)).ifloor()).apply_carry().ifloor()) elif op == tk.MOD: numerator = vartypes.pass_int_unpack(right) if numerator == 0: # simulate division by zero return fp.pack(fp.div(fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack(vartypes.pass_single_keep(right)).ifloor()).ifloor()) return vartypes.pack_int(vartypes.pass_int_unpack(left) % numerator) elif op == tk.O_PLUS: return vplus(left, right) elif op == tk.O_MINUS: return vartypes.number_add(left, vartypes.number_neg(right)) elif op == tk.O_GT: return vartypes.bool_to_int_keep(vartypes.gt(left,right)) elif op == tk.O_EQ: return vartypes.bool_to_int_keep(vartypes.equals(left, right)) elif op == tk.O_LT: return vartypes.bool_to_int_keep(not(vartypes.gt(left,right) or vartypes.equals(left, right))) elif op == tk.O_GT + tk.O_EQ: return vartypes.bool_to_int_keep(vartypes.gt(left,right) or vartypes.equals(left, right)) elif op == tk.O_LT + tk.O_EQ: return vartypes.bool_to_int_keep(not vartypes.gt(left,right)) elif op == tk.O_LT + tk.O_GT: return vartypes.bool_to_int_keep(not vartypes.equals(left, right)) elif op == tk.AND: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) & vartypes.pass_twoscomp(right) ) elif op == tk.OR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) | vartypes.pass_twoscomp(right) ) elif op == tk.XOR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right) ) elif op == tk.EQV: return vartypes.twoscomp_to_int( ~(vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right)) ) elif op == tk.IMP: return vartypes.twoscomp_to_int( (~vartypes.pass_twoscomp(left)) | vartypes.pass_twoscomp(right) ) else: raise error.RunError(error.STX)
def value_sgn(ins): """ SGN: get sign. """ inp = vartypes.pass_number(parse_bracket(ins)) if inp[0] == '%': inp_int = vartypes.integer_to_int_signed(inp) return vartypes.int_to_integer_signed(0 if inp_int==0 else (1 if inp_int > 0 else -1)) else: return vartypes.int_to_integer_signed(fp.unpack(inp).sign())
def value_sgn(ins): """ SGN: get sign. """ inp = vartypes.pass_number(parse_bracket(ins)) if inp[0] == '%': inp_int = vartypes.integer_to_int_signed(inp) return vartypes.int_to_integer_signed(0 if inp_int == 0 else ( 1 if inp_int > 0 else -1)) else: return vartypes.int_to_integer_signed(fp.unpack(inp).sign())
def number_to_str(inp, screen=False, write=False, allow_empty_expression=False): """ Convert BASIC number to Python str. """ # screen=False means in a program listing # screen=True is used for screen, str$ and sequential files if not inp: if allow_empty_expression: return '' else: raise error.RunError(error.STX) typechar = inp[0] if typechar == '%': if screen and not write and vartypes.integer_to_int_signed(inp) >= 0: return ' ' + str(vartypes.integer_to_int_signed(inp)) else: return str(vartypes.integer_to_int_signed(inp)) elif typechar == '!': return float_to_str(fp.unpack(inp), screen, write) elif typechar == '#': return float_to_str(fp.unpack(inp), screen, write) else: raise ValueError('Number operation on string')
def number_sgn(inp): """ Return the sign of a number. """ if inp[0] == '%': i = vartypes.integer_to_int_signed(inp) if i > 0: return vartypes.int_to_integer_signed(1) elif i < 0: return vartypes.int_to_integer_signed(-1) else: return vartypes.int_to_integer_signed(0) elif inp[0] in ('!', '#'): return vartypes.int_to_integer_signed(fp.unpack(inp).sign()) return inp
def number_sgn(inp): """ Return the sign of a number. """ if inp[0] == '%': i = unpack_int(inp) if i > 0: return pack_int(1) elif i < 0: return pack_int(-1) else: return pack_int(0) elif inp[0] in ('!', '#'): return pack_int(fp.unpack(inp).sign()) return inp
def pass_single_keep(num): """ Check if variable is numeric, convert to Single. """ if not num: raise error.RunError(error.STX) typechar = num[0] if typechar == '!': return num elif typechar == '%': return fp.pack(fp.Single.from_int(unpack_int(num))) elif typechar == '#': # *round* to single return fp.pack(fp.unpack(num).round_to_single()) elif typechar == '$': raise error.RunError(error.TYPE_MISMATCH)
def value_to_str_keep(inp, screen=False, write=False, allow_empty_expression=False): """ Convert BASIC number to BASIC string. """ # screen=False means in a program listing # screen=True is used for screen, str$ and sequential files if not inp: if allow_empty_expression: return ('$', '') else: raise error.RunError(2) typechar = inp[0] if typechar == '$': return ('$', inp[1]) elif typechar == '%': if screen and not write and vartypes.unpack_int(inp) >= 0: return ('$', ' '+ int_to_str(vartypes.unpack_int(inp)) ) else: return ('$', int_to_str(vartypes.unpack_int(inp))) elif typechar == '!': return ('$', float_to_str(fp.unpack(inp), screen, write) ) elif typechar == '#': return ('$', float_to_str(fp.unpack(inp), screen, write) ) else: raise error.RunError(2)
def pass_single(num): """ Check if variable is numeric, convert to Single. """ if not num: raise error.RunError(error.STX) typechar = num[0] if typechar == '!': return num elif typechar == '%': return fp.pack(fp.Single.from_int(integer_to_int_signed(num))) elif typechar == '#': # *round* to single return fp.pack(fp.unpack(num).round_to_single()) elif typechar == '$': raise error.RunError(error.TYPE_MISMATCH)
def _bool_gt(left, right): """ Ordering: return -1 if left > right, 0 otherwise. """ if left[0] == '$': left, right = var.copy_str(vartypes.pass_string(left)), var.copy_str(vartypes.pass_string(right)) shortest = min(len(left), len(right)) for i in range(shortest): if left[i] > right[i]: return True elif left[i] < right[i]: return False # the same so far... # the shorter string is said to be less than the longer, # provided they are the same up till the length of the shorter. if len(left) > len(right): return True # left is shorter, or equal strings return False else: left, right = vartypes.pass_most_precise(left, right) if left[0] in ('#', '!'): return fp.unpack(left).gt(fp.unpack(right)) else: return vartypes.integer_to_int_signed(left) > vartypes.integer_to_int_signed(right)
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 pass_int_keep(inp, maxint=0x7fff, err=error.TYPE_MISMATCH): """ Check if variable is numeric, convert to Int. """ if not inp: raise error.RunError(error.STX) typechar = inp[0] if typechar == '%': return inp elif typechar in ('!', '#'): val = fp.unpack(inp).round_to_int() if val > maxint or val < -0x8000: # overflow raise error.RunError(error.OVERFLOW) return pack_int(val) else: # type mismatch raise error.RunError(err)
def pass_integer(inp, maxint=0x7fff, err=error.TYPE_MISMATCH): """ Check if variable is numeric, convert to Int. """ if not inp: raise error.RunError(error.STX) typechar = inp[0] if typechar == '%': return inp elif typechar in ('!', '#'): val = fp.unpack(inp).round_to_int() if val > maxint or val < -0x8000: # overflow raise error.RunError(error.OVERFLOW) return int_to_integer_unsigned(val) else: # type mismatch raise error.RunError(err)
def format_number(value, tokens, digits_before, decimals): """ Format a number to a format string. For PRINT USING. """ # illegal function call if too many digits if digits_before + decimals > 24: raise error.RunError(error.IFC) # extract sign, mantissa, exponent value = unpack(value) # dollar sign, decimal point has_dollar, force_dot = '$' in tokens, '.' in tokens # leading sign, if any valstr, post_sign = '', '' if tokens[0] == '+': valstr += '-' if value.neg else '+' elif tokens[-1] == '+': post_sign = '-' if value.neg else '+' elif tokens[-1] == '-': post_sign = '-' if value.neg else ' ' else: valstr += '-' if value.neg else '' # reserve space for sign in scientific notation by taking away a digit position if not has_dollar: digits_before -= 1 if digits_before < 0: digits_before = 0 # just one of those things GW does #if force_dot and digits_before == 0 and decimals != 0: # valstr += '0' # take absolute value value.neg = False # currency sign, if any valstr += '$' if has_dollar else '' # format to string if '^' in tokens: valstr += format_float_scientific(value, digits_before, decimals, force_dot) else: valstr += format_float_fixed(value, decimals, force_dot) # trailing signs, if any valstr += post_sign if len(valstr) > len(tokens): valstr = '%' + valstr else: # filler valstr = ('*' if '*' in tokens else ' ') * (len(tokens) - len(valstr)) + valstr return valstr
def number_divide(left, right): """ Left/right. """ if left[0] == '#' or right[0] == '#': return fp.pack( fp.div(fp.unpack(vartypes.pass_double(left)), fp.unpack(vartypes.pass_double(right))) ) else: return fp.pack( fp.div(fp.unpack(vartypes.pass_single(left)), fp.unpack(vartypes.pass_single(right))) )
def value_int(ins): """ INT: get floor value. """ inp = vartypes.pass_number(parse_bracket(ins)) return inp if inp[0] == '%' else fp.pack(fp.unpack(inp).ifloor())
def vtimes(left, right): """ Left*right. """ if left[0] == '#' or right[0] == '#': return fp.pack( fp.unpack(vartypes.pass_double_keep(left)).imul(fp.unpack(vartypes.pass_double_keep(right))) ) else: return fp.pack( fp.unpack(vartypes.pass_single_keep(left)).imul(fp.unpack(vartypes.pass_single_keep(right))) )
def value_rnd(ins): """ RND: get pseudorandom value. """ if util.skip_white(ins) == '(': return rnd.get_random(fp.unpack(vartypes.pass_single(parse_bracket(ins)))) else: return rnd.get_random_int(1)
def value_func(ins, fn): """ Return value of unary math function. """ return fp.pack(fn(fp.unpack(vartypes.pass_float(parse_bracket(ins), vartypes.option_double))))
def number_unpack(value): """ Unpack a number value. """ if value[0] in ('#', '!'): return fp.unpack(value) else: return vartypes.integer_to_int_signed(value)
def vdiv(left, right): """ Left/right. """ if left[0] == '#' or right[0] == '#': return fp.pack( fp.div(fp.unpack(vartypes.pass_double_keep(left)), fp.unpack(vartypes.pass_double_keep(right))) ) else: return fp.pack( fp.div(fp.unpack(vartypes.pass_single_keep(left)), fp.unpack(vartypes.pass_single_keep(right))) )
def number_unpack(value): """ Unpack a number value. """ if value[0] in ('#', '!'): return fp.unpack(value) else: return vartypes.unpack_int(value)