Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • 11:07
    feeley commented #800
  • Nov 28 20:09
    amirouche commented #800
  • Nov 28 20:08
    amirouche commented #800
  • Nov 28 13:10
    feeley commented #800
  • Nov 28 12:01
    feeley edited #800
  • Nov 28 12:00
    feeley commented #800
  • Nov 28 11:52
    amirouche closed #800
  • Nov 28 11:52
    amirouche commented #800
  • Nov 27 22:48
    feeley commented #800
  • Nov 27 22:29
    lassik commented #800
  • Nov 27 18:20
    amirouche commented #800
  • Nov 27 18:17
    amirouche opened #800
  • Nov 25 15:00
    CI run 3548417753 passed
  • Nov 25 13:58
    feeley commented on 8195d7d
  • Nov 25 13:39

    feeley on master

    Allow modules/libraries to be u… (compare)

  • Nov 21 10:40
    feeley commented #799
  • Nov 21 04:47
    FredericHamel commented #797
  • Nov 21 04:26
    FredericHamel edited #799
  • Nov 21 04:25
    FredericHamel opened #799
  • Nov 21 02:53
    FredericHamel commented #797
KM
@twoplustwo:matrix.org
[m]
Or if not, I could write my own, but how do I find a string position inside another one?
I found this string-contains here https://practical-scheme.net/wiliki/schemexref.cgi?string-contains can I use it somehow?
Marc Feeley
@feeley
@twoplustwo:matrix.org This could be useful:
(define (string-substitute str delim proc-or-alist)

  (define (index-of c start)
    (let loop ((i start))
      (if (fx< i (string-length str))
          (if (char=? c (string-ref str i))
              i
              (loop (fx+ i 1)))
          i)))

  (let loop ((i 0) (j 0) (out '()))
    (let ((start (index-of delim j)))
      (if (fx< start (string-length str))
          (let ((end (index-of delim (fx+ start 1))))
            (if (fx< end (string-length str))
                (if (fx= start (fx- end 1)) ;; two delimiters in a row?
                    (loop (fx+ end 1)
                          (fx+ end 1)
                          (cons (substring str i end)
                                  out))
                    (let* ((var
                            (substring str (fx+ start 1) end))
                           (subst
                            (if (procedure? proc-or-alist)
                                (proc-or-alist var)
                                (let ((x (assoc var proc-or-alist)))
                                  (and x (cdr x))))))
                      (if subst
                          (loop (fx+ end 1)
                                (fx+ end 1)
                                (cons subst
                                        (cons (substring str i start)
                                                out)))
                          (error "Unbound substitution variable in" str))))
                (error "Unbalanced delimiter in" str)))
          (string-concatenate
           (reverse (cons (substring str i start) out)))))))

(pp (string-substitute "@a@ plus 1 is @b@" #\@ '(("a" ."two") ("b" . "three"))))
KM
@twoplustwo:matrix.org
[m]
cool, I will walk through this. how can I import string-concatenate ?
Marc Feeley
@feeley
@twoplustwo:matrix.org string-concatenate is builtin (you need v4.9.4)
cs7
@cs7:matrix.org
[m]
= same as string-append ?
Marc Feeley
@feeley
@twoplustwo:matrix.org (string-concatenate lst) = (apply string-append lst)
cs7
@cs7:matrix.org
[m]
ah yesyes i see. many thanks.
jeffhhk
@jeffhhk

Hello, I'm trying gambit for the first time, starting with the javascript support in 4.9.4. I am able to reproduce the instructions at

http://www.gambitscheme.org/latest/manual/#Compiling-Modules

However, if I change much from that basic scenario, stuff stops working. For example, here is my attempt to extend to importing SRFI 78:

git clone https://github.com/scheme-requests-for-implementation/srfi-78

cat srfi-78/srfi-78.sld
    (define-library (srfi-78)
      (import (scheme base))
      (export hello-world)
      (include "check.scm")
      (begin
        (define (hello-world)
          (display "hello world\n"))
    ))

cat hello-test/hello-test.sld
    (define-library (hello-test)
      (import (srfi-78) (scheme base) (scheme write))
      (begin
        (display
         (cond-expand
           ((compilation-target C)   "compiled to C\n")
           ((compilation-target (_)) "interpreted\n")
           (else                     "compiled to other\n")))
        (hello-world)
        (newline)))

gsc -target js . srfi-78 hello-test
    Building module: srfi-78

gsc -target js . srfi-78
    <no output>
gsc -target js . hello-test
    <no output>

gsc -target js -exe -nopreload . srfi-78/srfi-78.sld hello-test/hello-test.sld
    srfi-78/srfi-78.sld:
    /home/jeff/srchome/src/zipper/srfi-78/srfi-78.js:
    hello-test/hello-test.sld:
    /home/jeff/srchome/src/zipper/hello-test/hello-test.js:
    /home/jeff/srchome/src/zipper/hello-test/hello-test_.js:

hello-test/hello-test
    compiled to other
    *** ERROR IN hello-test# -- Operator is not a PROCEDURE
    (#!void "hello world\n")
I would have expected:
  • two "Building module" messages for building srfi-78 and hello-test together
  • one "Building module" message for building srfi-78 and hello-test each separately
  • successful -exe generation to result in a runnable program.
Results are the same with or without the (include "check.scm") commented out.
jeffhhk
@jeffhhk
Thanks in advance for any help!
jeffhhk
@jeffhhk
Well I figured out one thing:
(define-library (srfi-78)
  (import (scheme base) (scheme write))

Now:

gsc -target js . srfi-78 hello-test && \
gsc -target js -exe -nopreload . srfi-78/srfi-78.sld hello-test/hello-test.sld && \
node hello-test/hello-test

emits:

Building module: srfi-78
srfi-78/srfi-78.sld:
/home/jeff/srchome/src/zipper/srfi-78/srfi-78.js:
hello-test/hello-test.sld:
/home/jeff/srchome/src/zipper/hello-test/hello-test.js:
/home/jeff/srchome/src/zipper/hello-test/hello-test_.js:

compiled to other
hello world
jeffhhk
@jeffhhk

So that's good. Still can't get these:

(export hello-world check)
(include "check.scm")

To allow this:

(check (+ 2 2) => 4)
Ok, this did the trick:
(define-library (srfi-78)
  (import (scheme base) (scheme write))
  (export hello-world check check-passed? check-report check-reset! check-set-mode!
    check:add-correct! check:add-failed! check:correct check:failed
    check:mode check:proc check:proc-ec check:report-actual-result
    check:report-correct check:report-expression check:report-failed
    check:write)
  (include "check.scm")
  (begin
    (define (hello-world)
      (display "hello world\n"))
))
I think I've answered my question. Thanks!
Marc Feeley
@feeley
@jeffhhk Yes the macro dependencies are not automatically exported (as they should be implicitly)… this is being worked on
BTW the -warnings option to gsc is useful in this situation
jeffhhk
@jeffhhk
@feeley Good to know, thanks!
jeffhhk
@jeffhhk

I'm looking for a workflow to incrementally develop a library in the r7rs define-library style, including the ability to test in a repl. Currently using emacs scheme-mode for sending to the repl.

Suppose I want to change the library and then as quickly as possible test with the repl. I wrote a wrapper script to run gsi which finds the correct directory to pass with -:search so that my import will work. But after making a change I noticed when doing import as above in gsi that I can't seem to do import again and pick up the change. I'm okay with clearing out my environment to do so.

  • I tried finding a clear scheme environment api, but didn't see one.
  • I tried passing -prelude "(import (my-lib))" to get a gsc repl, but gsc doesn't evaluate display statements before dropping to the repl.
  • I tried passing -prelude "(import (my-lib))" to gsi, but gsi seems to reject it outright.

I suppose I could script this with a custom emacs command or subprocess tty hacks, but I was hoping to stay within gambit for editor independence. Is there any similar api available?

jeffhhk
@jeffhhk
Here's an attempt to use .gambini to do a project-specific repl initial import:
(display "hello $HOME/.gambini\n")

(define (dir-for-project)
  (let loop ((d (path-strip-trailing-directory-separator (current-directory))))
    (let ((files (directory-files (list (string->keyword "path") d (string->keyword "ignore-hidden") #f))))
      (if (or (equal? 0 (string-length d))
          (member ".gambini-local" files))
      d
      (loop (path-strip-trailing-directory-separator (path-directory d)))))))

(map display `(about to add ,(dir-for-project) "\n"))
(module-search-order-add! (dir-for-project))

;; TODO: look for project-specific modules to load in .gambini-local

;; For now, simulate by hard-coding:

;;(import (srfi-78))
;;  =>
;;  Cannot find library (srfi-78)
(eval "(define foo 123)")
;; does not cause error, but foo is not bound in the repl
Marc Feeley
@feeley
@jeffhhk you probably want:
$ gsi . -e "(import (srfi 28))" -
> (format "~a + ~a = ~a" 1 2 3)
"1 + 2 = 3"
and for eval you want: (eval ‘(define foo 123))
because (eval “a string”) => ”a string”
Marc Feeley
@feeley
This undocumented feature may also be useful:
$ gsi
Gambit v4.9.4-39-g9a887b80

> (import foo/bar) ;; same as (import (foo bar))
> (##remove-registered-module ‘foo/bar)
...
> (import foo/bar) ;; will load it again
jeffhhk
@jeffhhk
Great thanks! All useful. Here it is all put together:
#|
Initializes project-specific path and imports for repl-based testing.
Place initialization code for your gambit based project in the project
root directory.

For example:
    mkdir -p srfi-78
    git clone https://github.com/scheme-requests-for-implementation/srfi-78 srfi-78/srfi-78
    cat > srfi-78/srfi-78.sld 
        (define-library (srfi-78)
          (import (scheme base) (scheme write))
          (export hello-world check check-passed? check-report check-reset! check-set-mode!
            check:add-correct! check:add-failed! check:correct check:failed
            check:mode check:proc check:proc-ec check:report-actual-result
             check:report-correct check:report-expression check:report-failed
            check:write)
          (include "srfi-78/check.scm")
          (begin
            (define (hello-world)
              (display "hello world\n"))
        ))
    cat > .gambini-local
        (import (srfi-78))
        (define bar 456)
    gsi
        hello HOME/.gambini
        Found .gambini-local.  Will module-search-order add ../src/zipper
        About to eval: (begin (import (srfi-78)) (define bar 456))
        Gambit v4.9.4

        > bar
        456
        > (check (+ 2 2) => 4)

        (+ 2 2) => 4 ; correct
        >     
|#
(import (srfi 28))

(define rfile-local ".gambini-local")

(define (dir-for-project)
  (let loop ((d (path-strip-trailing-directory-separator (current-directory))))
    (let ((files (directory-files (list (string->keyword "path") d (string->keyword "ignore-hidden") #f))))
      (cond
       ((equal? 0 (string-length d)) #f)
       ((member rfile-local files) d)
       (else 
    (loop (path-strip-trailing-directory-separator (path-directory d))))))))

(define (file-for-project)
  (path-expand rfile-local (dir-for-project)))

(if (dir-for-project)
    (begin
      (display (format "Found .gambini-local.  Will module-search-order add ~a\n" (dir-for-project)))
      (module-search-order-add! (dir-for-project))

      (let ((sexp-local `(begin ,@(with-input-from-file ".gambini-local" (lambda () (read-all (current-input-port)))))))

    (display (format "About to eval: ~a\n" sexp-local))
    (eval sexp-local))))
jeffhhk
@jeffhhk

A curious thing about the above .gambini is that it runs even when initializing gsc for batch compilation. Is there an API for detecting running in a repl, such as cond-expand?

If not, I suppose I could guard the above with an environment variable and only set it in my testing repl.

Marc Feeley
@feeley

@jeffhhk The Gambit manual has this explanation:

Extensions which are meant to apply to a single user or to a specific working directory are best placed in the initialization file, which is a file containing Scheme code. In all modes, the interpreter first tries to locate the initialization file by searching the following locations: ‘.gambini’ and ‘ ̃/.gambini’ (with no extension, a ‘.sld’ extension, a ‘.scm’ extension, and a ‘.six’ extension in that order). The first file that is found is examined as though the expression (include initialization-file) had been entered at the read-eval-print loop where initialization-file is the file that was found. Note that by using an include the macros defined in the initialization file will be visible from the read-eval-print loop (this would not have been the case if load had been used). The initialization file is not searched for or examined when the ‘-f’ option is specified.

The .gambini file will be visited by gsi and gsc (unless the -f option is specified) because the code it contains is meant to configure or extend the Gambit runtime library. There are various ways to detect if code is being run by gsi or gsc:
1) check for presence of compile-file procedure which is defined only by gsc:

(if (##unbound? (##global-var-ref (##make-global-var 'compile-file)))
    (display “gsi\n”)
    (display “gsc\n”))

2) check the name of the executable:

(if (member (path-strip-directory (executable-path)) '("gsi" "gsi-script”))
    (display “gsi\n”)
    (display “gsc\n”))

3) if you want to check if code is interpreted or compiled:

$ cat .gambini
(define-macro (interpreted-code?)
  `(cond-expand ((compilation-target (_))
                 #t)
                (else
                 #f)))
$ cat foo.scm
(if (interpreted-code?)
    (display "interpreted code\n")
    (display "compiled code\n"))
$ gsi foo.scm
interpreted code
$ gsc -exe foo.scm
$ ./foo
compiled code
$ gsc -i foo.scm
interpreted code
$ gsc
Gambit v4.9.4-39-g9a887b80

> (load "foo.scm")
interpreted code
"/Users/feeley/foo.scm"
> (compile-file "foo.scm")
"/Users/feeley/foo.o1"
> (load "foo.o1")
compiled code
"/Users/feeley/foo.o1"

Note that with #3 it is not the program (gsi or gsc) that is checked, but rather the way the code is executed, which is often a more robust test because gsc can both compile and interpret code (when given the -i option or no command line arguments).

1 reply
Ricardo G. Herdt
@r.herdt_gitlab

Hi there!
While porting my json-rpc to Gambit, I found a possible bug:

> (alist->hash-table '())
*** ERROR IN (stdin)@2.1 -- PAIR LIST expected
(srfi/69#alist->hash-table '())

Trying to convert an empty list into a hash-table sounds lame, but I'm using it as a set-filter for make-parameter, like this:

(define json-rpc-handler-table
  (make-parameter '() (lambda (alist) (alist->hash-table alist equal?))))

I'm using v4.9.4. BTW, I also noticed that gsi still shows v4.9.3

Ricardo G. Herdt
@r.herdt_gitlab
another bug: define-values seems not to work inside a lambda/function definition. According to R7RS define-values "is allowed wherever define is allowed":
> (define (f) (define-values (a b) 1 2) #t)     
*** ERROR IN (stdin)@2.13 -- Unknown expression parsing exception
Marc Feeley
@feeley
The bug with SRFI 69 is kind of embarassing… now fixed and I have added unit tests for this.
Concerning the problem with define-values, the correct implementation of this form and other R7RS forms depends on the new macro system we are working on… in the meantime you can use this definition:
(define-macro (define-values vars expr)
  (cond ((null? vars)
         (let ((temp (gensym)))
           `(##define ,temp
              (##call-with-values (##lambda () ,expr) ##list))))
        ((null? (cdr vars))
         `(##define ,(car vars) ,expr))
        (else
         (let ((temp (gensym)))
           `(##begin
              (##define ,temp
                (##call-with-values (##lambda () ,expr) ##list))
              ,@(map (lambda (var)
                       `(##define ,var
                          (##if (##pair? ,temp)
                                (##let ((val (##car ,temp)))
                                  (##set! ,temp (##cdr ,temp))
                                  val)
                                (##error "too few values"))))
                     vars))))))
Ricardo G. Herdt
@r.herdt_gitlab
Thanks Marc!
Mark Friedman
@mark-friedman

In the "try" IDE, I'd like to change the orientation of the console and editor panes from horizontal to vertical, i.e. have the console on top of the editor. I thought that maybe just changing UI.js:59 from:

  elem.classList.add('g-h-panes');

to

  elem.classList.add('g-v-panes');

might suffice, but no such luck. I end up just seeing the console. Most all of the class/style stuff seems to be nicely abstracted but I'm guessing that there is an assumption built somewhere in there (maybe the CSS) that is breaking it. Any guidance would be appreciated. My CSS-fu is not strong.

Thanks.

Mark Friedman
@mark-friedman

Another question about the web-based IDE in contrib/try: Do I really need to server all the files in the try\try\lib directory? I assume that some or all of it is to support a set of auto-loaded modules, some or all of which are needed by the demo code. Are any of them needed for core R7RS-small execution? Also, are all the various file types in a given subdirectory necessary? Typically I will see foo.scm, foo.js, foo#.scm, foo.o1, foo.o1.js, and foo.o1.js.gzfiles.

I'm fairly new to Gambit (though not to Scheme), so forgive my naiveté ;-)

Marc Feeley
@feeley
@mark-friedman Sorry but my CSS-fu is not that strong either. As I recall, CodeMirror causes a lot of headaches to do resizing correctly. I did notice however that the pane-splitter is actually dragable close to the top of the REPL and you can drag it down to reveal the console. I hope someone with a PhD in CSS can sort out this issue...
1 reply
tck42
@tck42
Is there any way to override the default CFLAGS etc that gsc issues at runtime during build without changing the flags that are used to compile? The bleeding edge Fedora build is using custom linker scripts that are fine for gambit itself but they reference a linker script that's only available on the build server. I'd like to open the bug with a suggested working build. I checked the build docs but it's not clear to me which options end up where.
Mark Friedman
@mark-friedman
Thanks, @feeley for your answer about the orientation of the console and editor panes in "try". Do you (or anybody else) have an answer for my subsequent "try"-related question relating to all the different files and files types?
Konstantin Astafurov
@konstantin-aa
Hello, I'm writing some scheme that involves parsing JSON, and am having a bit of trouble with using the json.scm from here
Marc Feeley
@feeley
@mark-friedman None of the try/lib files are essential… they are there for dynamic loading of various standard modules… if you use the R7RS define-library then you will need try/lib/_define-library
8 replies
@konstantin-aa What troubles are you having?
Konstantin Astafurov
@konstantin-aa
I keep getting seg faults, which files should I be compiling?
Marc Feeley
@feeley

@tck42 You can set GAMBUILD_VERBOSE=yes or use gsc -verbose … to get a trace of the C compiler invocations. For example:

$ GAMBUILD_VERBOSE=yes gsc foo.scm
gcc-9  -O1    -bundle  -Wno-unused -Wno-write-strings -Wdisabled-optimization -fwrapv -fno-strict-aliasing -fno-trapping-math -fno-math-errno -fschedule-insns2 -foptimize-sibling-calls -fomit-frame-pointer -fPIC -fno-common -mpc64    -D___SINGLE_HOST -D___DYNAMIC -I"/usr/local/Gambit/include" -o 'foo.o1'   'foo.c'
$ GAMBUILD_VERBOSE=yes gsc -exe foo.scm
gcc-9  -O1    -Wno-unused -Wno-write-strings -Wdisabled-optimization -fwrapv -fno-strict-aliasing -fno-trapping-math -fno-math-errno -fschedule-insns2 -foptimize-sibling-calls -fomit-frame-pointer -fPIC -fno-common -mpc64   -D___SINGLE_HOST  -I"/usr/local/Gambit/include" -c -o 'foo.o'  'foo.c'
gcc-9  -O1    -Wno-unused -Wno-write-strings -Wdisabled-optimization -fwrapv -fno-strict-aliasing -fno-trapping-math -fno-math-errno -fschedule-insns2 -foptimize-sibling-calls -fomit-frame-pointer -fPIC -fno-common -mpc64   -D___SINGLE_HOST  -I"/usr/local/Gambit/include" -c -o 'foo_.o'  'foo_.c'
gcc-9     -Wno-unused -Wno-write-strings -Wdisabled-optimization -fwrapv -fno-strict-aliasing -fno-trapping-math -fno-math-errno -fschedule-insns2 -foptimize-sibling-calls -fomit-frame-pointer -fPIC -fno-common -mpc64    -D___SINGLE_HOST  -I"/usr/local/Gambit/include"  -o 'foo'   'foo_.o' 'foo.o' "/usr/local/Gambit/lib/libgambit.a”

After gsc has generated the C file(s) it will call the ~~bin/gambuild-Cscript as the last step of the compilation to invoke the C compiler and linker. When that script is called with no command line arguments it will dump all of the environment variable bindings it uses:

$ `gsc -e '(display (path-expand "~~bin/gambuild-C"))'`
C_COMPILER="gcc-9"
C_PREPROC="gcc-9 -E"
PKG_CONFIG="pkg-config"
FLAGS_OBJ=" -Wno-unused -Wno-write-strings -Wdisabled-optimization -fwrapv -fno-strict-aliasing -fno-trapping-math -fno-math-errno -fschedule-insns2 -foptimize-sibling-calls -fomit-frame-pointer -fPIC -fno-common -mpc64 "
FLAGS_DYN=" -bundle -Wno-unused -Wno-write-strings -Wdisabled-optimization -fwrapv -fno-strict-aliasing -fno-trapping-math -fno-math-errno -fschedule-insns2 -foptimize-sibling-calls -fomit-frame-pointer -fPIC -fno-common -mpc64 "
FLAGS_LIB=" -dynamiclib -install_name \$(libdir)/\$(LIBRARY)\$(LIB_VERSION_SUFFIX) "
FLAGS_EXE=" -Wno-unused -Wno-write-strings -Wdisabled-optimization -fwrapv -fno-strict-aliasing -fno-trapping-math -fno-math-errno -fschedule-insns2 -foptimize-sibling-calls -fomit-frame-pointer -fPIC -fno-common -mpc64 "
FLAGS_OPT=" -O1"
FLAGS_OPT_RTS=" -O3"
DEFS_OBJ=" -D___SINGLE_HOST "
DEFS_DYN=" -D___SINGLE_HOST -D___DYNAMIC"
DEFS_LIB=" -D___SINGLE_HOST "
DEFS_EXE=" -D___SINGLE_HOST “
…

You can see for example that FLAGS_DYN are the flags used for compiling a dynamically loadable object file.
If you need additional command line parameters to be passed to the C compiler you can do it manually with the -cc-options XXX argument to gsc, or set CFLAGS.

tck42
@tck42
@feeley Thanks very much for this info!
Bradley Lucier
@gambiteer

There's also:

    -ld-options 'option ...'    Extra command line options for C linker
    -ld-options-prelude 'option ...'

from gsc --help.

Marc Feeley
@feeley
@konstantin-aa Here’s how you can compile the module, import it and call it:
$ cp contrib/GambitREPL/json*.scm .
$ gsc . json
$ gsi .
Gambit v4.9.4-39-g9a887b80

> (import json)
> (define x (call-with-input-string "{\"name\":\"John\", \"age\":30, \"car\":null}" json-read))
> (table-ref x "age")
30
> (table->list x)
(("name" . "John") ("car") ("age" . 30))
tck42
@tck42
@gambiteer thanks as well! I think it'll come down to simply removing the problematic flags via sed on gambuild-C before the rpm gets created.
Marc Feeley
@feeley
@tck42 Let me know what flag is a problem and if it is a serious problem I can add an option to the configure script to disable that flag.
Konstantin Astafurov
@konstantin-aa
thank you!
tck42
@tck42
@feeley This isn't actually with gambit per se; when building gambit from source for fedora, the fedora build process is adding (among a large # of other flags) a CFLAG telling the linker to use a custom script that adds a so-called "package note" to the output binaries that can be used for bug reports. That linker script is available at time of building gambit (it's generated as part of the build process), but when using gambit on a system that it wasn't built on, that linker script doesn't exist. So it's more about how gambit is generating the contents of gambuild-C I think. It's easy enough to remove inappropriate flags directly from the file as part of the package spec. Though I may be misunderstanding; I was also going to try to rebuilt Gambit with FLAGS_* explicitly set to see if it would take those instead of taking the various flags that were used to compile gambit.