[decompiler] Better support for non-virtual methods (#543)

* fix up nonvirtual method calls and stack new method calls

* look at final in compiler too
This commit is contained in:
water111
2021-05-30 22:52:40 -04:00
committed by GitHub
parent b1a76b2291
commit c4f44e265f
18 changed files with 217 additions and 139 deletions
+17
View File
@@ -630,6 +630,23 @@ int BasicType::get_inline_array_start_alignment() const {
}
}
bool BasicType::operator==(const Type& other) const {
if (typeid(*this) != typeid(other)) {
return false;
}
auto* p_other = dynamic_cast<const BasicType*>(&other);
// clang-format off
return other.is_equal(*this) &&
m_fields == p_other->m_fields &&
m_dynamic == p_other->m_dynamic &&
m_size_in_mem == p_other->m_size_in_mem &&
m_pack == p_other->m_pack &&
m_allow_misalign == p_other->m_allow_misalign &&
m_final == p_other->m_final;
// clang-format on
}
/////////////////
// Bitfield
/////////////////
+6 -1
View File
@@ -107,7 +107,6 @@ class Type {
bool m_allow_in_runtime = true;
std::string m_runtime_name;
bool m_is_boxed = false; // does this have runtime type information?
int m_heap_base = 0;
};
@@ -286,7 +285,13 @@ class BasicType : public StructureType {
int get_offset() const override;
int get_inline_array_start_alignment() const override;
std::string print() const override;
bool final() const { return m_final; }
void set_final() { m_final = true; }
~BasicType() = default;
bool operator==(const Type& other) const override;
protected:
bool m_final = false;
};
class BitField {
+14
View File
@@ -724,6 +724,7 @@ void TypeSystem::add_builtin_types() {
auto symbol_type = add_builtin_basic("basic", "symbol");
auto type_type = add_builtin_basic("basic", "type");
auto string_type = add_builtin_basic("basic", "string");
string_type->set_final(); // no virtual calls used on string.
auto function_type = add_builtin_basic("basic", "function");
auto vu_function_type = add_builtin_structure("structure", "vu-function");
auto link_block_type = add_builtin_basic("basic", "link-block");
@@ -1539,3 +1540,16 @@ std::string TypeSystem::generate_deftype(const Type* type) const {
";; cannot generate deftype for {}, it is not a structure, basic, or bitfield (parent {})\n",
type->get_name(), type->get_parent());
}
bool TypeSystem::should_use_virtual_methods(const Type* type) const {
auto as_basic = dynamic_cast<const BasicType*>(type);
if (as_basic && !as_basic->final()) {
return true;
} else {
return false;
}
}
bool TypeSystem::should_use_virtual_methods(const TypeSpec& type) const {
return should_use_virtual_methods(lookup_type(type));
}
+3
View File
@@ -174,6 +174,9 @@ class TypeSystem {
int offset,
int field_size);
bool should_use_virtual_methods(const Type* type) const;
bool should_use_virtual_methods(const TypeSpec& type) const;
/*!
* Get a type by name and cast to a child class of Type*. Must succeed.
*/
+15
View File
@@ -208,6 +208,7 @@ struct StructureDefResult {
bool generate_runtime_type = true;
bool pack_me = false;
bool allow_misaligned = false;
bool final = false;
};
StructureDefResult parse_structure_def(StructureType* type,
@@ -271,6 +272,8 @@ StructureDefResult parse_structure_def(StructureType* type,
flags.heap_base = hb;
} else if (opt_name == ":allow-misaligned") {
result.allow_misaligned = true;
} else if (opt_name == ":final") {
result.final = true;
} else {
throw std::runtime_error("Invalid option in field specification: " + opt_name);
}
@@ -436,6 +439,11 @@ DeftypeResult parse_deftype(const goos::Object& deftype, TypeSystem* ts) {
auto new_type = std::make_unique<BasicType>(parent_type_name, name, false, 0);
auto pto = dynamic_cast<BasicType*>(ts->lookup_type(parent_type));
assert(pto);
if (pto->final()) {
throw std::runtime_error(
fmt::format("[TypeSystem] Cannot make a child type {} of final basic type {}", name,
parent_type_name));
}
new_type->inherit(pto);
ts->forward_declare_type_as_basic(name);
auto sr = parse_structure_def(new_type.get(), ts, field_list_obj, options_obj);
@@ -452,6 +460,9 @@ DeftypeResult parse_deftype(const goos::Object& deftype, TypeSystem* ts) {
throw std::runtime_error("invalid pack option on basic");
}
new_type->set_heap_base(result.flags.heap_base);
if (sr.final) {
new_type->set_final();
}
ts->add_type(name, std::move(new_type));
} else if (is_type("structure", parent_type, ts)) {
auto new_type = std::make_unique<StructureType>(parent_type_name, name, false, false, false, 0);
@@ -468,6 +479,10 @@ DeftypeResult parse_deftype(const goos::Object& deftype, TypeSystem* ts) {
if (sr.allow_misaligned) {
new_type->set_allow_misalign(true);
}
if (sr.final) {
throw std::runtime_error(
fmt::format("[TypeSystem] :final option cannot be used on structure type {}", name));
}
new_type->set_heap_base(result.flags.heap_base);
ts->add_type(name, std::move(new_type));
} else if (is_type("integer", parent_type, ts)) {
+3 -3
View File
@@ -726,9 +726,9 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input,
if (method_id == GOAL_NEW_METHOD) {
return TP_Type::make_from_ts(method_type);
} else if (input_type.kind == TP_Type::Kind::TYPE_OF_TYPE_NO_VIRTUAL) {
return TP_Type::make_non_virtual_method(method_type);
return TP_Type::make_non_virtual_method(method_type, TypeSpec(type_name));
} else {
return TP_Type::make_virtual_method(method_type);
return TP_Type::make_virtual_method(method_type, TypeSpec(type_name));
}
}
@@ -740,7 +740,7 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input,
if (method_id != GOAL_NEW_METHOD && method_id != GOAL_RELOC_METHOD) {
// this can get us the wrong thing for `new` methods. And maybe relocate?
return TP_Type::make_non_virtual_method(
method_info.type.substitute_for_method_call("object"));
method_info.type.substitute_for_method_call("object"), TypeSpec("object"));
}
}
+1
View File
@@ -1329,6 +1329,7 @@ class StackVarDefElement : public FormElement {
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) override;
const TypeSpec& type() const { return m_entry.ref_type; }
private:
StackVarEntry m_entry;
+90 -2
View File
@@ -1796,12 +1796,23 @@ void FunctionCallElement::update_from_stack(const Env& env,
}
std::vector<Form*> arg_forms;
bool has_good_types = env.has_type_analysis() && function_type.arg_count() == nargs + 1;
TypeSpec first_arg_type;
for (size_t arg_id = 0; arg_id < nargs; arg_id++) {
auto val = unstacked.at(arg_id + 1); // first is the function itself.
auto& var = all_pop_vars.at(arg_id + 1);
if (env.has_type_analysis() && function_type.arg_count() == nargs + 1) {
if (has_good_types) {
auto actual_arg_type = env.get_types_before_op(var.idx()).get(var.reg()).typespec();
auto val_atom = form_as_atom(val);
if (val_atom && val_atom->is_var()) {
actual_arg_type = env.get_variable_type(val_atom->var(), true);
}
if (arg_id == 0) {
first_arg_type = actual_arg_type;
}
auto desired_arg_type = function_type.get_arg(arg_id);
if (!env.dts->ts.tc(desired_arg_type, actual_arg_type)) {
arg_forms.push_back(cast_form(val, desired_arg_type, pool, env));
@@ -1826,6 +1837,17 @@ void FunctionCallElement::update_from_stack(const Env& env,
auto vtable_var_name = env.get_variable_name(*vtable_reg);
auto arg0_mr = match(Matcher::any_reg(0), unstacked.at(1));
if (arg0_mr.matched && env.get_variable_name(*arg0_mr.maps.regs.at(0)) == vtable_var_name) {
if (tp_type.kind != TP_Type::Kind::VIRTUAL_METHOD) {
throw std::runtime_error(
"Method internal mismatch. METHOD_OF_OBJECT operator didn't get a VIRTUAL_METHOD "
"type.");
}
if (!env.dts->ts.should_use_virtual_methods(tp_type.method_from_type())) {
throw std::runtime_error(
fmt::format("Method call on {} used a virtual call unexpectedly.",
tp_type.method_from_type().print()));
}
// fmt::print("STACK\n{}\n\n", stack.print(env));
auto pop =
pop_to_forms({*arg0_mr.maps.regs.at(0)}, env, pool, stack, allow_side_effects, {}, {2})
@@ -1944,7 +1966,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
{
// detect method calls:
// ex: ((method-of-type x new) (quote global) pair gp-0 a3-0)
// ex: ((method-of-type x blah) arg...)
constexpr int method_name = 0;
constexpr int type_source = 1;
@@ -1957,7 +1979,73 @@ void FunctionCallElement::update_from_stack(const Env& env,
auto match_result = match(matcher, temp_form);
if (match_result.matched) {
auto name = match_result.maps.strings.at(method_name);
if (name != "new") {
// only do these checks on non-new methods. New methods are treated as functions because
// they are never virtual and are never called like a method.
if (tp_type.kind != TP_Type::Kind::NON_VIRTUAL_METHOD) {
throw std::runtime_error(fmt::format(
"Method internal mismatch. METHOD_OF_TYPE operator didn't get a NON_VIRTUAL_METHOD "
"type. Got {} instead.",
tp_type.print()));
}
if (env.dts->ts.should_use_virtual_methods(tp_type.method_from_type())) {
throw std::runtime_error(
fmt::format("Expected type {} to use virtual methods, but it didn't. Set option "
":final in the deftype to disable virtual method calls",
tp_type.method_from_type().print()));
}
}
auto type_source_form = match_result.maps.forms.at(type_source);
// if the type is the exact type of the argument, we want to build it into a method call
if (type_source_form->to_string(env) == first_arg_type.base_type() && name != "new") {
auto method_op = pool.alloc_single_element_form<ConstantTokenElement>(nullptr, name);
auto gop = GenericOperator::make_function(method_op);
result->push_back(pool.alloc_element<GenericElement>(gop, arg_forms));
return;
}
if (name == "new" && arg_forms.size() >= 2) {
bool got_stack_new = true;
// method
// (the-as symbol (new 'stack-no-clear 'draw-context))
// draw-context
auto first_cast = arg_forms.at(0)->try_as_element<CastElement>();
if (!first_cast || first_cast->type() != TypeSpec("symbol")) {
got_stack_new = false;
}
if (got_stack_new) {
auto new_op = first_cast->source()->try_as_element<StackVarDefElement>();
if (!new_op || new_op->type().base_type() != type_source_form->to_string(env)) {
got_stack_new = false;
}
}
if (got_stack_new) {
if (arg_forms.at(1)->to_string(env) != type_source_form->to_string(env)) {
got_stack_new = false;
}
}
if (got_stack_new) {
std::vector<Form*> stack_new_args;
stack_new_args.push_back(
pool.alloc_single_element_form<ConstantTokenElement>(nullptr, "'stack"));
stack_new_args.push_back(pool.alloc_single_element_form<ConstantTokenElement>(
nullptr, fmt::format("'{}", type_source_form->to_string(env))));
for (size_t i = 2; i < arg_forms.size(); i++) {
stack_new_args.push_back(arg_forms.at(i));
}
result->push_back(pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::NEW), stack_new_args));
return;
}
}
auto method_op =
pool.alloc_single_element_form<GetMethodElement>(nullptr, type_source_form, name, false);
auto gop = GenericOperator::make_function(method_op);
+10 -2
View File
@@ -111,16 +111,18 @@ class TP_Type {
static TP_Type make_from_ts(const std::string& ts) { return make_from_ts(TypeSpec(ts)); }
static TP_Type make_virtual_method(const TypeSpec& method_type) {
static TP_Type make_virtual_method(const TypeSpec& method_type, const TypeSpec& obj_type) {
TP_Type result;
result.kind = Kind::VIRTUAL_METHOD;
result.m_ts = method_type;
result.m_method_from_type = obj_type;
return result;
}
static TP_Type make_non_virtual_method(const TypeSpec& method_type) {
static TP_Type make_non_virtual_method(const TypeSpec& method_type, const TypeSpec& obj_type) {
TP_Type result;
result.kind = Kind::NON_VIRTUAL_METHOD;
result.m_method_from_type = obj_type;
result.m_ts = method_type;
return result;
}
@@ -288,8 +290,14 @@ class TP_Type {
return false;
}
const TypeSpec& method_from_type() const {
assert(kind == Kind::VIRTUAL_METHOD || kind == Kind::NON_VIRTUAL_METHOD);
return m_method_from_type;
}
private:
TypeSpec m_ts;
TypeSpec m_method_from_type;
std::string m_str;
int64_t m_int = 0;
bool m_pcpyud = false; // have we extracted the top doubleword of a bitfield?
+1 -1
View File
@@ -72,7 +72,7 @@ RegVal* Compiler::compile_get_method_of_object(const goos::Object& form,
auto fe = get_parent_env_of_type<FunctionEnv>(env);
RegVal* runtime_type = nullptr;
if (is_basic(compile_time_type)) {
if (m_ts.should_use_virtual_methods(compile_time_type)) {
runtime_type = fe->make_gpr(m_ts.make_typespec("type"));
MemLoadInfo info;
info.size = 4;
@@ -666,24 +666,11 @@
(set! (-> s5-0 vector 1 quad) (the-as uint128 0))
(set! (-> s5-0 vector 2 quad) (the-as uint128 0))
(set! (-> s5-0 vector 3 quad) (the-as uint128 0))
(let
((s4-0
((method-of-type vector4s-3 new)
(the-as symbol (new 'stack-no-clear 'vector4s-3))
vector4s-3
)
)
(s3-0 (new 'stack-no-clear 'vector))
)
(let ((s4-0 (new 'stack 'vector4s-3))
(s3-0 (new 'stack-no-clear 'vector))
)
(set! (-> s3-0 quad) (the-as uint128 0))
(let
((s2-0
((method-of-type vector4s-3 new)
(the-as symbol (new 'stack-no-clear 'vector4s-3))
vector4s-3
)
)
)
(let ((s2-0 (new 'stack 'vector4s-3)))
(matrix*! s5-0 arg0 (-> *math-camera* camera-temp))
(matrix-3x3-inverse-transpose! gp-0 arg0)
(let ((v1-3 s3-0))
@@ -757,7 +744,3 @@
(none)
)
)
@@ -95,7 +95,7 @@
;; definition for method 12 of type connection
(defmethod belongs-to-process? connection ((obj connection) (arg0 process))
(= arg0 ((method-of-type connection get-process) obj))
(= arg0 (get-process obj))
)
;; definition for method 2 of type connection
@@ -253,25 +253,25 @@
(format #t "~Talive-list:~%")
(let ((s5-0 *print-column*))
(set! *print-column* (+ *print-column* (the-as uint 64)))
((method-of-type connectable inspect) (-> obj alive-list))
(inspect (-> obj alive-list))
(set! *print-column* s5-0)
)
(format #t "~Talive-list-end:~%")
(let ((s5-1 *print-column*))
(set! *print-column* (+ *print-column* (the-as uint 64)))
((method-of-type connectable inspect) (-> obj alive-list-end))
(inspect (-> obj alive-list-end))
(set! *print-column* s5-1)
)
(format #t "~Tdead-list:~%")
(let ((s5-2 *print-column*))
(set! *print-column* (+ *print-column* (the-as uint 64)))
((method-of-type connectable inspect) (-> obj dead-list))
(inspect (-> obj dead-list))
(set! *print-column* s5-2)
)
(format #t "~Tdead-list-end:~%")
(let ((s5-3 *print-column*))
(set! *print-column* (+ *print-column* (the-as uint 64)))
((method-of-type connectable inspect) (-> obj dead-list-end))
(inspect (-> obj dead-list-end))
(set! *print-column* s5-3)
)
(format #t "~Tdata[~D]: @ #x~X~%" (-> obj allocated-length) (-> obj data))
@@ -427,7 +427,7 @@
;; definition for method 13 of type connection
(defmethod move-to-dead connection ((obj connection))
(let ((v1-1 ((method-of-type connection get-engine) obj)))
(let ((v1-1 (get-engine obj)))
(set! (-> obj prev0 next0) (-> obj next0))
(set! (-> obj next0 prev0) (-> obj prev0))
(set! (-> obj prev1 next1) (-> obj next1))
@@ -506,32 +506,21 @@
(defun
draw-sprite2d-xy
((buf dma-buffer) (x int) (y int) (w int) (h int) (color rgba))
(let*
((context
((method-of-type draw-context new)
(the-as symbol (new 'stack-no-clear 'draw-context))
draw-context
x
y
w
h
color
)
)
(draw-x (max 1792 (min 2304 (+ (-> context orgx) 1792))))
(draw-y
(max
(min
(+ (-> context orgy) (-> *video-parms* screen-miny))
(-> *video-parms* screen-maxy)
)
(-> *video-parms* screen-miny)
)
)
(draw-w (-> context width))
(draw-h (-> context height))
(end-dma (the-as dma-packet (-> buf base)))
)
(let* ((context (new 'stack 'draw-context x y w h color))
(draw-x (max 1792 (min 2304 (+ (-> context orgx) 1792))))
(draw-y
(max
(min
(+ (-> context orgy) (-> *video-parms* screen-miny))
(-> *video-parms* screen-maxy)
)
(-> *video-parms* screen-miny)
)
)
(draw-w (-> context width))
(draw-h (-> context height))
(end-dma (the-as dma-packet (-> buf base)))
)
(let* ((a2-2 buf)
(dma (the-as dma-packet (-> a2-2 base)))
)
@@ -742,19 +731,7 @@
(defun
screen-gradient
((arg0 dma-buffer) (arg1 rgba) (arg2 rgba) (arg3 rgba) (arg4 rgba))
(let
((a1-2
((method-of-type draw-context new)
(the-as symbol (new 'stack-no-clear 'draw-context))
draw-context
0
0
512
224
(new 'static 'rgba)
)
)
)
(let ((a1-2 (new 'stack 'draw-context 0 0 512 224 (new 'static 'rgba))))
(set! (-> a1-2 color 0) arg1)
(set! (-> a1-2 color 1) arg2)
(set! (-> a1-2 color 2) arg3)
@@ -76,7 +76,7 @@
trajectory
((obj trajectory) (arg0 vector) (arg1 vector) (arg2 float) (arg3 float))
(let ((f0-1 (/ (vector-vector-xz-distance arg1 arg0) arg2)))
((method-of-type trajectory TODO-RENAME-11) obj arg0 arg1 f0-1 arg3)
(TODO-RENAME-11 obj arg0 arg1 f0-1 arg3)
)
(let ((v0-1 0))
)
@@ -98,7 +98,7 @@
(set! f0-3 (fmax (/ (- (- arg2) f0-4) arg3) (/ (+ (- arg2) f0-4) arg3)))
)
)
((method-of-type trajectory TODO-RENAME-11) obj arg0 arg1 f0-3 arg3)
(TODO-RENAME-11 obj arg0 arg1 f0-3 arg3)
)
(let ((v0-1 0))
)
@@ -118,7 +118,7 @@
(if (< 0.0 f1-5)
(set! f0-3 (sqrtf f1-5))
)
((method-of-type trajectory TODO-RENAME-13) obj arg0 arg1 f0-3 arg3)
(TODO-RENAME-13 obj arg0 arg1 f0-3 arg3)
)
(let ((v0-1 0))
)
@@ -142,7 +142,7 @@
)
(let
((f0-1 (* (-> obj time) (/ (+ 1.0 (the float s2-0)) (the float s3-0)))))
((method-of-type trajectory TODO-RENAME-9) obj f0-1 s4-0)
(TODO-RENAME-9 obj f0-1 s4-0)
)
(add-debug-line #t 68 s5-0 s4-0 (new 'static 'rgba :r #xff :a #x80) #f -1)
)
@@ -151,7 +151,3 @@
)
(none)
)
@@ -69,11 +69,11 @@
(set! (-> obj period) (* (-> obj period) (-> obj damp-period)))
(set! (-> obj ticks) f30-0)
(if (< (-> obj damp-period) 0.0)
((method-of-type smush-control set-zero!) obj)
(set-zero! obj)
)
)
(if (>= f30-0 (-> obj duration))
((method-of-type smush-control set-zero!) obj)
(set-zero! obj)
)
(*
(sin (/ (* 65536.0 f28-0) (-> obj period)))
@@ -130,11 +130,7 @@
(arg4 float)
(arg5 float)
)
(when
(>=
(fabs (* 0.2 (-> obj amp)))
(fabs ((method-of-type smush-control get-no-update) obj))
)
(when (>= (fabs (* 0.2 (-> obj amp))) (fabs (get-no-update obj)))
(set! (-> obj amp) arg0)
(set! (-> obj period) (the float arg1))
(set! (-> obj duration) (the float arg2))
@@ -145,7 +141,3 @@
)
obj
)
@@ -196,7 +196,7 @@
;; definition for method 9 of type sync-info-paused
(defmethod dummy-9 sync-info-paused ((obj sync-info-paused) (arg0 float))
(* ((method-of-type sync-info-paused dummy-11) obj) arg0)
(* (dummy-11 obj) arg0)
)
;; definition for method 13 of type sync-info
@@ -337,12 +337,12 @@
;; definition for method 12 of type sync-info-eased
(defmethod dummy-12 sync-info-eased ((obj sync-info-eased) (arg0 float))
(* ((method-of-type sync-info-eased dummy-13) obj) arg0)
(* (dummy-13 obj) arg0)
)
;; definition for method 12 of type sync-info-paused
(defmethod dummy-12 sync-info-paused ((obj sync-info-paused) (arg0 float))
(* ((method-of-type sync-info-paused dummy-13) obj) arg0)
(* (dummy-13 obj) arg0)
)
;; definition for method 9 of type delayed-rand-float
@@ -427,7 +427,7 @@
(arg5 float)
(arg6 float)
)
((method-of-type oscillating-float dummy-9) (-> obj osc) arg0 arg4 arg5 arg6)
(dummy-9 (-> obj osc) arg0 arg4 arg5 arg6)
(set! (-> obj max-value) arg1)
(set! (-> obj min-value) arg2)
(set! (-> obj elasticity) arg3)
@@ -437,7 +437,7 @@
;; definition for method 10 of type bouncing-float
(defmethod dummy-10 bouncing-float ((obj bouncing-float) (arg0 float))
((method-of-type oscillating-float dummy-10) (-> obj osc) arg0)
(dummy-10 (-> obj osc) arg0)
(set! (-> obj state) 0)
(when (>= (-> obj osc value) (-> obj max-value))
(set! (-> obj osc value) (-> obj max-value))
@@ -510,7 +510,7 @@
(the-as int (- (-> *display* base-frame-counter) (-> obj start-time)))
(-> obj timer)
)
((method-of-type delayed-rand-vector dummy-10) obj)
(dummy-10 obj)
)
(-> obj value)
)
@@ -524,7 +524,7 @@
(the-as int (- (-> *display* base-frame-counter) (-> obj start-time)))
(-> obj timer)
)
((method-of-type delayed-rand-vector dummy-10) obj)
(dummy-10 obj)
(.svf (&-> (-> obj value) quad) vf0)
)
(-> obj value)
@@ -41,7 +41,7 @@
((allocation symbol) (type-to-make type) (arg0 int) (arg1 string))
(cond
(arg1
(let* ((s2-1 (max ((method-of-type string length) arg1) arg0))
(let* ((s2-1 (max (length arg1) arg0))
(a0-4
(object-new
allocation
@@ -277,11 +277,7 @@
;; definition for function string<?
(defun string<? ((a string) (b string))
(let
((len
(min ((method-of-type string length) a) ((method-of-type string length) b))
)
)
(let ((len (min (length a) (length b))))
(dotimes (i len)
(cond
((< (-> a data i) (-> b data i))
@@ -298,11 +294,7 @@
;; definition for function string>?
(defun string>? ((a string) (b string))
(let
((len
(min ((method-of-type string length) a) ((method-of-type string length) b))
)
)
(let ((len (min (length a) (length b))))
(dotimes (i len)
(cond
((< (-> a data i) (-> b data i))
@@ -319,11 +311,7 @@
;; definition for function string<=?
(defun string<=? ((a string) (b string))
(let
((len
(min ((method-of-type string length) a) ((method-of-type string length) b))
)
)
(let ((len (min (length a) (length b))))
(dotimes (i len)
(cond
((< (-> a data i) (-> b data i))
@@ -340,11 +328,7 @@
;; definition for function string>=?
(defun string>=? ((a string) (b string))
(let
((len
(min ((method-of-type string length) a) ((method-of-type string length) b))
)
)
(let ((len (min (length a) (length b))))
(dotimes (i len)
(cond
((< (-> a data i) (-> b data i))
@@ -437,8 +421,8 @@
;; definition for function string-strip-trailing-whitespace!
(defun string-strip-trailing-whitespace! ((str string))
(when (nonzero? ((method-of-type string length) str))
(let ((ptr (&+ (-> str data) (+ ((method-of-type string length) str) -1))))
(when (nonzero? (length str))
(let ((ptr (&+ (-> str data) (+ (length str) -1))))
(while
(and
(>= (the-as int ptr) (the-as int (-> str data)))
+10 -15
View File
@@ -2467,19 +2467,15 @@ TEST_F(FormRegressionTest, StringLt) {
std::string type = "(function string string symbol)";
std::string expected =
"(begin\n"
" (let\n"
" ((s4-1\n"
" (min\n"
" ((method-of-type string length) arg0)\n"
" ((method-of-type string length) arg1)\n"
" )\n"
" )\n"
" )\n"
" (dotimes\n"
" (v1-4 s4-1)\n"
" (let ((s4-1 (min (length arg0) (length arg1))))\n"
" (dotimes (v1-4 s4-1)\n"
" (cond\n"
" ((< (-> arg0 data v1-4) (-> arg1 data v1-4)) (return #t))\n"
" ((< (-> arg1 data v1-4) (-> arg0 data v1-4)) (return #f))\n"
" ((< (-> arg0 data v1-4) (-> arg1 data v1-4))\n"
" (return #t)\n"
" )\n"
" ((< (-> arg1 data v1-4) (-> arg0 data v1-4))\n"
" (return #f)\n"
" )\n"
" )\n"
" )\n"
" )\n"
@@ -2714,9 +2710,8 @@ TEST_F(FormRegressionTest, StripStripTrailingWhitespace) {
std::string type = "(function string symbol)";
std::string expected =
"(begin\n"
" (when (nonzero? ((method-of-type string length) arg0))\n"
" (let\n"
" ((v1-6 (&+ (-> arg0 data) (+ ((method-of-type string length) arg0) -1))))\n"
" (when (nonzero? (length arg0))\n"
" (let ((v1-6 (&+ (-> arg0 data) (+ (length arg0) -1))))\n"
" (while\n"
" (and\n"
" (>= (the-as int v1-6) (the-as int (-> arg0 data)))\n"