Files
nunuhara_xsystem4/test/Source/strings.jaf
T
Nunuhara Cabbage 49586506d0 Fix memory managment of objects on stack
A few things.

The S_REF instruction creates a _copy_ of the referenced string. Proof:

    FUNC foo
    // string local_string = "foo"
    SH_LOCALREF local_string
    S_PUSH "foo"
    S_ASSIGN
    S_POP

    // prepare argument for bar()
    PUSHLOCALPAGE
    PUSH local_string
    S_REF

    // stealthily alter local_string
    SH_LOCALREF local_string
    S_PUSH "bar"
    S_ASSIGN
    S_POP

    // bar(local_string)
    CALLFUNC bar // local_string is still "foo" in the body of bar()!

Thus, it is not CALLFUNC's responsibility to copy by-value string
arguments. CALLFUNC need only copy the index from the stack into the
local page.

Objects pushed to the stack with SH_LOCALREF, SH_GLOBALREF and REF do
not gain a reference. They are already referenced by the page they
belong to.

I believe the implementation of S_REF is still not quite right. What
I've noticed is that System40.exe is able to distinguish between strings
pushed with S_REF/S_PUSH and strings pushed with
SH_LOCALREF/SH_GLOBALREF/REF. It seems the former are r-values and the
latter are l-values (i.e. the latter can be assigned to, but not the
former), and the VM will throw an error if you try to assign to an
r-value.
The underlying implementation is not clear to me. Both types appear to
be indices into the heap, which suggests that the distinguishing factor
must be stored either in the object itself, or as part of the pointer to
an object. Perhaps its as simple as a flag marking an object as an
r-value?
2019-10-19 21:36:52 -07:00

71 lines
3.4 KiB
C
Executable File

// -*-mode: C; coding: sjis; -*-
void test_strings(void)
{
int i;
float f;
string s;
test_bool("\"a\" == \"a\"", "a" == "a", true);
test_bool("\"a\" != \"b\"", "a" == "b", false);
test_bool("\"a\" < \"b\"", "a" < "b", true);
test_bool("\"a\" < \"a\"", "a" < "a", false);
test_bool("\"b\" < \"a\"", "b" < "a", false);
test_bool("\"a\" > \"b\"", "a" > "b", false);
test_bool("\"a\" > \"a\"", "a" > "a", false);
test_bool("\"b\" > \"a\"", "b" > "a", true);
test_bool("\"a\" <= \"b\"", "a" <= "b", true);
test_bool("\"a\" <= \"a\"", "a" <= "a", true);
test_bool("\"b\" <= \"a\"", "b" <= "a", false);
test_bool("\"a\" >= \"b\"", "a" >= "b", false);
test_bool("\"a\" >= \"a\"", "a" >= "a", true);
test_bool("\"b\" >= \"a\"", "b" >= "a", true);
test_bool("var = \"str\"", (s = "str", s == "str"), true);
test_string("foo += \"bar\"", (s = "foo", s += "bar"), "foobar");
// S_ADD
test_string("\"a\" + \"b\"", "a" + "b", "ab");
// S_LENGTH
test_equal("\"\".Length()", (s = "", s.Length()), 0);
test_equal("\"abc\".Length()", (s = "abc", s.Length()), 3);
test_equal("\"あbc\".Length()", (s = "あbc", s.Length()), 3);
// S_LENGTHBYTE
test_equal("\"\".LengthByte()", (s = "", s.LengthByte()), 0);
test_equal("\"abc\".LengthByte()", (s = "abc", s.LengthByte()), 3);
test_equal("\"あbc\".LengthByte()", (s = "あbc", s.LengthByte()), 4);
// S_EMPTY
test_bool("\"\".Empty()", (s = "", s.Empty()), true);
test_bool("\"a\".Empty()", (s = "a", s.Empty()), false);
// S_FIND
test_equal("\"abあいう\".Find(\"bあ\")", (s = "abあいう", s.Find("bあ")), 1);
test_equal("\"abあいう\".Find(\"bあ\")", (s = "abあいう", s.Find("い")), 3);
test_equal("\"abあいう\".Find(\"うえお\")", (s = "abあいう", s.Find("うえお")), -1);
// S_GETPART
test_string("\"abあいう\".GetPart(0, 0)", (s = "abあいう", s.GetPart(0, 0)), "");
test_string("\"abあいう\".GetPart(16, 2)", (s = "abあいう", s.GetPart(16, 2)), "");
test_string("\"abあいう\".GetPart(1, 3)", (s = "abあいう", s.GetPart(1, 3)), "bあい");
test_string("\"abあいう\".GetPart(-1, 3)", (s = "abあいう", s.GetPart(-1, 3)), "abあ");
test_string("\"abあいう\".GetPart(2, 16)", (s = "abあいう", s.GetPart(2, 16)), "あいう");
// S_PUSHBACK2
test_string("\"\".PushBack('a')", (s = "", s.PushBack('a'), s), "a");
test_string("\"あ\".PushBack('a')", (s = "あ", s.PushBack('a'), s), "あa");
// S_POPBACK2
test_string("\"あa\".PopBack()", (s = "あa", s.PopBack(), s), "あ");
test_string("\"あ\".PopBack()", (s = "あ", s.PopBack(), s), "");
// S_ERASE2
test_string("\"\".Erase(-1)", (s = "", s.Erase(-1), s), "");
test_string("\"\".Erase(0)", (s = "", s.Erase(0), s), "");
test_string("\"\".Erase(1)", (s = "", s.Erase(1), s), "");
test_string("\"a\".Erase(-1)", (s = "a", s.Erase(-1), s), "");
test_string("\"a\".Erase(0)", (s = "a", s.Erase(0), s), "");
test_string("\"a\".Erase(1)", (s = "a", s.Erase(1), s), "a");
test_string("\"あ\".Erase(-1)", (s = "あ", s.Erase(-1), s), "");
test_string("\"あ\".Erase(0)", (s = "あ", s.Erase(0), s), "");
test_string("\"あ\".Erase(1)", (s = "あ", s.Erase(1), s), "あ");
test_string("\"あbc\".Erase(1)", (s = "あbc", s.Erase(1), s), "あc");
// I_STRING
test_bool("(42).String()", (i = 42, i.String() == "42"), true);
// FTOS
test_bool("(4.2).String()", (f = 4.2, f.String() == "4.200000"), true);
test_bool("(4.222).String(2)", (f = 4.222, f.String(2) == "4.22"), true);
}