ocsigen / eliomlang Goto Github PK
View Code? Open in Web Editor NEWRuntime and tools for the eliom language
License: ISC License
Runtime and tools for the eliom language
License: ISC License
To split mixed-side cmi in two cmi, one client and one server.
Could be useful for export to normal ocaml world.
Example:
module T = struct type%server t = int type%client t' = t fragment end
Functors are difficult to handle, mainly because of code like that:
module type S = sig
type%client t
type%server t'
end
module F (M : S) = struct
...
end
Since .cmi
should be split between client and server, there is no way to check if a given module fulfill this signature (there is not even a way to export this signature properly ...)
This kind of functions should be forbidden with a decent error message:
let%client f x = ~%( [%client x] )
Right now, it crashes, but it's not obvious why.
The good way to check for this is to walk the typedtree after typechecking, register the (server) env when entering a client scope and check that each identifier mentioned in a server slice (inside the client scope) is defined in the outer env.
Let's consider a .cmi
exporting this api:
val f : unit -> Dom.t Fragment.t
If this is loaded by vanilla ocaml Dom.t
will not be considered client, and the symbol might not even exist. Fragment.t
should still be a black box, though.
@vouillon proposed to emit a different magic for such cmi.
There are two steps here:
If we ignore the typing difficulties related to functors (See #4), there is also a difficult for runtime execution. The number and content of sections must be static, in order to be synchronized between client and server. It could be possible to use fragments to implement those specific sections.
This is a schematic implementation of global and request fragments given converters:
type%server 'a frag = Global of int | Request of int
type%server fragment = { clojure_id : string ; args : poly array }
Two tables, on both side
On the server side:
global_fragments : id_r -> fragment
request_fragments : id_g -> fragment
The tables are built during execution of Eliom_runtime.fragment
. On the first request, both tables are sent. On subsequent requests, only request_fragments
is sent.
On the client side,
global_fragments : id_r -> Obj.t
request_fragments : id_g -> Obj.t
close_server_section
populates the global table. A function in init
(to be implemented) executes fragment requests and populates the fragment table.deserialize
function for fragments will do a lookup in the appropriate table and return the value of the fragment.Due to oasis/ocamlfind issues, installation doesn't work yet. Patch for oasis is being worked on here: ocaml/oasis#76
module T : sig type%client t = int type%server t' = t fragment end
At the moment, side-switch happens when a type expression of the form foo Eliom_fragment.t
. It doesn't work with aliases. More problematic, even if we were to resolve aliases, there is still the issue of abstract types that contains some client fragments (type 'a t = { foo : int ; bar : ('a * string) Eliom_fragment.t }
).
One proposition to resolve this is to use a similar mechanism to variance: it's correctly propagated by the compiler and annotate type variables. For a given type constructor, we just need to lookup the type declaration to know we should switch side.
When in eliom mode, all crc must be duplicated with a @c
and @s
version.
functors with mixed parameters and/or result needs decliate handling of names. After discussion with @vouillon , we can try the following scheme:
It should be possible to make a toplevel by spliting the code as it is entered and by compiling the client bytecode with js_of_ocaml
when a page is served.
module%client M = Map.Make(String)
module%server N = Map.Make(String)
module N = struct type%client t type%server t' end
module%client M = N
This doesn't work at the moment:
module%server A = struct
type t = int * string fragment
let compare (x,y) (x',y') = compare x x'
end
module%server B = Map.Make(A)
The issue is that Map.Make
expects a module in scope base, not in scope server. We need to lift the module type into the server scope when lifting the module itself.
Since sides are on Ident.t
only, and Path.t
contains an Ident
only for the first segment of the path. M.foo
doesn't properly account for side. However opam M
put foo
in the correct scope.
Example of badly handled code:
module M = struct
let%client foo = 3
let%server bar = 4
end
let%server x = M.foo (* Typechecks, WRONG *)
let%server x = let open M in foo (* Does not typechecks *)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.