Mercurial > urweb
comparison src/jscomp.sml @ 970:8371d12ae63f
Hopefully complete refactoring of Jscomp to output ASTs; partial implementation of interpreter in runtime system (demo/alert works)
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Tue, 22 Sep 2009 12:23:21 -0400 |
parents | 8c37699de273 |
children | e30c2409c9d0 |
comparison
equal
deleted
inserted
replaced
969:001edfbe2561 | 970:8371d12ae63f |
---|---|
49 listInjectors : int TM.map, | 49 listInjectors : int TM.map, |
50 decoders : int IM.map, | 50 decoders : int IM.map, |
51 maxName : int | 51 maxName : int |
52 } | 52 } |
53 | 53 |
54 fun varDepth (e, _) = | |
55 case e of | |
56 EPrim _ => 0 | |
57 | ERel _ => 0 | |
58 | ENamed _ => 0 | |
59 | ECon (_, _, NONE) => 0 | |
60 | ECon (_, _, SOME e) => varDepth e | |
61 | ENone _ => 0 | |
62 | ESome (_, e) => varDepth e | |
63 | EFfi _ => 0 | |
64 | EFfiApp (_, _, es) => foldl Int.max 0 (map varDepth es) | |
65 | EApp (e1, e2) => Int.max (varDepth e1, varDepth e2) | |
66 | EAbs _ => 0 | |
67 | EUnop (_, e) => varDepth e | |
68 | EBinop (_, e1, e2) => Int.max (varDepth e1, varDepth e2) | |
69 | ERecord xes => foldl Int.max 0 (map (fn (_, e, _) => varDepth e) xes) | |
70 | EField (e, _) => varDepth e | |
71 | ECase (e, pes, _) => | |
72 foldl Int.max (varDepth e) | |
73 (map (fn (p, e) => E.patBindsN p + varDepth e) pes) | |
74 | EStrcat (e1, e2) => Int.max (varDepth e1, varDepth e2) | |
75 | EError (e, _) => varDepth e | |
76 | EReturnBlob {blob = e1, mimeType = e2, ...} => Int.max (varDepth e1, varDepth e2) | |
77 | EWrite e => varDepth e | |
78 | ESeq (e1, e2) => Int.max (varDepth e1, varDepth e2) | |
79 | ELet (_, _, e1, e2) => Int.max (varDepth e1, 1 + varDepth e2) | |
80 | EClosure _ => 0 | |
81 | EQuery _ => 0 | |
82 | EDml _ => 0 | |
83 | ENextval _ => 0 | |
84 | EUnurlify _ => 0 | |
85 | EJavaScript _ => 0 | |
86 | ESignalReturn e => varDepth e | |
87 | ESignalBind (e1, e2) => Int.max (varDepth e1, varDepth e2) | |
88 | ESignalSource e => varDepth e | |
89 | EServerCall (e, ek, _, _) => Int.max (varDepth e, varDepth ek) | |
90 | ERecv (e, ek, _) => Int.max (varDepth e, varDepth ek) | |
91 | ESleep (e, ek) => Int.max (varDepth e, varDepth ek) | |
92 | |
93 fun closedUpto d = | |
94 let | |
95 fun cu inner (e, _) = | |
96 case e of | |
97 EPrim _ => true | |
98 | ERel n => n < inner orelse n - inner >= d | |
99 | ENamed _ => true | |
100 | ECon (_, _, NONE) => true | |
101 | ECon (_, _, SOME e) => cu inner e | |
102 | ENone _ => true | |
103 | ESome (_, e) => cu inner e | |
104 | EFfi _ => true | |
105 | EFfiApp (_, _, es) => List.all (cu inner) es | |
106 | EApp (e1, e2) => cu inner e1 andalso cu inner e2 | |
107 | EAbs (_, _, _, e) => cu (inner + 1) e | |
108 | EUnop (_, e) => cu inner e | |
109 | EBinop (_, e1, e2) => cu inner e1 andalso cu inner e2 | |
110 | ERecord xes => List.all (fn (_, e, _) => cu inner e) xes | |
111 | EField (e, _) => cu inner e | |
112 | ECase (e, pes, _) => | |
113 cu inner e | |
114 andalso List.all (fn (p, e) => cu (inner + E.patBindsN p) e) pes | |
115 | EStrcat (e1, e2) => cu inner e1 andalso cu inner e2 | |
116 | EError (e, _) => cu inner e | |
117 | EReturnBlob {blob = e1, mimeType = e2, ...} => cu inner e1 andalso cu inner e2 | |
118 | EWrite e => cu inner e | |
119 | ESeq (e1, e2) => cu inner e1 andalso cu inner e2 | |
120 | ELet (_, _, e1, e2) => cu inner e1 andalso cu (inner + 1) e2 | |
121 | EClosure (_, es) => List.all (cu inner) es | |
122 | EQuery {query, body, initial, ...} => | |
123 cu inner query | |
124 andalso cu (inner + 2) body | |
125 andalso cu inner initial | |
126 | EDml e => cu inner e | |
127 | ENextval e => cu inner e | |
128 | EUnurlify (e, _) => cu inner e | |
129 | EJavaScript (_, e) => cu inner e | |
130 | ESignalReturn e => cu inner e | |
131 | ESignalBind (e1, e2) => cu inner e1 andalso cu inner e2 | |
132 | ESignalSource e => cu inner e | |
133 | EServerCall (e, ek, _, _) => cu inner e andalso cu inner ek | |
134 | ERecv (e, ek, _) => cu inner e andalso cu inner ek | |
135 | ESleep (e, ek) => cu inner e andalso cu inner ek | |
136 in | |
137 cu 0 | |
138 end | |
139 | |
140 fun strcat loc es = | 54 fun strcat loc es = |
141 case es of | 55 case es of |
142 [] => (EPrim (Prim.String ""), loc) | 56 [] => (EPrim (Prim.String ""), loc) |
143 | [x] => x | 57 | [x] => x |
144 | x :: es' => (EStrcat (x, strcat loc es'), loc) | 58 | x :: es' => (EStrcat (x, strcat loc es'), loc) |
145 | 59 |
146 fun patDepth (p, _) = | |
147 case p of | |
148 PWild => 0 | |
149 | PVar _ => 0 | |
150 | PPrim _ => 0 | |
151 | PCon (_, _, NONE) => 0 | |
152 | PCon (_, _, SOME p) => 1 + patDepth p | |
153 | PRecord xpts => foldl Int.max 0 (map (fn (_, p, _) => 1 + patDepth p) xpts) | |
154 | PNone _ => 0 | |
155 | PSome (_, p) => 1 + patDepth p | |
156 | |
157 val compact = | |
158 U.Exp.mapB {typ = fn t => t, | |
159 exp = fn inner => fn e => | |
160 case e of | |
161 ERel n => | |
162 if n >= inner then | |
163 ERel (n - inner) | |
164 else | |
165 e | |
166 | _ => e, | |
167 bind = fn (inner, b) => | |
168 case b of | |
169 U.Exp.RelE _ => inner+1 | |
170 | _ => inner} | |
171 | |
172 exception CantEmbed of typ | 60 exception CantEmbed of typ |
173 | 61 |
174 fun inString {needle, haystack} = | 62 fun inString {needle, haystack} = String.isSubstring needle haystack |
175 let | |
176 val (_, suffix) = Substring.position needle (Substring.full haystack) | |
177 in | |
178 not (Substring.isEmpty suffix) | |
179 end | |
180 | 63 |
181 fun process file = | 64 fun process file = |
182 let | 65 let |
183 val (someTs, nameds) = | 66 val (someTs, nameds) = |
184 foldl (fn ((DVal (_, n, t, e, _), _), (someTs, nameds)) => (someTs, IM.insert (nameds, n, e)) | 67 foldl (fn ((DVal (_, n, t, e, _), _), (someTs, nameds)) => (someTs, IM.insert (nameds, n, e)) |
518 | 401 |
519 fun jsE inner (e as (_, loc), st) = | 402 fun jsE inner (e as (_, loc), st) = |
520 let | 403 let |
521 val str = str loc | 404 val str = str loc |
522 | 405 |
523 fun var n = Int.toString (len + inner - n - 1) | |
524 | |
525 fun patCon pc = | 406 fun patCon pc = |
526 case pc of | 407 case pc of |
527 PConVar n => str (Int.toString n) | 408 PConVar n => str (Int.toString n) |
528 | PConFfi {mod = "Basis", con = "True", ...} => str "true" | 409 | PConFfi {mod = "Basis", con = "True", ...} => str "true" |
529 | PConFfi {mod = "Basis", con = "False", ...} => str "false" | 410 | PConFfi {mod = "Basis", con = "False", ...} => str "false" |
530 | PConFfi {con, ...} => str ("\"_" ^ con ^ "\"") | 411 | PConFfi {con, ...} => str ("\"" ^ con ^ "\"") |
531 | 412 |
532 fun unsupported s = | 413 fun unsupported s = |
533 (EM.errorAt loc (s ^ " in code to be compiled to JavaScript[2]"); | 414 (EM.errorAt loc (s ^ " in code to be compiled to JavaScript[2]"); |
534 Print.preface ("Code", MonoPrint.p_exp MonoEnv.empty e); | 415 Print.preface ("Code", MonoPrint.p_exp MonoEnv.empty e); |
535 (str "ERROR", st)) | 416 (str "ERROR", st)) |
564 str ("\"" ^ String.translate jsChar s ^ "\"") | 445 str ("\"" ^ String.translate jsChar s ^ "\"") |
565 | Prim.Char ch => str ("'" ^ jsChar ch ^ "'") | 446 | Prim.Char ch => str ("'" ^ jsChar ch ^ "'") |
566 | _ => str (Prim.toString p) | 447 | _ => str (Prim.toString p) |
567 end | 448 end |
568 | 449 |
569 fun jsPat depth inner (p, _) succ fail = | 450 fun jsPat (p, _) = |
570 case p of | 451 case p of |
571 PWild => succ | 452 PWild => str "{c:\"w\"}" |
572 | PVar _ => strcat [str ("(_" ^ Int.toString (len + inner) ^ "=d" | 453 | PVar _ => str "{c:\"v\"}" |
573 ^ Int.toString depth ^ ","), | 454 | PPrim p => strcat [str "{c:\"c\",v:", |
574 succ, | |
575 str ")"] | |
576 | PPrim p => strcat [str ("(d" ^ Int.toString depth ^ "=="), | |
577 jsPrim p, | 455 jsPrim p, |
578 str "?", | 456 str "}"] |
579 succ, | |
580 str ":", | |
581 fail, | |
582 str ")"] | |
583 | PCon (_, PConFfi {mod = "Basis", con = "True", ...}, NONE) => | 457 | PCon (_, PConFfi {mod = "Basis", con = "True", ...}, NONE) => |
584 strcat [str ("(d" ^ Int.toString depth ^ "?"), | 458 str "{c:\"c\",v:true}" |
585 succ, | |
586 str ":", | |
587 fail, | |
588 str ")"] | |
589 | PCon (_, PConFfi {mod = "Basis", con = "False", ...}, NONE) => | 459 | PCon (_, PConFfi {mod = "Basis", con = "False", ...}, NONE) => |
590 strcat [str ("(d" ^ Int.toString depth ^ "?"), | 460 str "{c:\"c\",v:false}" |
591 fail, | |
592 str ":", | |
593 succ, | |
594 str ")"] | |
595 | PCon (Option, _, NONE) => | 461 | PCon (Option, _, NONE) => |
596 strcat [str ("(d" ^ Int.toString depth ^ "!=null?"), | 462 str "{c:\"c\",v:null}" |
597 fail, | |
598 str ":", | |
599 succ, | |
600 str ")"] | |
601 | PCon (Option, PConVar n, SOME p) => | 463 | PCon (Option, PConVar n, SOME p) => |
602 (case IM.find (someTs, n) of | 464 (case IM.find (someTs, n) of |
603 NONE => raise Fail "Jscomp: Not in someTs" | 465 NONE => raise Fail "Jscomp: Not in someTs" |
604 | SOME t => | 466 | SOME t => strcat [str ("{c:\"s\",n:" |
605 strcat [str ("(d" ^ Int.toString depth ^ "!=null?(d" | 467 ^ (if isNullable t then |
606 ^ Int.toString (depth+1) ^ "=d" ^ Int.toString depth | 468 "true" |
607 ^ (if isNullable t then | 469 else |
608 ".v," | 470 "false") |
609 else | 471 ^ ",p:"), |
610 "") | 472 jsPat p, |
611 ^ ","), | 473 str "}"]) |
612 jsPat (depth+1) inner p succ fail, | 474 | PCon (_, pc, NONE) => strcat [str "{c:\"0\",n:", |
613 str "):", | 475 patCon pc, |
614 fail, | 476 str "}"] |
615 str ")"]) | 477 | PCon (_, pc, SOME p) => strcat [str "{c:\"1\",n:", |
616 | PCon (_, pc, NONE) => | 478 patCon pc, |
617 strcat [str ("(d" ^ Int.toString depth ^ "=="), | 479 str ",p:", |
618 patCon pc, | 480 jsPat p, |
619 str "?", | 481 str "}"] |
620 succ, | 482 | PRecord xps => strcat [str "{c:\"r\",l:", |
621 str ":", | 483 foldr (fn ((x, p, _), e) => |
622 fail, | 484 strcat [str ("cons({n:\"" ^ x ^ "\",p:"), |
623 str ")"] | 485 jsPat p, |
624 | PCon (_, pc, SOME p) => | 486 str "},", |
625 strcat [str ("(d" ^ Int.toString depth ^ ".n=="), | 487 e, |
626 patCon pc, | 488 str ")"]) |
627 str ("?(d" ^ Int.toString (depth+1) ^ "=d" ^ Int.toString depth ^ ".v,"), | 489 (str "null") xps, |
628 jsPat (depth+1) inner p succ fail, | 490 str "}"] |
629 str "):", | 491 | PNone _ => str "{c:\"c\",v:null}" |
630 fail, | 492 | PSome (t, p) => strcat [str ("{c:\"s\",n:" |
631 str ")"] | |
632 | PRecord xps => | |
633 let | |
634 val (_, succ) = foldl | |
635 (fn ((x, p, _), (inner, succ)) => | |
636 (inner + E.patBindsN p, | |
637 strcat [str ("(d" ^ Int.toString (depth+1) ^ "=d" | |
638 ^ Int.toString depth ^ "._" ^ x ^ ","), | |
639 jsPat (depth+1) inner p succ fail, | |
640 str ")"])) | |
641 (inner, succ) xps | |
642 in | |
643 succ | |
644 end | |
645 | PNone _ => strcat [str ("(d" ^ Int.toString depth ^ "!=null?"), | |
646 fail, | |
647 str ":", | |
648 succ, | |
649 str ")"] | |
650 | PSome (t, p) => strcat [str ("(d" ^ Int.toString depth ^ "!=null?(d" ^ Int.toString (depth+1) | |
651 ^ "=d" ^ Int.toString depth | |
652 ^ (if isNullable t then | 493 ^ (if isNullable t then |
653 ".v" | 494 "true" |
654 else | 495 else |
655 "") | 496 "false") |
656 ^ ","), | 497 ^ ",p:"), |
657 jsPat (depth+1) inner p succ fail, | 498 jsPat p, |
658 str "):", | 499 str "}"] |
659 fail, | |
660 str ")"] | |
661 | 500 |
662 val jsifyString = String.translate (fn #"\"" => "\\\"" | 501 val jsifyString = String.translate (fn #"\"" => "\\\"" |
663 | #"\\" => "\\\\" | 502 | #"\\" => "\\\\" |
664 | ch => String.str ch) | 503 | ch => String.str ch) |
665 | 504 |
675 | EFfiApp ("Basis", "jsifyString", [e]) => "\"" ^ deStrcat (level + 1) e ^ "\"" | 514 | EFfiApp ("Basis", "jsifyString", [e]) => "\"" ^ deStrcat (level + 1) e ^ "\"" |
676 | _ => (Print.prefaces "deStrcat" [("e", MonoPrint.p_exp MonoEnv.empty all)]; | 515 | _ => (Print.prefaces "deStrcat" [("e", MonoPrint.p_exp MonoEnv.empty all)]; |
677 raise Fail "Jscomp: deStrcat") | 516 raise Fail "Jscomp: deStrcat") |
678 | 517 |
679 val quoteExp = quoteExp loc | 518 val quoteExp = quoteExp loc |
680 | |
681 val hasQuery = U.Exp.exists {typ = fn _ => false, | |
682 exp = fn EQuery _ => true | |
683 | _ => false} | |
684 | |
685 val indirectQuery = U.Exp.exists {typ = fn _ => false, | |
686 exp = fn ENamed n => | |
687 (case IM.find (nameds, n) of | |
688 NONE => false | |
689 | SOME e => hasQuery e) | |
690 | _ => false} | |
691 | |
692 in | 519 in |
693 (*if indirectQuery e then | |
694 Print.preface ("Indirect", MonoPrint.p_exp MonoEnv.empty e) | |
695 else | |
696 ();*) | |
697 | |
698 (*Print.prefaces "jsE" [("e", MonoPrint.p_exp MonoEnv.empty e), | 520 (*Print.prefaces "jsE" [("e", MonoPrint.p_exp MonoEnv.empty e), |
699 ("inner", Print.PD.string (Int.toString inner))];*) | 521 ("inner", Print.PD.string (Int.toString inner))];*) |
700 | 522 |
701 case #1 e of | 523 case #1 e of |
702 EPrim p => (jsPrim p, st) | 524 EPrim p => (strcat [str "{c:\"c\",v:", |
525 jsPrim p, | |
526 str "}"], | |
527 st) | |
703 | ERel n => | 528 | ERel n => |
704 if n < inner then | 529 if n < inner then |
705 (str ("_" ^ var n), st) | 530 (str ("{c:\"v\",n:" ^ Int.toString n ^ "}"), st) |
706 else | 531 else |
707 let | 532 let |
708 val n = n - inner | 533 val n = n - inner |
709 (*val () = Print.prefaces "quote" [("t", MonoPrint.p_typ MonoEnv.empty | 534 (*val () = Print.prefaces "quote" [("t", MonoPrint.p_typ MonoEnv.empty |
710 (List.nth (outer, n)))]*) | 535 (List.nth (outer, n)))]*) |
536 val (e, st) = quoteExp (List.nth (outer, n)) ((ERel n, loc), st) | |
711 in | 537 in |
712 quoteExp (List.nth (outer, n)) ((ERel n, loc), st) | 538 (strcat [str "{c:\"c\",v:", |
539 e, | |
540 str "}"], st) | |
713 end | 541 end |
714 | 542 |
715 | ENamed n => | 543 | ENamed n => |
716 let | 544 let |
717 val st = | 545 val st = |
729 listInjectors = #listInjectors st, | 557 listInjectors = #listInjectors st, |
730 decoders = #decoders st, | 558 decoders = #decoders st, |
731 maxName = #maxName st} | 559 maxName = #maxName st} |
732 | 560 |
733 val old = e | 561 val old = e |
734 val (e, st) = jsExp mode [] 0 (e, st) | 562 val (e, st) = jsExp mode [] (e, st) |
735 val new = e | 563 val new = e |
736 val e = deStrcat 0 e | 564 val e = deStrcat 0 e |
737 | 565 |
738 val sc = "_n" ^ Int.toString n ^ "=" ^ e ^ ";\n" | 566 val sc = "urfuncs[" ^ Int.toString n ^ "] = " ^ e ^ ";\n" |
739 in | 567 in |
740 (*Print.prefaces "jsify'" [("old", MonoPrint.p_exp MonoEnv.empty old), | 568 (*Print.prefaces "jsify'" [("old", MonoPrint.p_exp MonoEnv.empty old), |
741 ("new", MonoPrint.p_exp MonoEnv.empty new)];*) | 569 ("new", MonoPrint.p_exp MonoEnv.empty new)];*) |
742 {decls = #decls st, | 570 {decls = #decls st, |
743 script = sc :: #script st, | 571 script = sc :: #script st, |
746 listInjectors = #listInjectors st, | 574 listInjectors = #listInjectors st, |
747 decoders= #decoders st, | 575 decoders= #decoders st, |
748 maxName = #maxName st} | 576 maxName = #maxName st} |
749 end | 577 end |
750 in | 578 in |
751 (str ("_n" ^ Int.toString n), st) | 579 (str ("{c:\"n\",n:" ^ Int.toString n ^ "}"), st) |
752 end | 580 end |
753 | 581 |
754 | ECon (Option, _, NONE) => (str "null", st) | 582 | ECon (Option, _, NONE) => (str "{c:\"c\",v:null}", st) |
755 | ECon (Option, PConVar n, SOME e) => | 583 | ECon (Option, PConVar n, SOME e) => |
756 let | 584 let |
757 val (e, st) = jsE inner (e, st) | 585 val (e, st) = jsE inner (e, st) |
758 in | 586 in |
759 case IM.find (someTs, n) of | 587 case IM.find (someTs, n) of |
760 NONE => raise Fail "Jscomp: Not in someTs [2]" | 588 NONE => raise Fail "Jscomp: Not in someTs [2]" |
761 | SOME t => | 589 | SOME t => |
762 (if isNullable t then | 590 (if isNullable t then |
763 strcat [str "{v:", | 591 strcat [str "{c:\"s\",v:", |
764 e, | 592 e, |
765 str "}"] | 593 str "}"] |
766 else | 594 else |
767 e, st) | 595 e, st) |
768 end | 596 end |
769 | 597 |
770 | ECon (_, pc, NONE) => (patCon pc, st) | 598 | ECon (_, pc, NONE) => (strcat [str "{c:\"c\",v:", |
599 patCon pc, | |
600 str "}"], | |
601 st) | |
771 | ECon (_, pc, SOME e) => | 602 | ECon (_, pc, SOME e) => |
772 let | 603 let |
773 val (s, st) = jsE inner (e, st) | 604 val (s, st) = jsE inner (e, st) |
774 in | 605 in |
775 (strcat [str "{n:", | 606 (strcat [str "{c:\"1\",n:", |
776 patCon pc, | 607 patCon pc, |
777 str ",v:", | 608 str ",v:", |
778 s, | 609 s, |
779 str "}"], st) | 610 str "}"], st) |
780 end | 611 end |
781 | 612 |
782 | ENone _ => (str "null", st) | 613 | ENone _ => (str "{c:\"c\",v:null}", st) |
783 | ESome (t, e) => | 614 | ESome (t, e) => |
784 let | 615 let |
785 val (e, st) = jsE inner (e, st) | 616 val (e, st) = jsE inner (e, st) |
786 in | 617 in |
787 (if isNullable t then | 618 (if isNullable t then |
788 strcat [str "{v:", e, str "}"] | 619 strcat [str "{c:\"s\",v:", e, str "}"] |
789 else | 620 else |
790 e, st) | 621 e, st) |
791 end | 622 end |
792 | 623 |
793 | EFfi k => | 624 | EFfi k => |
796 NONE => (EM.errorAt loc ("Unsupported FFI identifier " ^ #2 k | 627 NONE => (EM.errorAt loc ("Unsupported FFI identifier " ^ #2 k |
797 ^ " in JavaScript"); | 628 ^ " in JavaScript"); |
798 "ERROR") | 629 "ERROR") |
799 | SOME s => s | 630 | SOME s => s |
800 in | 631 in |
801 (str name, st) | 632 (str ("{c:\"c\",v:" ^ name ^ "}"), st) |
802 end | 633 end |
803 | EFfiApp ("Basis", "sigString", [_]) => (strcat [str "\"", | 634 | EFfiApp ("Basis", "sigString", [_]) => (strcat [str "{c:\"c\",v:\"", |
804 e, | 635 e, |
805 str "\""], st) | 636 str "\"}"], st) |
806 | EFfiApp ("Basis", "kc", []) => (str "kc(event)", st) | |
807 | EFfiApp (m, x, args) => | 637 | EFfiApp (m, x, args) => |
808 let | 638 let |
809 val name = case Settings.jsFunc (m, x) of | 639 val name = case Settings.jsFunc (m, x) of |
810 NONE => (EM.errorAt loc ("Unsupported FFI function " | 640 NONE => (EM.errorAt loc ("Unsupported FFI function " |
811 ^ x ^ " in JavaScript"); | 641 ^ x ^ " in JavaScript"); |
812 "ERROR") | 642 "ERROR") |
813 | SOME s => s | 643 | SOME s => s |
814 in | 644 |
815 case args of | 645 val (e, st) = foldr (fn (e, (acc, st)) => |
816 [] => (str (name ^ "()"), st) | 646 let |
817 | [e] => | 647 val (e, st) = jsE inner (e, st) |
818 let | 648 in |
819 val (e, st) = jsE inner (e, st) | 649 (strcat [str "cons(", |
820 in | 650 e, |
821 (strcat [str (name ^ "("), | 651 str ",", |
822 e, | 652 acc, |
823 str ")"], st) | 653 str ")"], |
824 end | 654 st) |
825 | e :: es => | 655 end) |
826 let | 656 (str "null", st) args |
827 val (e, st) = jsE inner (e, st) | 657 in |
828 val (es, st) = ListUtil.foldlMapConcat | 658 (strcat [str ("{c:\"f\",f:" ^ name ^ ",a:"), |
829 (fn (e, st) => | 659 e, |
830 let | 660 str "}"], |
831 val (e, st) = jsE inner (e, st) | 661 st) |
832 in | |
833 ([str ",", e], st) | |
834 end) | |
835 st es | |
836 in | |
837 (strcat (str (name ^ "(") | |
838 :: e | |
839 :: es | |
840 @ [str ")"]), st) | |
841 end | |
842 end | 662 end |
843 | 663 |
844 | EApp (e1, e2) => | 664 | EApp (e1, e2) => |
845 let | 665 let |
846 val (e1, st) = jsE inner (e1, st) | 666 val (e1, st) = jsE inner (e1, st) |
847 val (e2, st) = jsE inner (e2, st) | 667 val (e2, st) = jsE inner (e2, st) |
848 in | 668 in |
849 (strcat [e1, str "(", e2, str ")"], st) | 669 (strcat [str "{c:\"a\",f:", |
670 e1, | |
671 str ",x:", | |
672 e2, | |
673 str "}"], st) | |
850 end | 674 end |
851 | EAbs (_, _, _, e) => | 675 | EAbs (_, _, _, e) => |
852 let | 676 let |
853 val locals = List.tabulate | |
854 (varDepth e, | |
855 fn i => str ("var _" ^ Int.toString (len + inner + i + 1) ^ ";")) | |
856 val (e, st) = jsE (inner + 1) (e, st) | 677 val (e, st) = jsE (inner + 1) (e, st) |
857 in | 678 in |
858 (strcat (str ("function(_" | 679 (strcat [str "{c:\"l\",b:", |
859 ^ Int.toString (len + inner) | 680 e, |
860 ^ "){") | 681 str "}"], st) |
861 :: locals | 682 end |
862 @ [str "return ", | 683 |
863 e, | 684 | EUnop (s, e) => |
864 str "}"]), | 685 let |
686 val name = case s of | |
687 "!" => "not" | |
688 | "-" => "neg" | |
689 | _ => raise Fail "Jscomp: Unknown unary operator" | |
690 | |
691 val (e, st) = jsE inner (e, st) | |
692 in | |
693 (strcat [str ("{c:\"f\",f:" ^ name ^ ",:a:cons("), | |
694 e, | |
695 str ",null)}"], | |
865 st) | 696 st) |
866 end | 697 end |
867 | 698 | EBinop (s, e1, e2) => |
868 | EUnop (s, e) => | 699 let |
869 let | 700 val name = case s of |
870 val (e, st) = jsE inner (e, st) | 701 "==" => "eq" |
871 in | 702 | "!strcmp" => "eq" |
872 (strcat [str ("(" ^ s), | 703 | "+" => "plus" |
873 e, | 704 | "-" => "minus" |
874 str ")"], | 705 | "*" => "times" |
875 st) | 706 | "/" => "div" |
876 end | 707 | "%" => "mod" |
877 | EBinop ("strcmp", e1, e2) => | 708 | "<" => "lt" |
878 let | 709 | "<=" => "le" |
710 | _ => raise Fail "Jscomp: Unknown binary operator" | |
711 | |
879 val (e1, st) = jsE inner (e1, st) | 712 val (e1, st) = jsE inner (e1, st) |
880 val (e2, st) = jsE inner (e2, st) | 713 val (e2, st) = jsE inner (e2, st) |
881 in | 714 in |
882 (strcat [str "strcmp(", | 715 (strcat [str ("{c:\"f\",f:" ^ name ^ ",a:cons("), |
883 e1, | 716 e1, |
884 str ",", | 717 str ",cons(", |
885 e2, | 718 e2, |
886 str ")"], | 719 str ",null))}"], |
887 st) | 720 st) |
888 end | 721 end |
889 | EBinop (s, e1, e2) => | 722 |
890 let | 723 | ERecord [] => (str "{c:\"c\",v:null}", st) |
891 val s = | 724 | ERecord xes => |
892 case s of | 725 let |
893 "!strcmp" => "==" | |
894 | _ => s | |
895 | |
896 val (e1, st) = jsE inner (e1, st) | |
897 val (e2, st) = jsE inner (e2, st) | |
898 in | |
899 (strcat [str "(", | |
900 e1, | |
901 str s, | |
902 e2, | |
903 str ")"], | |
904 st) | |
905 end | |
906 | |
907 | ERecord [] => (str "null", st) | |
908 | ERecord [(x, e, _)] => | |
909 let | |
910 val (e, st) = jsE inner (e, st) | |
911 in | |
912 (strcat [str ("{_" ^ x ^ ":"), e, str "}"], st) | |
913 end | |
914 | ERecord ((x, e, _) :: xes) => | |
915 let | |
916 val (e, st) = jsE inner (e, st) | |
917 | |
918 val (es, st) = | 726 val (es, st) = |
919 foldr (fn ((x, e, _), (es, st)) => | 727 foldr (fn ((x, e, _), (es, st)) => |
920 let | 728 let |
921 val (e, st) = jsE inner (e, st) | 729 val (e, st) = jsE inner (e, st) |
922 in | 730 in |
923 (str (",_" ^ x ^ ":") | 731 (strcat [str ("cons({n:\"" ^ x ^ ",v:"), |
924 :: e | 732 e, |
925 :: es, | 733 str "},", |
734 es, | |
735 str ")"], | |
926 st) | 736 st) |
927 end) | 737 end) |
928 ([str "}"], st) xes | 738 (str "null", st) xes |
929 in | 739 in |
930 (strcat (str ("{_" ^ x ^ ":") | 740 (strcat [str "{c:\"r\",l:", |
931 :: e | 741 es, |
932 :: es), | 742 str "}"], |
933 st) | 743 st) |
934 end | 744 end |
935 | EField (e', x) => | 745 | EField (e', x) => |
936 let | 746 let |
937 fun default () = | 747 fun default () = |
938 let | 748 let |
939 val (e', st) = jsE inner (e', st) | 749 val (e', st) = jsE inner (e', st) |
940 in | 750 in |
941 (strcat [e', | 751 (strcat [str "{c:\".\",r:", |
942 str ("._" ^ x)], st) | 752 e', |
753 str (",f:\"" ^ x ^ "\"}")], st) | |
943 end | 754 end |
944 | 755 |
945 fun seek (e, xs) = | 756 fun seek (e, xs) = |
946 case #1 e of | 757 case #1 e of |
947 ERel n => | 758 ERel n => |
958 | _ => raise Fail "Jscomp: Bad seek [2]") | 769 | _ => raise Fail "Jscomp: Bad seek [2]") |
959 t xs | 770 t xs |
960 | 771 |
961 val e = (ERel n, loc) | 772 val e = (ERel n, loc) |
962 val e = foldl (fn (x, e) => (EField (e, x), loc)) e xs | 773 val e = foldl (fn (x, e) => (EField (e, x), loc)) e xs |
774 val (e, st) = quoteExp t (e, st) | |
963 in | 775 in |
964 quoteExp t (e, st) | 776 (strcat [str "{c:\"c\",v:", |
777 e, | |
778 str "}"], | |
779 st) | |
965 end | 780 end |
966 | EField (e', x) => seek (e', x :: xs) | 781 | EField (e', x) => seek (e', x :: xs) |
967 | _ => default () | 782 | _ => default () |
968 in | 783 in |
969 seek (e', [x]) | 784 seek (e', [x]) |
970 end | 785 end |
971 | 786 |
972 | ECase (e', pes, {result, ...}) => | 787 | ECase (e', pes, _) => |
973 let | 788 let |
974 val plen = length pes | 789 val (e', st) = jsE inner (e', st) |
975 | 790 |
976 val (cases, st) = ListUtil.foldliMap | 791 val (ps, st) = |
977 (fn (i, (p, e), st) => | 792 foldr (fn ((p, e), (ps, st)) => |
978 let | 793 let |
979 val (e, st) = jsE (inner + E.patBindsN p) (e, st) | 794 val (e, st) = jsE inner (e, st) |
980 val fail = | 795 in |
981 if i = plen - 1 then | 796 (strcat [str "cons({p:", |
982 str ("pf(\"" ^ ErrorMsg.spanToString loc ^ "\")") | 797 jsPat p, |
983 else | 798 str ",b:", |
984 str ("c" ^ Int.toString (i+1) ^ "()") | 799 e, |
985 val c = jsPat 0 inner p e fail | 800 str "},", |
986 in | 801 ps, |
987 (strcat [str ("c" ^ Int.toString i ^ "=function(){return "), | 802 str ")"], |
988 c, | 803 st) |
989 str "},"], | 804 end) |
990 st) | 805 (str "null", st) pes |
991 end) | 806 in |
992 st pes | 807 (strcat [str "{c:\"m\",e:", |
993 | 808 e, |
994 val depth = foldl Int.max 0 (map (fn (p, _) => 1 + patDepth p) pes) | 809 str ",p:", |
995 val normalDepth = foldl Int.max 0 (map (fn (_, e) => 1 + varDepth e) pes) | 810 ps, |
996 val (e, st) = jsE inner (e', st) | 811 str "}"], st) |
997 | |
998 val len = inner + len | |
999 val normalVars = List.tabulate (normalDepth, fn n => "_" ^ Int.toString (n + len)) | |
1000 val patVars = List.tabulate (depth, fn n => "d" ^ Int.toString n) | |
1001 val caseVars = ListUtil.mapi (fn (i, _) => "c" ^ Int.toString i) pes | |
1002 in | |
1003 (strcat (str "(function (){ var " | |
1004 :: str (String.concatWith "," (normalVars @ patVars @ caseVars) ^ ";d0=") | |
1005 :: e | |
1006 :: str ";\nreturn (" | |
1007 :: List.revAppend (cases, | |
1008 [str "c0()) } ())"])), st) | |
1009 end | 812 end |
1010 | 813 |
1011 | EStrcat (e1, e2) => | 814 | EStrcat (e1, e2) => |
1012 let | 815 let |
1013 val (e1, st) = jsE inner (e1, st) | 816 val (e1, st) = jsE inner (e1, st) |
1014 val (e2, st) = jsE inner (e2, st) | 817 val (e2, st) = jsE inner (e2, st) |
1015 in | 818 in |
1016 (strcat [str "cat(", e1, str ",", e2, str ")"], st) | 819 (strcat [str "{c:\"f\",f:cat,a:cons(", e1, str ",cons(", e2, str ",null))}"], st) |
1017 end | 820 end |
1018 | 821 |
1019 | EError (e, _) => | 822 | EError (e, _) => |
1020 let | 823 let |
1021 val (e, st) = jsE inner (e, st) | 824 val (e, st) = jsE inner (e, st) |
1022 in | 825 in |
1023 (strcat [str "er(", e, str ")"], | 826 (strcat [str "{c:\"f\",f:er,a:cons(", e, str ",null)}"], |
1024 st) | 827 st) |
1025 end | |
1026 | |
1027 | EWrite e => | |
1028 let | |
1029 val (e, st) = jsE inner (e, st) | |
1030 in | |
1031 (strcat [str "document.write(", | |
1032 e, | |
1033 str ".v)"], st) | |
1034 end | 828 end |
1035 | 829 |
1036 | ESeq (e1, e2) => | 830 | ESeq (e1, e2) => |
1037 let | 831 let |
1038 val (e1, st) = jsE inner (e1, st) | 832 val (e1, st) = jsE inner (e1, st) |
1039 val (e2, st) = jsE inner (e2, st) | 833 val (e2, st) = jsE inner (e2, st) |
1040 in | 834 in |
1041 (strcat [str "(", e1, str ",", e2, str ")"], st) | 835 (strcat [str "{c:\";\",e1:", e1, str ",e2:", e2, str "}"], st) |
1042 end | 836 end |
1043 | ELet (_, _, e1, e2) => | 837 | ELet (_, _, e1, e2) => |
1044 let | 838 let |
1045 val (e1, st) = jsE inner (e1, st) | 839 val (e1, st) = jsE inner (e1, st) |
1046 val (e2, st) = jsE (inner + 1) (e2, st) | 840 val (e2, st) = jsE (inner + 1) (e2, st) |
1047 in | 841 in |
1048 (strcat [str ("(_" ^ Int.toString (len + inner) ^ "="), | 842 (strcat [str "{c:\"=\",e1:", |
1049 e1, | 843 e1, |
1050 str ",", | 844 str ",e2:", |
1051 e2, | 845 e2, |
1052 str ")"], st) | 846 str "}"], st) |
1053 end | 847 end |
1054 | 848 |
1055 | EJavaScript (Source _, e) => | 849 | EJavaScript (Source _, e) => |
1056 (foundJavaScript := true; | 850 (foundJavaScript := true; |
1057 jsE inner (e, st)) | 851 jsE inner (e, st)) |
1058 | EJavaScript (_, e) => | 852 | EJavaScript (_, e) => |
1059 let | 853 let |
1060 val locals = List.tabulate | |
1061 (varDepth e, | |
1062 fn i => str ("var _" ^ Int.toString (len + inner + i) ^ ";")) | |
1063 | |
1064 val (e, st) = jsE inner (e, st) | 854 val (e, st) = jsE inner (e, st) |
1065 in | 855 in |
1066 foundJavaScript := true; | 856 foundJavaScript := true; |
1067 (strcat (str "cs(function(){" | 857 (strcat [str "{c:\"e\",e:", |
1068 :: locals | 858 e, |
1069 @ [str "return ", | 859 str "}"], |
1070 (*compact inner*) e, | |
1071 str "})"]), | |
1072 st) | 860 st) |
1073 end | 861 end |
1074 | 862 |
863 | EWrite _ => unsupported "EWrite" | |
1075 | EClosure _ => unsupported "EClosure" | 864 | EClosure _ => unsupported "EClosure" |
1076 | EQuery _ => unsupported "Query" | 865 | EQuery _ => unsupported "Query" |
1077 | EDml _ => unsupported "DML" | 866 | EDml _ => unsupported "DML" |
1078 | ENextval _ => unsupported "Nextval" | 867 | ENextval _ => unsupported "Nextval" |
1079 | EUnurlify _ => unsupported "EUnurlify" | 868 | EUnurlify _ => unsupported "EUnurlify" |
1081 | 870 |
1082 | ESignalReturn e => | 871 | ESignalReturn e => |
1083 let | 872 let |
1084 val (e, st) = jsE inner (e, st) | 873 val (e, st) = jsE inner (e, st) |
1085 in | 874 in |
1086 (strcat [str "sr(", | 875 (strcat [str "{c:\"f\",f:sr,a:cons(", |
1087 e, | 876 e, |
1088 str ")"], | 877 str ",null)}"], |
1089 st) | 878 st) |
1090 end | 879 end |
1091 | ESignalBind (e1, e2) => | 880 | ESignalBind (e1, e2) => |
1092 let | 881 let |
1093 val (e1, st) = jsE inner (e1, st) | 882 val (e1, st) = jsE inner (e1, st) |
1094 val (e2, st) = jsE inner (e2, st) | 883 val (e2, st) = jsE inner (e2, st) |
1095 in | 884 in |
1096 (strcat [str "sb(", | 885 (strcat [str "{c:\"b\",e1:", |
1097 e1, | 886 e1, |
1098 str ",", | 887 str ",e2:", |
1099 e2, | 888 e2, |
1100 str ")"], | 889 str "}"], |
1101 st) | 890 st) |
1102 end | 891 end |
1103 | ESignalSource e => | 892 | ESignalSource e => |
1104 let | 893 let |
1105 val (e, st) = jsE inner (e, st) | 894 val (e, st) = jsE inner (e, st) |
1106 in | 895 in |
1107 (strcat [str "ss(", | 896 (strcat [str "{c:\"f\",f:ss,a:cons(", |
1108 e, | 897 e, |
1109 str ")"], | 898 str ",null)}"], |
1110 st) | 899 st) |
1111 end | 900 end |
1112 | 901 |
1113 | EServerCall (e, ek, t, eff) => | 902 | EServerCall (e, ek, t, eff) => |
1114 let | 903 let |
1115 val (e, st) = jsE inner (e, st) | 904 val (e, st) = jsE inner (e, st) |
1116 val (ek, st) = jsE inner (ek, st) | 905 val (ek, st) = jsE inner (ek, st) |
1117 val (unurl, st) = unurlifyExp loc (t, st) | 906 val (unurl, st) = unurlifyExp loc (t, st) |
1118 in | 907 in |
1119 (strcat [str ("rc(cat(\"" ^ Settings.getUrlPrefix () ^ "\","), | 908 (strcat [str ("{c:\"f\",f:rc,a:cons({c:\"c\",v:\"" |
909 ^ Settings.getUrlPrefix () | |
910 ^ "\"},cons("), | |
1120 e, | 911 e, |
1121 str ("), function(s){var t=s.split(\"/\");var i=0;return " | 912 str (",cons({c:\"c\",v:function(s){var t=s.split(\"/\");var i=0;return " |
1122 ^ unurl ^ "},"), | 913 ^ unurl ^ "}},cons({c:\"!\",e:"), |
1123 ek, | 914 ek, |
1124 str ("," | 915 str ("},cons(" |
1125 ^ (case eff of | 916 ^ (case eff of |
1126 ReadCookieWrite => "true" | 917 ReadCookieWrite => "true" |
1127 | _ => "false") | 918 | _ => "false") |
1128 ^ ")")], | 919 ^ ",null)))))}")], |
1129 st) | 920 st) |
1130 end | 921 end |
1131 | 922 |
1132 | ERecv (e, ek, t) => | 923 | ERecv (e, ek, t) => |
1133 let | 924 let |
1134 val (e, st) = jsE inner (e, st) | 925 val (e, st) = jsE inner (e, st) |
1135 val (ek, st) = jsE inner (ek, st) | 926 val (ek, st) = jsE inner (ek, st) |
1136 val (unurl, st) = unurlifyExp loc (t, st) | 927 val (unurl, st) = unurlifyExp loc (t, st) |
1137 in | 928 in |
1138 (strcat [str "rv(", | 929 (strcat [str ("{c:\"f\",f:rv,a:cons("), |
1139 e, | 930 e, |
1140 str (", function(s){var t=s.split(\"/\");var i=0;return " | 931 str (",cons({c:\"c\",v:function(s){var t=s.split(\"/\");var i=0;return " |
1141 ^ unurl ^ "},"), | 932 ^ unurl ^ "}},cons({c:\"!\",e:"), |
1142 ek, | 933 ek, |
1143 str ")"], | 934 str ("},null)))}")], |
1144 st) | 935 st) |
1145 end | 936 end |
1146 | 937 |
1147 | ESleep (e, ek) => | 938 | ESleep (e, ek) => |
1148 let | 939 let |
1149 val (e, st) = jsE inner (e, st) | 940 val (e, st) = jsE inner (e, st) |
1150 val (ek, st) = jsE inner (ek, st) | 941 val (ek, st) = jsE inner (ek, st) |
1151 in | 942 in |
1152 (strcat [str "window.setTimeout(", | 943 (strcat [str "{c:\"f\",f:window.setTimeout,a:cons(", |
1153 ek, | 944 ek, |
1154 str ", ", | 945 str ",cons(", |
1155 e, | 946 e, |
1156 str ")"], | 947 str ",null))}"], |
1157 st) | 948 st) |
1158 end | 949 end |
1159 end | 950 end |
1160 in | 951 in |
1161 jsE | 952 jsE 0 |
1162 end | 953 end |
1163 | |
1164 | 954 |
1165 fun patBinds ((p, _), env) = | 955 fun patBinds ((p, _), env) = |
1166 case p of | 956 case p of |
1167 PWild => env | 957 PWild => env |
1168 | PVar (_, t) => t :: env | 958 | PVar (_, t) => t :: env |
1348 in | 1138 in |
1349 ((EUnurlify (e, t), loc), st) | 1139 ((EUnurlify (e, t), loc), st) |
1350 end | 1140 end |
1351 | 1141 |
1352 | EJavaScript (m, e') => | 1142 | EJavaScript (m, e') => |
1353 (let | 1143 (foundJavaScript := true; |
1354 val len = length outer | 1144 jsExp m outer (e', st) |
1355 fun str s = (EPrim (Prim.String s), #2 e') | 1145 handle CantEmbed _ => (e, st)) |
1356 | |
1357 val locals = List.tabulate | |
1358 (varDepth e', | |
1359 fn i => str ("var _" ^ Int.toString (len + i) ^ ";")) | |
1360 | |
1361 val (e', st) = jsExp m outer 0 (e', st) | |
1362 | |
1363 val e' = | |
1364 case locals of | |
1365 [] => e' | |
1366 | _ => | |
1367 strcat (#2 e') (str "(function(){" | |
1368 :: locals | |
1369 @ [str "return ", | |
1370 e', | |
1371 str "}())"]) | |
1372 in | |
1373 (e', st) | |
1374 end handle CantEmbed _ => (e, st)) | |
1375 | 1146 |
1376 | ESignalReturn e => | 1147 | ESignalReturn e => |
1377 let | 1148 let |
1378 val (e, st) = exp outer (e, st) | 1149 val (e, st) = exp outer (e, st) |
1379 in | 1150 in |