summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ur/basis.urs3
-rw-r--r--src/c/urweb.c76
-rw-r--r--tests/megaform.ur67
-rw-r--r--tests/megaform.urp3
-rw-r--r--tests/megaform.urs1
5 files changed, 126 insertions, 24 deletions
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 117f944c..b59ab26a 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -508,6 +508,7 @@ con html = [Html]
con head = [Head]
con body = [Body]
con form = [Body, Form]
+con subform = [Body, Subform]
con tabl = [Body, Table]
con tr = [Body, Tr]
@@ -570,7 +571,7 @@ val subform : ctx ::: {Unit} -> use ::: {Type} -> bind ::: {Type}
val subforms : ctx ::: {Unit} -> use ::: {Type} -> bind ::: {Type}
-> [[Form] ~ ctx] =>
nm :: Name -> [[nm] ~ use] =>
- xml [Body, Subform] [Entry = $bind] []
+ xml subform [Entry = $bind] []
-> xml ([Form] ++ ctx) use [nm = list ($bind)]
val entry : ctx ::: {Unit} -> bind ::: {Type}
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 2d18be98..cc02b3d1 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -591,28 +591,28 @@ static input *INP(uw_context ctx) {
else if (ctx->cur_container->kind == ENTRY)
return ctx->cur_container->data.entry.fields;
else
- uw_error(ctx, FATAL, "INP: Wrong kind");
+ uw_error(ctx, FATAL, "INP: Wrong kind (%d, %p)", ctx->cur_container->kind, ctx->cur_container);
}
-static void adjust_input(input *x, size_t offset) {
+static void adjust_pointer(input **ptr, input *old_start, input *new_start, size_t len) {
+ if (*ptr != NULL && *ptr >= old_start && *ptr < old_start + len)
+ *ptr += new_start - old_start;
+}
+
+static void adjust_input(input *x, input *old_start, input *new_start, size_t len) {
switch (x->kind) {
case SUBFORM:
- x->data.subform.fields += offset;
- if (x->data.subform.parent != NULL)
- x->data.subform.parent += offset;
+ adjust_pointer(&x->data.subform.fields, old_start, new_start, len);
+ adjust_pointer(&x->data.subform.parent, old_start, new_start, len);
break;
case SUBFORMS:
- if (x->data.subforms.entries != NULL)
- x->data.subforms.entries += offset;
- if (x->data.subforms.parent != NULL)
- x->data.subforms.parent += offset;
+ adjust_pointer(&x->data.subforms.entries, old_start, new_start, len);
+ adjust_pointer(&x->data.subforms.parent, old_start, new_start, len);
break;
case ENTRY:
- x->data.entry.fields += offset;
- if (x->data.entry.next != NULL)
- x->data.entry.next += offset;
- if (x->data.entry.parent != NULL)
- x->data.entry.parent += offset;
+ adjust_pointer(&x->data.entry.fields, old_start, new_start, len);
+ adjust_pointer(&x->data.entry.next, old_start, new_start, len);
+ adjust_pointer(&x->data.entry.parent, old_start, new_start, len);
}
}
@@ -624,16 +624,17 @@ static input *check_input_space(uw_context ctx, size_t len) {
input *new_subinputs = realloc(ctx->subinputs, sizeof(input) * (ctx->used_subinputs + len));
size_t offset = new_subinputs - ctx->subinputs;
- for (i = 0; i < ctx->used_subinputs; ++i)
- adjust_input(&new_subinputs[i], offset);
- for (i = 0; i < uw_inputs_len; ++i)
- adjust_input(&ctx->inputs[i], offset);
+ if (ctx->subinputs != new_subinputs) {
+ for (i = 0; i < ctx->used_subinputs; ++i)
+ adjust_input(&new_subinputs[i], ctx->subinputs, new_subinputs, ctx->used_subinputs);
+ for (i = 0; i < uw_inputs_len; ++i)
+ adjust_input(&ctx->inputs[i], ctx->subinputs, new_subinputs, ctx->used_subinputs);
- if (ctx->cur_container >= ctx->subinputs && ctx->cur_container < ctx->subinputs + ctx->n_subinputs)
- ctx->cur_container += offset;
+ adjust_pointer(&ctx->cur_container, ctx->subinputs, new_subinputs, ctx->used_subinputs);
- ctx->n_subinputs = ctx->used_subinputs + len;
- ctx->subinputs = new_subinputs;
+ ctx->n_subinputs = ctx->used_subinputs + len;
+ ctx->subinputs = new_subinputs;
+ }
}
r = &ctx->subinputs[ctx->used_subinputs];
@@ -791,6 +792,35 @@ void uw_set_file_input(uw_context ctx, const char *name, uw_Basis_file f) {
void *uw_malloc(uw_context ctx, size_t len);
+
+static void parents(input *inp) {
+ printf("Stack: %p\n", inp);
+ while (inp) {
+ switch (inp->kind) {
+ case NORMAL:
+ printf("Normal(%p)\n", inp);
+ break;
+ case FIL:
+ printf("File(%p)\n", inp);
+ break;
+ case SUBFORM:
+ printf("Subform; fields = %p\n", inp->data.subform.fields);
+ inp = inp->data.subform.parent;
+ break;
+ case SUBFORMS:
+ printf("Subforms; entries = %p\n", inp->data.subforms.entries);
+ inp = inp->data.subforms.parent;
+ break;
+ case ENTRY:
+ printf("Entry; fields = %p; next = %p\n", inp->data.entry.fields, inp->data.entry.next);
+ inp = inp->data.entry.parent;
+ break;
+ default:
+ inp = NULL;
+ }
+ }
+}
+
uw_Basis_file uw_get_file_input(uw_context ctx, int n) {
if (n < 0)
uw_error(ctx, FATAL, "Negative file input index %d", n);
@@ -838,7 +868,7 @@ void uw_enter_subform(uw_context ctx, int n) {
uw_error(ctx, FATAL, "Tried to read an entry form input as subform");
case SUBFORM:
INP(ctx)[n].data.subform.parent = ctx->cur_container;
- ctx->cur_container = INP(ctx)[n].data.subform.fields;
+ ctx->cur_container = &INP(ctx)[n];
return;
default:
uw_error(ctx, FATAL, "Impossible input kind");
diff --git a/tests/megaform.ur b/tests/megaform.ur
new file mode 100644
index 00000000..2db2f678
--- /dev/null
+++ b/tests/megaform.ur
@@ -0,0 +1,67 @@
+fun handler'' ls =
+ case ls of
+ Nil => <xml/>
+ | Cons (r, ls) => <xml><li>{[r.C]}</li>{handler'' ls}</xml>
+
+fun handler' ls =
+ case ls of
+ Nil => <xml/>
+ | Cons (r, ls) => <xml><li>{[r.Sub.A]} <ul>{handler'' r.Sub.Sub2}</ul></li>{handler' ls}</xml>
+
+fun handler r = return <xml><body>
+ {[r.A]}
+ <ul>{handler' r.Sub}</ul>
+ {[r.C]}<br/>
+ {[r.Sub2.A]}<br/>
+ {handler'' r.Sub2.Nested}
+</body></xml>
+
+fun main () = return <xml><body>
+ <form>
+ <textbox{#A}/><br/>
+ <subforms{#Sub}>
+ <entry>
+ <subform{#Sub}>
+ <textbox{#A}/><br/>
+ <subforms{#Sub2}>
+ <entry>
+ <textbox{#C}/><br/>
+ </entry>
+
+ <entry>
+ <textbox{#C}/><br/>
+ </entry>
+ </subforms>
+ </subform>
+ </entry>
+
+ <entry>
+ <subform{#Sub}>
+ <textbox{#A}/><br/>
+ <subforms{#Sub2}>
+ <entry>
+ <textbox{#C}/><br/>
+ </entry>
+
+ <entry>
+ <textbox{#C}/><br/>
+ </entry>
+ </subforms>
+ </subform>
+ </entry>
+ </subforms>
+ <textbox{#C}/><br/>
+
+ <subform{#Sub2}>
+ <textbox{#A}/><br/>
+
+ <subforms{#Nested}>
+ <entry>
+ <textbox{#C}/>
+ </entry>
+ </subforms>
+ </subform><br/>
+
+ <submit action={handler}/>
+ </form>
+</body></xml>
diff --git a/tests/megaform.urp b/tests/megaform.urp
new file mode 100644
index 00000000..714ede1c
--- /dev/null
+++ b/tests/megaform.urp
@@ -0,0 +1,3 @@
+debug
+
+megaform
diff --git a/tests/megaform.urs b/tests/megaform.urs
new file mode 100644
index 00000000..6ac44e0b
--- /dev/null
+++ b/tests/megaform.urs
@@ -0,0 +1 @@
+val main : unit -> transaction page