ブログトップ 記事一覧 ログイン 無料ブログ開設

翡翠はコンピュータに卵を生むか

2016-12-01

インストール不要でブラウザ上からSchemeを試せるサイトscheme.contellas.comを作った

Common LispでWebアプリケーションを作る練習として、簡単なSchemeの開発環境的なものを作った。

  • Javascript製のSchemeインタプリタBiwaschemeにエディタ(CodeMirror)をつけたもの
  • HTML5の機能を使っているので対応したブラウザが必要 (Chrome、Firefox、IE11で確認済)
    • 書いたコードをブラウザのローカル領域に保存できる(Local Storage)
    • Schemeインタプリタは別スレッド(Web Worker)で動いており、無限ループに入ってしまったときなどにSchemeインタプリタだけ再起動できる(Killボタン)
  • 評価
    • 何も選択せずにEvalボタンを押すとファイル全体が評価される
    • 領域を選択してEvalボタンを押すとその領域が評価される
    • 括弧にカーソルを合わせてハイライト表示させた上で Ctrl+J でその式だけを評価できる(式単位の評価)
  • 自動インデント
    • Returnで改行するとその時点で適切な位置に移動する
    • Tabを押すとその行がインデントされる
    • 領域を選択してTabを押すとその領域がインデントされる
  • ファイル操作
    • Newボタンでファイルの新規作成
    • ファイルを選択した状態でRenameで名称変更、Deleteで削除ができる
    • 何かコードを評価したときや、ファイル操作をしたタイミングで状態が自動保存される
    • 右上の設定ボタンからClear localStorageを選ぶとブラウザに保存されていた情報が全て削除される

Schemeインタプリタの仕様はBiwaschemeのサイトを参照。R7RS対応とされているがマクロ定義は伝統的マクロだったりと少し異なる部分もある。

BiwaschemeではSchemeインタプリタからJavascriptのコードも呼べるが、Web Worker上で動いているのでSchemeインタプリタからJavascriptを呼んでもDocumentやWindowはいじれない。

TODO

  • (load "file-name") で localStorageからファイルを読み込めるようにする
  • ファイルをzipでまとめてダウンロードできるようにする
  • カラーテーマ、キーバインドの設定などの個人設定
  • 領域でコメント、アンコメント

2006-03-24

Gauche-gtk

http://www.kitanet.ne.jp/~asler/linux/gtk/ja/gtk_tut_ja.html

を見ながらgaucheでgtkを使ってみる。gauche-gtkに関するドキュメントはほとんどないが、Cとの対応でなんとかわかる。

;;; windowを表示するだけのプログラム

(use gtk)

(define (main args)
  (gtk-init args)
  (let ((window (gtk-window-new GTK_WINDOW_TOPLEVEL)))
    (gtk-widget-show window))
  (gtk-main)
  0)

2006-02-17

正規表現

emacsからsdicを使って英辞郎を参照できるようにしているのだけれど、いちいちルビが: 漢字{かんじ}のように表示されるのがうざったいのでルビを取り除くフィルタを書いてみた。

正規表現はGaucheの標準ライブラリで用意されていて、マッチがオブジェクトとして実装されているのが面白い。

#!/usr/local/bin/gosh

;;;英辞郎のSDIC形式からルビを取り除く
(define (delete-rubi line)
  (while (rxmatch #/{.*?}/ line)
    (set! line (regexp-replace #/{.*?}/ line "")))
  line)

(define (main args)
  (let loop ((line (read-line (current-input-port))))
    (if (eof-object? line)
        0
        (begin
          (format (current-output-port) "~A~%"
                  (delete-rubi line))
          (loop (read-line (current-input-port)))))))

ここで正規表現を単に #/{.*}/ と書くと最長一致する。つまり"ほにゃらら{hoge}ほげほげ{mage}"という文字列に対し#/{.*}/でマッチを取ると"{hoge}ほげほげ{mage}"が対応してしまう。最短一致の為にここでは#/{.*?}/を使用している。これで"{hoge}"がマッチするようになる。

最近やっとnamed-letを理解して使うようになってきた。letrecではやはりネストが深くなりすぎる。

英辞郎は50MB以上あるのでこのスクリプトで2時間以上かかる…

2006-02-11

高レベルソケットインターフェース

Cとかと比べるととっても簡単。echoサーバ/クライアントを書いてみた。

;;;echo-server.scm
#!/usr/local/bin/gosh

(use gauche.net)

(define (echo-server port)
  (let* ((serv-soc (make-server-socket 'inet port))
         (soc (socket-accept serv-soc))          
         (in (socket-input-port soc))
         (out (socket-output-port soc)))
    (letrec ((iter ; メインループ
              (lambda (line)
                (if (eof-object? line)
                    (begin ; 終了処理
                      (socket-close soc)
                      (socket-close serv-soc)
                      (exit))
                    (begin ; 処理と再帰呼び出し
                      (format out "~A~%" line)
;                      (flush out)
                      (iter (read-line in)))))))
      (iter (read-line in)))))


(define (main args)
  (if (not (= (length args) 2))
      (begin
        (format #t "Usage: echo-server port~%")
        (exit)))
  (echo-server (string->number (cadr args))))
;;;echo-client.scm
#!/usr/local/bin/gosh

(use gauche.net)

(define (echo-client host port)
  (let ((soc (make-client-socket 'inet host port)))
    (call-with-client-socket soc
      (lambda (soc-in-port soc-out-port)
        ;メインループ
        (letrec ((iter (lambda (line)
          (if (string=? line "quit")
              (begin ; 終了処理
                (socket-close soc)
                (exit))
              (begin ; 処理と再帰呼び出し
                (format soc-out-port "~A~%" line) ; 入力をサーバに送信
;                (flush soc-out-port)
                (format  #t "~A~%" (read-line soc-in-port)) ; サーバからの返答を標準出力に出す
;                (flush (current-output-port))
                (iter (read-line (current-input-port))))))))
          (iter (read-line (current-input-port))))))))


(define (main args)
  (if (not (= (length args) 3))
      (begin
        (format #t "Usage: echo-client hostname port-numbar~%")
        (exit)))
  (echo-client (cadr args) (string->number (caddr args))))