package js_of_ocaml-compiler

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file pseudoFs.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
(* Js_of_ocaml compiler
 * http://www.ocsigen.org/js_of_ocaml/
 * Copyright (C) 2014 Hugo Heuzard
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, with linking exception;
 * either version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *)

open Stdlib

let expand_path exts real virt =
  let rec loop realfile virtfile acc =
    if try Sys.is_directory realfile with _ -> false
    then
      Array.fold_left (Sys.readdir realfile) ~init:acc ~f:(fun acc s ->
          loop (Filename.concat realfile s) (Filename.concat virtfile s) acc)
    else
      try
        let exmatch =
          try
            let b = Filename.basename realfile in
            let i = String.rindex b '.' in
            let e = String.sub b ~pos:(i + 1) ~len:(String.length b - i - 1) in
            List.mem e ~set:exts
          with Not_found -> List.mem "" ~set:exts
        in
        if exts = [] || exmatch then (virtfile, realfile) :: acc else acc
      with exc ->
        warn "ignoring %s: %s@." realfile (Printexc.to_string exc);
        acc
  in
  loop real virt []

let list_files name paths =
  let name, virtname =
    match String.lsplit2 name ~on:':' with
    | Some (src, dest) ->
        if String.length dest > 0 && dest.[0] <> '/'
        then
          failwith (Printf.sprintf "path '%s' for file '%s' must be absolute" dest src);
        let virtname =
          if dest.[String.length dest - 1] = '/'
          then dest ^ Filename.basename src
          else dest
        in
        src, virtname
    | None ->
        (* by default, files are store in /static/ directory *)
        name, "/static/" ^ Filename.basename name
  in
  let name, exts (* extensions filter *) =
    match String.lsplit2 name ~on:'=' with
    | Some (name, exts) -> name, String.split_char ~sep:',' exts
    | None -> name, []
  in
  let file =
    try Findlib.find_in_findlib_paths paths name
    with Not_found -> failwith (Printf.sprintf "file '%s' not found" name)
  in
  expand_path exts file virtname

let cmi_dir = "/static/cmis"

let find_cmi paths base =
  try
    let name = String.uncapitalize_ascii base ^ ".cmi" in
    Filename.concat cmi_dir name, Findlib.find_in_findlib_paths paths name
  with Not_found ->
    let name = String.capitalize_ascii base ^ ".cmi" in
    Filename.concat cmi_dir name, Findlib.find_in_findlib_paths paths name

open Code

let read name filename =
  let content = Fs.read_file filename in
  Pc (IString name), Pc (IString content)

let program_of_files l =
  let fs = List.map l ~f:(fun (name, filename) -> read name filename) in
  let body =
    List.map fs ~f:(fun (n, c) ->
        Let (Var.fresh (), Prim (Extern "caml_create_file_extern", [n; c])))
  in
  let pc = 0 in
  let blocks =
    Addr.Map.add
      pc
      {params = []; handler = None; body = []; branch = Stop}
      Addr.Map.empty
  in
  let p = pc, blocks, pc + 1 in
  Code.prepend p body

let make_body prim cmis files paths =
  let fs, missing =
    StringSet.fold
      (fun s (acc, missing) ->
        try
          let name, filename = find_cmi paths s in
          read name filename :: acc, missing
        with Not_found -> acc, s :: missing)
      cmis
      ([], [])
  in
  if missing <> []
  then (
    warn "Some OCaml interface files were not found.@.";
    warn "Use [-I dir_of_cmis] option to bring them into scope@.";
    (* [`ocamlc -where`/expunge in.byte out.byte moduleA moduleB ... moduleN] *)
    List.iter missing ~f:(fun nm -> warn "  %s@." nm));
  let fs =
    List.fold_left files ~init:fs ~f:(fun acc f ->
        let l = list_files f paths in
        List.fold_left l ~init:acc ~f:(fun acc (n, fn) -> read n fn :: acc))
  in
  let body =
    List.map fs ~f:(fun (n, c) -> Let (Var.fresh (), Prim (Extern prim, [n; c])))
  in
  body

let f p cmis files paths =
  let body = make_body "caml_create_file" cmis files paths in
  Code.prepend p body

let f_empty cmis files paths =
  let body = make_body "caml_create_file_extern" cmis files paths in
  let pc = 0 in
  let blocks =
    Addr.Map.add
      pc
      {params = []; handler = None; body = []; branch = Stop}
      Addr.Map.empty
  in
  let p = pc, blocks, pc + 1 in
  Code.prepend p body