# HG changeset patch # User Adam Chlipala # Date 1243355106 14400 # Node ID 395a5d450cc06ee2274e3732688556683cd8c518 # Parent 91f465ded07eebb3b1f68a2edf871ec24958cd56 Chars and more string operations diff -r 91f465ded07e -r 395a5d450cc0 include/types.h --- a/include/types.h Sat May 23 10:14:51 2009 -0400 +++ b/include/types.h Tue May 26 12:25:06 2009 -0400 @@ -6,6 +6,7 @@ typedef long long uw_Basis_int; typedef double uw_Basis_float; typedef char* uw_Basis_string; +typedef char uw_Basis_char; typedef time_t uw_Basis_time; typedef struct { size_t size; diff -r 91f465ded07e -r 395a5d450cc0 include/urweb.h --- a/include/urweb.h Sat May 23 10:14:51 2009 -0400 +++ b/include/urweb.h Tue May 26 12:25:06 2009 -0400 @@ -111,6 +111,8 @@ uw_Basis_bool uw_Basis_unurlifyBool(uw_context, char **); uw_Basis_time uw_Basis_unurlifyTime(uw_context, char **); +uw_Basis_char uw_Basis_strsub(uw_context, const char *, uw_Basis_int); +uw_Basis_string uw_Basis_strsuffix(uw_context, const char *, uw_Basis_int); uw_Basis_string uw_Basis_strcat(uw_context, const char *, const char *); uw_Basis_string uw_strdup(uw_context, const char *); uw_Basis_string uw_maybe_strdup(uw_context, const char *); @@ -138,16 +140,19 @@ uw_Basis_string uw_Basis_intToString(uw_context, uw_Basis_int); uw_Basis_string uw_Basis_floatToString(uw_context, uw_Basis_float); +uw_Basis_string uw_Basis_charToString(uw_context, uw_Basis_char); uw_Basis_string uw_Basis_boolToString(uw_context, uw_Basis_bool); uw_Basis_string uw_Basis_timeToString(uw_context, uw_Basis_time); uw_Basis_int *uw_Basis_stringToInt(uw_context, uw_Basis_string); uw_Basis_float *uw_Basis_stringToFloat(uw_context, uw_Basis_string); +uw_Basis_char *uw_Basis_stringToChar(uw_context, uw_Basis_string); uw_Basis_bool *uw_Basis_stringToBool(uw_context, uw_Basis_string); uw_Basis_time *uw_Basis_stringToTime(uw_context, uw_Basis_string); uw_Basis_int uw_Basis_stringToInt_error(uw_context, uw_Basis_string); uw_Basis_float uw_Basis_stringToFloat_error(uw_context, uw_Basis_string); +uw_Basis_char uw_Basis_stringToChar_error(uw_context, uw_Basis_string); uw_Basis_bool uw_Basis_stringToBool_error(uw_context, uw_Basis_string); uw_Basis_time uw_Basis_stringToTime_error(uw_context, uw_Basis_string); uw_Basis_blob uw_Basis_stringToBlob_error(uw_context, uw_Basis_string, size_t); diff -r 91f465ded07e -r 395a5d450cc0 lib/js/urweb.js --- a/lib/js/urweb.js Sat May 23 10:14:51 2009 -0400 +++ b/lib/js/urweb.js Tue May 26 12:25:06 2009 -0400 @@ -351,6 +351,9 @@ function ts(x) { return x.toString() } function bs(b) { return (b ? "True" : "False") } +function sub(x, i) { return x[i]; } +function suf(x, i) { return x.substring(i); } + function pi(s) { var r = parseInt(s); if (r.toString() == s) diff -r 91f465ded07e -r 395a5d450cc0 lib/ur/basis.urs --- a/lib/ur/basis.urs Sat May 23 10:14:51 2009 -0400 +++ b/lib/ur/basis.urs Tue May 26 12:25:06 2009 -0400 @@ -1,6 +1,7 @@ type int type float type string +type char type time type blob @@ -21,6 +22,7 @@ val eq_int : eq int val eq_float : eq float val eq_string : eq string +val eq_char : eq char val eq_bool : eq bool val eq_time : eq time val mkEq : t ::: Type -> (t -> t -> bool) -> eq t @@ -44,6 +46,7 @@ val ord_int : ord int val ord_float : ord float val ord_string : ord string +val ord_char : ord char val ord_bool : ord bool val ord_time : ord time @@ -51,12 +54,15 @@ (** String operations *) val strcat : string -> string -> string +val strsub : string -> int -> char +val strsuffix : string -> int -> string class show val show : t ::: Type -> show t -> t -> string val show_int : show int val show_float : show float val show_string : show string +val show_char : show char val show_bool : show bool val show_time : show time val mkShow : t ::: Type -> (t -> string) -> show t @@ -68,6 +74,7 @@ val read_int : read int val read_float : read float val read_string : read string +val read_char : read char val read_bool : read bool val read_time : read time val mkRead : t ::: Type -> (string -> t) -> (string -> option t) -> read t diff -r 91f465ded07e -r 395a5d450cc0 lib/ur/list.ur --- a/lib/ur/list.ur Sat May 23 10:14:51 2009 -0400 +++ b/lib/ur/list.ur Tue May 26 12:25:06 2009 -0400 @@ -20,6 +20,18 @@ rev' [] end +val revAppend (a ::: Type) = + let + fun ra (ls : list a) acc = + case ls of + [] => acc + | x :: ls => ra ls (x :: acc) + in + ra + end + +fun append (a ::: Type) (ls1 : t a) (ls2 : t a) = revAppend (rev ls1) ls2 + fun mp (a ::: Type) (b ::: Type) f = let fun mp' acc ls = @@ -30,6 +42,18 @@ mp' [] end +fun mapPartial (a ::: Type) (b ::: Type) f = + let + fun mp' acc ls = + case ls of + [] => rev acc + | x :: ls => mp' (case f x of + None => acc + | Some y => y :: acc) ls + in + mp' [] + end + fun mapX (a ::: Type) (ctx ::: {Unit}) f = let fun mapX' ls = @@ -49,3 +73,13 @@ in mapM' [] end + +fun filter (a ::: Type) f = + let + fun fil acc ls = + case ls of + [] => rev acc + | x :: ls => fil (if f x then x :: acc else acc) ls + in + fil [] + end diff -r 91f465ded07e -r 395a5d450cc0 lib/ur/list.urs --- a/lib/ur/list.urs Sat May 23 10:14:51 2009 -0400 +++ b/lib/ur/list.urs Tue May 26 12:25:06 2009 -0400 @@ -4,9 +4,17 @@ val rev : a ::: Type -> t a -> t a +val revAppend : a ::: Type -> t a -> t a -> t a + +val append : a ::: Type -> t a -> t a -> t a + val mp : a ::: Type -> b ::: Type -> (a -> b) -> t a -> t b +val mapPartial : a ::: Type -> b ::: Type -> (a -> option b) -> t a -> t b + val mapX : a ::: Type -> ctx ::: {Unit} -> (a -> xml ctx [] []) -> t a -> xml ctx [] [] val mapM : m ::: (Type -> Type) -> monad m -> a ::: Type -> b ::: Type -> (a -> m b) -> list a -> m (list b) + +val filter : a ::: Type -> (a -> bool) -> t a -> t a diff -r 91f465ded07e -r 395a5d450cc0 lib/ur/string.ur --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/ur/string.ur Tue May 26 12:25:06 2009 -0400 @@ -0,0 +1,4 @@ +type t = Basis.string + +val sub = Basis.strsub +val suffix = Basis.strsuffix diff -r 91f465ded07e -r 395a5d450cc0 lib/ur/string.urs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/ur/string.urs Tue May 26 12:25:06 2009 -0400 @@ -0,0 +1,4 @@ +type t = string + +val sub : t -> int -> char +val suffix : t -> int -> string diff -r 91f465ded07e -r 395a5d450cc0 src/c/urweb.c --- a/src/c/urweb.c Sat May 23 10:14:51 2009 -0400 +++ b/src/c/urweb.c Tue May 26 12:25:06 2009 -0400 @@ -1793,6 +1793,20 @@ return uw_unit_v; } +uw_Basis_char uw_Basis_strsub(uw_context ctx, uw_Basis_string s, uw_Basis_int n) { + if (n >= 0 && n < strlen(s)) + return s[n]; + else + uw_error(ctx, FATAL, "Out-of-bounds strsub"); +} + +uw_Basis_string uw_Basis_strsuffix(uw_context ctx, uw_Basis_string s, uw_Basis_int n) { + if (n >= 0 && n < strlen(s)) + return &s[n]; + else + uw_error(ctx, FATAL, "Out-of-bounds strsuffix"); +} + uw_Basis_string uw_Basis_strcat(uw_context ctx, uw_Basis_string s1, uw_Basis_string s2) { int len = strlen(s1) + strlen(s2) + 1; char *s; @@ -2081,6 +2095,13 @@ return r; } +uw_Basis_string uw_Basis_charToString(uw_context ctx, uw_Basis_char ch) { + char *r = uw_malloc(ctx, 2); + r[0] = ch; + r[1] = 0; + return r; +} + uw_Basis_string uw_Basis_boolToString(uw_context ctx, uw_Basis_bool b) { if (b == uw_Basis_False) return "False"; @@ -2127,6 +2148,20 @@ return NULL; } +uw_Basis_char *uw_Basis_stringToChar(uw_context ctx, uw_Basis_string s) { + if (s[0] == 0) { + uw_Basis_char *r = uw_malloc(ctx, 1); + r[0] = 0; + return r; + } else if (s[1] != 0) + return NULL; + else { + uw_Basis_char *r = uw_malloc(ctx, 1); + r[0] = s[0]; + return r; + } +} + uw_Basis_bool *uw_Basis_stringToBool(uw_context ctx, uw_Basis_string s) { static uw_Basis_bool true = uw_Basis_True; static uw_Basis_bool false = uw_Basis_False; @@ -2215,6 +2250,15 @@ uw_error(ctx, FATAL, "Can't parse float: %s", s); } +uw_Basis_char uw_Basis_stringToChar_error(uw_context ctx, uw_Basis_string s) { + if (s[0] == 0) + return 0; + else if (s[1] != 0) + uw_error(ctx, FATAL, "Can't parse char: %s", s); + else + return s[0]; +} + uw_Basis_bool uw_Basis_stringToBool_error(uw_context ctx, uw_Basis_string s) { if (!strcasecmp(s, "T") || !strcasecmp (s, "True")) return uw_Basis_True; diff -r 91f465ded07e -r 395a5d450cc0 src/elaborate.sml --- a/src/elaborate.sml Sat May 23 10:14:51 2009 -0400 +++ b/src/elaborate.sml Tue May 26 12:25:06 2009 -0400 @@ -140,6 +140,7 @@ val int = ref cerror val float = ref cerror val string = ref cerror + val char = ref cerror val table = ref cerror local @@ -1096,6 +1097,7 @@ P.Int _ => !int | P.Float _ => !float | P.String _ => !string + | P.Char _ => !char datatype constraint = Disjoint of D.goal @@ -3974,6 +3976,7 @@ val () = discoverC int "int" val () = discoverC float "float" val () = discoverC string "string" + val () = discoverC char "char" val () = discoverC table "sql_table" val (topSgn, gs) = elabSgn (env', D.empty) (L.SgnConst topSgn, ErrorMsg.dummySpan) diff -r 91f465ded07e -r 395a5d450cc0 src/jscomp.sml --- a/src/jscomp.sml Sat May 23 10:14:51 2009 -0400 +++ b/src/jscomp.sml Tue May 26 12:25:06 2009 -0400 @@ -541,6 +541,7 @@ Int.fmt StringCvt.OCT (ord ch), 3)) s ^ "\"") + | Prim.Char ch => str ("'" ^ String.str ch ^ "'") | _ => str (Prim.toString p) fun jsPat depth inner (p, _) succ fail = diff -r 91f465ded07e -r 395a5d450cc0 src/monoize.sml --- a/src/monoize.sml Sat May 23 10:14:51 2009 -0400 +++ b/src/monoize.sml Tue May 26 12:25:06 2009 -0400 @@ -762,6 +762,13 @@ (L'.TFfi ("Basis", "bool"), loc), (L'.EBinop ("!strcmp", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc), fm) + | L.EFfi ("Basis", "eq_char") => + ((L'.EAbs ("x", (L'.TFfi ("Basis", "char"), loc), + (L'.TFun ((L'.TFfi ("Basis", "char"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc), + (L'.EAbs ("y", (L'.TFfi ("Basis", "char"), loc), + (L'.TFfi ("Basis", "bool"), loc), + (L'.EBinop ("==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc), + fm) | L.EFfi ("Basis", "eq_time") => ((L'.EAbs ("x", (L'.TFfi ("Basis", "time"), loc), (L'.TFun ((L'.TFfi ("Basis", "time"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc), @@ -971,6 +978,19 @@ boolBin "<", boolBin "<=") end + | L.EFfi ("Basis", "ord_char") => + let + fun charBin s = + (L'.EAbs ("x", (L'.TFfi ("Basis", "char"), loc), + (L'.TFun ((L'.TFfi ("Basis", "char"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc), + (L'.EAbs ("y", (L'.TFfi ("Basis", "char"), loc), + (L'.TFfi ("Basis", "bool"), loc), + (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc) + in + ordEx ((L'.TFfi ("Basis", "char"), loc), + charBin "<", + charBin "<=") + end | L.EFfi ("Basis", "ord_time") => let fun boolBin s = @@ -1003,6 +1023,8 @@ in ((L'.EAbs ("s", s, s, (L'.ERel 0, loc)), loc), fm) end + | L.EFfi ("Basis", "show_char") => + ((L'.EFfi ("Basis", "charToString"), loc), fm) | L.EFfi ("Basis", "show_bool") => ((L'.EFfi ("Basis", "boolToString"), loc), fm) | L.EFfi ("Basis", "show_time") => @@ -1080,6 +1102,15 @@ ("ReadError", (L'.EAbs ("s", s, s, (L'.ERel 0, loc)), loc), readErrType (s, loc))], loc), fm) end + | L.EFfi ("Basis", "read_char") => + let + val t = (L'.TFfi ("Basis", "char"), loc) + in + ((L'.ERecord [("Read", (L'.EFfi ("Basis", "stringToChar"), loc), readType' (t, loc)), + ("ReadError", (L'.EFfi ("Basis", "stringToChar_error"), loc), readErrType (t, loc))], + loc), + fm) + end | L.EFfi ("Basis", "read_bool") => let val t = (L'.TFfi ("Basis", "bool"), loc) diff -r 91f465ded07e -r 395a5d450cc0 src/prim.sig --- a/src/prim.sig Sat May 23 10:14:51 2009 -0400 +++ b/src/prim.sig Tue May 26 12:25:06 2009 -0400 @@ -31,6 +31,7 @@ Int of Int64.int | Float of Real64.real | String of string + | Char of char val p_t : t Print.printer val p_t_GCC : t Print.printer diff -r 91f465ded07e -r 395a5d450cc0 src/prim.sml --- a/src/prim.sml Sat May 23 10:14:51 2009 -0400 +++ b/src/prim.sml Tue May 26 12:25:06 2009 -0400 @@ -31,6 +31,7 @@ Int of Int64.int | Float of Real64.real | String of string + | Char of char open Print.PD open Print @@ -40,6 +41,7 @@ Int n => string (Int64.toString n) | Float n => string (Real64.toString n) | String s => box [string "\"", string (String.toString s), string "\""] + | Char ch => box [string "#\"", string (String.str ch), string "\""] fun int2s n = if Int64.compare (n, Int64.fromInt 0) = LESS then @@ -64,18 +66,21 @@ Int n => int2s' n | Float n => float2s n | String s => s + | Char ch => str ch fun p_t_GCC t = case t of Int n => string (int2s n) | Float n => string (float2s n) | String s => box [string "\"", string (String.toString s), string "\""] + | Char ch => box [string "'", string (str ch), string "'"] fun equal x = case x of (Int n1, Int n2) => n1 = n2 | (Float n1, Float n2) => Real64.== (n1, n2) | (String s1, String s2) => s1 = s2 + | (Char ch1, Char ch2) => ch1 = ch2 | _ => false @@ -87,8 +92,12 @@ | (Float n1, Float n2) => Real64.compare (n1, n2) | (Float _, _) => LESS - | (_, Float _) => GREATER + | (_, Float _) => GREATER | (String n1, String n2) => String.compare (n1, n2) + | (String _, _) => LESS + | (_, String _) => GREATER + + | (Char ch1, Char ch2) => Char.compare (ch1, ch2) end diff -r 91f465ded07e -r 395a5d450cc0 src/settings.sml --- a/src/settings.sml Sat May 23 10:14:51 2009 -0400 +++ b/src/settings.sml Tue May 26 12:25:06 2009 -0400 @@ -140,6 +140,7 @@ ("strcat", "cat"), ("intToString", "ts"), ("floatToString", "ts"), + ("charToString", "ts"), ("onError", "onError"), ("onFail", "onFail"), ("onConnectFail", "onConnectFail"), @@ -149,7 +150,9 @@ ("attrifyInt", "ts"), ("attrifyFloat", "ts"), ("attrifyBool", "bs"), - ("boolToString", "ts")] + ("boolToString", "ts"), + ("strsub", "sub"), + ("strsuffix", "suf")] val jsFuncs = ref jsFuncsBase fun setJsFuncs ls = jsFuncs := foldl (fn ((k, v), m) => M.insert (m, k, v)) jsFuncsBase ls fun jsFunc x = M.find (!jsFuncs, x) diff -r 91f465ded07e -r 395a5d450cc0 src/urweb.grm --- a/src/urweb.grm Sat May 23 10:14:51 2009 -0400 +++ b/src/urweb.grm Tue May 26 12:25:06 2009 -0400 @@ -183,7 +183,7 @@ %term EOF - | STRING of string | INT of Int64.int | FLOAT of Real64.real + | STRING of string | INT of Int64.int | FLOAT of Real64.real | CHAR of char | SYMBOL of string | CSYMBOL of string | LPAREN | RPAREN | LBRACK | RBRACK | LBRACE | RBRACE | EQ | COMMA | COLON | DCOLON | TCOLON | DOT | HASH | UNDER | UNDERUNDER | BAR @@ -1080,6 +1080,7 @@ | INT (EPrim (Prim.Int INT), s (INTleft, INTright)) | FLOAT (EPrim (Prim.Float FLOAT), s (FLOATleft, FLOATright)) | STRING (EPrim (Prim.String STRING), s (STRINGleft, STRINGright)) + | CHAR (EPrim (Prim.Char CHAR), s (CHARleft, CHARright)) | path DOT idents (let val loc = s (pathleft, identsright) @@ -1228,6 +1229,7 @@ | UNDER (PWild, s (UNDERleft, UNDERright)) | INT (PPrim (Prim.Int INT), s (INTleft, INTright)) | STRING (PPrim (Prim.String STRING), s (STRINGleft, STRINGright)) + | CHAR (PPrim (Prim.Char CHAR), s (CHARleft, CHARright)) | LPAREN pat RPAREN (pat) | LBRACE RBRACE (PRecord ([], false), s (LBRACEleft, RBRACEright)) | UNIT (PRecord ([], false), s (UNITleft, UNITright)) diff -r 91f465ded07e -r 395a5d450cc0 src/urweb.lex --- a/src/urweb.lex Sat May 23 10:14:51 2009 -0400 +++ b/src/urweb.lex Tue May 26 12:25:06 2009 -0400 @@ -160,7 +160,7 @@ %% %header (functor UrwebLexFn(structure Tokens : Urweb_TOKENS)); %full -%s COMMENT STRING XML XMLTAG; +%s COMMENT STRING CHAR XML XMLTAG; id = [a-z_][A-Za-z0-9_']*; cid = [A-Z][A-Za-z0-9_]*; @@ -193,6 +193,31 @@ "*)" => (if exitComment () then YYBEGIN INITIAL else (); continue ()); + "#\"" => (YYBEGIN CHAR; strEnder := #"\""; strStart := pos yypos; str := []; continue()); + "\\\"" => (str := #"\"" :: !str; continue()); + "\\'" => (str := #"'" :: !str; continue()); + "\n" => (newline yypos; + str := #"\n" :: !str; continue()); + . => (let + val ch = String.sub (yytext, 0) + in + if ch = !strEnder then + let + val s = String.implode (List.rev (!str)) + in + YYBEGIN INITIAL; + if size s = 1 then + Tokens.CHAR (String.sub (s, 0), !strStart, pos yypos + 1) + else + (ErrorMsg.errorAt' (yypos, yypos) + "Character constant is zero or multiple characters"; + continue ()) + end + else + (str := ch :: !str; + continue ()) + end); + "\"" => (YYBEGIN STRING; strEnder := #"\""; strStart := pos yypos; str := []; continue()); "'" => (YYBEGIN STRING; strEnder := #"'"; strStart := pos yypos; str := []; continue()); "\\\"" => (str := #"\"" :: !str; continue()); diff -r 91f465ded07e -r 395a5d450cc0 tests/char.ur --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/char.ur Tue May 26 12:25:06 2009 -0400 @@ -0,0 +1,4 @@ +fun main () = + case #"A" of + #"B" => return + | _ => return A! diff -r 91f465ded07e -r 395a5d450cc0 tests/char.urp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/char.urp Tue May 26 12:25:06 2009 -0400 @@ -0,0 +1,3 @@ +debug + +char diff -r 91f465ded07e -r 395a5d450cc0 tests/char.urs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/char.urs Tue May 26 12:25:06 2009 -0400 @@ -0,0 +1,1 @@ +val main : unit -> transaction page