[gambit-list] -target js
feeley at iro.umontreal.ca
Sat Nov 23 09:54:23 EST 2013
On Nov 22, 2013, at 4:52 PM, Mikael <mikael.rcv at gmail.com> wrote:
> (For general interest)
> 2013/11/22 Marc Feeley <feeley at iro.umontreal.ca>
> On Nov 22, 2013, at 1:40 AM, Mikael <mikael.rcv at gmail.com> wrote:
> > Francois,
> > Two Q:s:
> > First, when you got a very basic sample app like a DOM-based hangman going, feel free to share code
> > Second, how is the type mapping - fixnums, flonums, bignums all wrapped to JS double, Scheme string and vector to JS string and vector?
> The data representation is customizable with two options for each type. There is a "natural" mapping (Scheme number -> JS number, Scheme vector -> JS array, etc) and one which uses classes.
> Note that the natural mapping may violate some of the Scheme semantics. For example, JS numbers don't carry the concept of exactness, and JS strings are immutable whereas Scheme strings are mutable. On the other hand the natural mapping may be useful in cases where some details of the Scheme semantics are not important (the generated JS code is easier to read/understand, the generated JS code can be more easily interfaced with existing JS libraries, etc). A mapping which respects the Scheme semantics is:
> - Fixnums are mapped to JS numbers
> - Booleans are mapped to JS booleans
> - Symbols are mapped to JS strings
> - Vectors are mapped to JS arrays
> - Procedures are mapped to JS functions
> - Strings, characters, flonums (and other numbers), and pairs are implemented with JS classes
> Wait, first(1) you suggest there's a customizable option, and then second(2) you outline a holistic approach for Scheme-JS type mapping.
> How is it? And if anything is configurable, where's the switch?
The source code of the universal backend was written to support both data representations, selectable for each type. So it is "customizable" in the sense that you simply have to change a single definition in _t-univ.scm to select the representation for each Scheme type (see the top of the file, e.g. (define (univ-flonum-representation ctx) 'class) ). It would be possible to expose these settings to the user, although it is not clear what is the best way to do that. Perhaps that could be part of the target's name, e.g.
gsc -target js file.scm
gsc -target js-foo file.scm
gsc -target js-bar file.scm
where foo and bar would indicate a particular choice of data representations that make some compromises (e.g. incomplete support of the Gambit specific features, lesser performance for some of the Gambit specific features, etc).
> Unfortunately, this mapping makes it expensive to implement some Gambit specific operations, such as ##subtype, ##subtype-set! and
> Didn't even hear about ##subtype* til now - Any use of JS turns out to be for some special purpose anyhow, so that there's some real corner case of Scheme execution in this environment that has a low performance is really completely cool.
The problem is that ##subtype, etc are used in the implementation of the Gambit runtime library. For example, ##subtype is used in the implementation of the procedure equal?-hash and some type predicates. So even if ##subtype is not used directly by users, some user callable procedures in the Gambit runtime library do use ##subtype.
> Wait, why, can't this just be ordinarily expanded to JS' variable[index]?
Because ##vector-ref is used to access slots of many Gambit objects, not just vectors. For example the slot at index 0 of a symbol is the symbol's name, and the slot at index 0 of a structure is the type descriptor:
> (##vector-ref 'foo 0)
> (##vector-ref (current-input-port) 0)
#<type #4 device-port>
If a Scheme datatype is represented using a JS class (for example a Scheme symbol is represented with a JS class with a "name" property), then (##vector-ref sym 0) if it is translated to sym will not retrieve the name of the symbol. It would be possible to avoid this problem by using JS arrays to represent all memory allocated Gambit objects, but this would not be a natural translation (harder to understand the generated code, harder to write external JS code accessing the data representation, etc). Another approach would be to put some type dispatch logic in ##vector-ref to do the right thing with symbols, structures, etc, but this would slow down ##vector-ref.
Of course another approach would be to refactor the Gambit runtime system to replace such "unclean" uses of ##vector-ref by calls to type specific primitives. It is not clear how much work this would be (primitives have to be added to the compiler and the runtime system has to be refactored).
> So it may be necessary to implement non immediate data (vectors, structures, etc) uniformly with classes when using the standard Gambit runtime system.
> I haven't explored this aspect much, but it may be that supporting all the Gambit primitives isn't practical.
> (same note as above re special purpose here)
> A solution may be to have two modes (Standard Scheme and Gambit Scheme) so the user can select the best mode for his needs.
> What would the difference be approx here?
Hard to say. The Gambit runtime system has to be examined carefully to see what would break for a particular choice of representation. For example, in a mode where number exactness is not supported (allowing all Scheme numbers to be represented with the JS "number" type, except for complex numbers), there will be a major impact on the numerical functions in lib/_num.scm . Some (how many?) will have to be modified to be consistent with the fact that there is no exactness. Should the lack of exactness be handled the same as treating all numbers as inexact numbers? etc.
More information about the Gambit-list