def test_tail_call_in_conditional_then(self) -> None: prog = sexp.parse( '(define (vacuous-tail) (if true (vacuous-tail) false))') self.finder.visit(prog) self.assertEqual(1, len(self.finder.tail_calls)) self.assert_symbol_in_tail_calls(sexp.SSym('vacuous-tail'), self.finder.tail_calls)
def test_tail_call_in_one_branch_linear_call_in_other(self) -> None: prog = sexp.parse(''' (define (vacuous-tail) (if true (+ 1 (vacuous-tail)) (vacuous-tail)) )''') self.finder.visit(prog) self.assertEqual(1, len(self.finder.tail_calls)) self.assert_symbol_in_tail_calls(sexp.SSym('vacuous-tail'), self.finder.tail_calls)
def _is_true_assertion(self, call: sexp.SCall) -> bool: if self._expr_types is None: return False if call.func != sexp.SSym('assert') or len(call.args) != 1: return False call_arg = call.args[0] if not self._expr_types.expr_value_known(call_arg): return False return self._expr_types.get_expr_value(call_arg) == sexp.SBool(True)
def _get_replacement_vector_index_func( self, call: sexp.SCall) -> Optional[sexp.SSym]: if self._expr_types is None: return None if not isinstance(call.func, sexp.SSym): return None if call.func not in (sexp.SSym('vector-index'), sexp.SSym('vector-set!')): return None if len(call.args) < 2: return None if not self._expr_types.expr_type_known(call.args[0]): return None vec_arg_type = self._expr_types.get_expr_type(call.args[0]) if not isinstance(vec_arg_type, scheme_types.SchemeVectType): return None if vec_arg_type.length is None: return None index_arg = call.args[1] if not self._expr_types.expr_value_known(index_arg): return None index = self._expr_types.get_expr_value(index_arg) if not isinstance(index, sexp.SNum): return None in_bounds = index.value >= 0 and index.value < vec_arg_type.length if not in_bounds: return None return (sexp.SSym('inst/load') if call.func == sexp.SSym('vector-index') else sexp.SSym('inst/store'))
def _add_is_function_check( self, function_expr: bytecode.Parameter, add_to_block: bytecode.BasicBlock) -> None: typeof_var = bytecode.Var(next(self.var_names)) typeof_instr = bytecode.TypeofInst( typeof_var, function_expr) is_function_var = bytecode.Var(next(self.var_names)) is_function_instr = bytecode.BinopInst( is_function_var, bytecode.Binop.SYM_EQ, typeof_var, bytecode.SymLit(sexp.SSym('function')) ) branch_instr = bytecode.BrnInst(is_function_var, IS_FUNCTION_TRAP) for instr in [typeof_instr, is_function_instr, branch_instr]: add_to_block.add_inst(instr)
def test_fib_tail(self) -> None: prog = sexp.parse(''' (define (fib-tail n) (fib-tail-impl n 0 1) ) (define (fib-tail-impl n first second) (if (= n 0) first (if (= n 1) second (fib-tail-impl (- n 1) second (+ first second)) ) ) )''') self.finder.visit(prog) self.assertEqual(1, len(self.finder.tail_calls)) self.assert_symbol_in_tail_calls(sexp.SSym('fib-tail-impl'), self.finder.tail_calls)
def test_basic_tail_call(self) -> None: prog = sexp.parse('(define (vacuous-tail) (vacuous-tail))') self.finder.visit(prog) self.assertEqual(1, len(self.finder.tail_calls)) self.assert_symbol_in_tail_calls(sexp.SSym('vacuous-tail'), self.finder.tail_calls)
def type_name(self) -> sexp.SSym: return sexp.SSym('symbol')
def type_name(self) -> sexp.SSym: return sexp.SSym('number')
def decorator(cls: Type[BuiltinCallTypeEvaler] ) -> Type[BuiltinCallTypeEvaler]: _builtin_const_exprs[sexp.SSym(func_name)] = cls return cls
def type_name(self) -> sexp.SSym: return sexp.SSym('function')
def type_name(self) -> sexp.SSym: return sexp.SSym('vector')
else_type = self.get_expr_type(cond.else_expr) if (self.get_expr_type(cond.test) == SchemeBool and self.expr_value_known(cond.test)): expr_val = self.get_expr_value(cond.test) assert isinstance(expr_val, sexp.SBool) if expr_val.value: self.set_expr_type(cond, then_type) else: self.set_expr_type(cond, else_type) else: self.set_expr_type(cond, then_type.join_with(else_type)) _BUILTINS_FUNC_TYPES: Dict[sexp.SSym, SchemeObjectType] = { sexp.SSym('inst/typeof'): SchemeFunctionType(1, SchemeSym), sexp.SSym('inst/trap'): SchemeFunctionType(0, SchemeBottom), sexp.SSym('inst/trace'): SchemeFunctionType(1, SchemeNum), sexp.SSym('inst/display'): SchemeFunctionType(1, SchemeNum), sexp.SSym('inst/newline'): SchemeFunctionType(0, SchemeNum), sexp.SSym('inst/breakpoint'): SchemeFunctionType(0, SchemeNum), sexp.SSym('inst/alloc'): SchemeFunctionType(1, SchemeVectType(None)), sexp.SSym('inst/load'): SchemeFunctionType(2, SchemeObject), sexp.SSym('inst/store'): SchemeFunctionType(3, SchemeVectType(None)), sexp.SSym('inst/length'): SchemeFunctionType(1, SchemeNum), sexp.SSym('inst/+'): SchemeFunctionType(2, SchemeNum), sexp.SSym('inst/-'): SchemeFunctionType(2, SchemeNum), sexp.SSym('inst/*'): SchemeFunctionType(2, SchemeNum), sexp.SSym('inst//'): SchemeFunctionType(2, SchemeNum), sexp.SSym('inst/%'): SchemeFunctionType(2, SchemeNum),