Skip to content

Commit

Permalink
directory: Fix rendering of directories
Browse files Browse the repository at this point in the history
Rendering variables in a directory requires spacing.
This also impacted the saving of any state with directories.

Also accept `DIR` to introduce directories.

Add the corresponding parsing and rendering tests.

Fixes: #1208

Signed-off-by: Christophe de Dinechin <christophe@dinechin.org>
  • Loading branch information
c3d committed Sep 26, 2024
1 parent b1d6415 commit f6ecdc3
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 44 deletions.
7 changes: 7 additions & 0 deletions src/tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,13 @@ void tests::data_types()
test(CHS).type(object::ID_neg_big_fraction).expect(mbf);
test(DOWN, CHS, ENTER).type(object::ID_big_fraction).expect(mbf+1);

step("Directory from command line")
.test(CLEAR, "DIR { A 2 B 3 }", ENTER)
.want("Directory { A 2 B 3 }");
step("Empty directory on command line")
.test(CLEAR, "DIR A 2 B 3", ENTER)
.got("3", "'B'", "2", "'A'", "Directory {}");

step("Graphic objects")
.test(CLEAR,
"GROB 9 15 "
Expand Down
122 changes: 78 additions & 44 deletions src/variables.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,61 +52,84 @@ PARSE_BODY(directory)
// A directory has the following structure:
// Directory { Name1 Value1 Name2 Value2 ... }
{
cstring ref = cstring(utf8(p.source));
size_t maxlen = p.length;
cstring ref = cstring(utf8(p.source));
size_t max = p.length;
cstring label = "directory";
size_t len = strlen(label);
if (len <= maxlen
&& strncasecmp(ref, label, len) == 0
&& is_separator(utf8(ref + len)))
size_t len = strlen(label);
bool isdir = false;

do
{
isdir = (len <= max
&& strncasecmp(ref, label, len) == 0
&& is_separator(utf8(ref + len)));
} while (!isdir && len > 3 && (len = 3));

if (isdir)
{
gcutf8 body = utf8(ref + len);
maxlen -= len;
if (object_g obj = object::parse(body, maxlen))
utf8 body = utf8(ref + len);
max -= len;
size_t ws = utf8_skip_whitespace(body, max);
if (ws < max && body[ws] == '{')
{
if (obj->type() == ID_list)
if (object_g obj = object::parse(body, max))
{
// Check that we only have names in there
uint count = 0;
gcbytes bytes = obj->payload();
byte_p ptr = bytes;
size_t size = leb128<size_t>(ptr);
gcbytes start = ptr;
size_t offset = 0;

// Loop on all objects inside the list
while (offset < size)
if (obj->type() == ID_list)
{
object_p obj = object_p(byte_p(start) + offset);
size_t objsize = obj->size();

if ((count & 1) == 0)
// Check that we only have names in there
uint count = 0;
gcbytes bytes = obj->payload();
byte_p ptr = bytes;
size_t size = leb128<size_t>(ptr);
gcbytes start = ptr;
size_t offset = 0;

// Loop on all objects inside the list
while (offset < size)
{
if (obj->type() != ID_symbol)
object_p obj = object_p(byte_p(start) + offset);
size_t objsize = obj->size();

if ((count & 1) == 0)
{
rt.error("Invalid name in directory").source(body);
return ERROR;
// In directories, we accept Eq as a name,
// and with the right option, we may have
// numbered variables as well
if (obj->arity() != 0)
{
body = p.source + len + ws;
rt.malformed_directory_error().source(body);
return ERROR;
}
}
count++;

// Loop on next object
offset += objsize;
}
count++;

// Loop on next object
offset += objsize;
}
// We should have an even number of items here
if (count & 1)
{
body = p.source + len + ws;
rt.malformed_directory_error().source(body);
return SKIP;
}

// We should have an even number of items here
if (count & 1)
{
rt.malformed_directory_error().source(body);
return SKIP;
// If we passed all these tests, build a directory
p.out = rt.make<directory>(ID_directory, start, size);
p.length = max + len;
return p.out ? OK : ERROR;
}

// If we passed all these tests, build a directory
p.out = rt.make<directory>(ID_directory, start, size);
p.length = maxlen + len;
return OK;
}
}
else
{
// The word 'DIR' alone denotes an empty directory on HP calculators
p.out = rt.make<directory>(ID_directory, rt.allocate(0), 0);
p.length = ws + len;
return p.out ? OK : ERROR;
}
}

return SKIP;
Expand All @@ -119,10 +142,21 @@ bool directory::render_name(object_p name, object_p obj, void *arg)
// ----------------------------------------------------------------------------
{
renderer &r = *((renderer *) arg);
r.wantCR();
name->render(r);
r.indent();
obj->render(r);
r.unindent();
if (obj->is_algebraic())
{
r.wantSpace();
obj->render(r);
}
else
{
r.indent();
r.wantCR();
obj->render(r);
r.unindent();
}
r.wantCR();
return true;
}

Expand Down

0 comments on commit f6ecdc3

Please sign in to comment.