diff options
-rw-r--r-- | include/lacweb.h | 3 | ||||
-rw-r--r-- | src/c/driver.c | 30 | ||||
-rw-r--r-- | src/c/lacweb.c | 85 | ||||
-rw-r--r-- | src/cjr.sml | 2 | ||||
-rw-r--r-- | src/cjr_print.sml | 410 | ||||
-rw-r--r-- | src/cjrize.sml | 4 | ||||
-rw-r--r-- | src/core.sml | 6 | ||||
-rw-r--r-- | src/core_print.sig | 1 | ||||
-rw-r--r-- | src/core_print.sml | 17 | ||||
-rw-r--r-- | src/corify.sml | 2 | ||||
-rw-r--r-- | src/mono.sml | 2 | ||||
-rw-r--r-- | src/mono_print.sml | 24 | ||||
-rw-r--r-- | src/mono_shake.sml | 2 | ||||
-rw-r--r-- | src/mono_util.sml | 4 | ||||
-rw-r--r-- | src/monoize.sml | 4 | ||||
-rw-r--r-- | src/shake.sml | 2 | ||||
-rw-r--r-- | src/tag.sml | 30 | ||||
-rw-r--r-- | tests/form2.lac | 25 | ||||
-rw-r--r-- | tests/form3.lac | 39 | ||||
-rw-r--r-- | tests/link.lac | 4 | ||||
-rw-r--r-- | tests/plink.lac | 2 |
21 files changed, 546 insertions, 152 deletions
diff --git a/include/lacweb.h b/include/lacweb.h index 0d256f61..09f002fd 100644 --- a/include/lacweb.h +++ b/include/lacweb.h @@ -12,6 +12,9 @@ void lw_reset(lw_context); void *lw_malloc(lw_context, size_t); int lw_send(lw_context, int sock); +void lw_set_input(lw_context, char *name, char *value); +char *lw_get_input(lw_context, int name); + void lw_write(lw_context, const char*); diff --git a/src/c/driver.c b/src/c/driver.c index ac0b0c86..af3bca08 100644 --- a/src/c/driver.c +++ b/src/c/driver.c @@ -86,9 +86,11 @@ static void *worker(void *data) { *back = 0; if (s = strstr(buf, "\r\n\r\n")) { - char *cmd, *path; + char *cmd, *path, *inputs; *s = 0; + + printf("Read: %s\n", buf); if (!(s = strstr(buf, "\r\n"))) { fprintf(stderr, "No newline in buf\n"); @@ -114,9 +116,33 @@ static void *worker(void *data) { break; } + if (inputs = strchr(path, '?')) { + char *name, *value; + *inputs++ = 0; + + while (*inputs) { + name = inputs; + if (value = strchr(inputs, '=')) { + *value++ = 0; + if (inputs = strchr(value, '&')) + *inputs++ = 0; + else + inputs = strchr(value, 0); + lw_set_input(ctx, name, value); + } + else if (inputs = strchr(value, '&')) { + *inputs++ = 0; + lw_set_input(ctx, name, ""); + } + else { + inputs = strchr(value, 0); + lw_set_input(ctx, name, ""); + } + } + } + printf("Serving URI %s....\n", path); - ctx = lw_init(1024, 1024); lw_write (ctx, "HTTP/1.1 200 OK\r\n"); lw_write(ctx, "Content-type: text/html\r\n\r\n"); lw_write(ctx, "<html>"); diff --git a/src/c/lacweb.c b/src/c/lacweb.c index 2b806f86..9543c642 100644 --- a/src/c/lacweb.c +++ b/src/c/lacweb.c @@ -11,8 +11,11 @@ lw_unit lw_unit_v = {}; struct lw_context { char *page, *page_front, *page_back; char *heap, *heap_front, *heap_back; + char **inputs; }; +extern int lw_inputs_len; + lw_context lw_init(size_t page_len, size_t heap_len) { lw_context ctx = malloc(sizeof(struct lw_context)); @@ -22,18 +25,45 @@ lw_context lw_init(size_t page_len, size_t heap_len) { ctx->heap_front = ctx->heap = malloc(heap_len); ctx->heap_back = ctx->heap_front + heap_len; + ctx->inputs = calloc(lw_inputs_len, sizeof(char *)); + return ctx; } void lw_free(lw_context ctx) { free(ctx->page); free(ctx->heap); + free(ctx->inputs); free(ctx); } void lw_reset(lw_context ctx) { ctx->page_front = ctx->page; ctx->heap_front = ctx->heap; + memset(ctx->inputs, 0, lw_inputs_len * sizeof(char *)); +} + +int lw_input_num(char*); + +void lw_set_input(lw_context ctx, char *name, char *value) { + int n = lw_input_num(name); + + if (n < 0) { + printf("Bad input name"); + exit(1); + } + + assert(n < lw_inputs_len); + ctx->inputs[n] = value; + + printf("[%d] %s = %s\n", n, name, value); +} + +char *lw_get_input(lw_context ctx, int n) { + assert(n >= 0); + assert(n < lw_inputs_len); + printf("[%d] = %s\n", n, ctx->inputs[n]); + return ctx->inputs[n]; } static void lw_check_heap(lw_context ctx, size_t extra) { @@ -294,14 +324,20 @@ void lw_Basis_urlifyString_w(lw_context ctx, lw_Basis_string s) { } -lw_Basis_int lw_unurlifyInt(char **s) { - char *new_s = strchr(*s, '/'); - int r; +static char *lw_unurlify_advance(char *s) { + char *new_s = strchr(s, '/'); if (new_s) *new_s++ = 0; else - new_s = strchr(*s, 0); + new_s = strchr(s, 0); + + return new_s; +} + +lw_Basis_int lw_unurlifyInt(char **s) { + char *new_s = lw_unurlify_advance(*s); + int r; r = atoi(*s); *s = new_s; @@ -309,34 +345,19 @@ lw_Basis_int lw_unurlifyInt(char **s) { } lw_Basis_float lw_unurlifyFloat(char **s) { - char *new_s = strchr(*s, '/'); + char *new_s = lw_unurlify_advance(*s); int r; - if (new_s) - *new_s++ = 0; - else - new_s = strchr(*s, 0); - r = atof(*s); *s = new_s; return r; } -lw_Basis_string lw_unurlifyString(lw_context ctx, char **s) { - char *new_s = strchr(*s, '/'); - char *r, *s1, *s2; - int len, n; +static lw_Basis_string lw_unurlifyString_to(char *r, char *s) { + char *s1, *s2; + int n; - if (new_s) - *new_s++ = 0; - else - new_s = strchr(*s, 0); - - len = strlen(*s); - lw_check_heap(ctx, len + 1); - - r = ctx->heap_front; - for (s1 = r, s2 = *s; *s2; ++s1, ++s2) { + for (s1 = r, s2 = s; *s2; ++s1, ++s2) { char c = *s2; switch (c) { @@ -344,7 +365,7 @@ lw_Basis_string lw_unurlifyString(lw_context ctx, char **s) { *s1 = ' '; break; case '%': - assert(s2 + 2 < new_s); + assert(s2[1] != 0 && s2[2] != 0); sscanf(s2+1, "%02X", &n); *s1 = n; s2 += 2; @@ -354,7 +375,19 @@ lw_Basis_string lw_unurlifyString(lw_context ctx, char **s) { } } *s1++ = 0; - ctx->heap_front = s1; + return s1; +} + +lw_Basis_string lw_unurlifyString(lw_context ctx, char **s) { + char *new_s = lw_unurlify_advance(*s); + char *r, *s1, *s2; + int len, n; + + len = strlen(*s); + lw_check_heap(ctx, len + 1); + + r = ctx->heap_front; + ctx->heap_front = lw_unurlifyString_to(ctx->heap_front, *s); *s = new_s; return r; } diff --git a/src/cjr.sml b/src/cjr.sml index 8e8e6cab..129ff4e9 100644 --- a/src/cjr.sml +++ b/src/cjr.sml @@ -62,6 +62,6 @@ datatype decl' = withtype decl = decl' located -type file = decl list * (string * int * typ list) list +type file = decl list * (Core.export_kind * string * int * typ list) list end diff --git a/src/cjr_print.sml b/src/cjr_print.sml index 218fcdee..f483d400 100644 --- a/src/cjr_print.sml +++ b/src/cjr_print.sml @@ -37,6 +37,20 @@ open Cjr structure E = CjrEnv structure EM = ErrorMsg +structure SK = struct +type ord_key = string +val compare = String.compare +end + +structure SS = BinarySetFn(SK) +structure SM = BinaryMapFn(SK) +structure IS = IntBinarySet + +structure CM = BinaryMapFn(struct + type ord_key = char + val compare = Char.compare + end) + val debug = ref false val dummyTyp = (TNamed 0, ErrorMsg.dummySpan) @@ -208,90 +222,11 @@ fun p_decl env (dAll as (d, _) : decl) = newline] end -fun unurlify env (t, loc) = - case t of - TFfi ("Basis", "int") => string "lw_unurlifyInt(&request)" - | TFfi ("Basis", "float") => string "lw_unurlifyFloat(&request)" - | TFfi ("Basis", "string") => string "lw_unurlifyString(ctx, &request)" +datatype 'a search = + Found of 'a + | NotFound + | Error - | TRecord 0 => string "lw_unit_v" - | TRecord i => - let - val xts = E.lookupStruct env i - in - box [string "({", - newline, - box (map (fn (x, t) => - box [p_typ env t, - space, - string x, - space, - string "=", - space, - unurlify env t, - string ";", - newline]) xts), - string "struct", - space, - string "__lws_", - string (Int.toString i), - space, - string "__lw_tmp", - space, - string "=", - space, - string "{", - space, - p_list_sep (box [string ",", space]) (fn (x, _) => string x) xts, - space, - string "};", - newline, - string "__lw_tmp;", - newline, - string "})"] - end - - | _ => (ErrorMsg.errorAt loc "Unable to choose a URL decoding function"; - space) - -fun p_page env (s, n, ts) = - box [string "if (!strncmp(request, \"", - string (String.toString s), - string "\", ", - string (Int.toString (size s)), - string ")) {", - newline, - string "request += ", - string (Int.toString (size s)), - string ";", - newline, - string "if (*request == '/') ++request;", - newline, - box [string "{", - newline, - box (ListUtil.mapi (fn (i, t) => box [p_typ env t, - space, - string "arg", - string (Int.toString i), - space, - string "=", - space, - unurlify env t, - string ";", - newline]) ts), - p_enamed env n, - string "(", - p_list_sep (box [string ",", space]) - (fn x => x) - (string "ctx" :: ListUtil.mapi (fn (i, _) => string ("arg" ^ Int.toString i)) ts), - string ");", - newline, - string "return;", - newline, - string "}", - newline, - string "}"] - ] fun p_file env (ds, ps) = let @@ -299,13 +234,318 @@ fun p_file env (ds, ps) = (p_decl env d, E.declBinds env d)) env ds - val pds' = map (p_page env) ps + + val fields = foldl (fn ((ek, _, _, ts), fields) => + case ek of + Core.Link => fields + | Core.Action => + case List.last ts of + (TRecord i, _) => + let + val xts = E.lookupStruct env i + val xtsSet = SS.addList (SS.empty, map #1 xts) + in + foldl (fn ((x, _), fields) => + let + val xtsSet' = Option.getOpt (SM.find (fields, x), SS.empty) + in + SM.insert (fields, x, SS.union (SS.delete (xtsSet, x), + xtsSet')) + end) fields xts + end + | _ => raise Fail "CjrPrint: Last argument of action isn't record") + SM.empty ps + + val fnums = SM.foldli (fn (x, xs, fnums) => + let + val unusable = SS.foldl (fn (x', unusable) => + case SM.find (fnums, x') of + NONE => unusable + | SOME n => IS.add (unusable, n)) + IS.empty xs + + fun findAvailable n = + if IS.member (unusable, n) then + findAvailable (n + 1) + else + n + in + SM.insert (fnums, x, findAvailable 0) + end) + SM.empty fields + + fun makeSwitch (fnums, i) = + case SM.foldl (fn (n, NotFound) => Found n + | (n, Error) => Error + | (n, Found n') => if n = n' then + Found n' + else + Error) NotFound fnums of + NotFound => box [string "return", + space, + string "-1;"] + | Found n => box [string "return", + space, + string (Int.toString n), + string ";"] + | Error => + let + val cmap = SM.foldli (fn (x, n, cmap) => + let + val ch = if i < size x then + String.sub (x, i) + else + chr 0 + + val fnums = case CM.find (cmap, ch) of + NONE => SM.empty + | SOME fnums => fnums + val fnums = SM.insert (fnums, x, n) + in + CM.insert (cmap, ch, fnums) + end) + CM.empty fnums + + val cmap = CM.listItemsi cmap + in + case cmap of + [(_, fnums)] => + box [string "if", + space, + string "(name[", + string (Int.toString i), + string "]", + space, + string "==", + space, + string "0)", + space, + string "return", + space, + string "-1;", + newline, + makeSwitch (fnums, i+1)] + | _ => + box [string "switch", + space, + string "(name[", + string (Int.toString i), + string "])", + space, + string "{", + newline, + box (map (fn (ch, fnums) => + box [string "case", + space, + if ch = chr 0 then + string "0:" + else + box [string "'", + string (Char.toString ch), + string "':"], + newline, + makeSwitch (fnums, i+1), + newline]) cmap), + string "default:", + newline, + string "return", + space, + string "-1;", + newline, + string "}"] + end + + fun unurlify (t, loc) = + case t of + TFfi ("Basis", "int") => string "lw_unurlifyInt(&request)" + | TFfi ("Basis", "float") => string "lw_unurlifyFloat(&request)" + | TFfi ("Basis", "string") => string "lw_unurlifyString(ctx, &request)" + + | TRecord 0 => string "lw_unit_v" + | TRecord i => + let + val xts = E.lookupStruct env i + in + box [string "({", + newline, + box (map (fn (x, t) => + box [p_typ env t, + space, + string x, + space, + string "=", + space, + unurlify t, + string ";", + newline]) xts), + string "struct", + space, + string "__lws_", + string (Int.toString i), + space, + string "__lw_tmp", + space, + string "=", + space, + string "{", + space, + p_list_sep (box [string ",", space]) (fn (x, _) => string x) xts, + space, + string "};", + newline, + string "__lw_tmp;", + newline, + string "})"] + end + + | _ => (ErrorMsg.errorAt loc "Unable to choose a URL decoding function"; + space) + + + fun p_page (ek, s, n, ts) = + let + val (ts, defInputs, inputsVar) = + case ek of + Core.Link => (ts, string "", string "") + | Core.Action => + case List.last ts of + (TRecord i, _) => + let + val xts = E.lookupStruct env i + in + (List.drop (ts, 1), + box [box (map (fn (x, t) => box [p_typ env t, + space, + string "lw_input_", + string x, + string ";", + newline]) xts), + newline, + box (map (fn (x, t) => + let + val n = case SM.find (fnums, x) of + NONE => raise Fail "CjrPrint: Can't find in fnums" + | SOME n => n + in + box [string "request = lw_get_input(ctx, ", + string (Int.toString n), + string ");", + newline, + string "if (request == NULL) {", + newline, + box [string "printf(\"Missing input ", + string x, + string "\\n\");", + newline, + string "exit(1);"], + newline, + string "}", + newline, + string "lw_input_", + string x, + space, + string "=", + space, + unurlify t, + string ";", + newline] + end) xts), + string "struct __lws_", + string (Int.toString i), + space, + string "lw_inputs", + space, + string "= {", + newline, + box (map (fn (x, _) => box [string "lw_input_", + string x, + string ",", + newline]) xts), + string "};", + newline], + box [string ",", + space, + string "lw_inputs"]) + end + + | _ => raise Fail "CjrPrint: Last argument to an action isn't a record" + in + box [string "if (!strncmp(request, \"", + string (String.toString s), + string "\", ", + string (Int.toString (size s)), + string ")) {", + newline, + string "request += ", + string (Int.toString (size s)), + string ";", + newline, + string "if (*request == '/') ++request;", + newline, + box [string "{", + newline, + box (ListUtil.mapi (fn (i, t) => box [p_typ env t, + space, + string "arg", + string (Int.toString i), + space, + string "=", + space, + unurlify t, + string ";", + newline]) ts), + defInputs, + p_enamed env n, + string "(", + p_list_sep (box [string ",", space]) + (fn x => x) + (string "ctx" :: ListUtil.mapi (fn (i, _) => string ("arg" ^ Int.toString i)) ts), + inputsVar, + string ");", + newline, + string "return;", + newline, + string "}", + newline, + string "}"] + ] + end + + val pds' = map p_page ps in - box [string "#include \"lacweb.h\"", + box [string "#include <stdio.h>", + newline, + string "#include <stdlib.h>", + newline, + newline, + string "#include \"lacweb.h\"", newline, newline, p_list_sep newline (fn x => x) pds, newline, + string "int lw_inputs_len = ", + string (Int.toString (SM.foldl Int.max 0 fnums + 1)), + string ";", + newline, + newline, + string "int lw_input_num(char *name) {", + newline, + string "if", + space, + string "(name[0]", + space, + string "==", + space, + string "0)", + space, + string "return", + space, + string "-1;", + newline, + makeSwitch (fnums, 0), + string "}", + newline, + newline, string "void lw_handle(lw_context ctx, char *request) {", newline, p_list_sep newline (fn x => x) pds', diff --git a/src/cjrize.sml b/src/cjrize.sml index cb2557f6..6796b467 100644 --- a/src/cjrize.sml +++ b/src/cjrize.sml @@ -225,11 +225,11 @@ fun cifyDecl ((d, loc), sm) = (SOME (L'.DFunRec vis, loc), NONE, sm) end - | L.DExport (s, n, ts) => + | L.DExport (ek, s, n, ts) => let val (ts, sm) = ListUtil.foldlMap cifyTyp sm ts in - (NONE, SOME ("/" ^ s, n, ts), sm) + (NONE, SOME (ek, "/" ^ s, n, ts), sm) end fun cjrize ds = diff --git a/src/core.sml b/src/core.sml index 448113cc..ffd149f3 100644 --- a/src/core.sml +++ b/src/core.sml @@ -80,11 +80,15 @@ datatype exp' = withtype exp = exp' located +datatype export_kind = + Link + | Action + datatype decl' = DCon of string * int * kind * con | DVal of string * int * con * exp * string | DValRec of (string * int * con * exp * string) list - | DExport of int + | DExport of export_kind * int withtype decl = decl' located diff --git a/src/core_print.sig b/src/core_print.sig index ecc7fdeb..1899ce15 100644 --- a/src/core_print.sig +++ b/src/core_print.sig @@ -33,6 +33,7 @@ signature CORE_PRINT = sig val p_exp : CoreEnv.env -> Core.exp Print.printer val p_decl : CoreEnv.env -> Core.decl Print.printer val p_file : CoreEnv.env -> Core.file Print.printer + val p_export_kind : Core.export_kind Print.printer val debug : bool ref end diff --git a/src/core_print.sml b/src/core_print.sml index 3436d313..590b90fd 100644 --- a/src/core_print.sml +++ b/src/core_print.sml @@ -264,6 +264,11 @@ fun p_vali env (x, n, t, e, s) = p_exp env e] end +fun p_export_kind ck = + case ck of + Link => string "link" + | Action => string "action" + fun p_decl env (dAll as (d, _) : decl) = case d of DCon (x, n, k, c) => @@ -300,9 +305,15 @@ fun p_decl env (dAll as (d, _) : decl) = space, p_list_sep (box [newline, string "and", space]) (p_vali env) vis] end - | DExport n => box [string "export", - space, - p_enamed env n] + | DExport (ek, n) => box [string "export", + space, + p_export_kind ek, + space, + p_enamed env n, + space, + string "as", + space, + p_con env (#2 (E.lookupENamed env n))] fun p_file env file = let diff --git a/src/corify.sml b/src/corify.sml index 719b4215..d1b44384 100644 --- a/src/corify.sml +++ b/src/corify.sml @@ -496,7 +496,7 @@ fun corifyDecl ((d, loc : EM.span), st) = e), loc) :: wds, (fn st => case #1 (corifyExp st (L.EModProj (en, [], "wrap_" ^ s), loc)) of - L'.ENamed n => (L'.DExport n, loc) + L'.ENamed n => (L'.DExport (L'.Link, n), loc) | _ => raise Fail "Corify: Value to export didn't corify properly") :: eds) end diff --git a/src/mono.sml b/src/mono.sml index 22a5a8e0..13ba3adf 100644 --- a/src/mono.sml +++ b/src/mono.sml @@ -62,7 +62,7 @@ withtype exp = exp' located datatype decl' = DVal of string * int * typ * exp * string | DValRec of (string * int * typ * exp * string) list - | DExport of string * int * typ list + | DExport of Core.export_kind * string * int * typ list withtype decl = decl' located diff --git a/src/mono_print.sml b/src/mono_print.sml index 6f9c1b66..c485e3c8 100644 --- a/src/mono_print.sml +++ b/src/mono_print.sml @@ -178,17 +178,19 @@ fun p_decl env (dAll as (d, _) : decl) = p_list_sep (box [newline, string "and", space]) (p_vali env) vis] end - | DExport (s, n, ts) => box [string "export", - space, - p_enamed env n, - space, - string "as", - space, - string s, - p_list_sep (string "") (fn t => box [space, - string "(", - p_typ env t, - string ")"]) ts] + | DExport (ek, s, n, ts) => box [string "export", + space, + CorePrint.p_export_kind ek, + space, + p_enamed env n, + space, + string "as", + space, + string s, + p_list_sep (string "") (fn t => box [space, + string "(", + p_typ env t, + string ")"]) ts] fun p_file env file = let diff --git a/src/mono_shake.sml b/src/mono_shake.sml index b5b45a0e..76d05061 100644 --- a/src/mono_shake.sml +++ b/src/mono_shake.sml @@ -44,7 +44,7 @@ type free = { fun shake file = let val page_es = List.foldl - (fn ((DExport (_, n, _), _), page_es) => n :: page_es + (fn ((DExport (_, _, n, _), _), page_es) => n :: page_es | (_, page_es) => page_es) [] file val (cdef, edef) = foldl (fn ((DVal (_, n, t, e, _), _), (cdef, edef)) => (cdef, IM.insert (edef, n, (t, e))) diff --git a/src/mono_util.sml b/src/mono_util.sml index 99393b10..2395cc90 100644 --- a/src/mono_util.sml +++ b/src/mono_util.sml @@ -266,10 +266,10 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} = S.map2 (ListUtil.mapfold (mfvi ctx) vis, fn vis' => (DValRec vis', loc)) - | DExport (s, n, ts) => + | DExport (ek, s, n, ts) => S.map2 (ListUtil.mapfold mft ts, fn ts' => - (DExport (s, n, ts'), loc)) + (DExport (ek, s, n, ts'), loc)) and mfvi ctx (x, n, t, e, s) = S.bind2 (mft t, diff --git a/src/monoize.sml b/src/monoize.sml index dbe69c6a..e6c6b6c8 100644 --- a/src/monoize.sml +++ b/src/monoize.sml @@ -383,7 +383,7 @@ fun monoDecl env (all as (d, loc)) = SOME (env, (L'.DValRec (map (fn (x, n, t, e, s) => (x, n, monoType env t, monoExp env e, s)) vis), loc)) end - | L.DExport n => + | L.DExport (ek, n) => let val (_, t, _, s) = Env.lookupENamed env n @@ -394,7 +394,7 @@ fun monoDecl env (all as (d, loc)) = val ts = map (monoType env) (unwind t) in - SOME (env, (L'.DExport (s, n, ts), loc)) + SOME (env, (L'.DExport (ek, s, n, ts), loc)) end end diff --git a/src/shake.sml b/src/shake.sml index 038dc8f9..693385d9 100644 --- a/src/shake.sml +++ b/src/shake.sml @@ -44,7 +44,7 @@ type free = { fun shake file = let val page_es = List.foldl - (fn ((DExport n, _), page_es) => n :: page_es + (fn ((DExport (_, n), _), page_es) => n :: page_es | (_, page_es) => page_es) [] file val (cdef, edef) = foldl (fn ((DCon (_, n, _, c), _), (cdef, edef)) => (IM.insert (cdef, n, c), edef) diff --git a/src/tag.sml b/src/tag.sml index 3bd9f3f1..c61fc23f 100644 --- a/src/tag.sml +++ b/src/tag.sml @@ -66,7 +66,7 @@ fun exp env (e, s) = val (xets, s) = ListUtil.foldlMap (fn ((x, e, t), (count, tags, byTag, newTags)) => let - fun tagIt newAttr = + fun tagIt (ek, newAttr) = let fun unravel (e, _) = case e of @@ -88,20 +88,25 @@ fun exp env (e, s) = case IM.find (tags, f) of NONE => (count, count + 1, IM.insert (tags, f, count), - (f, count) :: newTags) + (ek, f, count) :: newTags) | SOME cn => (cn, count, tags, newTags) val (_, _, _, s) = E.lookupENamed env f val byTag = case SM.find (byTag, s) of - NONE => SM.insert (byTag, s, f) - | SOME f' => + NONE => SM.insert (byTag, s, (ek, f)) + | SOME (ek', f') => (if f = f' then () else ErrorMsg.errorAt loc ("Duplicate HTTP tag " ^ s); + if ek = ek' then + () + else + ErrorMsg.errorAt loc + "Function needed as both a link and a form "; byTag) val e = (EClosure (cn, args), loc) @@ -112,8 +117,8 @@ fun exp env (e, s) = end in case x of - (CName "Link", _) => tagIt "Href" - | (CName "Action", _) => tagIt "Action" + (CName "Link", _) => tagIt (Link, "Href") + | (CName "Action", _) => tagIt (Action, "Action") | _ => ((x, e, t), (count, tags, byTag, newTags)) end) s xets @@ -154,13 +159,18 @@ fun tag file = fun doDecl (d as (d', loc), (env, count, tags, byTag)) = case d' of - DExport n => + DExport (ek, n) => let val (_, _, _, s) = E.lookupENamed env n in case SM.find (byTag, s) of NONE => ([d], (env, count, tags, byTag)) - | SOME n' => ([], (env, count, tags, byTag)) + | SOME (ek', n') => + (if ek = ek' then + () + else + ErrorMsg.errorAt loc "Function needed for both a link and a form"; + ([], (env, count, tags, byTag))) end | _ => let @@ -179,7 +189,7 @@ fun tag file = val env = env' val newDs = map - (fn (f, cn) => + (fn (ek, f, cn) => let fun unravel (all as (t, _)) = case t of @@ -225,7 +235,7 @@ fun tag file = end in (("wrap_" ^ fnam, cn, t, abs, tag), - (DExport cn, loc)) + (DExport (ek, cn), loc)) end) newTags val (newVals, newExports) = ListPair.unzip newDs diff --git a/tests/form2.lac b/tests/form2.lac new file mode 100644 index 00000000..d3ea4736 --- /dev/null +++ b/tests/form2.lac @@ -0,0 +1,25 @@ +val handler1 = fn r => <html><body> + <li> Name: {cdata r.Nam}</li> + <li> Word: {cdata r.Word}</li> +</body></html> + +val handler2 = fn r => <html><body> + <li> Name: {cdata r.Nam}</li> + <li> Ward: {cdata r.Ward}</li> +</body></html> + +val main : unit -> page = fn () => <html><body> + <lform> + Name: <textbox{#Nam} /><br/> + Word: <textbox{#Word} /><br/> + + <submit action={handler1}/> + </lform> + + <lform> + Name: <textbox{#Nam} /><br/> + Word: <textbox{#Ward} /><br/> + + <submit action={handler2}/> + </lform> +</body></html> diff --git a/tests/form3.lac b/tests/form3.lac new file mode 100644 index 00000000..3c0915f7 --- /dev/null +++ b/tests/form3.lac @@ -0,0 +1,39 @@ +val handler1 = fn r => <html><body> + <li> Name: {cdata r.Nam}</li> + <li> Word: {cdata r.Word}</li> +</body></html> + +val handler2 = fn r => <html><body> + <li> Name: {cdata r.Nam}</li> + <li> Ward: {cdata r.Ward}</li> +</body></html> + +val handler3 = fn r => <html><body> + <li> Name: {cdata r.Nam}</li> + <li> Ward: {cdata r.Ward}</li> + <li> Words: {cdata r.Words}</li> +</body></html> + +val main : unit -> page = fn () => <html><body> + <lform> + Name: <textbox{#Nam} /><br/> + Word: <textbox{#Word} /><br/> + + <submit action={handler1}/> + </lform> + + <lform> + Name: <textbox{#Nam} /><br/> + Word: <textbox{#Ward} /><br/> + + <submit action={handler2}/> + </lform> + + <lform> + Name: <textbox{#Nam} /><br/> + Ward: <textbox{#Ward} /><br/> + Words: <textbox{#Words} /><br/> + + <submit action={handler3}/> + </lform> +</body></html> diff --git a/tests/link.lac b/tests/link.lac index 8d806c54..26f093ed 100644 --- a/tests/link.lac +++ b/tests/link.lac @@ -1,7 +1,7 @@ -val ancillary : {} -> xhtml = fn () => <html> +val ancillary = fn () => <html> Welcome to the ancillary page! </html> -val main : {} -> xhtml = fn () => <html><body> +val main : unit -> page = fn () => <html><body> <a link={ancillary ()}>Enter the unknown!</a> </body></html> diff --git a/tests/plink.lac b/tests/plink.lac index 9601f08a..eda255f4 100644 --- a/tests/plink.lac +++ b/tests/plink.lac @@ -2,7 +2,7 @@ val pA = fn size => <html><body> <font size={size}>Hello World!</font> </body></html> -val main = fn () => <html><body> +val main : unit -> page = fn () => <html><body> <li> <a link={pA 5}>Size 5</a></li> <li> <a link={pA 10}>Size 10</a></li> </body></html> |