加算ができた

やった。加算ができたっ。

$ cat example/add.scm
(print (+ 1 2))

$ ./main.byte -o add example/add.scm

$ avmplus add
3

トークンを作るときに、"+1"(整数の1)と"+ 1"(+というシンボルと1という整数)を区別するのが大変だった。整数のパースを先にやると+が消費されてしまうので"+"がうまくパースできないし、シンボルのパースを先にやると+1が+と1で別々にパースされてしまう。

Parsecで言うところのtryみたいなのがあればうれしいけれども、Streamモジュールにはない。
しょうがないので、悪魔のObjモジュールを使って、状態を操作するようにした。

let try_ f stream =
  (* 
     Use black-magic to save stream state
     
     from stream.ml:
     type 'a t = { count : int; data : 'a data }
  *)
  let t =
    Obj.repr stream in
  let count =
    Obj.field t 0 in
  let data =
    Obj.field t 1 in
    try
      f stream
    with Stream.Failure ->
      Obj.set_field t 0 count;
      Obj.set_field t 1 data;
      fail ()