mirror of https://github.com/nealey/irc-bot
Remove OCS, create plugin system
This commit is contained in:
parent
b8f72603f4
commit
11998b91ca
|
@ -0,0 +1,6 @@
|
||||||
|
*.cmi
|
||||||
|
*.cmo
|
||||||
|
*~
|
||||||
|
bot
|
||||||
|
.omake*
|
||||||
|
.depend
|
16
Makefile
16
Makefile
|
@ -1,25 +1,13 @@
|
||||||
OCS_VERSION = 1.0.3
|
INCLUDES =
|
||||||
OCS_DIR = ocs-$(OCS_VERSION)
|
|
||||||
|
|
||||||
|
|
||||||
INCLUDES = -I $(OCS_DIR)/src
|
|
||||||
OCAMLFLAGS = $(INCLUDES)
|
OCAMLFLAGS = $(INCLUDES)
|
||||||
OCAMLOPT = ocamlopt
|
OCAMLOPT = ocamlopt
|
||||||
OCAMLC = ocamlc
|
OCAMLC = ocamlc
|
||||||
OCAMLDEP = ocamldep $(INCLUDES)
|
OCAMLDEP = ocamldep $(INCLUDES)
|
||||||
OCAMLLIBS = unix.cma str.cma nums.cma
|
OCAMLLIBS = unix.cma str.cma nums.cma
|
||||||
|
|
||||||
bot: irc.cmo dispatch.cmo command.cmo iobuf.cmo cdb.cmo bot.cmo
|
bot: irc.cmo dispatch.cmo command.cmo iobuf.cmo cdb.cmo bindings.cmo plugin.cmo infobot.cmo bot.cmo infobot.cmo
|
||||||
bot: $(OCS_DIR)/src/ocs.cma
|
|
||||||
$(OCAMLC) -o $@ $(OCAMLLIBS) $^
|
$(OCAMLC) -o $@ $(OCAMLLIBS) $^
|
||||||
|
|
||||||
callback: callback.cmo
|
|
||||||
callback: $(OCS_DIR)/src/ocs.cma
|
|
||||||
$(OCAMLC) -o $@ $(OCAMLLIBS) $^
|
|
||||||
|
|
||||||
$(OCS_DIR)/src/ocs.cma $(OCS_DIR)/src/ocs.cmxa: $(OCS_DIR)
|
|
||||||
cd $(OCS_DIR)/src && make
|
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -f bot *.cm* *.o
|
rm -f bot *.cm* *.o
|
||||||
|
|
8
arf.ml
8
arf.ml
|
@ -1,8 +0,0 @@
|
||||||
type goob = Goob of (int ref) * int
|
|
||||||
|
|
||||||
let _ =
|
|
||||||
let a = Goob (ref 1, 2) in
|
|
||||||
if (match a with
|
|
||||||
| Goob ({contents = 1}, _) -> true
|
|
||||||
| _ -> false) then
|
|
||||||
print_endline "hi asl"
|
|
69
bot.ml
69
bot.ml
|
@ -1,71 +1,8 @@
|
||||||
let info_db = Cdb.open_cdb_in "/home/neale/src/firebot/info.cdb"
|
|
||||||
let _ = Random.self_init ()
|
|
||||||
|
|
||||||
let choice l =
|
|
||||||
let n = Random.int (List.length l) in
|
|
||||||
List.nth l n
|
|
||||||
|
|
||||||
let choose_one key =
|
|
||||||
let matches = Cdb.get_matches info_db key in
|
|
||||||
match Stream.npeek 120 matches with
|
|
||||||
| [] -> raise Not_found
|
|
||||||
| keys -> choice keys
|
|
||||||
|
|
||||||
let write iobuf command args text =
|
let write iobuf command args text =
|
||||||
let cmd = Command.create None command args text in
|
let cmd = Command.create None command args text in
|
||||||
print_endline ("--> " ^ (Command.as_string cmd));
|
print_endline ("--> " ^ (Command.as_string cmd));
|
||||||
Iobuf.write iobuf cmd
|
Iobuf.write iobuf cmd
|
||||||
|
|
||||||
let make_sandbox_env () =
|
|
||||||
let e = Ocs_env.top_env () in
|
|
||||||
Ocs_compile.bind_lang e;
|
|
||||||
Ocs_macro.bind_macro e;
|
|
||||||
Ocs_num.init e;
|
|
||||||
Ocs_numstr.init e;
|
|
||||||
Ocs_prim.init e;
|
|
||||||
Ocs_vector.init e;
|
|
||||||
Ocs_list.init e;
|
|
||||||
Ocs_char.init e;
|
|
||||||
Ocs_string.init e;
|
|
||||||
Ocs_contin.init e;
|
|
||||||
e
|
|
||||||
|
|
||||||
let scheme_eval str =
|
|
||||||
try
|
|
||||||
let thread = Ocs_top.make_thread () in
|
|
||||||
let env = make_sandbox_env () in
|
|
||||||
let inport = Ocs_port.open_input_string str in
|
|
||||||
let outport = Ocs_port.open_output_string () in
|
|
||||||
let lexer = Ocs_lex.make_lexer inport "interactive" in
|
|
||||||
let v = Ocs_read.read_expr lexer in
|
|
||||||
let c = Ocs_compile.compile env v in
|
|
||||||
Ocs_eval.eval thread (Ocs_print.print outport false) c;
|
|
||||||
Ocs_port.get_output_string outport
|
|
||||||
with
|
|
||||||
| Ocs_error.Error msg
|
|
||||||
| Ocs_error.ErrorL (_, msg) ->
|
|
||||||
"Error: " ^ msg
|
|
||||||
|
|
||||||
|
|
||||||
let handle_privmsg iobuf sender target text =
|
|
||||||
try
|
|
||||||
let factoid = choose_one text in
|
|
||||||
let response =
|
|
||||||
match factoid.[0] with
|
|
||||||
| ':' ->
|
|
||||||
"\001ACTION " ^ (Str.string_after factoid 1) ^ "\001"
|
|
||||||
| '\\' ->
|
|
||||||
Str.string_after factoid 1
|
|
||||||
| _ ->
|
|
||||||
Printf.sprintf "I've heard that %s is %s" text factoid
|
|
||||||
in
|
|
||||||
write iobuf "PRIVMSG" [target] (Some response)
|
|
||||||
with Not_found ->
|
|
||||||
if text.[0] == '(' then
|
|
||||||
let result = scheme_eval text in
|
|
||||||
write iobuf "PRIVMSG" [target] (Some result)
|
|
||||||
|
|
||||||
|
|
||||||
let handle_command iobuf cmd =
|
let handle_command iobuf cmd =
|
||||||
print_endline ("<-- " ^ (Command.as_string cmd));
|
print_endline ("<-- " ^ (Command.as_string cmd));
|
||||||
match Command.as_tuple cmd with
|
match Command.as_tuple cmd with
|
||||||
|
@ -75,9 +12,6 @@ let handle_command iobuf cmd =
|
||||||
write iobuf "JOIN" ["#bot"] None
|
write iobuf "JOIN" ["#bot"] None
|
||||||
| (Some sender, "JOIN", [], Some chan) ->
|
| (Some sender, "JOIN", [], Some chan) ->
|
||||||
write iobuf "PRIVMSG" [chan] (Some "hi asl")
|
write iobuf "PRIVMSG" [chan] (Some "hi asl")
|
||||||
| (Some sender, "PRIVMSG", [target], Some text) ->
|
|
||||||
if Irc.is_channel target then
|
|
||||||
handle_privmsg iobuf sender target text
|
|
||||||
| _ ->
|
| _ ->
|
||||||
()
|
()
|
||||||
|
|
||||||
|
@ -89,7 +23,8 @@ let main () =
|
||||||
let dispatcher = Dispatch.create 5 in
|
let dispatcher = Dispatch.create 5 in
|
||||||
let conn = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
|
let conn = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
|
||||||
let _ = Unix.connect conn (Unix.ADDR_INET (host.Unix.h_addr_list.(0), 6667)) in
|
let _ = Unix.connect conn (Unix.ADDR_INET (host.Unix.h_addr_list.(0), 6667)) in
|
||||||
let iobuf = Iobuf.create dispatcher conn "woozle" handle_command handle_error in
|
let iobuf = Iobuf.create dispatcher conn "woozle" Plugin.handle_command handle_error in
|
||||||
|
Plugin.register handle_command;
|
||||||
write iobuf "NICK" ["bot"] None;
|
write iobuf "NICK" ["bot"] None;
|
||||||
write iobuf "USER" ["bot"; "bot"; "bot"] (Some "A Bot");
|
write iobuf "USER" ["bot"; "bot"; "bot"] (Some "A Bot");
|
||||||
Dispatch.run dispatcher
|
Dispatch.run dispatcher
|
||||||
|
|
44
bot_ocs.ml
44
bot_ocs.ml
|
@ -1,44 +0,0 @@
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
module Iobuf =
|
|
||||||
Ocs_wrap.Make (struct
|
|
||||||
type t = Iobuf.t
|
|
||||||
end)
|
|
||||||
|
|
||||||
let rec string_list_of_spair v acc =
|
|
||||||
match v with
|
|
||||||
| Snull ->
|
|
||||||
acc
|
|
||||||
| Spair { car = Sstring s; cdr = cdr } ->
|
|
||||||
string_list_of_spair cdr (acc @ s)
|
|
||||||
| _ ->
|
|
||||||
raise Ocs_error.Error "Not a string list"
|
|
||||||
|
|
||||||
let write_vals iobuf vals =
|
|
||||||
let cmd =
|
|
||||||
match vals with
|
|
||||||
| [| Swrapped iobuf; Sstring command; Spair args; Sstring text |] ->
|
|
||||||
Command.create None command (string_list_of_spair args) (Some text)
|
|
||||||
| [| Swrapped iobuf; Sstring command; Spair args |] ->
|
|
||||||
Command.create None command (string_list_of_spair args) None
|
|
||||||
| _ ->
|
|
||||||
raise Ocs_error.Error "Invalid arguments"
|
|
||||||
in
|
|
||||||
Iobuf.write iobuf cmd
|
|
||||||
|
|
||||||
let iobuf_write_proc iobuf =
|
|
||||||
let primf = Pfn (write_vals iobuf) in
|
|
||||||
let sprim = { prim_fun = primf; prim_name = "iobuf-write" } in
|
|
||||||
Sproc (sprim, [| [| |] |])
|
|
||||||
|
|
||||||
let ocs_bind b regexp cb =
|
|
||||||
match (regexp, cb) with
|
|
||||||
| (Sstring regexp_s, Sproc (p, d)) ->
|
|
||||||
let regexp = Str.regexp regexp_s in
|
|
||||||
b := Bindings.add (regexp_s, regexp, p)
|
|
||||||
| _ ->
|
|
||||||
raise Ocs_error.Error "invalid arguments"
|
|
||||||
|
|
||||||
let init b e =
|
|
||||||
set_pf3 e (ocs_bind b) "bind"
|
|
||||||
|
|
24
callback.ml
24
callback.ml
|
@ -1,24 +0,0 @@
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
let prefix_print prefix =
|
|
||||||
function
|
|
||||||
| [| Sstring txt |] ->
|
|
||||||
print_endline (prefix ^ txt);
|
|
||||||
Sunspec
|
|
||||||
| _ ->
|
|
||||||
raise (Ocs_error.Error "Invalid arguments")
|
|
||||||
|
|
||||||
let prefix_print_proc prefix =
|
|
||||||
let primf = Pfn (prefix_print prefix) in
|
|
||||||
let sprim = { prim_fun = primf; prim_name = "iobuf-write" } in
|
|
||||||
Sprim sprim
|
|
||||||
|
|
||||||
let code =
|
|
||||||
Capply1 ((Cval (prefix_print_proc "pfx: ")),
|
|
||||||
(Cval (Sstring "hello world")))
|
|
||||||
|
|
||||||
let _ =
|
|
||||||
let thread = Ocs_top.make_thread () in
|
|
||||||
let outport = Ocs_port.open_output_string () in
|
|
||||||
Ocs_eval.eval thread (Ocs_print.print outport false) code;
|
|
||||||
Ocs_port.get_output_string outport
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
let info_db = Cdb.open_cdb_in "/home/neale/src/firebot/info.cdb"
|
||||||
|
let _ = Random.self_init ()
|
||||||
|
|
||||||
|
let choice l =
|
||||||
|
let n = Random.int (List.length l) in
|
||||||
|
List.nth l n
|
||||||
|
|
||||||
|
let choose_one key =
|
||||||
|
let matches = Cdb.get_matches info_db key in
|
||||||
|
match Stream.npeek 120 matches with
|
||||||
|
| [] -> raise Not_found
|
||||||
|
| keys -> choice keys
|
||||||
|
|
||||||
|
let handle_privmsg iobuf sender target text =
|
||||||
|
try
|
||||||
|
let factoid = choose_one text in
|
||||||
|
let response =
|
||||||
|
match factoid.[0] with
|
||||||
|
| ':' ->
|
||||||
|
"\001ACTION " ^ (Str.string_after factoid 1) ^ "\001"
|
||||||
|
| '\\' ->
|
||||||
|
Str.string_after factoid 1
|
||||||
|
| _ ->
|
||||||
|
Printf.sprintf "I've heard that %s is %s" text factoid
|
||||||
|
in
|
||||||
|
Iobuf.write iobuf (Command.create None "PRIVMSG" [target] (Some response))
|
||||||
|
with Not_found ->
|
||||||
|
()
|
||||||
|
|
||||||
|
let handle_command iobuf cmd =
|
||||||
|
print_endline ("<I- " ^ (Command.as_string cmd));
|
||||||
|
match Command.as_tuple cmd with
|
||||||
|
| (Some sender, "PRIVMSG", [target], Some text) ->
|
||||||
|
if Irc.is_channel target then
|
||||||
|
handle_privmsg iobuf sender target text
|
||||||
|
| _ ->
|
||||||
|
()
|
||||||
|
|
||||||
|
let _ = Plugin.register handle_command
|
||||||
|
let _ = print_endline "========= INFOBOT"
|
|
@ -1,76 +0,0 @@
|
||||||
1.0.3
|
|
||||||
|
|
||||||
- The various let forms now create new frames. This fixes
|
|
||||||
behavior for situations where the initializers for the bound
|
|
||||||
variables return multiple times due to captured continuations.
|
|
||||||
|
|
||||||
- Change define-syntax to return the unspecified value.
|
|
||||||
|
|
||||||
- Fix (lambda <var> ...) forms where <var> is env-tagged by
|
|
||||||
macro expansion.
|
|
||||||
|
|
||||||
1.0.2
|
|
||||||
|
|
||||||
- Try to find a smaller invariant precision when converting from
|
|
||||||
floating point values to strings.
|
|
||||||
|
|
||||||
- Add missing function vector-fill!.
|
|
||||||
|
|
||||||
- Add an unspecified value that isn't printed by the repl.
|
|
||||||
|
|
||||||
- Add a value and functor that can be used to safely wrap arbitrary
|
|
||||||
OCaml values in Scheme values.
|
|
||||||
|
|
||||||
- Fix internal definitions inside (begin ...) forms.
|
|
||||||
|
|
||||||
- Consider literals in the literal list of syntax-rules locally
|
|
||||||
bound while parsing (but not while matching) patterns. R5RS is not
|
|
||||||
clear on this, but it is necessary to avoid breaking hygiene when
|
|
||||||
some expansions of an outer macro could change the interpretation of
|
|
||||||
pattern variables to literals within the patterns of inner macros.
|
|
||||||
This seems consistent with the behavior of other implementations.
|
|
||||||
|
|
||||||
- Fix namespace lookup for syntax-rules literals to allow changes
|
|
||||||
in global bindings.
|
|
||||||
|
|
||||||
- Fix namespace handling for nested macros.
|
|
||||||
|
|
||||||
- Fix copy-paste error in log.
|
|
||||||
|
|
||||||
- Fix the behavior of eval and arguments.
|
|
||||||
|
|
||||||
- Fix inexact->exact for negative numbers that don't fit into an
|
|
||||||
integer.
|
|
||||||
|
|
||||||
- The reader now also accepts square brackets [ and ] as list
|
|
||||||
delimiters.
|
|
||||||
|
|
||||||
- Fix remainder to handle differing signs correctly.
|
|
||||||
|
|
||||||
1.0.1
|
|
||||||
|
|
||||||
- Fix sorting of byte code objects in Makefile.
|
|
||||||
|
|
||||||
- Add missing functions numerator and denominator.
|
|
||||||
|
|
||||||
- Keep rationals normalized.
|
|
||||||
|
|
||||||
1.0 (changes from pre-releases)
|
|
||||||
|
|
||||||
- Rearrange build to generate bytecode and native libraries and a
|
|
||||||
native interpreter usable from the command line.
|
|
||||||
|
|
||||||
- Remove CVS Id's (the project is now being stored in a GNU Arch
|
|
||||||
repository) from all files.
|
|
||||||
|
|
||||||
- Fix Ocs_port.string_input_port to actually initialize the
|
|
||||||
port with the string length.
|
|
||||||
|
|
||||||
- Fix internal definitions of the form (define (fun args ...) ...).
|
|
||||||
Previously the first item of the body would be skipped.
|
|
||||||
|
|
||||||
- Fix the order of arguments to atan when called with two arguments.
|
|
||||||
|
|
||||||
- When invoking continuations with multiple arguments, the
|
|
||||||
arguments are now wrapped with Svalues as if (values ...) were used.
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
|
|
||||||
Copyright (c) 2003-2004 Ville-Pertti Keinonen
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met:
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
SUCH DAMAGE.
|
|
||||||
|
|
136
ocs-1.0.3/README
136
ocs-1.0.3/README
|
@ -1,136 +0,0 @@
|
||||||
1. General
|
|
||||||
|
|
||||||
Ocs is an implementation of Scheme, as defined by R5RS. It is
|
|
||||||
written entirely in OCaml and can be trivially embedded in any
|
|
||||||
OCaml program.
|
|
||||||
|
|
||||||
Known deviations from R5RS:
|
|
||||||
|
|
||||||
- transcript-on and transcript-off are currently not implemented
|
|
||||||
- scheme-report-environment and null-environment ignore their
|
|
||||||
argument
|
|
||||||
|
|
||||||
Anything else that does not work as specified in R5RS is a bug.
|
|
||||||
|
|
||||||
|
|
||||||
2. Installation
|
|
||||||
|
|
||||||
Requirements:
|
|
||||||
|
|
||||||
- GNU make or pmake (BSD make)
|
|
||||||
- OCaml 3.x (versions 3.06 and newer tested)
|
|
||||||
|
|
||||||
Type make or gmake in the src directory. This should produce the
|
|
||||||
following:
|
|
||||||
|
|
||||||
- A bytecode library (ocs.cma)
|
|
||||||
- A native library (ocs.cmxa, ocs.a)
|
|
||||||
- A stand-alone, native interpreter (ocscm)
|
|
||||||
|
|
||||||
2.1 The 'ocscm' command
|
|
||||||
|
|
||||||
If invoked without arguments, the interpreter will run in interactive
|
|
||||||
mode.
|
|
||||||
|
|
||||||
If invoked with arguments, the interpreter will read and evaluate
|
|
||||||
the files listed as arguments and exit. The evaluation results are
|
|
||||||
not printed.
|
|
||||||
|
|
||||||
|
|
||||||
3. Implementation Details
|
|
||||||
|
|
||||||
Implementing Scheme in OCaml is so straightforward that it hardly
|
|
||||||
needs any documentation. The following mappings between languages
|
|
||||||
are done:
|
|
||||||
|
|
||||||
- Scheme is dynamically typed. Scheme values are represented by
|
|
||||||
the OCaml type Ocs_types.sval.
|
|
||||||
|
|
||||||
- In Scheme, top-level bindings are global and all variables are
|
|
||||||
mutable. Variables references are bound through environments
|
|
||||||
(Ocs_types.env) to global slots (Ocs_types.gvar) or frame indices
|
|
||||||
(the actual frames are visible at evaluation-time through
|
|
||||||
Ocs_types.thread).
|
|
||||||
|
|
||||||
- Scheme has capturable, first-class continuations. Most of the
|
|
||||||
evaluator is written in continuation-passing style in order to allow
|
|
||||||
this.
|
|
||||||
|
|
||||||
Where discussing types, the rest of this section assumes that the
|
|
||||||
types defined in the module Ocs_types are visible.
|
|
||||||
|
|
||||||
3.1 Evaluation
|
|
||||||
|
|
||||||
Scheme values (S-expressions) are of the type sval.
|
|
||||||
|
|
||||||
Before evaluation Scheme values are compiled to internal representations
|
|
||||||
of the type code. This is done by the function
|
|
||||||
|
|
||||||
Ocs_compile.compile : env -> sval -> code
|
|
||||||
|
|
||||||
The env type is used during compilation for variable bindings. A
|
|
||||||
new env is created for each new scope and frame. The base
|
|
||||||
environment with the basic language bindings can be created using
|
|
||||||
|
|
||||||
Ocs_top.make_env : unit -> env
|
|
||||||
|
|
||||||
Evaluation is done by
|
|
||||||
|
|
||||||
Ocs_eval.eval : thread -> (sval -> unit) -> code -> unit
|
|
||||||
|
|
||||||
where the second argument is a continuation to pass the result to.
|
|
||||||
|
|
||||||
The thread type is used during evaluation for storing the current
|
|
||||||
frame and display for local variables, the input/output ports and
|
|
||||||
the current dynamic extent. It does not represent a thread in the
|
|
||||||
concurrent sense, but rather the evaluation state, and is copied and
|
|
||||||
changed rather than modified in place. The initial thread to be
|
|
||||||
passed to the evaluator can be created using
|
|
||||||
Ocs_top.make_thread : unit -> thread.
|
|
||||||
|
|
||||||
3.2 Continuations and I/O
|
|
||||||
|
|
||||||
Any continuations captured are associated with the thread at the
|
|
||||||
time of capture, so if a continuation is used to escape a
|
|
||||||
with-input-from-file or with-output-to-file, the input/output port
|
|
||||||
is restored to those of the time of capture.
|
|
||||||
|
|
||||||
If a continuation is used to return to a with-input-from-file or
|
|
||||||
with-output-to-file, the port is once again set to the one
|
|
||||||
opened by the with-...-file call. However, if the thunk has
|
|
||||||
already exited once, the port will be closed and no longer be
|
|
||||||
valid for I/O calls.
|
|
||||||
|
|
||||||
3.3 Numbers
|
|
||||||
|
|
||||||
The full R5RS numeric tower is implemented, with the following
|
|
||||||
internal representations:
|
|
||||||
|
|
||||||
Exact numbers are
|
|
||||||
- 31- or 63-bit integers (OCaml int)
|
|
||||||
- Big_int objects from the Num library when unboxed integers are
|
|
||||||
too small
|
|
||||||
- Ratio objects from the Num library for rationals
|
|
||||||
|
|
||||||
Inexact numbers are
|
|
||||||
- 64-bit IEEE floats for reals (OCaml float)
|
|
||||||
- Pairs of 64-bit IEEE floats for complex numbers (OCaml Complex.t)
|
|
||||||
|
|
||||||
Since inexact numbers are represented internally as binary floating
|
|
||||||
point, conversions to exact numbers are most precise for fractions of
|
|
||||||
powers of two
|
|
||||||
|
|
||||||
(inexact->exact 2.125) ==> 17/8
|
|
||||||
|
|
||||||
compared to
|
|
||||||
|
|
||||||
(inexact->exact 0.3) ==> 5404319552844595/18014398509481984
|
|
||||||
|
|
||||||
And in fact many rationals will not satisfy
|
|
||||||
|
|
||||||
(= (inexact->exact (exact->inexact r)) r)
|
|
||||||
|
|
||||||
However
|
|
||||||
|
|
||||||
(rationalize (inexact->exact 0.3) (expt 2 -54)) ==> 3/10
|
|
||||||
|
|
|
@ -1,107 +0,0 @@
|
||||||
ocs_char.cmo: ocs_types.cmi ocs_error.cmo ocs_env.cmi ocs_char.cmi
|
|
||||||
ocs_char.cmx: ocs_types.cmi ocs_error.cmx ocs_env.cmx ocs_char.cmi
|
|
||||||
ocs_compile.cmo: ocs_vartable.cmi ocs_types.cmi ocs_sym.cmi ocs_misc.cmi \
|
|
||||||
ocs_error.cmo ocs_env.cmi ocs_compile.cmi
|
|
||||||
ocs_compile.cmx: ocs_vartable.cmx ocs_types.cmi ocs_sym.cmx ocs_misc.cmx \
|
|
||||||
ocs_error.cmx ocs_env.cmx ocs_compile.cmi
|
|
||||||
ocs_complex.cmo: ocs_complex.cmi
|
|
||||||
ocs_complex.cmx: ocs_complex.cmi
|
|
||||||
ocs_contin.cmo: ocs_types.cmi ocs_misc.cmi ocs_eval.cmi ocs_error.cmo \
|
|
||||||
ocs_env.cmi ocs_contin.cmi
|
|
||||||
ocs_contin.cmx: ocs_types.cmi ocs_misc.cmx ocs_eval.cmx ocs_error.cmx \
|
|
||||||
ocs_env.cmx ocs_contin.cmi
|
|
||||||
ocs_env.cmo: ocs_vartable.cmi ocs_types.cmi ocs_sym.cmi ocs_error.cmo \
|
|
||||||
ocs_env.cmi
|
|
||||||
ocs_env.cmx: ocs_vartable.cmx ocs_types.cmi ocs_sym.cmx ocs_error.cmx \
|
|
||||||
ocs_env.cmi
|
|
||||||
ocs_eval.cmo: ocs_types.cmi ocs_sym.cmi ocs_misc.cmi ocs_error.cmo \
|
|
||||||
ocs_eval.cmi
|
|
||||||
ocs_eval.cmx: ocs_types.cmi ocs_sym.cmx ocs_misc.cmx ocs_error.cmx \
|
|
||||||
ocs_eval.cmi
|
|
||||||
ocs_io.cmo: ocs_types.cmi ocs_read.cmi ocs_print.cmi ocs_port.cmi \
|
|
||||||
ocs_eval.cmi ocs_error.cmo ocs_env.cmi ocs_io.cmi
|
|
||||||
ocs_io.cmx: ocs_types.cmi ocs_read.cmx ocs_print.cmx ocs_port.cmx \
|
|
||||||
ocs_eval.cmx ocs_error.cmx ocs_env.cmx ocs_io.cmi
|
|
||||||
ocs_lex.cmo: ocs_types.cmi ocs_port.cmi ocs_numstr.cmi ocs_error.cmo \
|
|
||||||
ocs_char.cmi ocs_lex.cmi
|
|
||||||
ocs_lex.cmx: ocs_types.cmi ocs_port.cmx ocs_numstr.cmx ocs_error.cmx \
|
|
||||||
ocs_char.cmx ocs_lex.cmi
|
|
||||||
ocs_list.cmo: ocs_types.cmi ocs_misc.cmi ocs_error.cmo ocs_env.cmi \
|
|
||||||
ocs_list.cmi
|
|
||||||
ocs_list.cmx: ocs_types.cmi ocs_misc.cmx ocs_error.cmx ocs_env.cmx \
|
|
||||||
ocs_list.cmi
|
|
||||||
ocs_macro.cmo: ocs_types.cmi ocs_sym.cmi ocs_misc.cmi ocs_error.cmo \
|
|
||||||
ocs_env.cmi ocs_compile.cmi ocs_macro.cmi
|
|
||||||
ocs_macro.cmx: ocs_types.cmi ocs_sym.cmx ocs_misc.cmx ocs_error.cmx \
|
|
||||||
ocs_env.cmx ocs_compile.cmx ocs_macro.cmi
|
|
||||||
ocs_main.cmo: ocs_types.cmi ocs_top.cmi ocs_prim.cmi ocs_error.cmo
|
|
||||||
ocs_main.cmx: ocs_types.cmi ocs_top.cmx ocs_prim.cmx ocs_error.cmx
|
|
||||||
ocs_misc.cmo: ocs_types.cmi ocs_error.cmo ocs_misc.cmi
|
|
||||||
ocs_misc.cmx: ocs_types.cmi ocs_error.cmx ocs_misc.cmi
|
|
||||||
ocs_num.cmo: ocs_types.cmi ocs_numaux.cmi ocs_error.cmo ocs_env.cmi \
|
|
||||||
ocs_complex.cmi ocs_num.cmi
|
|
||||||
ocs_num.cmx: ocs_types.cmi ocs_numaux.cmx ocs_error.cmx ocs_env.cmx \
|
|
||||||
ocs_complex.cmx ocs_num.cmi
|
|
||||||
ocs_numaux.cmo: ocs_types.cmi ocs_error.cmo ocs_numaux.cmi
|
|
||||||
ocs_numaux.cmx: ocs_types.cmi ocs_error.cmx ocs_numaux.cmi
|
|
||||||
ocs_numstr.cmo: ocs_types.cmi ocs_numaux.cmi ocs_num.cmi ocs_error.cmo \
|
|
||||||
ocs_env.cmi ocs_numstr.cmi
|
|
||||||
ocs_numstr.cmx: ocs_types.cmi ocs_numaux.cmx ocs_num.cmx ocs_error.cmx \
|
|
||||||
ocs_env.cmx ocs_numstr.cmi
|
|
||||||
ocs_port.cmo: ocs_error.cmo ocs_port.cmi
|
|
||||||
ocs_port.cmx: ocs_error.cmx ocs_port.cmi
|
|
||||||
ocs_prim.cmo: ocs_types.cmi ocs_sym.cmi ocs_read.cmi ocs_port.cmi \
|
|
||||||
ocs_misc.cmi ocs_macro.cmi ocs_lex.cmi ocs_io.cmi ocs_eval.cmi \
|
|
||||||
ocs_error.cmo ocs_env.cmi ocs_compile.cmi ocs_prim.cmi
|
|
||||||
ocs_prim.cmx: ocs_types.cmi ocs_sym.cmx ocs_read.cmx ocs_port.cmx \
|
|
||||||
ocs_misc.cmx ocs_macro.cmx ocs_lex.cmx ocs_io.cmx ocs_eval.cmx \
|
|
||||||
ocs_error.cmx ocs_env.cmx ocs_compile.cmx ocs_prim.cmi
|
|
||||||
ocs_print.cmo: ocs_types.cmi ocs_sym.cmi ocs_port.cmi ocs_numstr.cmi \
|
|
||||||
ocs_char.cmi ocs_print.cmi
|
|
||||||
ocs_print.cmx: ocs_types.cmi ocs_sym.cmx ocs_port.cmx ocs_numstr.cmx \
|
|
||||||
ocs_char.cmx ocs_print.cmi
|
|
||||||
ocs_read.cmo: ocs_types.cmi ocs_sym.cmi ocs_port.cmi ocs_misc.cmi ocs_lex.cmi \
|
|
||||||
ocs_error.cmo ocs_read.cmi
|
|
||||||
ocs_read.cmx: ocs_types.cmi ocs_sym.cmx ocs_port.cmx ocs_misc.cmx ocs_lex.cmx \
|
|
||||||
ocs_error.cmx ocs_read.cmi
|
|
||||||
ocs_string.cmo: ocs_types.cmi ocs_error.cmo ocs_env.cmi ocs_string.cmi
|
|
||||||
ocs_string.cmx: ocs_types.cmi ocs_error.cmx ocs_env.cmx ocs_string.cmi
|
|
||||||
ocs_sym.cmo: ocs_types.cmi ocs_error.cmo ocs_sym.cmi
|
|
||||||
ocs_sym.cmx: ocs_types.cmi ocs_error.cmx ocs_sym.cmi
|
|
||||||
ocs_top.cmo: ocs_vector.cmi ocs_types.cmi ocs_string.cmi ocs_read.cmi \
|
|
||||||
ocs_print.cmi ocs_prim.cmi ocs_port.cmi ocs_numstr.cmi ocs_num.cmi \
|
|
||||||
ocs_macro.cmi ocs_list.cmi ocs_lex.cmi ocs_io.cmi ocs_eval.cmi \
|
|
||||||
ocs_error.cmo ocs_env.cmi ocs_contin.cmi ocs_compile.cmi ocs_char.cmi \
|
|
||||||
ocs_top.cmi
|
|
||||||
ocs_top.cmx: ocs_vector.cmx ocs_types.cmi ocs_string.cmx ocs_read.cmx \
|
|
||||||
ocs_print.cmx ocs_prim.cmx ocs_port.cmx ocs_numstr.cmx ocs_num.cmx \
|
|
||||||
ocs_macro.cmx ocs_list.cmx ocs_lex.cmx ocs_io.cmx ocs_eval.cmx \
|
|
||||||
ocs_error.cmx ocs_env.cmx ocs_contin.cmx ocs_compile.cmx ocs_char.cmx \
|
|
||||||
ocs_top.cmi
|
|
||||||
ocs_vartable.cmo: ocs_vartable.cmi
|
|
||||||
ocs_vartable.cmx: ocs_vartable.cmi
|
|
||||||
ocs_vector.cmo: ocs_types.cmi ocs_error.cmo ocs_env.cmi ocs_vector.cmi
|
|
||||||
ocs_vector.cmx: ocs_types.cmi ocs_error.cmx ocs_env.cmx ocs_vector.cmi
|
|
||||||
ocs_wrap.cmo: ocs_types.cmi ocs_error.cmo
|
|
||||||
ocs_wrap.cmx: ocs_types.cmi ocs_error.cmx
|
|
||||||
ocs_char.cmi: ocs_types.cmi
|
|
||||||
ocs_compile.cmi: ocs_types.cmi
|
|
||||||
ocs_contin.cmi: ocs_types.cmi
|
|
||||||
ocs_env.cmi: ocs_types.cmi ocs_sym.cmi
|
|
||||||
ocs_eval.cmi: ocs_types.cmi
|
|
||||||
ocs_io.cmi: ocs_types.cmi
|
|
||||||
ocs_lex.cmi: ocs_types.cmi ocs_port.cmi ocs_error.cmo
|
|
||||||
ocs_list.cmi: ocs_types.cmi
|
|
||||||
ocs_macro.cmi: ocs_types.cmi
|
|
||||||
ocs_misc.cmi: ocs_types.cmi
|
|
||||||
ocs_num.cmi: ocs_types.cmi
|
|
||||||
ocs_numaux.cmi: ocs_types.cmi
|
|
||||||
ocs_numstr.cmi: ocs_types.cmi
|
|
||||||
ocs_prim.cmi: ocs_types.cmi
|
|
||||||
ocs_print.cmi: ocs_types.cmi ocs_port.cmi
|
|
||||||
ocs_read.cmi: ocs_types.cmi ocs_port.cmi ocs_lex.cmi
|
|
||||||
ocs_string.cmi: ocs_types.cmi
|
|
||||||
ocs_sym.cmi: ocs_types.cmi
|
|
||||||
ocs_top.cmi: ocs_types.cmi
|
|
||||||
ocs_types.cmi: ocs_vartable.cmi ocs_port.cmi
|
|
||||||
ocs_vector.cmi: ocs_types.cmi
|
|
|
@ -1,57 +0,0 @@
|
||||||
#
|
|
||||||
# Build system for ocs library and interpreter
|
|
||||||
#
|
|
||||||
|
|
||||||
include Makefile.common
|
|
||||||
|
|
||||||
BC_LIB = ocs.cma
|
|
||||||
N_LIB = ocs.cmxa
|
|
||||||
C_LIB = ocs.a
|
|
||||||
INTERP = ocscm
|
|
||||||
|
|
||||||
BC_OBJS = ocs_error.cmo ocs_port.cmo ocs_vartable.cmo ocs_sym.cmo \
|
|
||||||
ocs_env.cmo ocs_char.cmo ocs_complex.cmo ocs_numaux.cmo \
|
|
||||||
ocs_num.cmo ocs_numstr.cmo ocs_lex.cmo ocs_misc.cmo ocs_read.cmo \
|
|
||||||
ocs_eval.cmo ocs_compile.cmo ocs_contin.cmo ocs_print.cmo \
|
|
||||||
ocs_io.cmo ocs_list.cmo ocs_macro.cmo ocs_prim.cmo ocs_string.cmo \
|
|
||||||
ocs_vector.cmo ocs_wrap.cmo ocs_top.cmo
|
|
||||||
|
|
||||||
N_OBJS = ocs_error.cmx ocs_sym.cmx ocs_vartable.cmx ocs_env.cmx \
|
|
||||||
ocs_char.cmx ocs_misc.cmx ocs_compile.cmx ocs_eval.cmx \
|
|
||||||
ocs_contin.cmx ocs_port.cmx ocs_complex.cmx ocs_numaux.cmx \
|
|
||||||
ocs_num.cmx ocs_numstr.cmx ocs_print.cmx ocs_lex.cmx ocs_read.cmx \
|
|
||||||
ocs_io.cmx ocs_list.cmx ocs_macro.cmx ocs_prim.cmx ocs_string.cmx \
|
|
||||||
ocs_vector.cmx ocs_wrap.cmx ocs_top.cmx
|
|
||||||
|
|
||||||
INTERP_OBJS = ocs_main.cmx
|
|
||||||
|
|
||||||
BCI_OBJS = ocs_main.cmo
|
|
||||||
BCI = ocscm-bc
|
|
||||||
|
|
||||||
all: $(BC_LIB) $(N_LIB) $(INTERP)
|
|
||||||
|
|
||||||
native: $(N_LIB)
|
|
||||||
|
|
||||||
bytecode: $(BC_LIB)
|
|
||||||
|
|
||||||
$(N_LIB): $(N_OBJS)
|
|
||||||
$(OCAMLOPT) -a -o $(N_LIB) $(N_OBJS)
|
|
||||||
|
|
||||||
$(BC_LIB): $(BC_OBJS)
|
|
||||||
$(OCAMLC) -a -o $(BC_LIB) $(BC_OBJS)
|
|
||||||
|
|
||||||
$(INTERP): $(N_LIB) $(INTERP_OBJS)
|
|
||||||
$(OCAMLOPT) -o $(INTERP) nums.cmxa unix.cmxa $(N_LIB) $(INTERP_OBJS)
|
|
||||||
|
|
||||||
$(BCI): $(BC_LIB) $(BCI_OBJS)
|
|
||||||
$(OCAMLC) $(OCAMLFLAGS) -o $(BCI) nums.cma unix.cma $(BC_LIB) $(BCI_OBJS)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
-rm -f $(N_LIB) $(BC_LIB) $(C_LIB) $(INTERP) *.cm* *.o
|
|
||||||
-rm -f $(BCI)
|
|
||||||
|
|
||||||
depend:
|
|
||||||
$(OCAMLDEP) *.ml *.mli > .depend
|
|
||||||
|
|
||||||
include .depend
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
#
|
|
||||||
# General OCaml build settings
|
|
||||||
#
|
|
||||||
|
|
||||||
OCAMLOPT = ocamlopt
|
|
||||||
OCAMLC = ocamlc
|
|
||||||
OCAMLDEP = ocamldep
|
|
||||||
|
|
||||||
OCAMLFLAGS =
|
|
||||||
|
|
||||||
.SUFFIXES: .o .c .h .cc .cpp .y .l .a .ml .mli .cmx .cmi .cmo
|
|
||||||
|
|
||||||
.mli.cmi:
|
|
||||||
$(OCAMLC) $(OCAMLFLAGS) -c $<
|
|
||||||
|
|
||||||
.ml.cmx:
|
|
||||||
$(OCAMLOPT) $(OCAMLFLAGS) -c $<
|
|
||||||
|
|
||||||
.ml.cmo:
|
|
||||||
$(OCAMLC) $(OCAMLFLAGS) -c $<
|
|
||||||
|
|
|
@ -1,153 +0,0 @@
|
||||||
(* Character primitives *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_env
|
|
||||||
|
|
||||||
(* Character name equivalents (long). *)
|
|
||||||
let char_long_names =
|
|
||||||
[|
|
|
||||||
"space", ' ';
|
|
||||||
"newline", '\n';
|
|
||||||
|
|
||||||
(* The rest are extensions. *)
|
|
||||||
"return", '\r';
|
|
||||||
"tab", '\t';
|
|
||||||
"backspace", '\008';
|
|
||||||
"escape", '\027';
|
|
||||||
"backslash", '\\';
|
|
||||||
"alarm", '\007';
|
|
||||||
"vtab", '\011';
|
|
||||||
"del", '\127' |]
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Table of short names for 0 .. 31 *)
|
|
||||||
let char_short_names =
|
|
||||||
[| "nul"; "soh"; "stx"; "etx"; "eot"; "enq"; "ack"; "bel";
|
|
||||||
"bs"; "ht"; "nl"; "vt"; "np"; "cr"; "so"; "si";
|
|
||||||
"dle"; "dc1"; "dc2"; "dc3"; "dc4"; "nak"; "syn"; "etb";
|
|
||||||
"can"; "em"; "sub"; "esc"; "fs"; "gs"; "rs"; "us" |]
|
|
||||||
;;
|
|
||||||
|
|
||||||
let name_to_char name =
|
|
||||||
let name = (String.lowercase name)
|
|
||||||
and ln = Array.length char_long_names
|
|
||||||
and sn = Array.length char_short_names in
|
|
||||||
let rec lloop i =
|
|
||||||
if i = ln then sloop 0
|
|
||||||
else
|
|
||||||
match char_long_names.(i) with
|
|
||||||
(n, c) -> if n = name then Some c else lloop (i + 1)
|
|
||||||
and sloop i =
|
|
||||||
if i = sn then None
|
|
||||||
else if char_short_names.(i) = name then Some (char_of_int i)
|
|
||||||
else sloop (i + 1)
|
|
||||||
in
|
|
||||||
lloop 0
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Generate the preferred printed literal form of a character. *)
|
|
||||||
let char_to_name =
|
|
||||||
function
|
|
||||||
'\n' -> "newline"
|
|
||||||
| ' ' -> "space"
|
|
||||||
| '\127' -> "del"
|
|
||||||
| '\000' .. '\031' as c -> char_short_names.(int_of_char c)
|
|
||||||
| '\033' .. '\126' as c -> String.make 1 c
|
|
||||||
| c -> Printf.sprintf "x%02x" (int_of_char c)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_cmp op c1 c2 =
|
|
||||||
match (c1, c2) with
|
|
||||||
(Schar c1, Schar c2) -> if op c1 c2 then Strue else Sfalse
|
|
||||||
| _ -> raise (Error "args not characters")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_eq = char_cmp (=);;
|
|
||||||
let char_lt = char_cmp (<);;
|
|
||||||
let char_gt = char_cmp (>);;
|
|
||||||
let char_le = char_cmp (<=);;
|
|
||||||
let char_ge = char_cmp (>=);;
|
|
||||||
|
|
||||||
let char_ci_cmp op c1 c2 =
|
|
||||||
match (c1, c2) with
|
|
||||||
(Schar c1, Schar c2) ->
|
|
||||||
if op (Char.lowercase c1) (Char.lowercase c2) then Strue else Sfalse
|
|
||||||
| _ -> raise (Error "args not characters")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_ci_eq = char_ci_cmp (=);;
|
|
||||||
let char_ci_lt = char_ci_cmp (<);;
|
|
||||||
let char_ci_gt = char_ci_cmp (>);;
|
|
||||||
let char_ci_le = char_ci_cmp (<=);;
|
|
||||||
let char_ci_ge = char_ci_cmp (>=);;
|
|
||||||
|
|
||||||
let char_unop op =
|
|
||||||
function
|
|
||||||
Schar c -> op c
|
|
||||||
| _ -> raise (Error "arg not character")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_alphabetic =
|
|
||||||
char_unop (function 'A' .. 'Z' | 'a' ..'z' -> Strue | _ -> Sfalse)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_numeric =
|
|
||||||
char_unop (function '0' ..'9' -> Strue | _ -> Sfalse)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_whitespace =
|
|
||||||
char_unop (function ' ' | '\t' | '\r' | '\n' | '\012' -> Strue | _ -> Sfalse)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_uppercase =
|
|
||||||
char_unop (function 'A' .. 'Z' -> Strue | _ -> Sfalse)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_lowercase =
|
|
||||||
char_unop (function 'a' .. 'z' -> Strue | _ -> Sfalse)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_integer =
|
|
||||||
char_unop (fun c -> Sint (int_of_char c))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let integer_char =
|
|
||||||
function
|
|
||||||
Sint i -> Schar (char_of_int i)
|
|
||||||
| _ -> raise (Error "arg not int")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_upcase =
|
|
||||||
char_unop (fun c -> Schar (Char.uppercase c))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_downcase =
|
|
||||||
char_unop (fun c -> Schar (Char.lowercase c))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let init e =
|
|
||||||
set_pf2 e char_eq "char=?";
|
|
||||||
set_pf2 e char_lt "char<?";
|
|
||||||
set_pf2 e char_gt "char>?";
|
|
||||||
set_pf2 e char_le "char<=?";
|
|
||||||
set_pf2 e char_ge "char>=?";
|
|
||||||
|
|
||||||
set_pf2 e char_ci_eq "char-ci=?";
|
|
||||||
set_pf2 e char_ci_lt "char-ci<?";
|
|
||||||
set_pf2 e char_ci_gt "char-ci>?";
|
|
||||||
set_pf2 e char_ci_le "char-ci<=?";
|
|
||||||
set_pf2 e char_ci_ge "char-ci>=?";
|
|
||||||
|
|
||||||
set_pf1 e char_alphabetic "char-alphabetic?";
|
|
||||||
set_pf1 e char_numeric "char-numeric?";
|
|
||||||
set_pf1 e char_whitespace "char-whitespace?";
|
|
||||||
set_pf1 e char_uppercase "char-upper-case?";
|
|
||||||
set_pf1 e char_lowercase "char-lower-case?";
|
|
||||||
|
|
||||||
set_pf1 e char_integer "char->integer";
|
|
||||||
set_pf1 e integer_char "integer->char";
|
|
||||||
|
|
||||||
set_pf1 e char_upcase "char-upcase";
|
|
||||||
set_pf1 e char_downcase "char-downcase";
|
|
||||||
;;
|
|
|
@ -1,9 +0,0 @@
|
||||||
(* Character primitives. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val name_to_char : string -> char option
|
|
||||||
val char_to_name : char -> string
|
|
||||||
|
|
||||||
val init : env -> unit
|
|
||||||
|
|
|
@ -1,487 +0,0 @@
|
||||||
(* Compile Scheme expressions into a form that can be evaluated efficiently. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_sym
|
|
||||||
open Ocs_misc
|
|
||||||
open Ocs_env
|
|
||||||
open Ocs_vartable
|
|
||||||
|
|
||||||
(* Split the variables that are arguments to let/let*/letrec *)
|
|
||||||
let letsplit f =
|
|
||||||
function
|
|
||||||
Spair { car = (Ssymbol _ | Sesym (_, _)) as s;
|
|
||||||
cdr = Spair { car = v; cdr = Snull }} -> f s v
|
|
||||||
| _ -> raise (Error "invalid let arglist")
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Split the variables that are arguments to do *)
|
|
||||||
let dosplit f =
|
|
||||||
function
|
|
||||||
Spair { car = (Ssymbol _ | Sesym (_, _)) as sym;
|
|
||||||
cdr = Spair { car = init; cdr = t }} ->
|
|
||||||
begin
|
|
||||||
match t with
|
|
||||||
Snull -> f sym init sym
|
|
||||||
| Spair { car = step; cdr = Snull } -> f sym init step
|
|
||||||
| _ -> raise (Error "invalid do arglist")
|
|
||||||
end
|
|
||||||
| _ -> raise (Error "invalid do arglist")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let genset b v =
|
|
||||||
match b with
|
|
||||||
Vglob g -> Csetg (g, v)
|
|
||||||
| Vloc (d, i) -> Csetl (d, i, v)
|
|
||||||
| _ -> raise (Error "cannot change syntactic keywords")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let gendef b v =
|
|
||||||
match b with
|
|
||||||
Vglob g -> Cdefine (g, v)
|
|
||||||
| Vloc (d, i) -> Csetl (d, i, v)
|
|
||||||
| _ -> raise (Error "cannot change syntactic keywords")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let genref =
|
|
||||||
function
|
|
||||||
Vglob g -> Cgetg g
|
|
||||||
| Vloc (d, i) -> Cgetl (d, i)
|
|
||||||
| Vsyntax _ -> Cval Sunspec
|
|
||||||
| Vmacro _ -> Cval Sunspec
|
|
||||||
| Vkeyword _ -> Cval Sunbound
|
|
||||||
;;
|
|
||||||
|
|
||||||
let mkseq s =
|
|
||||||
match Array.length s with
|
|
||||||
0 -> Cval Sunspec
|
|
||||||
| 1 -> s.(0)
|
|
||||||
| 2 -> Cseq2 (s.(0), s.(1))
|
|
||||||
| 3 -> Cseq3 (s.(0), s.(1), s.(2))
|
|
||||||
| _ -> Cseqn s
|
|
||||||
;;
|
|
||||||
|
|
||||||
let mkand s =
|
|
||||||
match Array.length s with
|
|
||||||
0 -> Cval Strue
|
|
||||||
| 1 -> s.(0)
|
|
||||||
| 2 -> Cand2 (s.(0), s.(1))
|
|
||||||
| 3 -> Cand3 (s.(0), s.(1), s.(2))
|
|
||||||
| _ -> Candn s
|
|
||||||
;;
|
|
||||||
|
|
||||||
let mkor s =
|
|
||||||
match Array.length s with
|
|
||||||
0 -> Cval Sfalse
|
|
||||||
| 1 -> s.(0)
|
|
||||||
| 2 -> Cor2 (s.(0), s.(1))
|
|
||||||
| 3 -> Cor3 (s.(0), s.(1), s.(2))
|
|
||||||
| _ -> Corn s
|
|
||||||
;;
|
|
||||||
|
|
||||||
let make_proc c n hr fs =
|
|
||||||
{ proc_body = c;
|
|
||||||
proc_nargs = n;
|
|
||||||
proc_has_rest = hr;
|
|
||||||
proc_frame_size = fs;
|
|
||||||
proc_name = "#<unknown>#" }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let chksplice a =
|
|
||||||
let n = Array.length a in
|
|
||||||
let rec loop i =
|
|
||||||
if i < n then
|
|
||||||
begin
|
|
||||||
match a.(i) with
|
|
||||||
Cqqspl _ -> true
|
|
||||||
| _ -> loop (i + 1)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
false
|
|
||||||
in
|
|
||||||
loop 0
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Scan quoted sections, eliminate environment-specific symbols *)
|
|
||||||
let rec scanquoted =
|
|
||||||
function
|
|
||||||
Sesym (_, sym) -> sym
|
|
||||||
| Spair { car = h; cdr = t } ->
|
|
||||||
Spair { car = scanquoted h; cdr = scanquoted t }
|
|
||||||
| Svector v ->
|
|
||||||
Svector (Array.map (fun x -> scanquoted x) v)
|
|
||||||
| x -> x
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_uglobal e =
|
|
||||||
vt_global e.env_vartable
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_global e =
|
|
||||||
e.env_depth < 0
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec mkdefine e args =
|
|
||||||
let narg = Array.length args in
|
|
||||||
if narg < 1 then
|
|
||||||
raise (Error "define: not enough args");
|
|
||||||
match args.(0) with
|
|
||||||
Spair { car = (Ssymbol _ | Sesym (_, _)) as s; cdr = al } when narg > 1 ->
|
|
||||||
begin
|
|
||||||
match mklambda e al args with
|
|
||||||
Clambda p as l ->
|
|
||||||
p.proc_name <- sym_name s;
|
|
||||||
gendef (get_var e s) l
|
|
||||||
| _ -> assert false
|
|
||||||
end
|
|
||||||
| (Ssymbol _ | Sesym (_, _)) as s when narg = 2 ->
|
|
||||||
gendef (get_var e s) (compile e args.(1))
|
|
||||||
| (Ssymbol _ | Sesym (_, _)) as s when narg = 1 ->
|
|
||||||
gendef (get_var e s) (Cval Sunspec)
|
|
||||||
| _ -> raise (Error "define: invalid syntax")
|
|
||||||
|
|
||||||
(* The following functions up to mkbody are used to compile the body
|
|
||||||
of a lambda, let etc., with possible internal definitions. The
|
|
||||||
internal definitions may be created by macro expansion, so we need
|
|
||||||
to do that here, too...and we might end up expanding a macro more
|
|
||||||
than once (so there must be no side-effects to expansion). *)
|
|
||||||
and idpp =
|
|
||||||
function
|
|
||||||
Spair { car = (Ssymbol _ | Sesym (_, _)) as s;
|
|
||||||
cdr = Spair { car = v; cdr = Snull }} -> (s, s, v)
|
|
||||||
| Spair { car = Spair { car = (Ssymbol _ | Sesym (_, _)) as s;
|
|
||||||
cdr = _ } as x;
|
|
||||||
cdr = _ } as v -> (s, x, v)
|
|
||||||
| _ -> raise (Error "invalid internal definition")
|
|
||||||
|
|
||||||
and getidef e =
|
|
||||||
function
|
|
||||||
Spair { car = (Ssymbol _ | Sesym (_, _)) as s; cdr = t } ->
|
|
||||||
begin
|
|
||||||
match find_var e s with
|
|
||||||
Some (Vsyntax f) when f == mkdefine -> Some (idpp t)
|
|
||||||
| Some (Vmacro f) -> getidef e (f e (Array.of_list (list_to_caml t)))
|
|
||||||
| _ -> None
|
|
||||||
end
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
and mkid e x v =
|
|
||||||
match x with
|
|
||||||
Spair { car = _; cdr = al } ->
|
|
||||||
mklambda e al (Array.of_list (list_to_caml v))
|
|
||||||
| _ -> compile e v
|
|
||||||
|
|
||||||
and expand_begin e =
|
|
||||||
function
|
|
||||||
(Spair { car = (Ssymbol _ | Sesym (_, _)) as s; cdr = t }) as x ->
|
|
||||||
begin
|
|
||||||
match find_var e s with
|
|
||||||
Some (Vsyntax f) when f == mkbegin ->
|
|
||||||
Array.concat (List.map (expand_begin e) (list_to_caml t))
|
|
||||||
| Some (Vmacro f) ->
|
|
||||||
expand_begin e (f e (Array.of_list (list_to_caml t)))
|
|
||||||
| _ -> [| x |]
|
|
||||||
end
|
|
||||||
| x -> [| x |]
|
|
||||||
|
|
||||||
and mkbody e args =
|
|
||||||
let args = Array.concat (List.map (expand_begin e) (Array.to_list args)) in
|
|
||||||
let n = Array.length args in
|
|
||||||
let rec loop i r =
|
|
||||||
if i < n then
|
|
||||||
begin
|
|
||||||
match getidef e args.(i) with
|
|
||||||
Some d -> loop (i + 1) (d::r)
|
|
||||||
| None -> r
|
|
||||||
end
|
|
||||||
else
|
|
||||||
r
|
|
||||||
in
|
|
||||||
let ids = Array.map (fun (s, x, v) -> let r = bind_var e s in (r, x, v))
|
|
||||||
(Array.of_list (List.rev (loop 0 []))) in
|
|
||||||
let sets = Array.map (fun (r, x, v) -> gendef r (mkid e x v)) ids in
|
|
||||||
let nid = Array.length sets in
|
|
||||||
let rest = Array.map (fun x -> compile e x)
|
|
||||||
(Array.sub args nid (n - nid))
|
|
||||||
in
|
|
||||||
Array.append sets rest
|
|
||||||
|
|
||||||
and mkset e args =
|
|
||||||
if Array.length args != 2 then
|
|
||||||
raise (Error "set!: requires exactly two args");
|
|
||||||
match args.(0) with
|
|
||||||
(Ssymbol _ | Sesym (_, _)) as s ->
|
|
||||||
let v = compile e args.(1) in
|
|
||||||
genset (get_var e s) v
|
|
||||||
| _ -> raise (Error "set!: not a symbol")
|
|
||||||
|
|
||||||
(* Note that the first item of the "body" array is ignored, it
|
|
||||||
corresponds to the argument list but may be in the form expected
|
|
||||||
by either define or lambda. *)
|
|
||||||
and mklambda e args body =
|
|
||||||
let ne = new_frame e
|
|
||||||
and nargs = ref 0
|
|
||||||
and has_rest = ref false in
|
|
||||||
let rec scanargs =
|
|
||||||
function
|
|
||||||
Spair { car = (Ssymbol _ | Sesym (_, _)) as s; cdr = tl } ->
|
|
||||||
let _ = bind_var ne s in
|
|
||||||
incr nargs;
|
|
||||||
scanargs tl
|
|
||||||
| (Ssymbol _ | Sesym (_, _)) as s ->
|
|
||||||
let _ = bind_var ne s in
|
|
||||||
incr nargs;
|
|
||||||
has_rest := true;
|
|
||||||
()
|
|
||||||
| Snull -> ()
|
|
||||||
| _ -> raise (Error "lambda: bad arg list")
|
|
||||||
in
|
|
||||||
scanargs args;
|
|
||||||
let body =
|
|
||||||
mkseq (mkbody ne (Array.sub body 1 (Array.length body - 1)))
|
|
||||||
in
|
|
||||||
Clambda (make_proc body !nargs !has_rest !(ne.env_frame_size))
|
|
||||||
|
|
||||||
and mkif e args =
|
|
||||||
match Array.length args with
|
|
||||||
2 -> Cif (compile e args.(0), compile e args.(1), Cval Sunspec)
|
|
||||||
| 3 -> Cif (compile e args.(0), compile e args.(1), compile e args.(2))
|
|
||||||
| _ -> raise (Error "if: needs two or three args")
|
|
||||||
|
|
||||||
and mknamedlet e s args =
|
|
||||||
let argv =
|
|
||||||
Array.map
|
|
||||||
(letsplit (fun s v -> s, compile e v))
|
|
||||||
(Array.of_list (list_to_caml args.(1))) in
|
|
||||||
let ar = new_var e in
|
|
||||||
let ne = new_frame e in
|
|
||||||
bind_name ne s ar;
|
|
||||||
let av =
|
|
||||||
Array.map (fun (s, v) -> let _ = bind_var ne s in v) argv in
|
|
||||||
let body = mkseq (mkbody ne (Array.sub args 2 (Array.length args - 2))) in
|
|
||||||
let proc =
|
|
||||||
Clambda (make_proc body (Array.length av) false !(ne.env_frame_size))
|
|
||||||
in
|
|
||||||
Cseq2 (gendef ar proc, mkapply (genref ar) av)
|
|
||||||
|
|
||||||
and mklet e args =
|
|
||||||
if Array.length args < 2 then
|
|
||||||
raise (Error "let: too few args");
|
|
||||||
match args.(0) with
|
|
||||||
(Ssymbol _ | Sesym (_, _)) as s -> mknamedlet e s args
|
|
||||||
| Snull -> mkseq (mkbody e (Array.sub args 1 (Array.length args - 1)))
|
|
||||||
| Spair _ as al ->
|
|
||||||
let argv =
|
|
||||||
Array.map
|
|
||||||
(letsplit (fun s v -> s, compile e v))
|
|
||||||
(Array.of_list (list_to_caml al)) in
|
|
||||||
let ne = new_frame e in
|
|
||||||
let av = Array.map (fun (s, v) -> let _ = bind_var ne s in v) argv in
|
|
||||||
let body = mkseq (mkbody ne (Array.sub args 1 (Array.length args - 1))) in
|
|
||||||
let proc =
|
|
||||||
Clambda (make_proc body (Array.length av) false !(ne.env_frame_size))
|
|
||||||
in
|
|
||||||
mkapply proc av
|
|
||||||
| _ -> raise (Error "let: missing argument list")
|
|
||||||
|
|
||||||
and mkletstar e args =
|
|
||||||
if Array.length args < 2 then
|
|
||||||
raise (Error "let*: too few args");
|
|
||||||
let rec build e =
|
|
||||||
function
|
|
||||||
x::t ->
|
|
||||||
let (s, v) = letsplit (fun s v -> s, compile e v) x in
|
|
||||||
let ne = new_frame e in
|
|
||||||
let _ = bind_var ne s in
|
|
||||||
let body = build ne t in
|
|
||||||
let proc = Clambda (make_proc body 1 false !(ne.env_frame_size)) in
|
|
||||||
mkapply proc [| v |]
|
|
||||||
| [] -> mkseq (mkbody e (Array.sub args 1 (Array.length args - 1)))
|
|
||||||
in
|
|
||||||
build e (list_to_caml args.(0))
|
|
||||||
|
|
||||||
and mkletrec e args =
|
|
||||||
if Array.length args < 2 then
|
|
||||||
raise (Error "letrec: too few args");
|
|
||||||
let ne = new_frame e in
|
|
||||||
let av =
|
|
||||||
Array.map (letsplit (fun s v -> let r = bind_var ne s in (r, v)))
|
|
||||||
(Array.of_list (list_to_caml args.(0))) in
|
|
||||||
let avi = Array.map (fun (r, v) -> compile ne v) av in
|
|
||||||
let ne' = new_frame ne in
|
|
||||||
let sets = Array.map (fun (r, v) -> gendef r (genref (new_var ne'))) av in
|
|
||||||
let body = mkseq (Array.append sets
|
|
||||||
(mkbody ne' (Array.sub args 1 (Array.length args - 1)))) in
|
|
||||||
let proc =
|
|
||||||
Clambda (make_proc body (Array.length av) false !(ne'.env_frame_size)) in
|
|
||||||
let proc =
|
|
||||||
Clambda (make_proc (mkapply proc avi)
|
|
||||||
(Array.length av) false !(ne.env_frame_size))
|
|
||||||
in
|
|
||||||
mkapply proc (Array.map (fun _ -> Cval Sunspec) av)
|
|
||||||
|
|
||||||
and compileseq e s =
|
|
||||||
mkseq (Array.map (fun x -> compile e x)
|
|
||||||
(Array.of_list (list_to_caml s)))
|
|
||||||
|
|
||||||
and mkcond e args =
|
|
||||||
Ccond
|
|
||||||
(Array.map
|
|
||||||
(function
|
|
||||||
Spair { car = test;
|
|
||||||
cdr = Spair { car = (Ssymbol _ | Sesym (_, _)) as s;
|
|
||||||
cdr = Spair { car = x; cdr = Snull }}}
|
|
||||||
when is_keyword e s "=>" ->
|
|
||||||
(Ccondspec (compile e test), (compile e x))
|
|
||||||
| Spair { car = (Ssymbol _ | Sesym (_, _)) as s; cdr = body }
|
|
||||||
when is_keyword e s "else" ->
|
|
||||||
(Cval Strue, compileseq e body)
|
|
||||||
| Spair { car = test; cdr = body } ->
|
|
||||||
(compile e test, compileseq e body)
|
|
||||||
| _ -> raise (Error "cond: syntax error"))
|
|
||||||
args)
|
|
||||||
|
|
||||||
and mkcase e args =
|
|
||||||
Ccase
|
|
||||||
(compile e args.(0),
|
|
||||||
Array.map
|
|
||||||
(function
|
|
||||||
Spair { car = (Ssymbol _ | Sesym (_, _)) as s; cdr = body }
|
|
||||||
when is_keyword e s "else" ->
|
|
||||||
([| |], compileseq e body)
|
|
||||||
| Spair { car = Spair _ as c; cdr = body } ->
|
|
||||||
(Array.of_list (list_to_caml c), compileseq e body)
|
|
||||||
| _ -> raise (Error "case: syntax error"))
|
|
||||||
(Array.sub args 1 (Array.length args - 1)))
|
|
||||||
|
|
||||||
and mkdo e args =
|
|
||||||
if Array.length args < 2 then
|
|
||||||
raise (Error "do: bad args");
|
|
||||||
let vv =
|
|
||||||
Array.map
|
|
||||||
(dosplit (fun sym init step -> sym, compile e init, step))
|
|
||||||
(Array.of_list (list_to_caml args.(0)))
|
|
||||||
and (test, result) =
|
|
||||||
match args.(1) with
|
|
||||||
Spair { car = t; cdr = r } -> t, r
|
|
||||||
| _ -> raise (Error "do: bad args")
|
|
||||||
and anonvar = new_var e
|
|
||||||
and ne = new_frame e in
|
|
||||||
let av = Array.map (fun (sym, init, _) ->
|
|
||||||
let _ = bind_var ne sym in init) vv in
|
|
||||||
let body =
|
|
||||||
Cif (compile ne test, compileseq ne result,
|
|
||||||
mkseq
|
|
||||||
(Array.append
|
|
||||||
(Array.map (fun x -> compile ne x)
|
|
||||||
(Array.sub args 2 (Array.length args - 2)))
|
|
||||||
[| mkapply (genref anonvar)
|
|
||||||
(Array.map (fun (_, _, step) -> compile ne step) vv) |]))
|
|
||||||
in
|
|
||||||
let proc =
|
|
||||||
Clambda (make_proc body (Array.length av) false !(ne.env_frame_size))
|
|
||||||
in
|
|
||||||
Cseq2 (gendef anonvar proc, mkapply (genref anonvar) av)
|
|
||||||
|
|
||||||
and mkdelay e =
|
|
||||||
function
|
|
||||||
[| expr |] -> Cdelay (compile e expr)
|
|
||||||
| _ -> raise (Error "delay: bad args")
|
|
||||||
|
|
||||||
and mkqq e args =
|
|
||||||
if Array.length args <> 1 then
|
|
||||||
raise (Error "quasiquote: need exactly one arg")
|
|
||||||
else
|
|
||||||
let rec qq depth =
|
|
||||||
function
|
|
||||||
Spair { car = (Ssymbol _ | Sesym (_, _)) as s;
|
|
||||||
cdr = Spair { car = x; cdr = Snull }} ->
|
|
||||||
if is_syntax e s mkqq then
|
|
||||||
Cqqp (Cval s, Cqqp (qq (depth + 1) x, Cval Snull))
|
|
||||||
else if is_keyword e s "unquote" then
|
|
||||||
begin
|
|
||||||
if depth > 0 then
|
|
||||||
Cqqp (Cval s, Cqqp (qq (depth - 1) x, Cval Snull))
|
|
||||||
else
|
|
||||||
compile e x
|
|
||||||
end
|
|
||||||
else if is_keyword e s "unquote-splicing" then
|
|
||||||
begin
|
|
||||||
if depth > 0 then
|
|
||||||
Cqqp (Cval s, Cqqp (qq (depth - 1) x, Cval Snull))
|
|
||||||
else
|
|
||||||
Cqqspl (compile e x)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Cqqp (Cval s, Cqqp (qq depth x, Cval Snull))
|
|
||||||
| Spair { car = h; cdr = t } -> Cqqp (qq depth h, qq depth t)
|
|
||||||
| Svector v ->
|
|
||||||
let qv = Array.map (fun x -> qq depth x) v in
|
|
||||||
if chksplice qv then
|
|
||||||
Cqqvs (Array.to_list qv)
|
|
||||||
else
|
|
||||||
Cqqv qv
|
|
||||||
| x -> Cval (scanquoted x)
|
|
||||||
in
|
|
||||||
qq 0 args.(0)
|
|
||||||
|
|
||||||
and applysym e s args =
|
|
||||||
match get_var e s with
|
|
||||||
Vsyntax f -> f e args
|
|
||||||
| Vmacro f -> compile e (f e args)
|
|
||||||
| r -> mkapply (genref r) (Array.map (fun x -> compile e x) args)
|
|
||||||
|
|
||||||
and compile e =
|
|
||||||
function
|
|
||||||
(Ssymbol _ | Sesym (_, _)) as s -> genref (get_var e s)
|
|
||||||
| Spair p ->
|
|
||||||
let args = Array.of_list (list_to_caml p.cdr) in
|
|
||||||
begin
|
|
||||||
match p.car with
|
|
||||||
(Ssymbol _ | Sesym (_, _)) as s -> applysym e s args
|
|
||||||
| x ->
|
|
||||||
mkapply (compile e x) (Array.map (fun x -> compile e x) args)
|
|
||||||
end
|
|
||||||
| x -> Cval (scanquoted x)
|
|
||||||
|
|
||||||
and mkbegin e args =
|
|
||||||
mkseq (Array.map (fun x -> compile e x) args)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let bind_lang e =
|
|
||||||
let spec =
|
|
||||||
[ sym_define, mkdefine;
|
|
||||||
sym_set, mkset;
|
|
||||||
sym_let, mklet;
|
|
||||||
sym_letstar, mkletstar;
|
|
||||||
sym_letrec, mkletrec;
|
|
||||||
sym_if, mkif;
|
|
||||||
sym_cond, mkcond;
|
|
||||||
sym_case, mkcase;
|
|
||||||
sym_do, mkdo;
|
|
||||||
sym_begin, mkbegin;
|
|
||||||
sym_and, (fun e args -> mkand (Array.map (fun x -> compile e x) args));
|
|
||||||
sym_or, (fun e args -> mkor (Array.map (fun x -> compile e x) args));
|
|
||||||
sym_lambda,
|
|
||||||
(fun e args ->
|
|
||||||
if Array.length args >= 1 then
|
|
||||||
mklambda e args.(0) args
|
|
||||||
else
|
|
||||||
raise (Error "lambda: needs at least one arg"));
|
|
||||||
sym_delay, mkdelay;
|
|
||||||
sym_quote,
|
|
||||||
(fun e args ->
|
|
||||||
if Array.length args = 1 then
|
|
||||||
Cval (scanquoted args.(0))
|
|
||||||
else
|
|
||||||
raise (Error "quote: need exactly one arg"));
|
|
||||||
sym_quasiquote, mkqq ]
|
|
||||||
in
|
|
||||||
List.iter (fun (s, f) -> bind_name e s (Vsyntax f)) spec;
|
|
||||||
bind_name e sym_else (Vkeyword "else");
|
|
||||||
bind_name e sym_arrow (Vkeyword "=>");
|
|
||||||
bind_name e sym_unquote (Vkeyword "unquote");
|
|
||||||
bind_name e sym_unquote_splicing (Vkeyword "unquote-splicing");
|
|
||||||
bind_name e sym_syntax_rules (Vkeyword "syntax-rules");
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
(* Compile expressions *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val compile : env -> sval -> code
|
|
||||||
|
|
||||||
val bind_lang : env -> unit
|
|
||||||
|
|
||||||
(* Internal, used by ocs_macro *)
|
|
||||||
val letsplit : (sval -> sval -> 'a) -> sval -> 'a
|
|
||||||
val mkseq : code array -> code
|
|
||||||
val mkbody : env -> sval array -> code array
|
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
(* Implement functions missing from Complex. *)
|
|
||||||
|
|
||||||
open Complex
|
|
||||||
|
|
||||||
let sin_cplx z =
|
|
||||||
{ re = sin z.re *. cosh z.im;
|
|
||||||
im = cos z.re *. sinh z.im }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let cos_cplx z =
|
|
||||||
{ re = cos z.re *. cosh z.im;
|
|
||||||
im = -.(sin z.re) *. sinh z.im }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let tan_cplx z =
|
|
||||||
div (sin_cplx z) (cos_cplx z)
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* asin z = -i Ln (iz + sqrt (1 - z^2)) *)
|
|
||||||
|
|
||||||
let asin_cplx =
|
|
||||||
function { re = x; im = y } ->
|
|
||||||
let t = sqrt { re = 1.0 +. y *. y -. x *. x; im = -2.0 *. x *. y } in
|
|
||||||
let z = log { re = t.re -. y; im = t.im +. x } in
|
|
||||||
{ re = z.im; im = -.z.re }
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* acos z = pi/2 - asin z *)
|
|
||||||
|
|
||||||
let acos_cplx z =
|
|
||||||
match asin_cplx z with
|
|
||||||
{ re = x; im = y } -> { re = 1.57079632679489661923 -. x; im = -.y }
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* atan z = [Ln (1 + iz) - Ln (1 - iz)] / 2i *)
|
|
||||||
|
|
||||||
let atan_cplx =
|
|
||||||
function { re = x; im = y } ->
|
|
||||||
let t1 = log { re = 1.0 -. y; im = x }
|
|
||||||
and t2 = log { re = 1.0 +. y; im = -.x } in
|
|
||||||
{ re = (t1.im -. t2.im) *. 0.5;
|
|
||||||
im = -.(t1.re -. t2.re) *. 0.5 }
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
(* Functions missing from Complex. *)
|
|
||||||
|
|
||||||
open Complex
|
|
||||||
|
|
||||||
val sin_cplx : t -> t
|
|
||||||
val cos_cplx : t -> t
|
|
||||||
val tan_cplx : t -> t
|
|
||||||
val asin_cplx : t -> t
|
|
||||||
val acos_cplx : t -> t
|
|
||||||
val atan_cplx : t -> t
|
|
||||||
|
|
|
@ -1,114 +0,0 @@
|
||||||
(* Continuations *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_eval
|
|
||||||
open Ocs_env
|
|
||||||
open Ocs_misc
|
|
||||||
|
|
||||||
let rec find_depth fdx tdx al bl =
|
|
||||||
match (fdx, tdx) with
|
|
||||||
(Some f, Some t) ->
|
|
||||||
if f.dynext_parent == t.dynext_parent then
|
|
||||||
(List.rev (f.dynext_after::al), t.dynext_before::bl)
|
|
||||||
else if f.dynext_depth > t.dynext_depth then
|
|
||||||
find_depth f.dynext_parent tdx (f.dynext_after::al) bl
|
|
||||||
else if f.dynext_depth < t.dynext_depth then
|
|
||||||
find_depth fdx t.dynext_parent al (t.dynext_before::bl)
|
|
||||||
else
|
|
||||||
find_depth f.dynext_parent t.dynext_parent
|
|
||||||
(f.dynext_after::al) (t.dynext_before::bl)
|
|
||||||
| (Some f, None) ->
|
|
||||||
find_depth f.dynext_parent tdx (f.dynext_after::al) bl
|
|
||||||
| (None, Some t) ->
|
|
||||||
find_depth fdx t.dynext_parent al (t.dynext_before::bl)
|
|
||||||
| _ -> (List.rev al, bl)
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Change from the dynamic extent fdx to the dynamic extent tdx *)
|
|
||||||
let dxswitch fdx tdx cont =
|
|
||||||
if fdx == tdx then
|
|
||||||
cont ()
|
|
||||||
else
|
|
||||||
let (al, bl) = find_depth fdx tdx [] [] in
|
|
||||||
let rec bloop =
|
|
||||||
function
|
|
||||||
[] -> cont ()
|
|
||||||
| h::t -> eval (fst h) (fun _ -> bloop t) (snd h)
|
|
||||||
in
|
|
||||||
let rec aloop =
|
|
||||||
function
|
|
||||||
[] -> bloop bl
|
|
||||||
| h::t -> eval (fst h) (fun _ -> aloop t) (snd h)
|
|
||||||
in
|
|
||||||
aloop al
|
|
||||||
;;
|
|
||||||
|
|
||||||
let continuation dx cc th _ =
|
|
||||||
function
|
|
||||||
[| x |] -> dxswitch th.th_dynext dx (fun () -> cc x)
|
|
||||||
| av -> dxswitch th.th_dynext dx (fun () -> cc (Svalues av))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let call_cc th cc =
|
|
||||||
function
|
|
||||||
[| proc |] ->
|
|
||||||
let cont =
|
|
||||||
Sprim { prim_fun = Pfcn (continuation th.th_dynext cc);
|
|
||||||
prim_name = "<continuation>" }
|
|
||||||
in
|
|
||||||
eval th cc (Capply1 (Cval proc, Cval cont))
|
|
||||||
| _ -> raise (Error "call/cc: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let values =
|
|
||||||
function
|
|
||||||
[| x |] -> x
|
|
||||||
| av -> Svalues av
|
|
||||||
;;
|
|
||||||
|
|
||||||
let call_values th cc =
|
|
||||||
function
|
|
||||||
[| producer; consumer |] ->
|
|
||||||
eval th
|
|
||||||
(function
|
|
||||||
Svalues av ->
|
|
||||||
eval th cc (mkapply (Cval consumer)
|
|
||||||
(Array.map (fun x -> Cval x) av))
|
|
||||||
| x -> eval th cc (Capply1 (Cval consumer, Cval x)))
|
|
||||||
(Capply0 (Cval producer))
|
|
||||||
| _ -> raise (Error "call-with-values: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let dynamic_wind th cc =
|
|
||||||
function
|
|
||||||
[| before; thunk; after |] ->
|
|
||||||
let before = Capply0 (Cval before)
|
|
||||||
and after = Capply0 (Cval after) in
|
|
||||||
let ndx = {
|
|
||||||
dynext_parent = th.th_dynext;
|
|
||||||
dynext_depth =
|
|
||||||
(match th.th_dynext with
|
|
||||||
None -> 0
|
|
||||||
| Some dx -> dx.dynext_depth + 1);
|
|
||||||
dynext_before = (th, before);
|
|
||||||
dynext_after = (th, after)
|
|
||||||
} in
|
|
||||||
eval th
|
|
||||||
(fun _ ->
|
|
||||||
eval { th with th_dynext = Some ndx }
|
|
||||||
(fun r ->
|
|
||||||
eval th (fun _ -> cc r) after) (Capply0 (Cval thunk))) before
|
|
||||||
| _ -> raise (Error "dynamic-wind: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let init e =
|
|
||||||
set_pfcn e call_cc "call-with-current-continuation";
|
|
||||||
set_pfcn e call_cc "call/cc";
|
|
||||||
|
|
||||||
set_pfn e values "values";
|
|
||||||
|
|
||||||
set_pfcn e call_values "call-with-values";
|
|
||||||
set_pfcn e dynamic_wind "dynamic-wind";
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
(* Continuations *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val init : env -> unit
|
|
||||||
|
|
|
@ -1,143 +0,0 @@
|
||||||
(* Compilation environment, variable bindings. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_sym
|
|
||||||
open Ocs_vartable
|
|
||||||
|
|
||||||
let top_env () =
|
|
||||||
{ env_depth = -1;
|
|
||||||
env_vartable = vt_create ();
|
|
||||||
env_frame_size = ref 0;
|
|
||||||
env_tagged = [] }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let new_scope e =
|
|
||||||
{ env_depth = e.env_depth;
|
|
||||||
env_vartable = vt_inherit e.env_vartable;
|
|
||||||
env_frame_size = e.env_frame_size;
|
|
||||||
env_tagged = e.env_tagged }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let new_frame e =
|
|
||||||
{ env_depth = e.env_depth + 1;
|
|
||||||
env_vartable = vt_inherit e.env_vartable;
|
|
||||||
env_frame_size = ref 0;
|
|
||||||
env_tagged = e.env_tagged }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let new_var e =
|
|
||||||
if e.env_depth < 0 then
|
|
||||||
Vglob { g_sym = Snull; g_val = Sunbound }
|
|
||||||
else
|
|
||||||
let v = Vloc (e.env_depth, !(e.env_frame_size)) in
|
|
||||||
incr e.env_frame_size;
|
|
||||||
v
|
|
||||||
;;
|
|
||||||
|
|
||||||
let bind_name e sym v =
|
|
||||||
match sym with
|
|
||||||
Sesym (te, sym) ->
|
|
||||||
e.env_tagged <- (te, sym, v)::e.env_tagged
|
|
||||||
| _ ->
|
|
||||||
begin
|
|
||||||
match v with
|
|
||||||
Vglob g -> g.g_sym <- sym
|
|
||||||
| _ -> ()
|
|
||||||
end;
|
|
||||||
var_insert e.env_vartable (sym_name sym) v
|
|
||||||
;;
|
|
||||||
|
|
||||||
let bind_var e sym =
|
|
||||||
let r = new_var e in
|
|
||||||
bind_name e sym r;
|
|
||||||
r
|
|
||||||
;;
|
|
||||||
|
|
||||||
let find_tagged te ts l =
|
|
||||||
let rec loop =
|
|
||||||
function
|
|
||||||
(e, s, v)::t ->
|
|
||||||
if e == te && s == ts then
|
|
||||||
Some v
|
|
||||||
else
|
|
||||||
loop t
|
|
||||||
| [] -> None
|
|
||||||
in
|
|
||||||
loop l
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec find_var e sym =
|
|
||||||
match sym with
|
|
||||||
Sesym (te, sym) ->
|
|
||||||
begin
|
|
||||||
match find_tagged te sym e.env_tagged with
|
|
||||||
Some _ as v -> v
|
|
||||||
| None -> find_var te sym
|
|
||||||
end
|
|
||||||
| _ -> var_find e.env_vartable (sym_name sym)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec get_var e sym =
|
|
||||||
match sym with
|
|
||||||
Sesym (te, sym) ->
|
|
||||||
begin
|
|
||||||
match find_tagged te sym e.env_tagged with
|
|
||||||
Some v -> v
|
|
||||||
| None -> get_var te sym
|
|
||||||
end
|
|
||||||
| _ -> var_get e.env_vartable (sym_name sym)
|
|
||||||
(fun () -> Vglob { g_sym = sym; g_val = Sunbound })
|
|
||||||
;;
|
|
||||||
|
|
||||||
let set_glob e sym v =
|
|
||||||
match get_var e sym with
|
|
||||||
Vglob g -> g.g_val <- v
|
|
||||||
| _ -> raise (Error "set_glob: not a global")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let vb_copy =
|
|
||||||
function
|
|
||||||
Vglob g -> Vglob { g with g_val = g.g_val }
|
|
||||||
| x -> x
|
|
||||||
|
|
||||||
let env_copy e =
|
|
||||||
{ e with
|
|
||||||
env_vartable = vt_copy e.env_vartable vb_copy;
|
|
||||||
env_tagged = [] }
|
|
||||||
|
|
||||||
let is_a_keyword e sym =
|
|
||||||
match find_var e sym with
|
|
||||||
Some (Vkeyword _) -> true
|
|
||||||
| _ -> false
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_keyword e sym name =
|
|
||||||
match find_var e sym with
|
|
||||||
Some (Vkeyword kw) -> kw = name
|
|
||||||
| _ -> false
|
|
||||||
;;
|
|
||||||
|
|
||||||
let safe_is_keyword e sym name =
|
|
||||||
match sym with
|
|
||||||
Ssymbol _ | Sesym (_, _) -> is_keyword e sym name
|
|
||||||
| _ -> false
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_syntax e sym sf =
|
|
||||||
match find_var e sym with
|
|
||||||
Some (Vsyntax f) -> f == sf
|
|
||||||
| _ -> false
|
|
||||||
;;
|
|
||||||
|
|
||||||
let set_pfg e f n =
|
|
||||||
set_glob e (get_symbol n) (Sprim { prim_fun = f; prim_name = n })
|
|
||||||
;;
|
|
||||||
|
|
||||||
let set_pf0 e f n = set_pfg e (Pf0 f) n
|
|
||||||
let set_pf1 e f n = set_pfg e (Pf1 f) n
|
|
||||||
let set_pf2 e f n = set_pfg e (Pf2 f) n
|
|
||||||
let set_pf3 e f n = set_pfg e (Pf3 f) n
|
|
||||||
let set_pfn e f n = set_pfg e (Pfn f) n
|
|
||||||
let set_pfcn e f n = set_pfg e (Pfcn f) n
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
(* Compilation environment, variable bindings. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_sym
|
|
||||||
|
|
||||||
val top_env : unit -> env
|
|
||||||
val new_scope : env -> env
|
|
||||||
val new_frame : env -> env
|
|
||||||
val new_var : env -> vbind
|
|
||||||
val bind_name : env -> sval -> vbind -> unit
|
|
||||||
val bind_var : env -> sval -> vbind
|
|
||||||
val find_var : env -> sval -> vbind option
|
|
||||||
val get_var : env -> sval -> vbind
|
|
||||||
val set_glob : env -> sval -> sval -> unit
|
|
||||||
val env_copy : env -> env
|
|
||||||
|
|
||||||
val is_a_keyword : env -> sval -> bool
|
|
||||||
val is_keyword : env -> sval -> string -> bool
|
|
||||||
val safe_is_keyword : env -> sval -> string -> bool
|
|
||||||
|
|
||||||
val is_syntax : env -> sval -> (env -> sval array -> code) -> bool
|
|
||||||
|
|
||||||
val set_pf0 : env -> (unit -> sval) -> string -> unit
|
|
||||||
val set_pf1 : env -> (sval -> sval) -> string -> unit
|
|
||||||
val set_pf2 : env -> (sval -> sval -> sval) -> string -> unit
|
|
||||||
val set_pf3 : env -> (sval -> sval -> sval -> sval) -> string -> unit
|
|
||||||
val set_pfn : env -> (sval array -> sval) -> string -> unit
|
|
||||||
val set_pfcn :
|
|
||||||
env -> (thread -> (sval -> unit) -> sval array -> unit) -> string -> unit
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
(* Errors (exceptions) generated by the library. *)
|
|
||||||
|
|
||||||
(* Source location (file, line) *)
|
|
||||||
type location =
|
|
||||||
string * int
|
|
||||||
|
|
||||||
(* These errors indicate non-fatal run-time errors that should be
|
|
||||||
reported, generally interactively. *)
|
|
||||||
exception Error of string
|
|
||||||
exception ErrorL of location * string
|
|
||||||
|
|
|
@ -1,339 +0,0 @@
|
||||||
(* Actual evaluator for the semi-compiled form. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_sym
|
|
||||||
open Ocs_misc
|
|
||||||
|
|
||||||
(* Local variables are stored either in th_frame or th_display.
|
|
||||||
th_frame is the deepest frame, not yet part of the display. *)
|
|
||||||
|
|
||||||
let getl th d i =
|
|
||||||
if d >= Array.length th.th_display then
|
|
||||||
th.th_frame.(i)
|
|
||||||
else
|
|
||||||
th.th_display.(d).(i)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let setl th d i v =
|
|
||||||
if d >= Array.length th.th_display then
|
|
||||||
th.th_frame.(i) <- v
|
|
||||||
else
|
|
||||||
th.th_display.(d).(i) <- v
|
|
||||||
;;
|
|
||||||
|
|
||||||
let args_err p n =
|
|
||||||
if p.proc_has_rest then
|
|
||||||
Printf.sprintf "procedure %s expected %d or more args got %d"
|
|
||||||
p.proc_name (p.proc_nargs - 1) n
|
|
||||||
else
|
|
||||||
Printf.sprintf "procedure %s expected %d args got %d"
|
|
||||||
p.proc_name p.proc_nargs n
|
|
||||||
|
|
||||||
let chkargs p n =
|
|
||||||
match p with
|
|
||||||
Sproc (p, _) ->
|
|
||||||
if n <> p.proc_nargs && (not p.proc_has_rest || n < p.proc_nargs - 1) then
|
|
||||||
raise (Error (args_err p n))
|
|
||||||
else
|
|
||||||
()
|
|
||||||
| Sprim p ->
|
|
||||||
if
|
|
||||||
begin
|
|
||||||
match p.prim_fun with
|
|
||||||
Pf0 _ -> n = 0
|
|
||||||
| Pf1 _ -> n = 1
|
|
||||||
| Pf2 _ -> n = 2
|
|
||||||
| Pf3 _ -> n = 3
|
|
||||||
| Pfn _ | Pfcn _ -> true
|
|
||||||
end
|
|
||||||
then
|
|
||||||
()
|
|
||||||
else
|
|
||||||
raise (Error (p.prim_name ^ ": wrong number of arguments"))
|
|
||||||
| _ -> raise (Error "apply: not a procedure or primitive")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec doapply th cc p disp av =
|
|
||||||
let th = {
|
|
||||||
th with
|
|
||||||
th_frame = Array.make p.proc_frame_size Seof;
|
|
||||||
th_display = disp;
|
|
||||||
th_depth = Array.length disp }
|
|
||||||
in
|
|
||||||
if p.proc_has_rest then
|
|
||||||
begin
|
|
||||||
let nfixed = p.proc_nargs - 1
|
|
||||||
and n = Array.length av in
|
|
||||||
if nfixed > 0 then
|
|
||||||
Array.blit av 0 th.th_frame 0 nfixed;
|
|
||||||
let rec mkrest i r =
|
|
||||||
if i < nfixed then r
|
|
||||||
else mkrest (i - 1) (Spair { car = av.(i); cdr = r })
|
|
||||||
in
|
|
||||||
th.th_frame.(nfixed) <- mkrest (n - 1) Snull
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Array.blit av 0 th.th_frame 0 p.proc_nargs;
|
|
||||||
eval th cc p.proc_body
|
|
||||||
|
|
||||||
and eval th cc =
|
|
||||||
function
|
|
||||||
Cval v -> cc v
|
|
||||||
| Cseq2 (s1, s2) ->
|
|
||||||
eval th (fun _ -> eval th cc s2) s1
|
|
||||||
| Cseq3 (s1, s2, s3) ->
|
|
||||||
eval th (fun _ -> eval th (fun _ -> eval th cc s3) s2) s1
|
|
||||||
| Cseqn s ->
|
|
||||||
let n = Array.length s in
|
|
||||||
let rec loop i =
|
|
||||||
if i = n - 1 then
|
|
||||||
eval th cc s.(i)
|
|
||||||
else
|
|
||||||
eval th (fun _ -> loop (i + 1)) s.(i)
|
|
||||||
in
|
|
||||||
loop 0
|
|
||||||
| Cand2 (s1, s2) ->
|
|
||||||
eval th (function Sfalse -> cc Sfalse | _ -> eval th cc s2) s1
|
|
||||||
| Cand3 (s1, s2, s3) ->
|
|
||||||
eval th
|
|
||||||
(function
|
|
||||||
Sfalse -> cc Sfalse
|
|
||||||
| _ ->
|
|
||||||
eval th
|
|
||||||
(function
|
|
||||||
Sfalse -> cc Sfalse
|
|
||||||
| _ -> eval th cc s3) s2) s1
|
|
||||||
| Candn s ->
|
|
||||||
let n = Array.length s in
|
|
||||||
let rec loop i =
|
|
||||||
begin
|
|
||||||
if i = n - 1 then
|
|
||||||
eval th cc s.(i)
|
|
||||||
else
|
|
||||||
eval th (function Sfalse -> cc Sfalse | _ -> loop (i + 1)) s.(i)
|
|
||||||
end
|
|
||||||
in
|
|
||||||
loop 0
|
|
||||||
| Cor2 (s1, s2) ->
|
|
||||||
eval th (function Sfalse -> eval th cc s2 | x -> cc x) s1
|
|
||||||
| Cor3 (s1, s2, s3) ->
|
|
||||||
eval th
|
|
||||||
(function
|
|
||||||
Sfalse -> eval th
|
|
||||||
(function
|
|
||||||
Sfalse -> eval th cc s3
|
|
||||||
| x -> cc x) s2
|
|
||||||
| x -> cc x) s1
|
|
||||||
| Corn s ->
|
|
||||||
let n = Array.length s in
|
|
||||||
let rec loop i =
|
|
||||||
if i = n - 1 then
|
|
||||||
eval th cc s.(i)
|
|
||||||
else
|
|
||||||
eval th (function Sfalse -> loop (i + 1) | x -> cc x) s.(i)
|
|
||||||
in
|
|
||||||
loop 0
|
|
||||||
| Cif (c, tx, fx) ->
|
|
||||||
eval th
|
|
||||||
(function Sfalse -> eval th cc fx | _ -> eval th cc tx)
|
|
||||||
c
|
|
||||||
| Csetg (g, c) ->
|
|
||||||
eval th (fun v ->
|
|
||||||
if g.g_val == Sunbound then
|
|
||||||
raise (Error ("set!: unbound variable: " ^ (sym_name g.g_sym)))
|
|
||||||
else
|
|
||||||
g.g_val <- v; cc Sunspec) c
|
|
||||||
| Csetl (d, i, c) ->
|
|
||||||
eval th (fun v -> setl th d i v; cc Sunspec) c
|
|
||||||
| Cdefine (g, c) ->
|
|
||||||
eval th (fun v -> g.g_val <- v; cc Sunspec) c
|
|
||||||
| Cgetg g ->
|
|
||||||
if g.g_val == Sunbound then
|
|
||||||
raise (Error ("unbound variable: " ^ (sym_name g.g_sym)))
|
|
||||||
else
|
|
||||||
cc g.g_val
|
|
||||||
| Cgetl (d, i) -> cc (getl th d i)
|
|
||||||
| Capply0 c ->
|
|
||||||
eval th (fun cv ->
|
|
||||||
chkargs cv 0;
|
|
||||||
match cv with
|
|
||||||
Sproc (p, d) -> doapply th cc p d [| |]
|
|
||||||
| Sprim p ->
|
|
||||||
begin
|
|
||||||
match p.prim_fun with
|
|
||||||
Pf0 f -> cc (f ())
|
|
||||||
| Pfn f -> cc (f [| |])
|
|
||||||
| Pfcn f -> f th cc [| |]
|
|
||||||
| _ -> assert false
|
|
||||||
end
|
|
||||||
| _ -> assert false) c
|
|
||||||
| Capply1 (c, a1) ->
|
|
||||||
eval th (fun cv -> eval th (fun a1v ->
|
|
||||||
chkargs cv 1;
|
|
||||||
match cv with
|
|
||||||
Sproc (p, d) -> doapply th cc p d [| a1v |]
|
|
||||||
| Sprim p ->
|
|
||||||
begin
|
|
||||||
match p.prim_fun with
|
|
||||||
Pf1 f -> cc (f a1v)
|
|
||||||
| Pfn f -> cc (f [| a1v |])
|
|
||||||
| Pfcn f -> f th cc [| a1v |]
|
|
||||||
| _ -> assert false
|
|
||||||
end
|
|
||||||
| _ -> assert false) a1) c
|
|
||||||
| Capply2 (c, a1, a2) ->
|
|
||||||
eval th (fun cv -> eval th (fun a1v -> eval th (fun a2v ->
|
|
||||||
chkargs cv 2;
|
|
||||||
match cv with
|
|
||||||
Sproc (p, d) -> doapply th cc p d [| a1v; a2v |]
|
|
||||||
| Sprim p ->
|
|
||||||
begin
|
|
||||||
match p.prim_fun with
|
|
||||||
Pf2 f -> cc (f a1v a2v)
|
|
||||||
| Pfn f -> cc (f [| a1v; a2v |])
|
|
||||||
| Pfcn f -> f th cc [| a1v; a2v |]
|
|
||||||
| _ -> assert false
|
|
||||||
end
|
|
||||||
| _ -> assert false) a2) a1) c
|
|
||||||
| Capply3 (c, a1, a2, a3) ->
|
|
||||||
eval th (fun cv -> eval th (fun a1v -> eval th (fun a2v ->
|
|
||||||
eval th (fun a3v ->
|
|
||||||
chkargs cv 3;
|
|
||||||
match cv with
|
|
||||||
Sproc (p, d) -> doapply th cc p d [| a1v; a2v; a3v |]
|
|
||||||
| Sprim p ->
|
|
||||||
begin
|
|
||||||
match p.prim_fun with
|
|
||||||
Pf3 f -> cc (f a1v a2v a3v)
|
|
||||||
| Pfn f -> cc (f [| a1v; a2v; a3v |])
|
|
||||||
| Pfcn f -> f th cc [| a1v; a2v; a3v |]
|
|
||||||
| _ -> assert false
|
|
||||||
end
|
|
||||||
| _ -> assert false) a3) a2) a1) c
|
|
||||||
| Capplyn (c, a) ->
|
|
||||||
eval th (fun cv ->
|
|
||||||
let n = Array.length a in
|
|
||||||
let av = Array.make n Snull in
|
|
||||||
let rec loop i =
|
|
||||||
if i = n then
|
|
||||||
begin
|
|
||||||
chkargs cv n;
|
|
||||||
match cv with
|
|
||||||
Sproc (p, d) -> doapply th cc p d av
|
|
||||||
| Sprim p ->
|
|
||||||
begin
|
|
||||||
match p.prim_fun with
|
|
||||||
Pfn f -> cc (f av)
|
|
||||||
| Pfcn f -> f th cc av
|
|
||||||
| _ -> assert false
|
|
||||||
end
|
|
||||||
| _ -> assert false
|
|
||||||
end
|
|
||||||
else
|
|
||||||
eval th (fun x -> av.(i) <- x; loop (i + 1)) a.(i)
|
|
||||||
in
|
|
||||||
loop 0) c
|
|
||||||
| Clambda p ->
|
|
||||||
let n = th.th_depth + 1 in
|
|
||||||
let nd = Array.init n
|
|
||||||
(fun i -> if i < n - 1 then th.th_display.(i)
|
|
||||||
else th.th_frame)
|
|
||||||
in
|
|
||||||
cc (Sproc (p, nd))
|
|
||||||
| Cqqp (h, t) ->
|
|
||||||
begin
|
|
||||||
match h with
|
|
||||||
Cqqspl x ->
|
|
||||||
eval th (fun usl -> eval th (fun t ->
|
|
||||||
let rec findtl =
|
|
||||||
function
|
|
||||||
Spair ({ car = _; cdr = Snull } as p) ->
|
|
||||||
p.cdr <- t; usl
|
|
||||||
| Spair { car = _; cdr = nt } -> findtl nt
|
|
||||||
| Snull -> t
|
|
||||||
| _ -> raise (Error "unquote-splicing: not a list")
|
|
||||||
in
|
|
||||||
cc (findtl usl)) t) x
|
|
||||||
| _ ->
|
|
||||||
eval th (fun h -> eval th (fun t ->
|
|
||||||
cc (Spair { car = h; cdr = t })) t) h
|
|
||||||
end
|
|
||||||
| Cqqv v ->
|
|
||||||
let n = Array.length v in
|
|
||||||
let qv = Array.make n Snull in
|
|
||||||
let rec loop i =
|
|
||||||
if i = n then
|
|
||||||
cc (Svector qv)
|
|
||||||
else
|
|
||||||
eval th (fun x -> qv.(i) <- x; loop (i + 1)) v.(i)
|
|
||||||
in
|
|
||||||
loop 0
|
|
||||||
| Cqqvs l ->
|
|
||||||
begin
|
|
||||||
let rec loop r =
|
|
||||||
function
|
|
||||||
[] -> cc (Svector (Array.of_list r))
|
|
||||||
| (Cqqspl x)::t ->
|
|
||||||
eval th (fun l -> loop ((list_to_caml l) @ r) t) x
|
|
||||||
| h::t ->
|
|
||||||
eval th (fun x -> loop (x::r) t) h
|
|
||||||
in
|
|
||||||
loop [] (List.rev l)
|
|
||||||
end
|
|
||||||
| Cqqspl x -> raise (Error "unquote-splicing: not valid here")
|
|
||||||
| Ccond av ->
|
|
||||||
begin
|
|
||||||
let n = Array.length av in
|
|
||||||
let rec loop i =
|
|
||||||
if i < n then
|
|
||||||
begin
|
|
||||||
match av.(i) with
|
|
||||||
(Ccondspec c, b) ->
|
|
||||||
eval th (fun v ->
|
|
||||||
if v <> Sfalse then eval th cc (Capply1 (b, Cval v))
|
|
||||||
else loop (i + 1)) c
|
|
||||||
| (c, b) ->
|
|
||||||
eval th (fun v ->
|
|
||||||
if v <> Sfalse then eval th cc b
|
|
||||||
else loop (i + 1)) c
|
|
||||||
end
|
|
||||||
else
|
|
||||||
cc Sunspec
|
|
||||||
in
|
|
||||||
loop 0
|
|
||||||
end
|
|
||||||
| Ccase (c, m) ->
|
|
||||||
eval th (fun v ->
|
|
||||||
let n = Array.length m in
|
|
||||||
let rec loop i =
|
|
||||||
if i < n then
|
|
||||||
begin
|
|
||||||
match m.(i) with
|
|
||||||
([| |], b) -> eval th cc b
|
|
||||||
| (mv, b) ->
|
|
||||||
let n = Array.length mv in
|
|
||||||
let rec has i =
|
|
||||||
if i < n then
|
|
||||||
begin
|
|
||||||
let mvv = mv.(i) in
|
|
||||||
if mvv == v || test_eqv mvv v then true
|
|
||||||
else has (i + 1)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
false
|
|
||||||
in
|
|
||||||
if has 0 then eval th cc b
|
|
||||||
else loop (i + 1)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
cc Sunspec
|
|
||||||
in
|
|
||||||
loop 0) c
|
|
||||||
| Cdelay c ->
|
|
||||||
cc (Spromise { promise_code = c;
|
|
||||||
promise_val = None;
|
|
||||||
promise_th = Some { th with th_frame = th.th_frame } })
|
|
||||||
| _ -> raise (Error "eval: internal error")
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
(* Evaluation *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val eval : thread -> (sval -> unit) -> code -> unit
|
|
||||||
|
|
|
@ -1,224 +0,0 @@
|
||||||
(* I/O primitives. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_env
|
|
||||||
open Ocs_eval
|
|
||||||
open Ocs_print
|
|
||||||
|
|
||||||
let get_stdin th =
|
|
||||||
match th.th_stdin with
|
|
||||||
Sport p -> p
|
|
||||||
| _ -> assert false
|
|
||||||
;;
|
|
||||||
|
|
||||||
let get_stdout th =
|
|
||||||
match th.th_stdout with
|
|
||||||
Sport p -> p
|
|
||||||
| _ -> assert false
|
|
||||||
;;
|
|
||||||
|
|
||||||
let read th cc =
|
|
||||||
function
|
|
||||||
[| |] ->
|
|
||||||
cc (Ocs_read.read_from_port (get_stdin th))
|
|
||||||
| [| Sport port |] -> cc (Ocs_read.read_from_port port)
|
|
||||||
| _ -> raise (Error "read: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rdchr p cc =
|
|
||||||
match Ocs_port.getc p with
|
|
||||||
Some c -> cc (Schar c)
|
|
||||||
| None -> cc Seof
|
|
||||||
;;
|
|
||||||
|
|
||||||
let read_char th cc =
|
|
||||||
function
|
|
||||||
[| |] -> rdchr (get_stdin th) cc
|
|
||||||
| [| Sport port |] -> rdchr port cc
|
|
||||||
| _ -> raise (Error "read-char: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let peekchr p cc =
|
|
||||||
match Ocs_port.getc p with
|
|
||||||
Some c ->
|
|
||||||
Ocs_port.ungetc p c;
|
|
||||||
cc (Schar c)
|
|
||||||
| None -> cc Seof
|
|
||||||
;;
|
|
||||||
|
|
||||||
let peek_char th cc =
|
|
||||||
function
|
|
||||||
[| |] -> peekchr (get_stdin th) cc
|
|
||||||
| [| Sport port |] -> peekchr port cc
|
|
||||||
| _ -> raise (Error "peek-char: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let eof_object =
|
|
||||||
function
|
|
||||||
Seof -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let chrdy p cc =
|
|
||||||
cc (if Ocs_port.char_ready p then Strue else Sfalse)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let char_ready th cc =
|
|
||||||
function
|
|
||||||
[| |] -> chrdy (get_stdin th) cc
|
|
||||||
| [| Sport port |] -> chrdy port cc
|
|
||||||
| _ -> raise (Error "char-ready?: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let display th cc =
|
|
||||||
function
|
|
||||||
[| obj |] ->
|
|
||||||
let p = get_stdout th in print p true obj; Ocs_port.flush p; cc Sunspec
|
|
||||||
| [| obj; Sport p |] -> print p true obj; Ocs_port.flush p; cc Sunspec
|
|
||||||
| _ -> raise (Error "display: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let write th cc =
|
|
||||||
function
|
|
||||||
[| obj |] ->
|
|
||||||
let p = get_stdout th in print p false obj; Ocs_port.flush p; cc Sunspec
|
|
||||||
| [| obj; Sport p |] -> print p false obj; Ocs_port.flush p; cc Sunspec
|
|
||||||
| _ -> raise (Error "write: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let write_char th cc =
|
|
||||||
function
|
|
||||||
[| Schar c |] ->
|
|
||||||
let p = get_stdout th in Ocs_port.putc p c; Ocs_port.flush p; cc Sunspec
|
|
||||||
| [| Schar c; Sport p |] -> Ocs_port.putc p c; Ocs_port.flush p; cc Sunspec
|
|
||||||
| _ -> raise (Error "write-char: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let newline th cc =
|
|
||||||
function
|
|
||||||
[| |] ->
|
|
||||||
let p = get_stdout th in Ocs_port.putc p '\n'; Ocs_port.flush p; cc Sunspec
|
|
||||||
| [| Sport p |] -> Ocs_port.putc p '\n'; Ocs_port.flush p; cc Sunspec
|
|
||||||
| _ -> raise (Error "newline: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let current_input th cc =
|
|
||||||
function
|
|
||||||
[| |] -> cc th.th_stdin
|
|
||||||
| _ -> raise (Error "current-input-port: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let current_output th cc =
|
|
||||||
function
|
|
||||||
[| |] -> cc th.th_stdout
|
|
||||||
| _ -> raise (Error "current-output-port: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_input =
|
|
||||||
function
|
|
||||||
Sport p -> if Ocs_port.is_input p then Strue else Sfalse
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_output =
|
|
||||||
function
|
|
||||||
Sport p -> if Ocs_port.is_output p then Strue else Sfalse
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let open_input_file =
|
|
||||||
function
|
|
||||||
Sstring s -> Sport (Ocs_port.open_input_port s)
|
|
||||||
| _ -> raise (Error "expected string as input file name")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let open_output_file =
|
|
||||||
function
|
|
||||||
Sstring s -> Sport (Ocs_port.open_output_port s)
|
|
||||||
| _ -> raise (Error "expected string as output file name")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let close_port =
|
|
||||||
function
|
|
||||||
Sport p -> Ocs_port.close p
|
|
||||||
| _ -> raise (Error "close-port: invalid argument")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let scm_close_port p =
|
|
||||||
close_port p; Sunspec
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Note that the call-with-*-file functions close the port if the
|
|
||||||
procedure exits, so they must not be re-called using a captured
|
|
||||||
continuation after they exit once. Dynamic extents can't be used
|
|
||||||
for this because closing and reopening the file would be an even
|
|
||||||
bigger problem. *)
|
|
||||||
|
|
||||||
let call_w_in th cc =
|
|
||||||
function
|
|
||||||
[| name; proc |] ->
|
|
||||||
let p = open_input_file name in
|
|
||||||
eval th (fun x -> close_port p; cc x) (Capply1 (Cval proc, Cval p))
|
|
||||||
| _ -> raise (Error "call-with-input-file: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let call_w_out th cc =
|
|
||||||
function
|
|
||||||
[| name; proc |] ->
|
|
||||||
let p = open_output_file name in
|
|
||||||
eval th (fun x -> close_port p; cc x) (Capply1 (Cval proc, Cval p))
|
|
||||||
| _ -> raise (Error "call-with-output-file: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let w_in th cc =
|
|
||||||
function
|
|
||||||
[| name; thunk |] ->
|
|
||||||
let p = open_input_file name in
|
|
||||||
eval { th with th_stdin = p }
|
|
||||||
(fun x -> close_port p; cc x)
|
|
||||||
(Capply0 (Cval thunk))
|
|
||||||
| _ -> raise (Error "with-input-from-file: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let w_out th cc =
|
|
||||||
function
|
|
||||||
[| name; thunk |] ->
|
|
||||||
let p = open_output_file name in
|
|
||||||
eval { th with th_stdout = p }
|
|
||||||
(fun x -> close_port p; cc x)
|
|
||||||
(Capply0 (Cval thunk))
|
|
||||||
| _ -> raise (Error "with-output-to-file: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let init e =
|
|
||||||
set_pfcn e read "read";
|
|
||||||
set_pfcn e read_char "read-char";
|
|
||||||
set_pfcn e peek_char "peek-char";
|
|
||||||
set_pfcn e char_ready "char-ready?";
|
|
||||||
|
|
||||||
set_pf1 e eof_object "eof-object?";
|
|
||||||
|
|
||||||
set_pfcn e display "display";
|
|
||||||
set_pfcn e newline "newline";
|
|
||||||
set_pfcn e write "write";
|
|
||||||
set_pfcn e write_char "write-char";
|
|
||||||
|
|
||||||
set_pfcn e current_input "current-input-port";
|
|
||||||
set_pfcn e current_output "current-output-port";
|
|
||||||
|
|
||||||
set_pf1 e is_input "input-port?";
|
|
||||||
set_pf1 e is_output "output-port?";
|
|
||||||
|
|
||||||
set_pf1 e open_input_file "open-input-file";
|
|
||||||
set_pf1 e open_output_file "open-output-file";
|
|
||||||
|
|
||||||
set_pf1 e scm_close_port "close-input-port";
|
|
||||||
set_pf1 e scm_close_port "close-output-port";
|
|
||||||
|
|
||||||
set_pfcn e call_w_in "call-with-input-file";
|
|
||||||
set_pfcn e call_w_out "call-with-output-file";
|
|
||||||
|
|
||||||
set_pfcn e w_in "with-input-from-file";
|
|
||||||
set_pfcn e w_out "with-output-to-file";
|
|
||||||
;;
|
|
|
@ -1,11 +0,0 @@
|
||||||
(* I/O primitives *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val read : thread -> (sval -> unit) -> sval array -> unit
|
|
||||||
|
|
||||||
val open_input_file : sval -> sval
|
|
||||||
val open_output_file : sval -> sval
|
|
||||||
|
|
||||||
val init : env -> unit
|
|
||||||
|
|
|
@ -1,279 +0,0 @@
|
||||||
(* Lexer for Scheme. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
|
|
||||||
type token =
|
|
||||||
Leof
|
|
||||||
| Lopenv (* #( *)
|
|
||||||
| Lunqsplice (* ,@ *)
|
|
||||||
| Lident of string
|
|
||||||
| Lstring of string
|
|
||||||
| Lnumber of sval
|
|
||||||
| Lbool of sval
|
|
||||||
| Lchar of sval
|
|
||||||
| Ltoken of char
|
|
||||||
|
|
||||||
type lexer = {
|
|
||||||
l_port : Ocs_port.port;
|
|
||||||
l_buf : Buffer.t;
|
|
||||||
l_name : string;
|
|
||||||
mutable l_line : int
|
|
||||||
}
|
|
||||||
|
|
||||||
let make_lexer port name =
|
|
||||||
{ l_port = port;
|
|
||||||
l_buf = Buffer.create 512;
|
|
||||||
l_name = name;
|
|
||||||
l_line = 0 }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let get_loc lex =
|
|
||||||
(lex.l_name, lex.l_line)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let lex_error lex err =
|
|
||||||
if String.length lex.l_name = 0 then
|
|
||||||
Error err
|
|
||||||
else
|
|
||||||
ErrorL (get_loc lex, err)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let num_w_base lex s =
|
|
||||||
let base =
|
|
||||||
match s.[0] with
|
|
||||||
'B' | 'b' -> 2
|
|
||||||
| 'D' | 'd' -> 10
|
|
||||||
| 'O' | 'o' -> 8
|
|
||||||
| 'X' | 'x' -> 16
|
|
||||||
| _ -> raise (lex_error lex "invalid character literal")
|
|
||||||
and n = String.length s
|
|
||||||
in
|
|
||||||
let rec scn v i =
|
|
||||||
if i >= n then v
|
|
||||||
else
|
|
||||||
match s.[i] with
|
|
||||||
'0' .. '9' as c when (int_of_char c) - (int_of_char '0') < base ->
|
|
||||||
scn (v * base + (int_of_char c) - (int_of_char '0')) (i + 1)
|
|
||||||
| 'a' .. 'f' as c when base = 16 ->
|
|
||||||
scn (v * base + (int_of_char c) - (int_of_char 'a') + 10) (i + 1)
|
|
||||||
| 'A' .. 'F' as c when base = 16 ->
|
|
||||||
scn (v * base + (int_of_char c) - (int_of_char 'A') + 10) (i + 1)
|
|
||||||
| _ -> v (* Ignore trailing junk *)
|
|
||||||
in
|
|
||||||
scn 0 1
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_num_esc lex base n =
|
|
||||||
let rec scn v i =
|
|
||||||
if i >= n then char_of_int v
|
|
||||||
else
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some ('0' .. '9' as c) when
|
|
||||||
(int_of_char c) - (int_of_char '0') < base ->
|
|
||||||
scn (v * base + (int_of_char c) - (int_of_char '0')) (i + 1)
|
|
||||||
| Some ('a' .. 'f' as c) when base = 16 ->
|
|
||||||
scn (v * base + (int_of_char c) - (int_of_char 'a') + 10) (i + 1)
|
|
||||||
| Some ('A' .. 'F' as c) when base = 16 ->
|
|
||||||
scn (v * base + (int_of_char c) - (int_of_char 'A') + 10) (i + 1)
|
|
||||||
| Some c ->
|
|
||||||
Ocs_port.ungetc lex.l_port c;
|
|
||||||
char_of_int v
|
|
||||||
| None -> raise (lex_error lex "unexpected eof in string literal")
|
|
||||||
in
|
|
||||||
scn 0 0
|
|
||||||
;;
|
|
||||||
|
|
||||||
let read_char lex =
|
|
||||||
begin
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some c -> Buffer.add_char lex.l_buf c
|
|
||||||
| None -> raise (lex_error lex "unexpected eof")
|
|
||||||
end;
|
|
||||||
let rec loop () =
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some (('a' .. 'z' | 'A' .. 'Z' | '0' .. '9') as c) ->
|
|
||||||
Buffer.add_char lex.l_buf c; loop ()
|
|
||||||
| Some c -> Ocs_port.ungetc lex.l_port c
|
|
||||||
| None -> ()
|
|
||||||
in
|
|
||||||
loop ();
|
|
||||||
let s = Buffer.contents lex.l_buf in
|
|
||||||
if String.length s = 1 then
|
|
||||||
Lchar (Schar s.[0])
|
|
||||||
else
|
|
||||||
match Ocs_char.name_to_char s with
|
|
||||||
Some c -> Lchar (Schar c)
|
|
||||||
| None -> Lchar (Schar (char_of_int (num_w_base lex s)))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec read_string lex =
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some '\"' -> Lstring (Buffer.contents lex.l_buf)
|
|
||||||
| Some '\\' ->
|
|
||||||
begin
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some ('N' | 'n') ->
|
|
||||||
Buffer.add_char lex.l_buf '\n';
|
|
||||||
read_string lex
|
|
||||||
| Some ('R' | 'r') ->
|
|
||||||
Buffer.add_char lex.l_buf '\r';
|
|
||||||
read_string lex
|
|
||||||
| Some ('T' | 't') ->
|
|
||||||
Buffer.add_char lex.l_buf '\t';
|
|
||||||
read_string lex
|
|
||||||
| Some ('B' | 'b') ->
|
|
||||||
Buffer.add_char lex.l_buf (string_num_esc lex 2 8);
|
|
||||||
read_string lex
|
|
||||||
| Some ('D' | 'd') ->
|
|
||||||
Buffer.add_char lex.l_buf (string_num_esc lex 10 3);
|
|
||||||
read_string lex
|
|
||||||
| Some ('O' | 'o') ->
|
|
||||||
Buffer.add_char lex.l_buf (string_num_esc lex 8 3);
|
|
||||||
read_string lex
|
|
||||||
| Some ('X' | 'x') ->
|
|
||||||
Buffer.add_char lex.l_buf (string_num_esc lex 16 2);
|
|
||||||
read_string lex
|
|
||||||
| Some ('0' .. '9' as c) ->
|
|
||||||
Ocs_port.ungetc lex.l_port c;
|
|
||||||
Buffer.add_char lex.l_buf (string_num_esc lex 10 3);
|
|
||||||
read_string lex
|
|
||||||
| Some c ->
|
|
||||||
Buffer.add_char lex.l_buf c;
|
|
||||||
read_string lex
|
|
||||||
| None ->
|
|
||||||
raise (lex_error lex "unexpected eof in string literal")
|
|
||||||
end
|
|
||||||
| Some '\n' ->
|
|
||||||
lex.l_line <- lex.l_line + 1;
|
|
||||||
Buffer.add_char lex.l_buf '\n';
|
|
||||||
read_string lex
|
|
||||||
| Some c ->
|
|
||||||
Buffer.add_char lex.l_buf c;
|
|
||||||
read_string lex
|
|
||||||
| None -> raise (lex_error lex "unexpected eof in string literal")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec read_ident lex =
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some (('a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '!' | '$' | '%' | '&' |
|
|
||||||
'*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' |
|
|
||||||
'+' | '-' | '.' | '@') as c) ->
|
|
||||||
Buffer.add_char lex.l_buf c;
|
|
||||||
read_ident lex
|
|
||||||
| Some c ->
|
|
||||||
Ocs_port.ungetc lex.l_port c;
|
|
||||||
Lident (Buffer.contents lex.l_buf)
|
|
||||||
| None ->
|
|
||||||
Lident (Buffer.contents lex.l_buf)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let parse_number lex =
|
|
||||||
try
|
|
||||||
Lnumber (Ocs_numstr.string_to_num (Buffer.contents lex.l_buf) 0)
|
|
||||||
with
|
|
||||||
Error err -> raise (lex_error lex err)
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* When reading numbers, accept almost any characters that look
|
|
||||||
like they may be part of a number. Some extremely obfuscated
|
|
||||||
inputs may be misinterpreted. *)
|
|
||||||
let rec read_number lex =
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some (('0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' | '-' | '+' | '.' |
|
|
||||||
'#' | '/' | '@') as c) ->
|
|
||||||
Buffer.add_char lex.l_buf c;
|
|
||||||
read_number lex
|
|
||||||
| Some c ->
|
|
||||||
Ocs_port.ungetc lex.l_port c;
|
|
||||||
parse_number lex
|
|
||||||
| None ->
|
|
||||||
parse_number lex
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec tok lex =
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some c ->
|
|
||||||
begin
|
|
||||||
match c with
|
|
||||||
'\n' -> lex.l_line <- lex.l_line + 1; tok lex
|
|
||||||
| ' ' | '\t' | '\r' | '\012' -> tok lex
|
|
||||||
| ';' ->
|
|
||||||
begin
|
|
||||||
let rec loop () =
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some '\n' -> lex.l_line <- lex.l_line + 1; tok lex
|
|
||||||
| Some _ -> loop ()
|
|
||||||
| None -> Leof
|
|
||||||
in
|
|
||||||
loop ()
|
|
||||||
end
|
|
||||||
| ',' ->
|
|
||||||
begin
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some '@' -> Lunqsplice
|
|
||||||
| Some c -> Ocs_port.ungetc lex.l_port c; Ltoken ','
|
|
||||||
| None -> Ltoken ','
|
|
||||||
end
|
|
||||||
| '#' ->
|
|
||||||
begin
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some ('f' | 'F') -> Lbool Sfalse
|
|
||||||
| Some ('t' | 'T') -> Lbool Strue
|
|
||||||
| Some (('B' | 'b' | 'D' | 'd' | 'O' | 'o' | 'X' | 'x' |
|
|
||||||
'E' | 'e' | 'I' | 'i') as c) ->
|
|
||||||
Buffer.add_char lex.l_buf '#';
|
|
||||||
Buffer.add_char lex.l_buf c;
|
|
||||||
read_number lex
|
|
||||||
| Some '\\' -> read_char lex
|
|
||||||
| Some '(' -> Lopenv
|
|
||||||
| Some c -> Ocs_port.ungetc lex.l_port c; Ltoken '#'
|
|
||||||
| None -> Ltoken '#'
|
|
||||||
end
|
|
||||||
| '\"' -> read_string lex
|
|
||||||
| '+' | '-' ->
|
|
||||||
begin
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some (('0' .. '9' | 'i' | 'I' | '.') as x) ->
|
|
||||||
Buffer.add_char lex.l_buf c;
|
|
||||||
Buffer.add_char lex.l_buf x;
|
|
||||||
read_number lex
|
|
||||||
| Some x ->
|
|
||||||
Ocs_port.ungetc lex.l_port x;
|
|
||||||
Lident (String.make 1 c)
|
|
||||||
| None -> Lident (String.make 1 c)
|
|
||||||
end
|
|
||||||
| '.' ->
|
|
||||||
begin
|
|
||||||
match Ocs_port.getc lex.l_port with
|
|
||||||
Some '.' ->
|
|
||||||
Buffer.add_string lex.l_buf "..";
|
|
||||||
read_ident lex
|
|
||||||
| Some ('0' .. '9' as c) ->
|
|
||||||
Buffer.add_char lex.l_buf '.';
|
|
||||||
Buffer.add_char lex.l_buf c;
|
|
||||||
read_number lex
|
|
||||||
| Some c ->
|
|
||||||
Ocs_port.ungetc lex.l_port c;
|
|
||||||
Ltoken '.'
|
|
||||||
| None -> Ltoken '.'
|
|
||||||
end
|
|
||||||
| '0' .. '9' ->
|
|
||||||
Buffer.add_char lex.l_buf c;
|
|
||||||
read_number lex
|
|
||||||
| 'a' .. 'z' | 'A' .. 'Z' | '!' | '$' | '%' | '&' | '*' | '/'
|
|
||||||
| ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' ->
|
|
||||||
begin
|
|
||||||
Buffer.add_char lex.l_buf c;
|
|
||||||
read_ident lex
|
|
||||||
end
|
|
||||||
| _ -> Ltoken c
|
|
||||||
end
|
|
||||||
| None -> Leof
|
|
||||||
;;
|
|
||||||
|
|
||||||
let get_tok lex =
|
|
||||||
Buffer.clear lex.l_buf;
|
|
||||||
tok lex
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
(* Lexer for Scheme. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
|
|
||||||
type token =
|
|
||||||
Leof
|
|
||||||
| Lopenv (* #( *)
|
|
||||||
| Lunqsplice (* ,@ *)
|
|
||||||
| Lident of string
|
|
||||||
| Lstring of string
|
|
||||||
| Lnumber of sval
|
|
||||||
| Lbool of sval
|
|
||||||
| Lchar of sval
|
|
||||||
| Ltoken of char
|
|
||||||
|
|
||||||
type lexer
|
|
||||||
|
|
||||||
val make_lexer : Ocs_port.port -> string -> lexer
|
|
||||||
val get_loc : lexer -> location
|
|
||||||
val get_tok : lexer -> token
|
|
||||||
|
|
|
@ -1,302 +0,0 @@
|
||||||
(* List functionality. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_env
|
|
||||||
open Ocs_misc
|
|
||||||
|
|
||||||
(* Primitives *)
|
|
||||||
|
|
||||||
let make_list av =
|
|
||||||
let rec loop i r =
|
|
||||||
if i < 0 then r
|
|
||||||
else loop (i - 1) (Spair { car = Array.unsafe_get av i; cdr = r })
|
|
||||||
in
|
|
||||||
loop (Array.length av - 1) Snull
|
|
||||||
;;
|
|
||||||
|
|
||||||
let cons h t =
|
|
||||||
Spair { car = h; cdr = t }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let gcar =
|
|
||||||
function
|
|
||||||
Spair { car = r; cdr = _ } -> r
|
|
||||||
| _ -> raise (Error "car: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let gcdr =
|
|
||||||
function
|
|
||||||
Spair { car = _; cdr = r } -> r
|
|
||||||
| _ -> raise (Error "cdr: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let caar x = gcar (gcar x);;
|
|
||||||
let cadr x = gcar (gcdr x);;
|
|
||||||
let cdar x = gcdr (gcar x);;
|
|
||||||
let cddr x = gcdr (gcdr x);;
|
|
||||||
|
|
||||||
let gcxr seq =
|
|
||||||
List.fold_left (fun f g -> fun x -> f (g x)) (fun x -> x) seq
|
|
||||||
;;
|
|
||||||
|
|
||||||
let set_car l v =
|
|
||||||
match l with
|
|
||||||
Spair p -> p.car <- v; Sunspec
|
|
||||||
| _ -> raise (Error "set-car!: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let set_cdr l v =
|
|
||||||
match l with
|
|
||||||
Spair p -> p.cdr <- v; Sunspec
|
|
||||||
| _ -> raise (Error "set-cdr!: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let safe_length l =
|
|
||||||
let next =
|
|
||||||
function
|
|
||||||
Spair { car = _; cdr = t } -> t
|
|
||||||
| _ -> raise (Error "length: invalid list") in
|
|
||||||
let rec loop l r n =
|
|
||||||
if l == Snull then
|
|
||||||
n
|
|
||||||
else if n land 1 = 0 then
|
|
||||||
loop (next l) r (n + 1)
|
|
||||||
else if l == r then
|
|
||||||
raise (Error "length: loop detected")
|
|
||||||
else
|
|
||||||
loop (next l) (next r) (n + 1)
|
|
||||||
in
|
|
||||||
loop l l 0
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_list l =
|
|
||||||
try
|
|
||||||
let _ = safe_length l in Strue
|
|
||||||
with
|
|
||||||
_ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let length l =
|
|
||||||
Sint (safe_length l)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let reverse l =
|
|
||||||
let rec loop nl =
|
|
||||||
function
|
|
||||||
Snull -> nl
|
|
||||||
| Spair { car = h; cdr = t } -> loop (Spair { car = h; cdr = nl }) t
|
|
||||||
| _ -> raise (Error "reverse: invalid list")
|
|
||||||
in
|
|
||||||
loop Snull l
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Copy list and set tail, used by append *)
|
|
||||||
let cptl tl =
|
|
||||||
function
|
|
||||||
Snull -> tl
|
|
||||||
| Spair { car = h; cdr = t } ->
|
|
||||||
let nl = Spair { car = h; cdr = Snull } in
|
|
||||||
let rec loop =
|
|
||||||
function
|
|
||||||
Spair p ->
|
|
||||||
begin
|
|
||||||
function
|
|
||||||
Spair { car = h; cdr = t } ->
|
|
||||||
let n = Spair { car = h; cdr = Snull } in
|
|
||||||
p.cdr <- n; loop n t
|
|
||||||
| Snull -> p.cdr <- tl
|
|
||||||
| _ -> raise (Error "append: bad list")
|
|
||||||
end
|
|
||||||
| _ -> assert false
|
|
||||||
in
|
|
||||||
loop nl t; nl
|
|
||||||
| _ -> raise (Error "append: bad list")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let append =
|
|
||||||
function
|
|
||||||
[| |] -> Snull
|
|
||||||
| av ->
|
|
||||||
let n = Array.length av in
|
|
||||||
let rec loop i tl =
|
|
||||||
if i >= 0 then
|
|
||||||
loop (i - 1) (cptl tl av.(i))
|
|
||||||
else
|
|
||||||
tl
|
|
||||||
in
|
|
||||||
loop (n - 2) av.(n - 1)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let list_tail l =
|
|
||||||
function
|
|
||||||
Sint k ->
|
|
||||||
begin
|
|
||||||
let rec tail i x =
|
|
||||||
if i = 0 then x
|
|
||||||
else
|
|
||||||
match x with
|
|
||||||
Spair { car = _; cdr = t } -> tail (i - 1) t
|
|
||||||
| _ -> raise (Error "list-tail: bad list")
|
|
||||||
in
|
|
||||||
tail k l
|
|
||||||
end
|
|
||||||
| _ -> raise (Error "list-tail: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let list_ref l k =
|
|
||||||
match list_tail l k with
|
|
||||||
Spair { car = x; cdr = _ } -> x
|
|
||||||
| _ -> raise (Error "list-ref: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec memq o =
|
|
||||||
function
|
|
||||||
Snull -> Sfalse
|
|
||||||
| Spair { car = x; cdr = t } as p -> if o == x then p else memq o t
|
|
||||||
| _ -> raise (Error "memq: bad list")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec memv o =
|
|
||||||
function
|
|
||||||
Snull -> Sfalse
|
|
||||||
| Spair { car = x; cdr = t } as p ->
|
|
||||||
if o == x || test_eqv o x then p else memv o t
|
|
||||||
| _ -> raise (Error "memv: bad list")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec member o =
|
|
||||||
function
|
|
||||||
Snull -> Sfalse
|
|
||||||
| Spair { car = x; cdr = t } as p ->
|
|
||||||
if o == x || test_equal o x then p else member o t
|
|
||||||
| _ -> raise (Error "member: bad list")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec assq o =
|
|
||||||
function
|
|
||||||
Snull -> Sfalse
|
|
||||||
| Spair { car = Spair { car = x; cdr = _ } as p; cdr = t } ->
|
|
||||||
if o == x then p else assq o t
|
|
||||||
| _ -> raise (Error "assq: bad list")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec assv o =
|
|
||||||
function
|
|
||||||
Snull -> Sfalse
|
|
||||||
| Spair { car = Spair { car = x; cdr = _ } as p; cdr = t } ->
|
|
||||||
if o == x || test_eqv o x then p else assv o t
|
|
||||||
| _ -> raise (Error "assv: bad list")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec assoc o =
|
|
||||||
function
|
|
||||||
Snull -> Sfalse
|
|
||||||
| Spair { car = Spair { car = x; cdr = _ } as p; cdr = t } ->
|
|
||||||
if o == x || test_equal o x then p else assv o t
|
|
||||||
| _ -> raise (Error "assoc: bad list")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let list_to_vector =
|
|
||||||
function
|
|
||||||
Snull -> Svector [| |]
|
|
||||||
| Spair _ as l ->
|
|
||||||
let n = safe_length l in
|
|
||||||
let v = Array.make n Snull in
|
|
||||||
let rec loop i l =
|
|
||||||
if i < n then
|
|
||||||
begin
|
|
||||||
match l with
|
|
||||||
Spair { car = h; cdr = t } -> v.(i) <- h; loop (i + 1) t
|
|
||||||
| _ -> assert false (* length was wrong? *)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
()
|
|
||||||
in
|
|
||||||
loop 0 l;
|
|
||||||
Svector v
|
|
||||||
| _ -> raise (Error "list->vector: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let list_to_string =
|
|
||||||
function
|
|
||||||
Snull -> Sstring ""
|
|
||||||
| Spair _ as l ->
|
|
||||||
let n = safe_length l in
|
|
||||||
let s = String.create n in
|
|
||||||
let rec loop i l =
|
|
||||||
if i < n then
|
|
||||||
begin
|
|
||||||
match l with
|
|
||||||
Spair { car = Schar c; cdr = t } -> s.[i] <- c; loop (i + 1) t
|
|
||||||
| _ -> raise (Error "list->string: non-characters in list")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
()
|
|
||||||
in
|
|
||||||
loop 0 l;
|
|
||||||
Sstring s
|
|
||||||
| _ -> raise (Error "list->string: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let init e =
|
|
||||||
set_pf1 e is_list "list?";
|
|
||||||
set_pfn e make_list "list";
|
|
||||||
set_pf2 e cons "cons";
|
|
||||||
|
|
||||||
set_pf1 e gcar "car";
|
|
||||||
set_pf1 e gcdr "cdr";
|
|
||||||
|
|
||||||
set_pf1 e caar "caar";
|
|
||||||
set_pf1 e cadr "cadr";
|
|
||||||
set_pf1 e cdar "cdar";
|
|
||||||
set_pf1 e cddr "cddr";
|
|
||||||
|
|
||||||
set_pf1 e (gcxr [ gcar; gcar; gcar ]) "caaar";
|
|
||||||
set_pf1 e (gcxr [ gcar; gcar; gcdr ]) "caadr";
|
|
||||||
set_pf1 e (gcxr [ gcar; gcdr; gcar ]) "cadar";
|
|
||||||
set_pf1 e (gcxr [ gcar; gcdr; gcdr ]) "caddr";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcar; gcar ]) "cdaar";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcar; gcdr ]) "cdadr";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcdr; gcar ]) "cddar";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcdr; gcdr ]) "cdddr";
|
|
||||||
|
|
||||||
set_pf1 e (gcxr [ gcar; gcar; gcar; gcar ]) "caaaar";
|
|
||||||
set_pf1 e (gcxr [ gcar; gcar; gcar; gcdr ]) "caaadr";
|
|
||||||
set_pf1 e (gcxr [ gcar; gcar; gcdr; gcar ]) "caadar";
|
|
||||||
set_pf1 e (gcxr [ gcar; gcar; gcdr; gcdr ]) "caaddr";
|
|
||||||
set_pf1 e (gcxr [ gcar; gcdr; gcar; gcar ]) "cadaar";
|
|
||||||
set_pf1 e (gcxr [ gcar; gcdr; gcar; gcdr ]) "cadadr";
|
|
||||||
set_pf1 e (gcxr [ gcar; gcdr; gcdr; gcar ]) "caddar";
|
|
||||||
set_pf1 e (gcxr [ gcar; gcdr; gcdr; gcdr ]) "cadddr";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcar; gcar; gcar ]) "cdaaar";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcar; gcar; gcdr ]) "cdaadr";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcar; gcdr; gcar ]) "cdadar";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcar; gcdr; gcdr ]) "cdaddr";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcdr; gcar; gcar ]) "cddaar";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcdr; gcar; gcdr ]) "cddadr";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcdr; gcdr; gcar ]) "cdddar";
|
|
||||||
set_pf1 e (gcxr [ gcdr; gcdr; gcdr; gcdr ]) "cddddr";
|
|
||||||
|
|
||||||
set_pf2 e set_car "set-car!";
|
|
||||||
set_pf2 e set_cdr "set-cdr!";
|
|
||||||
|
|
||||||
set_pf1 e length "length";
|
|
||||||
set_pf1 e reverse "reverse";
|
|
||||||
|
|
||||||
set_pfn e append "append";
|
|
||||||
|
|
||||||
set_pf2 e list_tail "list-tail";
|
|
||||||
set_pf2 e list_ref "list-ref";
|
|
||||||
|
|
||||||
set_pf2 e memq "memq";
|
|
||||||
set_pf2 e memv "memv";
|
|
||||||
set_pf2 e member "member";
|
|
||||||
set_pf2 e assq "assq";
|
|
||||||
set_pf2 e assv "assv";
|
|
||||||
set_pf2 e assoc "assoc";
|
|
||||||
|
|
||||||
set_pf1 e list_to_vector "list->vector";
|
|
||||||
set_pf1 e list_to_string "list->string";
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
(* List functionality. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val init : env -> unit
|
|
||||||
|
|
|
@ -1,438 +0,0 @@
|
||||||
(* Macro definitions and expanders. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_sym
|
|
||||||
open Ocs_env
|
|
||||||
open Ocs_compile
|
|
||||||
open Ocs_misc
|
|
||||||
|
|
||||||
(* Pattern/template type in syntax rules. *)
|
|
||||||
type pattern =
|
|
||||||
Pkeyword of env * sval
|
|
||||||
| Pvar of sval
|
|
||||||
| Pvalue of sval
|
|
||||||
| Ppair of pattern * pattern
|
|
||||||
| Pvector of pattern array
|
|
||||||
| Pmulti of pattern * pattern (* pattern ... in a list *)
|
|
||||||
| Pvmulti of pattern (* pattern ... in a vector *)
|
|
||||||
| Pmvector of pattern list (* Vector with Pvmulti patterns *)
|
|
||||||
|
|
||||||
type ruleset = {
|
|
||||||
mutable r_rules : (pattern * pattern) list
|
|
||||||
}
|
|
||||||
(* Values of pattern variables *)
|
|
||||||
type pattvar =
|
|
||||||
Vitem of sval
|
|
||||||
| Vmulti of pattvar list
|
|
||||||
|
|
||||||
let rec var_name =
|
|
||||||
function
|
|
||||||
Sesym (_, s) -> var_name s
|
|
||||||
| Ssymbol _ as s -> sym_name s
|
|
||||||
| _ -> assert false
|
|
||||||
;;
|
|
||||||
|
|
||||||
let kw_name =
|
|
||||||
function
|
|
||||||
Vkeyword s -> s
|
|
||||||
| _ -> assert false
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Parse a pattern or template *)
|
|
||||||
let parseptt e patt dovar =
|
|
||||||
let rec parse =
|
|
||||||
function
|
|
||||||
Spair { car = h; cdr = t } ->
|
|
||||||
let x = parse h in
|
|
||||||
begin
|
|
||||||
match t with (* Special case, ... *)
|
|
||||||
Spair { car = (Ssymbol _ | Sesym (_, _)) as s; cdr = t }
|
|
||||||
when is_keyword e s "..." -> Pmulti (x, parse t)
|
|
||||||
| _ -> Ppair (x, parse t)
|
|
||||||
end
|
|
||||||
| (Ssymbol _ | Sesym (_, _)) as s -> dovar s
|
|
||||||
| Svector v ->
|
|
||||||
let n = Array.length v
|
|
||||||
and has_multi = ref false in
|
|
||||||
let rec loop r i =
|
|
||||||
if i < 0 then
|
|
||||||
r
|
|
||||||
else if safe_is_keyword e v.(i) "..." && i > 0 then
|
|
||||||
begin
|
|
||||||
has_multi := true;
|
|
||||||
loop (Pvmulti (parse v.(i - 1))::r) (i - 2)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
loop (parse v.(i)::r) (i - 1)
|
|
||||||
in
|
|
||||||
let nl = loop [] (n - 1) in
|
|
||||||
if !has_multi then
|
|
||||||
Pmvector nl
|
|
||||||
else
|
|
||||||
Pvector (Array.of_list nl)
|
|
||||||
| x -> Pvalue x
|
|
||||||
in
|
|
||||||
parse patt
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec match_sym s s' =
|
|
||||||
match (s, s') with
|
|
||||||
Sesym (e, s), Sesym (e', s') -> e == e' && match_sym s s'
|
|
||||||
| _, _ -> s == s'
|
|
||||||
;;
|
|
||||||
|
|
||||||
let parsepatt e litlist patt =
|
|
||||||
let vars = ref [] in
|
|
||||||
let p = parseptt e patt
|
|
||||||
(fun s ->
|
|
||||||
try
|
|
||||||
let _ = List.find (fun s' -> match_sym s s') litlist in
|
|
||||||
Pkeyword (e, s)
|
|
||||||
with Not_found ->
|
|
||||||
vars := s::!vars;
|
|
||||||
Pvar s)
|
|
||||||
in
|
|
||||||
(!vars, p)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let parsetmpl e varlist tmpl =
|
|
||||||
let assocvar =
|
|
||||||
function
|
|
||||||
Sesym (e, s) as sym ->
|
|
||||||
begin
|
|
||||||
try
|
|
||||||
Pvar (List.find (function
|
|
||||||
Sesym (e', s') -> e' == e && s' == s
|
|
||||||
| _ -> false) varlist)
|
|
||||||
with Not_found ->
|
|
||||||
Pvalue sym
|
|
||||||
end
|
|
||||||
| s -> if List.memq s varlist then Pvar s else Pvalue s
|
|
||||||
in
|
|
||||||
parseptt e tmpl assocvar
|
|
||||||
;;
|
|
||||||
|
|
||||||
let parserule e ll =
|
|
||||||
function
|
|
||||||
Spair { car = Spair { car = _; cdr = patt };
|
|
||||||
cdr = Spair { car = tmpl; cdr = Snull }} ->
|
|
||||||
let (vars, patt) = parsepatt e ll patt in
|
|
||||||
let tmpl = parsetmpl e vars tmpl in
|
|
||||||
(patt, tmpl)
|
|
||||||
| _ -> raise (Error "syntax definition: invalid syntax rule")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let parsetspec e sym =
|
|
||||||
function
|
|
||||||
Spair { car = (Ssymbol _ | Sesym (_, _)) as s;
|
|
||||||
cdr = Spair { car = literals; cdr = rules }}
|
|
||||||
when is_keyword e s "syntax-rules" ->
|
|
||||||
let litlist = list_to_caml literals in
|
|
||||||
List.map (parserule e litlist) (list_to_caml rules)
|
|
||||||
| _ -> raise (Error "syntax definition: invalid transformer spec")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rebuild a =
|
|
||||||
let rec loop i r =
|
|
||||||
if i < 0 then
|
|
||||||
r
|
|
||||||
else
|
|
||||||
loop (i - 1) (Spair { car = a.(i); cdr = r })
|
|
||||||
in
|
|
||||||
loop (Array.length a - 1) Snull
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Given a pattern, return an association list of pattern variables
|
|
||||||
with empty multiple value lists. *)
|
|
||||||
let rec empty_vars =
|
|
||||||
function
|
|
||||||
Pvar v -> [ v, Vmulti [] ]
|
|
||||||
| Ppair (h, t) -> (empty_vars h) @ (empty_vars t)
|
|
||||||
| Pmulti (p, t) -> (empty_vars p) @ (empty_vars t)
|
|
||||||
| Pvmulti p -> empty_vars p
|
|
||||||
| Pvector v ->
|
|
||||||
Array.fold_left (@) [] (Array.map empty_vars v)
|
|
||||||
| Pmvector l ->
|
|
||||||
List.fold_left (@) [] (List.map empty_vars l)
|
|
||||||
| _ -> []
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Merge an association list of multi-vars and a set of values *)
|
|
||||||
let merge_vars mv vs =
|
|
||||||
let rec merge =
|
|
||||||
function
|
|
||||||
(v, Vmulti m)::t -> (v, Vmulti (m @ [ List.assq v vs ]))::(merge t)
|
|
||||||
| [] -> []
|
|
||||||
| _ -> assert false
|
|
||||||
in
|
|
||||||
merge mv
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec normalize_name =
|
|
||||||
function
|
|
||||||
Ssymbol s -> s
|
|
||||||
| Sesym (_, s) -> normalize_name s
|
|
||||||
| _ -> "<not a symbol>"
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec match_patt e patt expr =
|
|
||||||
let vars = ref [] in
|
|
||||||
let rec match_sub p x =
|
|
||||||
match p with
|
|
||||||
Pkeyword (e', s') ->
|
|
||||||
begin
|
|
||||||
match x with
|
|
||||||
Ssymbol _ | Sesym (_, _) -> (get_var e x) == (get_var e' s')
|
|
||||||
| _ -> false
|
|
||||||
end
|
|
||||||
| Pvar v -> vars := (v, Vitem x)::!vars; true
|
|
||||||
| Pvalue v -> test_equal v x
|
|
||||||
| Ppair (h, t) ->
|
|
||||||
begin
|
|
||||||
match x with
|
|
||||||
Spair { car = xh; cdr = xt } -> match_sub h xh && match_sub t xt
|
|
||||||
| _ -> false
|
|
||||||
end
|
|
||||||
| Pvector v ->
|
|
||||||
begin
|
|
||||||
match x with
|
|
||||||
Svector sv ->
|
|
||||||
let n = Array.length v in
|
|
||||||
if Array.length sv <> n then
|
|
||||||
false
|
|
||||||
else
|
|
||||||
let rec loop i =
|
|
||||||
if i = n then
|
|
||||||
true
|
|
||||||
else if match_sub v.(i) sv.(i) then
|
|
||||||
loop (i + 1)
|
|
||||||
else
|
|
||||||
false
|
|
||||||
in
|
|
||||||
loop 0
|
|
||||||
| _ -> false
|
|
||||||
end
|
|
||||||
| Pmulti (p, t) ->
|
|
||||||
if t <> (Pvalue Snull) then
|
|
||||||
raise (Error "invalid pattern");
|
|
||||||
begin
|
|
||||||
let rec loop r =
|
|
||||||
function
|
|
||||||
Spair { car = h; cdr = t } ->
|
|
||||||
begin
|
|
||||||
match match_patt e p h with
|
|
||||||
Some v -> loop (merge_vars r v) t
|
|
||||||
| None -> None
|
|
||||||
end
|
|
||||||
| Snull -> Some r
|
|
||||||
| _ -> None
|
|
||||||
in
|
|
||||||
match loop (empty_vars p) x with
|
|
||||||
Some vl -> vars := vl @ !vars; true
|
|
||||||
| None -> false
|
|
||||||
end
|
|
||||||
| Pmvector l ->
|
|
||||||
begin
|
|
||||||
match x with
|
|
||||||
Svector v ->
|
|
||||||
begin
|
|
||||||
let n = Array.length v in
|
|
||||||
let rec loop i =
|
|
||||||
function
|
|
||||||
Pvmulti p::t ->
|
|
||||||
if i >= n then
|
|
||||||
begin
|
|
||||||
vars := (empty_vars p) @ !vars;
|
|
||||||
loop i t
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
let rec mloop r i =
|
|
||||||
if i >= n then Some r
|
|
||||||
else
|
|
||||||
match match_patt e p v.(i) with
|
|
||||||
Some v -> mloop (merge_vars r v) (i + 1)
|
|
||||||
| None -> None
|
|
||||||
in
|
|
||||||
match mloop (empty_vars p) i with
|
|
||||||
Some vl -> vars := vl @ !vars; true
|
|
||||||
| None -> false
|
|
||||||
end
|
|
||||||
| h::t ->
|
|
||||||
if i >= n then false
|
|
||||||
else if match_sub h v.(i) then loop (i + 1) t
|
|
||||||
else false
|
|
||||||
| [] -> i >= n
|
|
||||||
in
|
|
||||||
loop 0 l
|
|
||||||
end
|
|
||||||
| _ -> false
|
|
||||||
end
|
|
||||||
| _ -> assert false
|
|
||||||
in
|
|
||||||
if match_sub patt expr then
|
|
||||||
Some !vars
|
|
||||||
else
|
|
||||||
None
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Test whether a variable occurs in a pattern *)
|
|
||||||
let var_in_patt p (v, _) =
|
|
||||||
let rec is_in =
|
|
||||||
function
|
|
||||||
Pvar pv -> pv == v
|
|
||||||
| Ppair (h, t) -> is_in h || is_in t
|
|
||||||
| Pmulti (p, t) -> is_in p || is_in t
|
|
||||||
| Pvmulti p -> is_in p
|
|
||||||
| Pvector v ->
|
|
||||||
let rec loop i =
|
|
||||||
if i < 0 then false
|
|
||||||
else if is_in v.(i) then true
|
|
||||||
else loop (i - 1)
|
|
||||||
in
|
|
||||||
loop (Array.length v - 1)
|
|
||||||
| Pmvector l -> List.exists is_in l
|
|
||||||
| _ -> false
|
|
||||||
in
|
|
||||||
is_in p
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Select variables that are applicable to this pattern *)
|
|
||||||
let subvars vl p =
|
|
||||||
List.filter (var_in_patt p) vl
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Get the current values of variables, if available. *)
|
|
||||||
let varvals vl =
|
|
||||||
try
|
|
||||||
let l = List.map
|
|
||||||
(function
|
|
||||||
(v, Vmulti (x::_)) -> (v, x)
|
|
||||||
| (v, Vmulti []) -> raise Not_found
|
|
||||||
| x -> x) vl
|
|
||||||
in
|
|
||||||
if l = [] then
|
|
||||||
raise (Error "bad template")
|
|
||||||
else
|
|
||||||
(true, l)
|
|
||||||
with Not_found -> (false, [])
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Get the next position in the variable list. *)
|
|
||||||
let varnext vl =
|
|
||||||
List.map (function (v, Vmulti (_::t)) -> (v, Vmulti t) | x -> x) vl
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec expand_var =
|
|
||||||
function
|
|
||||||
Vitem x -> x
|
|
||||||
| Vmulti m -> make_slist Snull (List.rev_map expand_var m)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec expand_tmpl e tmpl vars =
|
|
||||||
let rec fix_syms =
|
|
||||||
function
|
|
||||||
Ssymbol _ as s -> Sesym (e, s)
|
|
||||||
| Spair { car = h; cdr = t } ->
|
|
||||||
Spair { car = fix_syms h; cdr = fix_syms t }
|
|
||||||
| Svector v ->
|
|
||||||
Svector (Array.map (fun x -> fix_syms x) v)
|
|
||||||
| x -> x in
|
|
||||||
let rec expand_sub =
|
|
||||||
function
|
|
||||||
Pvar v -> expand_var (List.assq v vars)
|
|
||||||
| Pvalue v -> fix_syms v
|
|
||||||
| Ppair (h, t) ->
|
|
||||||
Spair { car = expand_sub h; cdr = expand_sub t }
|
|
||||||
| Pvector v ->
|
|
||||||
Svector (Array.map (fun x -> expand_sub x) v)
|
|
||||||
| Pmulti (p, t) ->
|
|
||||||
let rec loop r v =
|
|
||||||
let (ok, vv) = varvals v in
|
|
||||||
if ok then loop ((expand_tmpl e p vv)::r) (varnext v)
|
|
||||||
else r
|
|
||||||
in
|
|
||||||
make_slist (expand_sub t) (loop [] (subvars vars p))
|
|
||||||
| Pmvector l ->
|
|
||||||
begin
|
|
||||||
let rec loop r =
|
|
||||||
function
|
|
||||||
Pvmulti p::t ->
|
|
||||||
let rec mloop r v =
|
|
||||||
let (ok, vv) = varvals v in
|
|
||||||
if ok then mloop ((expand_tmpl e p vv)::r) (varnext v)
|
|
||||||
else r
|
|
||||||
in
|
|
||||||
loop (mloop [] (subvars vars p) @ r) t
|
|
||||||
| h::t -> loop (expand_sub h::r) t
|
|
||||||
| [] -> r
|
|
||||||
in
|
|
||||||
Svector (Array.of_list (List.rev (loop [] l)))
|
|
||||||
end
|
|
||||||
| _ -> assert false
|
|
||||||
in
|
|
||||||
expand_sub tmpl
|
|
||||||
;;
|
|
||||||
|
|
||||||
let expand name me rs e av =
|
|
||||||
let me = new_scope me in
|
|
||||||
let al = rebuild av in
|
|
||||||
let rec try_rule =
|
|
||||||
function
|
|
||||||
(patt, tmpl)::t ->
|
|
||||||
begin
|
|
||||||
match match_patt e patt al with
|
|
||||||
Some vars -> expand_tmpl me tmpl vars
|
|
||||||
| None -> try_rule t
|
|
||||||
end
|
|
||||||
| [] -> raise (Error (name ^ ": no matching syntax rule"))
|
|
||||||
in
|
|
||||||
try_rule rs.r_rules
|
|
||||||
;;
|
|
||||||
|
|
||||||
let mkdefine_syntax e =
|
|
||||||
function
|
|
||||||
[| (Ssymbol _ | Sesym (_, _)) as sym; tspec |] ->
|
|
||||||
let rules = parsetspec (new_scope e) sym tspec in
|
|
||||||
bind_name e sym (Vmacro (expand (normalize_name sym) e
|
|
||||||
{ r_rules = rules }));
|
|
||||||
Cval Sunspec
|
|
||||||
| _ -> raise (Error "define-syntax: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let mklet_syntax e args =
|
|
||||||
if Array.length args < 2 then
|
|
||||||
raise (Error "let-syntax: too few args");
|
|
||||||
let av =
|
|
||||||
Array.map (letsplit (fun s v -> s,
|
|
||||||
Vmacro (expand (normalize_name s) e { r_rules = parsetspec e s v })))
|
|
||||||
(Array.of_list (list_to_caml args.(0))) in
|
|
||||||
let ne = new_scope e in
|
|
||||||
Array.iter (fun (s, r) -> bind_name ne s r) av;
|
|
||||||
mkseq (mkbody ne (Array.sub args 1 (Array.length args - 1)))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let mkletrec_syntax e args =
|
|
||||||
if Array.length args < 2 then
|
|
||||||
raise (Error "letrec-syntax: too few args");
|
|
||||||
let ne = new_scope e in
|
|
||||||
let t =
|
|
||||||
Array.map (letsplit
|
|
||||||
(fun s v -> let r = { r_rules = [] }
|
|
||||||
and name = normalize_name s in
|
|
||||||
bind_name ne s (Vmacro (expand name ne r));
|
|
||||||
r, s, v))
|
|
||||||
(Array.of_list (list_to_caml args.(0)))
|
|
||||||
in
|
|
||||||
Array.iter (fun (r, s, v) -> r.r_rules <- parsetspec (new_scope e) s v) t;
|
|
||||||
mkseq (mkbody ne (Array.sub args 1 (Array.length args - 1)))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let bind_macro e =
|
|
||||||
bind_name e sym_define_syntax (Vsyntax mkdefine_syntax);
|
|
||||||
bind_name e sym_let_syntax (Vsyntax mklet_syntax);
|
|
||||||
bind_name e sym_letrec_syntax (Vsyntax mkletrec_syntax);
|
|
||||||
bind_name e sym_ellipsis (Vkeyword "...")
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
(* Syntax definitions and expansions. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val bind_macro : env -> unit
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
(* Main program entry point. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
|
|
||||||
let main () =
|
|
||||||
let loadf = ref [] in
|
|
||||||
let addf x = loadf := !loadf @ [x] in
|
|
||||||
let argspec = [
|
|
||||||
("file", Arg.Rest addf, "Files to run in batch mode")
|
|
||||||
] in
|
|
||||||
Arg.parse argspec addf "Usage: ocscm [ file ... ]";
|
|
||||||
if !loadf = [] then
|
|
||||||
Ocs_top.interactive ()
|
|
||||||
else
|
|
||||||
let e = Ocs_top.make_env ()
|
|
||||||
and th = Ocs_top.make_thread () in
|
|
||||||
try
|
|
||||||
List.iter (fun x -> Ocs_prim.load_file e th x) !loadf
|
|
||||||
with
|
|
||||||
Error err ->
|
|
||||||
Printf.eprintf "Error: %s\n" err
|
|
||||||
| ErrorL ((file, line), err) ->
|
|
||||||
Printf.eprintf "%s:%d: %s\n" file line err
|
|
||||||
;;
|
|
||||||
|
|
||||||
main ();;
|
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
(* Miscellaneous utility functions *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
|
|
||||||
let list_to_caml l =
|
|
||||||
let rec loop r =
|
|
||||||
function
|
|
||||||
Snull -> List.rev r
|
|
||||||
| Spair p -> loop (p.car::r) p.cdr
|
|
||||||
| _ -> raise (Error "not a valid list")
|
|
||||||
in
|
|
||||||
loop [] l
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Create a Scheme list from a reversed native list. *)
|
|
||||||
let make_slist tl l =
|
|
||||||
let rec loop r =
|
|
||||||
function
|
|
||||||
h::t -> loop (Spair { car = h; cdr = r }) t
|
|
||||||
| [] -> r
|
|
||||||
in
|
|
||||||
loop tl l
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Create one of Capply[0123n] depending on the number of arguments. *)
|
|
||||||
let mkapply f av =
|
|
||||||
match av with
|
|
||||||
[| |] -> Capply0 (f)
|
|
||||||
| [| a1 |] -> Capply1 (f, a1)
|
|
||||||
| [| a1; a2 |] -> Capply2 (f, a1, a2)
|
|
||||||
| [| a1; a2; a3 |] -> Capply3 (f, a1, a2, a3)
|
|
||||||
| av -> Capplyn (f, av)
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Test equivalence (as in eqv?) *)
|
|
||||||
|
|
||||||
let test_eqv a b =
|
|
||||||
if a == b then true
|
|
||||||
else
|
|
||||||
match (a, b) with
|
|
||||||
(Sint i1, Sint i2) -> i1 = i2
|
|
||||||
| (Schar c1, Schar c2) -> c1 = c2
|
|
||||||
| (Sreal r1, Sreal r2) -> r1 = r2
|
|
||||||
| (Sbigint bi1, Sbigint bi2) -> Big_int.compare_big_int bi1 bi2 = 0
|
|
||||||
| (Srational r1, Srational r2) -> Ratio.compare_ratio r1 r2 = 0
|
|
||||||
| (Scomplex z1, Scomplex z2) -> z1 = z2
|
|
||||||
| (Sstring s1, Sstring s2) -> s1 = s2
|
|
||||||
| (Svector v1, Svector v2) -> v1 == v2
|
|
||||||
| _ -> false
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Test equality (as in equal?) *)
|
|
||||||
|
|
||||||
let rec test_equal a b =
|
|
||||||
if a == b then true
|
|
||||||
else
|
|
||||||
match (a, b) with
|
|
||||||
(Svector v1, Svector v2) ->
|
|
||||||
let n = Array.length v1 in
|
|
||||||
if Array.length v2 <> n then
|
|
||||||
false
|
|
||||||
else
|
|
||||||
let rec loop i =
|
|
||||||
if i >= n then
|
|
||||||
true
|
|
||||||
else
|
|
||||||
if test_equal v1.(i) v2.(i) then
|
|
||||||
loop (i + 1)
|
|
||||||
else
|
|
||||||
false
|
|
||||||
in
|
|
||||||
loop 0
|
|
||||||
| (Spair p1, Spair p2) ->
|
|
||||||
test_equal p1.car p2.car && test_equal p1.cdr p2.cdr
|
|
||||||
| _ -> test_eqv a b
|
|
||||||
;;
|
|
|
@ -1,12 +0,0 @@
|
||||||
(* Miscellaneous utility functions *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val list_to_caml : sval -> sval list
|
|
||||||
|
|
||||||
val make_slist : sval -> sval list -> sval
|
|
||||||
|
|
||||||
val mkapply : code -> code array -> code
|
|
||||||
|
|
||||||
val test_eqv : sval -> sval -> bool
|
|
||||||
val test_equal : sval -> sval -> bool
|
|
|
@ -1,633 +0,0 @@
|
||||||
(* Handle number types (Sint, Sreal, Sbigint, Srational, Scomplex) *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_env
|
|
||||||
open Ocs_numaux
|
|
||||||
open Ocs_complex
|
|
||||||
|
|
||||||
open Num
|
|
||||||
open Ratio
|
|
||||||
open Big_int
|
|
||||||
|
|
||||||
let rec negate =
|
|
||||||
function
|
|
||||||
(Sint i) as s ->
|
|
||||||
if i >= min_int then Sint (-i)
|
|
||||||
else negate (promote_bigint s)
|
|
||||||
| Sbigint bi -> Sbigint (minus_big_int bi)
|
|
||||||
| Srational r -> Srational (Ratio.minus_ratio r)
|
|
||||||
| Sreal r -> Sreal (-.r)
|
|
||||||
| Scomplex z -> Scomplex (Complex.neg z)
|
|
||||||
| _ -> raise (Error "bad number type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let add2 a b =
|
|
||||||
match (a, b) with
|
|
||||||
(Sint i1, Sint i2) ->
|
|
||||||
let r = i1 + i2 in
|
|
||||||
if (i1 lxor i2) lor (i1 lxor (r lxor (-1))) < 0
|
|
||||||
then Sint r
|
|
||||||
else Sbigint (add_big_int (big_int_of_int i1) (big_int_of_int i2))
|
|
||||||
| (Scomplex z1, Scomplex z2) -> Scomplex (Complex.add z1 z2)
|
|
||||||
| (Scomplex z, o) | (o, Scomplex z) ->
|
|
||||||
Scomplex (Complex.add z { Complex.re = float_of_snum o;
|
|
||||||
Complex.im = 0.0 })
|
|
||||||
| (Sreal r, o) | (o, Sreal r) ->
|
|
||||||
Sreal ((float_of_snum o) +. r)
|
|
||||||
| (Srational r, o) | (o, Srational r) ->
|
|
||||||
Srational (add_ratio (rational_of_snum o) r)
|
|
||||||
| (Sbigint bi, o) | (o, Sbigint bi) ->
|
|
||||||
bigint_res (add_big_int (bigint_of_snum o) bi)
|
|
||||||
| _ -> raise (Error "add: bad types")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let sub2 a b =
|
|
||||||
add2 a (negate b)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let mul2 a b =
|
|
||||||
match snum_fixtypes a b with
|
|
||||||
(Scomplex z1, Scomplex z2) -> Scomplex (Complex.mul z1 z2)
|
|
||||||
| (Sreal r1, Sreal r2) -> Sreal (r1 *. r2)
|
|
||||||
| (Srational r1, Srational r2) ->
|
|
||||||
snum_of_num (mult_num (Ratio r1) (Ratio r2))
|
|
||||||
| (Sbigint bi1, Sbigint bi2) ->
|
|
||||||
snum_of_num (mult_num (Big_int bi1) (Big_int bi2))
|
|
||||||
| (Sint i1, Sint i2) ->
|
|
||||||
snum_of_num (mult_num (Int i1) (Int i2))
|
|
||||||
| _ -> raise (Error "mul: invalid args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let div2 a b =
|
|
||||||
match snum_fixtypes a b with
|
|
||||||
(Scomplex n, Scomplex d) -> Scomplex (Complex.div n d)
|
|
||||||
| (Sreal n, Sreal d) -> Sreal (n /. d)
|
|
||||||
| (Srational n, Srational d) ->
|
|
||||||
snum_of_num (div_num (Ratio n) (Ratio d))
|
|
||||||
| (Sbigint n, Sbigint d) ->
|
|
||||||
snum_of_num (div_num (Big_int n) (Big_int d))
|
|
||||||
| (Sint n, Sint d) ->
|
|
||||||
if d = 0 then
|
|
||||||
raise (Error "division by zero")
|
|
||||||
else
|
|
||||||
snum_of_num (div_num (Int n) (Int d))
|
|
||||||
| _ -> raise (Error "div: invalid args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let cmp2 eq_only a b =
|
|
||||||
match (a, b) with
|
|
||||||
(Sint i1, Sint i2) ->
|
|
||||||
if i1 > i2 then 1 else if i1 < i2 then -1 else 0
|
|
||||||
| _ ->
|
|
||||||
begin
|
|
||||||
match snum_fixtypes a b with
|
|
||||||
(Sreal r1, Sreal r2) ->
|
|
||||||
let r = r1 -. r2 in
|
|
||||||
if r > 0.0 then 1 else if r < 0.0 then -1 else 0
|
|
||||||
| (Scomplex z1, Scomplex z2) ->
|
|
||||||
if eq_only then
|
|
||||||
if z1 = z2 then 0 else 1
|
|
||||||
else
|
|
||||||
if z1.Complex.im = 0.0 && z2.Complex.im = 0.0 then
|
|
||||||
begin
|
|
||||||
let r = z1.Complex.re -. z2.Complex.re in
|
|
||||||
if r > 0.0 then 1 else if r < 0.0 then -1 else 0
|
|
||||||
end
|
|
||||||
else
|
|
||||||
raise (Error "complex numbers compared")
|
|
||||||
| (Srational r1, Srational r2) ->
|
|
||||||
compare_ratio r1 r2
|
|
||||||
| (Sbigint bi1, Sbigint bi2) ->
|
|
||||||
compare_big_int bi1 bi2
|
|
||||||
| _ -> raise (Error "cmp: invalid args")
|
|
||||||
end
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_exact =
|
|
||||||
function
|
|
||||||
(Sint _ | Sbigint _ | Srational _) -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_inexact =
|
|
||||||
function
|
|
||||||
(Sreal _ | Scomplex _) -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let to_exact =
|
|
||||||
function
|
|
||||||
Sreal r -> float_to_exact r
|
|
||||||
| Scomplex z ->
|
|
||||||
if z.Complex.im = 0.0 then
|
|
||||||
float_to_exact z.Complex.re
|
|
||||||
else
|
|
||||||
raise (Error "inexact->exact: no exact complex representation")
|
|
||||||
| (Sint _ | Sbigint _ | Srational _) as n -> n
|
|
||||||
| _ -> raise (Error "inexact->exact: not a number")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let to_inexact =
|
|
||||||
function
|
|
||||||
Sreal _ as r -> r
|
|
||||||
| Scomplex _ as z -> z
|
|
||||||
| x -> Sreal (float_of_snum x)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let mkbool b = if b then Strue else Sfalse;;
|
|
||||||
|
|
||||||
let is_zero =
|
|
||||||
function
|
|
||||||
Sint i -> mkbool (i = 0)
|
|
||||||
| (Sbigint _ | Srational _) -> Sfalse
|
|
||||||
| Sreal r -> mkbool (r = 0.0)
|
|
||||||
| Scomplex z -> mkbool (z.Complex.re = 0.0 && z.Complex.im = 0.0)
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_positive =
|
|
||||||
function
|
|
||||||
Sint i -> mkbool (i > 0)
|
|
||||||
| Sbigint bi -> mkbool (sign_big_int bi > 0)
|
|
||||||
| Srational r -> mkbool (sign_ratio r > 0)
|
|
||||||
| Sreal r -> mkbool (r > 0.0)
|
|
||||||
| _ -> raise (Error "positive?: bad arg type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_negative =
|
|
||||||
function
|
|
||||||
Sint i -> mkbool (i < 0)
|
|
||||||
| Sbigint bi -> mkbool (sign_big_int bi < 0)
|
|
||||||
| Srational r -> mkbool (sign_ratio r < 0)
|
|
||||||
| Sreal r -> mkbool (r < 0.0)
|
|
||||||
| _ -> raise (Error "positive?: bad arg type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_number =
|
|
||||||
function
|
|
||||||
Sint _ | Sbigint _ | Srational _ | Sreal _ | Scomplex _ -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_real =
|
|
||||||
function
|
|
||||||
Sint _ | Sbigint _ | Srational _ | Sreal _ -> Strue
|
|
||||||
| Scomplex { Complex.re = _; Complex.im = i } -> mkbool (i = 0.0)
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_rational =
|
|
||||||
is_real
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_integer =
|
|
||||||
function
|
|
||||||
Sint _ | Sbigint _ -> Strue
|
|
||||||
| Sreal r -> mkbool (float_is_int r)
|
|
||||||
| Scomplex z -> mkbool (z.Complex.im = 0.0 && float_is_int z.Complex.re)
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let bi_modi bi i =
|
|
||||||
int_of_big_int (mod_big_int bi (big_int_of_int i))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_even =
|
|
||||||
function
|
|
||||||
Sint i -> mkbool (i land 1 = 0)
|
|
||||||
| Sbigint bi -> mkbool (bi_modi bi 2 = 0)
|
|
||||||
| _ -> raise (Error "even?: bad arg type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_odd =
|
|
||||||
function
|
|
||||||
Sint i -> mkbool (i land 1 <> 0)
|
|
||||||
| Sbigint bi -> mkbool (bi_modi bi 2 <> 0)
|
|
||||||
| _ -> raise (Error "odd?: bad arg type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let do_ops op av n =
|
|
||||||
let rec oploop v i =
|
|
||||||
if i < n then
|
|
||||||
let r = op v av.(i) in
|
|
||||||
oploop r (i + 1)
|
|
||||||
else
|
|
||||||
v
|
|
||||||
in
|
|
||||||
oploop av.(0) 1
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_add av =
|
|
||||||
let n = Array.length av in
|
|
||||||
if n = 0 then
|
|
||||||
Sint 0
|
|
||||||
else
|
|
||||||
do_ops add2 av n
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_sub av =
|
|
||||||
match Array.length av with
|
|
||||||
0 -> raise (Error "-: need args")
|
|
||||||
| 1 -> negate av.(0)
|
|
||||||
| n -> do_ops sub2 av n
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_mul av =
|
|
||||||
match Array.length av with
|
|
||||||
0 -> Sint 1
|
|
||||||
| n -> do_ops mul2 av n
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_div av =
|
|
||||||
match Array.length av with
|
|
||||||
0 -> raise (Error "/: need args")
|
|
||||||
| 1 -> div2 (Sint 1) av.(0)
|
|
||||||
| n -> do_ops div2 av n
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_eq av =
|
|
||||||
match Array.length av with
|
|
||||||
0 | 1 -> Strue
|
|
||||||
| n ->
|
|
||||||
let a0 = av.(0) in
|
|
||||||
let rec loop i =
|
|
||||||
if i < n then
|
|
||||||
begin
|
|
||||||
if cmp2 true a0 av.(i) <> 0 then Sfalse
|
|
||||||
else loop (i + 1)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Strue
|
|
||||||
in
|
|
||||||
loop 1
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_rel op av =
|
|
||||||
match Array.length av with
|
|
||||||
0 | 1 -> Strue
|
|
||||||
| n ->
|
|
||||||
let rec loop v i =
|
|
||||||
if i < n then
|
|
||||||
begin
|
|
||||||
if op (cmp2 false v av.(i)) 0 then loop av.(i) (i + 1)
|
|
||||||
else Sfalse
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Strue
|
|
||||||
in
|
|
||||||
loop av.(0) 1
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_minormax op av =
|
|
||||||
match Array.length av with
|
|
||||||
0 -> raise (Error "args required")
|
|
||||||
| 1 -> av.(0)
|
|
||||||
| n ->
|
|
||||||
let inex = ref false in
|
|
||||||
let r = do_ops (fun a b ->
|
|
||||||
if is_inexact a = Strue || is_inexact b = Strue then
|
|
||||||
inex := true;
|
|
||||||
if op (cmp2 false a b) 0 then a else b) av n
|
|
||||||
in
|
|
||||||
if !inex then to_inexact r else r
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_abs =
|
|
||||||
function
|
|
||||||
Sint i -> Sint (abs i)
|
|
||||||
| Sbigint bi -> Sbigint (abs_big_int bi)
|
|
||||||
| Sreal r -> Sreal (abs_float r)
|
|
||||||
| Srational r -> Srational (abs_ratio r)
|
|
||||||
| Scomplex _ -> raise (Error "abs: number is complex")
|
|
||||||
| _ -> raise (Error "abs: not a number")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_floor =
|
|
||||||
function
|
|
||||||
(Sint _ | Sbigint _) as x -> x
|
|
||||||
| Srational r -> bigint_res (floor_ratio r)
|
|
||||||
| Sreal r -> Sreal (floor r)
|
|
||||||
| _ -> raise (Error "floor: bad arg type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_ceiling =
|
|
||||||
function
|
|
||||||
(Sint _ | Sbigint _) as x -> x
|
|
||||||
| Srational r -> bigint_res (ceiling_ratio r)
|
|
||||||
| Sreal r -> Sreal (ceil r)
|
|
||||||
| _ -> raise (Error "ceiling: bad arg type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_truncate =
|
|
||||||
function
|
|
||||||
(Sint _ | Sbigint _) as x -> x
|
|
||||||
| Srational r -> bigint_res (integer_ratio r)
|
|
||||||
| Sreal r ->
|
|
||||||
if r < 0.0 then
|
|
||||||
Sreal (ceil r)
|
|
||||||
else
|
|
||||||
Sreal (floor r)
|
|
||||||
| _ -> raise (Error "truncate: bad arg type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_round =
|
|
||||||
function
|
|
||||||
(Sint _ | Sbigint _) as x -> x
|
|
||||||
| Srational r -> bigint_res (round_ratio r)
|
|
||||||
| Sreal r -> Sreal (round_float r)
|
|
||||||
| _ -> raise (Error "round: bad arg type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rcsw rfun cfun =
|
|
||||||
function
|
|
||||||
Scomplex z -> Scomplex (cfun z)
|
|
||||||
| x -> Sreal (rfun (float_of_snum x))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_exp = rcsw exp Complex.exp;;
|
|
||||||
let snum_log = rcsw log Complex.log;;
|
|
||||||
|
|
||||||
let snum_sin = rcsw sin sin_cplx;;
|
|
||||||
let snum_cos = rcsw cos cos_cplx;;
|
|
||||||
let snum_tan = rcsw tan tan_cplx;;
|
|
||||||
let snum_asin = rcsw asin asin_cplx;;
|
|
||||||
let snum_acos = rcsw acos acos_cplx;;
|
|
||||||
|
|
||||||
let snum_atan =
|
|
||||||
function
|
|
||||||
[| x |] -> rcsw atan atan_cplx x
|
|
||||||
| [| y; x |] ->
|
|
||||||
Sreal (Complex.arg { Complex.re = float_of_snum x;
|
|
||||||
Complex.im = float_of_snum y })
|
|
||||||
| _ -> raise (Error "atan: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_sqrt =
|
|
||||||
function
|
|
||||||
Scomplex z -> Scomplex (Complex.sqrt z)
|
|
||||||
| x ->
|
|
||||||
let r = float_of_snum x in
|
|
||||||
if r < 0.0 then
|
|
||||||
Scomplex (Complex.sqrt { Complex.re = r; Complex.im = 0.0 })
|
|
||||||
else
|
|
||||||
let sq = sqrt r in
|
|
||||||
if is_exact x <> Sfalse && float_is_int sq then
|
|
||||||
float_to_exact sq
|
|
||||||
else
|
|
||||||
Sreal sq
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Optimize the simplest cases, leave the rest to Num. *)
|
|
||||||
let snum_expt x y =
|
|
||||||
match (x, y) with
|
|
||||||
(_, Sint n) when n = 0 -> Sint 1
|
|
||||||
| ((Sint _ | Sbigint _), Sint n) when n > 0 ->
|
|
||||||
bigint_res (power_big_int_positive_int (bigint_of_snum x) n)
|
|
||||||
| ((Sint _ | Sbigint _ | Srational _), (Sint _ | Sbigint _)) ->
|
|
||||||
snum_of_num (power_num (num_of_snum x) (num_of_snum y))
|
|
||||||
| (Scomplex _, _) | (_, Scomplex _) ->
|
|
||||||
Scomplex (Complex.pow (complex_of_snum x) (complex_of_snum y))
|
|
||||||
| _ ->
|
|
||||||
Sreal (float_of_snum x ** float_of_snum y)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let make_rectangular x y =
|
|
||||||
Scomplex { Complex.re = float_of_snum x; Complex.im = float_of_snum y }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let make_polar x y =
|
|
||||||
Scomplex (Complex.polar (float_of_snum x) (float_of_snum y))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let real_part x =
|
|
||||||
Sreal (complex_of_snum x).Complex.re
|
|
||||||
;;
|
|
||||||
|
|
||||||
let imag_part x =
|
|
||||||
Sreal (complex_of_snum x).Complex.im
|
|
||||||
;;
|
|
||||||
|
|
||||||
let magnitude x =
|
|
||||||
Sreal (Complex.norm (complex_of_snum x))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let angle x =
|
|
||||||
Sreal (Complex.arg (complex_of_snum x))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let quotient n d =
|
|
||||||
match (n, d) with
|
|
||||||
((Sint _ | Sbigint _ | Srational _),
|
|
||||||
(Sint _ | Sbigint _ | Srational _)) ->
|
|
||||||
snum_of_num (integer_num (div_num (num_of_snum n) (num_of_snum d)))
|
|
||||||
| _ ->
|
|
||||||
let n = float_of_snum n
|
|
||||||
and d = float_of_snum d in
|
|
||||||
if not (float_is_int n && float_is_int d) then
|
|
||||||
raise (Error "quotient: non-integer arguments")
|
|
||||||
else
|
|
||||||
Sreal (n /. d -. (mod_float n d) /. d)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let remainder n d =
|
|
||||||
match (n, d) with
|
|
||||||
((Sint _ | Sbigint _ | Srational _),
|
|
||||||
(Sint _ | Sbigint _ | Srational _)) ->
|
|
||||||
let n = num_of_snum n
|
|
||||||
and d = num_of_snum d in
|
|
||||||
let m = mod_num n d in
|
|
||||||
if sign_num n + sign_num d = 0 then
|
|
||||||
snum_of_num (sub_num m d)
|
|
||||||
else
|
|
||||||
snum_of_num m
|
|
||||||
| _ ->
|
|
||||||
let n = float_of_snum n
|
|
||||||
and d = float_of_snum d in
|
|
||||||
if not (float_is_int n && float_is_int d) then
|
|
||||||
raise (Error "quotient: non-integer arguments")
|
|
||||||
else
|
|
||||||
Sreal (mod_float n d)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let modulo n d =
|
|
||||||
match (n, d) with
|
|
||||||
((Sint _ | Sbigint _ | Srational _),
|
|
||||||
(Sint _ | Sbigint _ | Srational _)) ->
|
|
||||||
snum_of_num (mod_num (num_of_snum n) (num_of_snum d))
|
|
||||||
| _ ->
|
|
||||||
let n = float_of_snum n
|
|
||||||
and d = float_of_snum d in
|
|
||||||
if not (float_is_int n && float_is_int d) then
|
|
||||||
raise (Error "quotient: non-integer arguments")
|
|
||||||
else
|
|
||||||
let m = mod_float n d in
|
|
||||||
if (n < 0.0 && d > 0.0) || (n > 0.0 && d < 0.0) then
|
|
||||||
Sreal (d +. m)
|
|
||||||
else
|
|
||||||
Sreal m
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Compute the gcd of two numbers *)
|
|
||||||
let rec gcd2 a b =
|
|
||||||
match (a, b) with
|
|
||||||
((Sint _ | Sbigint _), (Sint _ | Sbigint _)) ->
|
|
||||||
bigint_res (gcd_big_int (bigint_of_snum (snum_abs a))
|
|
||||||
(bigint_of_snum (snum_abs b)))
|
|
||||||
| _ ->
|
|
||||||
if is_integer a <> Sfalse && is_integer b <> Sfalse then
|
|
||||||
to_inexact (gcd2 (to_exact a) (to_exact b))
|
|
||||||
else
|
|
||||||
raise (Error "gcd: non-integer arguments")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_gcd av =
|
|
||||||
let n = Array.length av in
|
|
||||||
if n = 0 then
|
|
||||||
Sint 0
|
|
||||||
else
|
|
||||||
do_ops gcd2 av n
|
|
||||||
;;
|
|
||||||
|
|
||||||
let lcm2 a b =
|
|
||||||
let g = gcd2 a b in
|
|
||||||
snum_abs (mul2 (div2 a g) b)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_lcm av =
|
|
||||||
let n = Array.length av in
|
|
||||||
if n = 0 then
|
|
||||||
Sint 1
|
|
||||||
else
|
|
||||||
do_ops lcm2 av n
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* The algorithm for calculating the simplest rational form of a number
|
|
||||||
is translated from the appendix in the IEEE draft. It implicitly
|
|
||||||
preserves exactness. *)
|
|
||||||
|
|
||||||
let simplest_rational x y =
|
|
||||||
let one = Sint 1 in
|
|
||||||
let rec sri x y =
|
|
||||||
let fx = snum_floor x
|
|
||||||
and fy = snum_floor y in
|
|
||||||
if cmp2 false fx x >= 0 then
|
|
||||||
fx
|
|
||||||
else if cmp2 true fx fy = 0 then
|
|
||||||
add2 fx
|
|
||||||
(div2 one (sri (div2 one (sub2 y fy)) (div2 one (sub2 x fx))))
|
|
||||||
else
|
|
||||||
add2 fx one
|
|
||||||
in
|
|
||||||
if cmp2 false y x < 0 then
|
|
||||||
sri y x
|
|
||||||
else if cmp2 false x y >= 0 then
|
|
||||||
begin
|
|
||||||
if is_rational x <> Sfalse then
|
|
||||||
x
|
|
||||||
else
|
|
||||||
raise (Error "rationalize: not a rational")
|
|
||||||
end
|
|
||||||
else if is_positive x <> Sfalse then
|
|
||||||
sri x y
|
|
||||||
else if is_negative y <> Sfalse then
|
|
||||||
negate (sri (negate y) (negate x))
|
|
||||||
else if is_exact x <> Sfalse && is_exact y <> Sfalse then
|
|
||||||
Sint 0
|
|
||||||
else
|
|
||||||
Sreal 0.0
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_rationalize x e =
|
|
||||||
simplest_rational (sub2 x e) (add2 x e)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec snum_numerator =
|
|
||||||
function
|
|
||||||
(Sint _ | Sbigint _) as x -> x
|
|
||||||
| Srational q -> bigint_res (numerator_ratio q)
|
|
||||||
| Sreal _ as x -> to_inexact (snum_numerator (to_exact x))
|
|
||||||
| Scomplex _ -> raise (Error "numerator: not defined for complex numbers")
|
|
||||||
| _ -> raise (Error "numerator: not a numeric type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec snum_denominator =
|
|
||||||
function
|
|
||||||
Sint _ | Sbigint _ -> Sint 1
|
|
||||||
| Srational q -> bigint_res (denominator_ratio q)
|
|
||||||
| Sreal r as x ->
|
|
||||||
if r = 0.0 then Sreal 1.0 else
|
|
||||||
to_inexact (snum_denominator (to_exact x))
|
|
||||||
| Scomplex _ -> raise (Error "denominator: not defined for complex numbers")
|
|
||||||
| _ -> raise (Error "denominator: not a numeric type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let init e =
|
|
||||||
set_pf1 e is_exact "exact?";
|
|
||||||
set_pf1 e is_inexact "inexact?";
|
|
||||||
set_pf1 e is_zero "zero?";
|
|
||||||
set_pf1 e is_positive "positive?";
|
|
||||||
set_pf1 e is_negative "negative?";
|
|
||||||
set_pf1 e is_number "number?";
|
|
||||||
set_pf1 e is_number "complex?";
|
|
||||||
set_pf1 e is_real "real?";
|
|
||||||
set_pf1 e is_rational "rational?";
|
|
||||||
set_pf1 e is_integer "integer?";
|
|
||||||
set_pf1 e is_even "even?";
|
|
||||||
set_pf1 e is_odd "odd?";
|
|
||||||
|
|
||||||
set_pfn e snum_add "+";
|
|
||||||
set_pfn e snum_sub "-";
|
|
||||||
set_pfn e snum_mul "*";
|
|
||||||
set_pfn e snum_div "/";
|
|
||||||
set_pfn e snum_eq "=";
|
|
||||||
set_pfn e (snum_rel (>)) ">";
|
|
||||||
set_pfn e (snum_rel (<)) "<";
|
|
||||||
set_pfn e (snum_rel (>=)) ">=";
|
|
||||||
set_pfn e (snum_rel (<=)) "<=";
|
|
||||||
|
|
||||||
set_pfn e (snum_minormax (>)) "max";
|
|
||||||
set_pfn e (snum_minormax (<)) "min";
|
|
||||||
|
|
||||||
set_pf1 e snum_abs "abs";
|
|
||||||
|
|
||||||
set_pf1 e snum_floor "floor";
|
|
||||||
set_pf1 e snum_ceiling "ceiling";
|
|
||||||
set_pf1 e snum_truncate "truncate";
|
|
||||||
set_pf1 e snum_round "round";
|
|
||||||
|
|
||||||
set_pf1 e snum_exp "exp";
|
|
||||||
set_pf1 e snum_log "log";
|
|
||||||
|
|
||||||
set_pf1 e snum_sin "sin";
|
|
||||||
set_pf1 e snum_cos "cos";
|
|
||||||
set_pf1 e snum_tan "tan";
|
|
||||||
set_pf1 e snum_asin "asin";
|
|
||||||
set_pf1 e snum_acos "acos";
|
|
||||||
set_pfn e snum_atan "atan";
|
|
||||||
|
|
||||||
set_pf1 e snum_sqrt "sqrt";
|
|
||||||
set_pf2 e snum_expt "expt";
|
|
||||||
|
|
||||||
set_pf2 e make_rectangular "make-rectangular";
|
|
||||||
set_pf2 e make_polar "make-polar";
|
|
||||||
set_pf1 e real_part "real-part";
|
|
||||||
set_pf1 e imag_part "imag-part";
|
|
||||||
set_pf1 e magnitude "magnitude";
|
|
||||||
set_pf1 e angle "angle";
|
|
||||||
|
|
||||||
set_pf2 e quotient "quotient";
|
|
||||||
set_pf2 e remainder "remainder";
|
|
||||||
set_pf2 e modulo "modulo";
|
|
||||||
|
|
||||||
set_pf1 e to_exact "inexact->exact";
|
|
||||||
set_pf1 e to_inexact "exact->inexact";
|
|
||||||
|
|
||||||
set_pfn e snum_gcd "gcd";
|
|
||||||
set_pfn e snum_lcm "lcm";
|
|
||||||
|
|
||||||
set_pf2 e snum_rationalize "rationalize";
|
|
||||||
|
|
||||||
set_pf1 e snum_numerator "numerator";
|
|
||||||
set_pf1 e snum_denominator "denominator";
|
|
||||||
;;
|
|
|
@ -1,13 +0,0 @@
|
||||||
(* Operations on number types. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val negate : sval -> sval
|
|
||||||
|
|
||||||
val add2 : sval -> sval -> sval
|
|
||||||
val sub2 : sval -> sval -> sval
|
|
||||||
val mul2 : sval -> sval -> sval
|
|
||||||
val div2 : sval -> sval -> sval
|
|
||||||
|
|
||||||
val init : env -> unit
|
|
||||||
|
|
|
@ -1,201 +0,0 @@
|
||||||
(* Numeric utility functions. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
|
|
||||||
open Num
|
|
||||||
open Ratio
|
|
||||||
open Big_int
|
|
||||||
|
|
||||||
let fix_floating_precision () =
|
|
||||||
let n = Arith_status.get_floating_precision () in
|
|
||||||
if n < 25 then
|
|
||||||
Arith_status.set_floating_precision 25
|
|
||||||
;;
|
|
||||||
|
|
||||||
fix_floating_precision ();;
|
|
||||||
|
|
||||||
Arith_status.set_normalize_ratio true;;
|
|
||||||
|
|
||||||
let promote_real =
|
|
||||||
function
|
|
||||||
Sint i -> Sreal (float_of_int i)
|
|
||||||
| (Sreal _) as r -> r
|
|
||||||
| (Scomplex _) as z -> z
|
|
||||||
| Sbigint bi -> Sreal (float_of_big_int bi)
|
|
||||||
| Srational r -> Sreal (float_of_ratio r)
|
|
||||||
| _ -> raise (Error "bad number type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let float_of_snum =
|
|
||||||
function
|
|
||||||
Sint i -> float_of_int i
|
|
||||||
| Sreal r -> r
|
|
||||||
(* Note - the imaginary part is discarded! *)
|
|
||||||
| Scomplex { Complex.re = r; Complex.im = _ } -> r
|
|
||||||
| Sbigint bi -> float_of_big_int bi
|
|
||||||
| Srational r -> float_of_ratio r
|
|
||||||
| _ -> raise (Error "bad number type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let promote_complex =
|
|
||||||
function
|
|
||||||
(Scomplex _) as z -> z
|
|
||||||
| x -> Scomplex { Complex.re = float_of_snum x; Complex.im = 0.0 }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let complex_of_snum =
|
|
||||||
function
|
|
||||||
Scomplex z -> z
|
|
||||||
| x -> { Complex.re = float_of_snum x; Complex.im = 0.0 }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rational_of_snum =
|
|
||||||
function
|
|
||||||
Sbigint bi -> ratio_of_big_int bi
|
|
||||||
| Sint i -> ratio_of_int i
|
|
||||||
| Srational r -> r
|
|
||||||
| _ -> raise (Error "bad number type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let promote_rational s =
|
|
||||||
Srational (rational_of_snum s)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let bigint_of_snum =
|
|
||||||
function
|
|
||||||
Sint i -> big_int_of_int i
|
|
||||||
| Sbigint bi -> bi
|
|
||||||
| _ -> raise (Error "bad number type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let promote_bigint =
|
|
||||||
function
|
|
||||||
Sint i -> Sbigint (big_int_of_int i)
|
|
||||||
| (Sbigint _) as bi -> bi
|
|
||||||
| _ -> raise (Error "bad number type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_fixtypes a b =
|
|
||||||
match (a, b) with
|
|
||||||
(Sint _, Sint _) -> a, b
|
|
||||||
| (Scomplex _, _) -> a, promote_complex b
|
|
||||||
| (_, Scomplex _) -> (promote_complex a), b
|
|
||||||
| (Sreal _, _) -> a, promote_real b
|
|
||||||
| (_, Sreal _) -> (promote_real a), b
|
|
||||||
| (Srational _, _) -> a, promote_rational b
|
|
||||||
| (_, Srational _) -> (promote_rational a), b
|
|
||||||
| (Sbigint _, _) -> a, promote_bigint b
|
|
||||||
| (_, Sbigint _) -> (promote_bigint a), b
|
|
||||||
| _ -> raise (Error "snum_fixtypes: not numeric types")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_of_num =
|
|
||||||
function
|
|
||||||
Int x -> Sint x
|
|
||||||
| Big_int x -> Sbigint x
|
|
||||||
| Ratio x -> Srational x
|
|
||||||
;;
|
|
||||||
|
|
||||||
let num_of_snum =
|
|
||||||
function
|
|
||||||
Sint x -> Int x
|
|
||||||
| Sbigint x -> Big_int x
|
|
||||||
| Srational x -> Ratio x
|
|
||||||
| _ -> raise (Error "bad number type")
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Return a result as the simplest representation of a given bigint *)
|
|
||||||
let bigint_res bi =
|
|
||||||
if is_int_big_int bi then
|
|
||||||
Sint (int_of_big_int bi)
|
|
||||||
else
|
|
||||||
Sbigint bi
|
|
||||||
;;
|
|
||||||
|
|
||||||
let round_float r =
|
|
||||||
let d = floor (r +. 0.5)
|
|
||||||
and e = ceil (r -. 0.5) in
|
|
||||||
if d <> e && (mod_float e 2.0) = 0.0 then e
|
|
||||||
else d
|
|
||||||
;;
|
|
||||||
|
|
||||||
let float_is_int f =
|
|
||||||
let (x, _) = modf f in
|
|
||||||
x = 0.0
|
|
||||||
;;
|
|
||||||
|
|
||||||
let max_f_int = 2.0 ** (float_of_int (Sys.word_size - 2)) -. 1.0;;
|
|
||||||
let min_f_int = -.max_f_int -. 1.0;;
|
|
||||||
|
|
||||||
(* We need to deconstruct IEEE floats to convert them. *)
|
|
||||||
let fe_bits = Int64.of_string "0x7ff0000000000000";;
|
|
||||||
let fm_bits = Int64.of_string "0x000fffffffffffff";;
|
|
||||||
let fi_bit = Int64.of_string "0x0010000000000000";;
|
|
||||||
let fs_bit = Int64.of_string "0x8000000000000000";;
|
|
||||||
|
|
||||||
let fb_get_dm fb =
|
|
||||||
Int64.logand fb fm_bits
|
|
||||||
;;
|
|
||||||
|
|
||||||
let fb_get_m fb =
|
|
||||||
Int64.logor (fb_get_dm fb) fi_bit
|
|
||||||
;;
|
|
||||||
|
|
||||||
let fb_get_e fb =
|
|
||||||
Int64.to_int (Int64.shift_right (Int64.logand fb fe_bits) 52) - 1023
|
|
||||||
;;
|
|
||||||
|
|
||||||
let fb_get_s fb =
|
|
||||||
Int64.compare (Int64.logand fb fs_bit) Int64.zero <> 0;
|
|
||||||
;;
|
|
||||||
|
|
||||||
let f_is_int m e =
|
|
||||||
if e < 0 then false
|
|
||||||
else if e >= 52 then true
|
|
||||||
else Int64.compare (Int64.logand fm_bits
|
|
||||||
(Int64.shift_left m e)) Int64.zero = 0
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Convert an int64 into a bigint, possibly ignoring the most
|
|
||||||
significant 4 bits (on 32-bit machines). This is good enough
|
|
||||||
for the 52 + 1 -bit mantissa of 64-bit IEEE floats. *)
|
|
||||||
let big_int_of_int64 i =
|
|
||||||
if Sys.word_size = 64 then
|
|
||||||
(big_int_of_int (Int64.to_int i))
|
|
||||||
else (* Assume 32 *)
|
|
||||||
let lo = Int64.to_int i land 0x3fffffff
|
|
||||||
and hi = Int64.to_int (Int64.shift_right i 30) in
|
|
||||||
add_big_int (big_int_of_int lo)
|
|
||||||
(mult_big_int (big_int_of_int hi) (power_int_positive_int 2 30))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let float_to_exact f =
|
|
||||||
if float_is_int f && f >= min_f_int && f <= max_f_int then
|
|
||||||
Sint (int_of_float f)
|
|
||||||
else if f = infinity || f = neg_infinity || f = nan then
|
|
||||||
raise (Error "invalid float")
|
|
||||||
else
|
|
||||||
let fb = Int64.bits_of_float f in
|
|
||||||
let m = fb_get_m fb
|
|
||||||
and e = fb_get_e fb
|
|
||||||
and is_neg = fb_get_s fb in
|
|
||||||
let bm = big_int_of_int64 m in
|
|
||||||
if f_is_int m e then
|
|
||||||
let wrap = if is_neg then minus_big_int else fun x -> x in
|
|
||||||
if e = 52 then
|
|
||||||
Sbigint (wrap bm)
|
|
||||||
else if e > 52 then
|
|
||||||
Sbigint (wrap (mult_big_int bm (power_int_positive_int 2 (e - 52))))
|
|
||||||
else
|
|
||||||
Sbigint (wrap (div_big_int bm (power_int_positive_int 2 (52 - e))))
|
|
||||||
else
|
|
||||||
let wrap = if is_neg then minus_ratio else fun x -> x in
|
|
||||||
if e < -1022 then (* not normalized, no implied mantissa bit *)
|
|
||||||
Srational (wrap (create_ratio (big_int_of_int64 (fb_get_dm fb))
|
|
||||||
(power_int_positive_int 2 (51 - e))))
|
|
||||||
else
|
|
||||||
Srational (wrap (create_ratio bm
|
|
||||||
(power_int_positive_int 2 (52 - e))))
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
(* Numeric utility functions. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
open Num
|
|
||||||
open Ratio
|
|
||||||
open Big_int
|
|
||||||
|
|
||||||
val promote_real : sval -> sval
|
|
||||||
val promote_complex : sval -> sval
|
|
||||||
val promote_rational : sval -> sval
|
|
||||||
val promote_bigint : sval -> sval
|
|
||||||
|
|
||||||
val complex_of_snum : sval -> Complex.t
|
|
||||||
val float_of_snum : sval -> float
|
|
||||||
val rational_of_snum : sval -> ratio
|
|
||||||
val bigint_of_snum : sval -> big_int
|
|
||||||
|
|
||||||
val snum_fixtypes : sval -> sval -> sval * sval
|
|
||||||
|
|
||||||
val snum_of_num : num -> sval
|
|
||||||
val num_of_snum : sval -> num
|
|
||||||
|
|
||||||
val bigint_res : big_int -> sval
|
|
||||||
|
|
||||||
val round_float : float -> float
|
|
||||||
val float_is_int : float -> bool
|
|
||||||
val float_to_exact : float -> sval
|
|
||||||
|
|
|
@ -1,403 +0,0 @@
|
||||||
(* Conversions between numbers and strings. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_numaux
|
|
||||||
open Ocs_num
|
|
||||||
open Ocs_env
|
|
||||||
|
|
||||||
open Num
|
|
||||||
open Big_int
|
|
||||||
open Ratio
|
|
||||||
|
|
||||||
(* We need to scan strings and keep track of our position. *)
|
|
||||||
|
|
||||||
type sbuf = {
|
|
||||||
s_str : string;
|
|
||||||
mutable s_pos : int
|
|
||||||
}
|
|
||||||
|
|
||||||
let speek s =
|
|
||||||
if s.s_pos < String.length s.s_str then
|
|
||||||
Some s.s_str.[s.s_pos]
|
|
||||||
else
|
|
||||||
None
|
|
||||||
;;
|
|
||||||
|
|
||||||
let skip s =
|
|
||||||
s.s_pos <- s.s_pos + 1
|
|
||||||
;;
|
|
||||||
|
|
||||||
let sget s =
|
|
||||||
match speek s with
|
|
||||||
(Some _) as c -> skip s; c
|
|
||||||
| _ -> None
|
|
||||||
;;
|
|
||||||
|
|
||||||
let ssleft s =
|
|
||||||
(String.length s.s_str) - s.s_pos
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Converting strings to numbers is fairly complex. We have a lot of
|
|
||||||
cases to consider. *)
|
|
||||||
|
|
||||||
type exactness =
|
|
||||||
Exact
|
|
||||||
| Inexact
|
|
||||||
| Undef
|
|
||||||
|
|
||||||
let parse_prefix s =
|
|
||||||
let rec nextp b e =
|
|
||||||
match speek s with
|
|
||||||
Some '#' ->
|
|
||||||
begin
|
|
||||||
skip s;
|
|
||||||
match sget s with
|
|
||||||
Some ('E' | 'e') ->
|
|
||||||
if e <> Undef then raise (Error "invalid #e") else nextp b Exact
|
|
||||||
| Some ('I' | 'i') ->
|
|
||||||
if e <> Undef then raise (Error "invalid #i") else nextp b Inexact
|
|
||||||
| Some ('B' | 'b') ->
|
|
||||||
if b <> 0 then raise (Error "invalid #b") else nextp 2 e
|
|
||||||
| Some ('O' | 'o') ->
|
|
||||||
if b <> 0 then raise (Error "invalid #o") else nextp 8 e
|
|
||||||
| Some ('D' | 'd') ->
|
|
||||||
if b <> 0 then raise (Error "invalid #d") else nextp 10 e
|
|
||||||
| Some ('X' | 'x') ->
|
|
||||||
if b <> 0 then raise (Error "invalid #x") else nextp 16 e
|
|
||||||
| _ -> raise (Error "invalid prefix")
|
|
||||||
end
|
|
||||||
| _ -> (b, e)
|
|
||||||
in
|
|
||||||
nextp 0 Undef
|
|
||||||
;;
|
|
||||||
|
|
||||||
let strtobi s base =
|
|
||||||
let n = String.length s
|
|
||||||
and am v i = add_int_big_int i (mult_int_big_int base v) in
|
|
||||||
let rec loop i v =
|
|
||||||
if i >= n then
|
|
||||||
v
|
|
||||||
else
|
|
||||||
loop (i + 1) (am v
|
|
||||||
(match s.[i] with
|
|
||||||
'0' .. '9' as c -> int_of_char c - int_of_char '0'
|
|
||||||
| 'a' .. 'f' as c -> int_of_char c - int_of_char 'a' + 10
|
|
||||||
| 'A' .. 'F' as c -> int_of_char c - int_of_char 'A' + 10
|
|
||||||
| _ -> raise (Error "invalid number")))
|
|
||||||
in
|
|
||||||
loop 0 (big_int_of_int 0)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let read_bigint s base =
|
|
||||||
if base = 10 then
|
|
||||||
big_int_of_string s
|
|
||||||
else
|
|
||||||
strtobi s base
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* The largest integer is at *least* this big (bigger on 64-bit machines). *)
|
|
||||||
let max_int = 0x3fffffff
|
|
||||||
let min_int = -max_int - 1
|
|
||||||
|
|
||||||
let parse_num s base =
|
|
||||||
let fixsign =
|
|
||||||
match speek s with
|
|
||||||
Some '-' -> skip s; negate
|
|
||||||
| Some '+' -> skip s; fun x -> x
|
|
||||||
| _ -> fun x -> x
|
|
||||||
and maxv = max_int / base
|
|
||||||
and maxi = max_int mod base
|
|
||||||
in
|
|
||||||
let rec scann v o =
|
|
||||||
match speek s with
|
|
||||||
Some ('0' .. '9' as c)
|
|
||||||
when (int_of_char c) - (int_of_char '0') < base ->
|
|
||||||
addo v ((int_of_char c) - (int_of_char '0')) o
|
|
||||||
| Some ('a' .. 'f' as c) when base = 16 ->
|
|
||||||
addo v ((int_of_char c) - (int_of_char 'a') + 10) o
|
|
||||||
| Some ('A' .. 'F' as c) when base = 16 ->
|
|
||||||
addo v ((int_of_char c) - (int_of_char 'A') + 10) o
|
|
||||||
| _ -> (v, o)
|
|
||||||
and addo v i o =
|
|
||||||
skip s;
|
|
||||||
if o || v > maxv || (v = maxv && i > maxi) then
|
|
||||||
scann 0 true
|
|
||||||
else
|
|
||||||
scann (v * base + i) o
|
|
||||||
and readn () =
|
|
||||||
let sp = s.s_pos in
|
|
||||||
match scann 0 false with
|
|
||||||
(i, false) ->
|
|
||||||
if s.s_pos = sp then
|
|
||||||
raise (Error "invalid number")
|
|
||||||
else
|
|
||||||
Sint i
|
|
||||||
| (_, true) ->
|
|
||||||
Sbigint (read_bigint (String.sub s.s_str sp (s.s_pos - sp)) base)
|
|
||||||
in
|
|
||||||
let num = readn () in
|
|
||||||
match speek s with
|
|
||||||
Some '/' ->
|
|
||||||
skip s;
|
|
||||||
fixsign (div2 (Sbigint (bigint_of_snum num))
|
|
||||||
(Sbigint (bigint_of_snum (readn ()))))
|
|
||||||
| Some ('+' | '-' | '@') | None -> fixsign num
|
|
||||||
| _ -> raise (Error "invalid rational")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let parse_flo10 s =
|
|
||||||
let sp = s.s_pos in
|
|
||||||
let rec skipd isfirst =
|
|
||||||
match speek s with
|
|
||||||
Some '0' .. '9' | Some '#' -> skip s; skipd false
|
|
||||||
| Some ('+' | '-') when isfirst -> skip s; skipd false
|
|
||||||
| _ -> ()
|
|
||||||
in
|
|
||||||
skipd true;
|
|
||||||
if speek s = Some '.' then
|
|
||||||
begin
|
|
||||||
skip s;
|
|
||||||
skipd false
|
|
||||||
end;
|
|
||||||
begin
|
|
||||||
match speek s with
|
|
||||||
Some ('E' | 'e' | 'F' | 'f' | 'D' | 'd' | 'S' | 's' | 'L' | 'l') ->
|
|
||||||
skip s; skipd true
|
|
||||||
| _ -> ()
|
|
||||||
end;
|
|
||||||
let t = String.sub s.s_str sp (s.s_pos - sp) in
|
|
||||||
for i = 0 to String.length t - 1 do
|
|
||||||
match t.[i] with
|
|
||||||
'#' -> t.[i] <- '0'
|
|
||||||
| 'F' | 'f' | 'D' | 'd' | 'S' | 's' | 'L' | 'l' -> t.[i] <- 'e'
|
|
||||||
| _ -> ()
|
|
||||||
done;
|
|
||||||
try
|
|
||||||
Sreal (float_of_string t)
|
|
||||||
with
|
|
||||||
Failure _ -> raise (Error "invalid float")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_to_num str ub =
|
|
||||||
(* Special cases for [-+][iI] *)
|
|
||||||
if str = "+i" || str = "+I" then
|
|
||||||
Scomplex { Complex.re = 0.0; Complex.im = 1.0; }
|
|
||||||
else if str = "-i" || str = "-I" then
|
|
||||||
Scomplex { Complex.re = 0.0; Complex.im = -1.0; }
|
|
||||||
else
|
|
||||||
let s = { s_str = str; s_pos = 0 } in
|
|
||||||
let (base, ex) =
|
|
||||||
match parse_prefix s with
|
|
||||||
0, x -> if ub = 0 then (10, x) else (ub, x)
|
|
||||||
| (b, x) as r ->
|
|
||||||
if ub <> 0 && ub <> b then
|
|
||||||
raise (Error "Base mismatch")
|
|
||||||
else r
|
|
||||||
in
|
|
||||||
let getn () =
|
|
||||||
if base = 10 && ex <> Exact then
|
|
||||||
begin
|
|
||||||
let sp = s.s_pos in
|
|
||||||
try
|
|
||||||
parse_num s 10
|
|
||||||
with _ ->
|
|
||||||
s.s_pos <- sp;
|
|
||||||
parse_flo10 s
|
|
||||||
end
|
|
||||||
else
|
|
||||||
parse_num s base
|
|
||||||
and fixex n =
|
|
||||||
match (ex, n) with
|
|
||||||
(Inexact, (Sint _ | Sbigint _ | Srational _)) -> promote_real n
|
|
||||||
| (Exact, (Sreal _ | Scomplex _)) -> raise (Error "Not exact")
|
|
||||||
| _ -> n
|
|
||||||
in
|
|
||||||
let a = fixex (getn ()) in
|
|
||||||
match speek s with
|
|
||||||
Some ('+' | '-' as c) ->
|
|
||||||
if ex = Exact then
|
|
||||||
raise (Error "Complex not exact")
|
|
||||||
else
|
|
||||||
if ssleft s = 2 && s.s_str.[s.s_pos + 1] = 'i' then
|
|
||||||
Scomplex { Complex.re = float_of_snum a;
|
|
||||||
Complex.im = (if c = '-' then -1.0 else 1.0) }
|
|
||||||
else
|
|
||||||
let b = getn () in
|
|
||||||
if ssleft s <> 1 || speek s <> Some 'i' then
|
|
||||||
raise (Error "invalid number")
|
|
||||||
else
|
|
||||||
Scomplex { Complex.re = float_of_snum a;
|
|
||||||
Complex.im = float_of_snum b }
|
|
||||||
| Some '@' ->
|
|
||||||
skip s;
|
|
||||||
if ex = Exact then
|
|
||||||
raise (Error "Complex not exact")
|
|
||||||
else
|
|
||||||
let b = getn () in
|
|
||||||
if ssleft s <> 0 then
|
|
||||||
raise (Error "invalid number")
|
|
||||||
else
|
|
||||||
let r = float_of_snum a
|
|
||||||
and t = float_of_snum b in
|
|
||||||
Scomplex (Complex.polar r t)
|
|
||||||
| Some c -> raise (Error "invalid number")
|
|
||||||
| None -> a
|
|
||||||
;;
|
|
||||||
|
|
||||||
let snum_strtonum av =
|
|
||||||
match Array.length av with
|
|
||||||
(1 | 2) as n ->
|
|
||||||
let r =
|
|
||||||
if n = 2 then
|
|
||||||
begin
|
|
||||||
match av.(1) with
|
|
||||||
Sint i -> i
|
|
||||||
| _ -> raise (Error "string->number: invalid radix")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
0
|
|
||||||
in
|
|
||||||
begin
|
|
||||||
match av.(0) with
|
|
||||||
Sstring s ->
|
|
||||||
begin
|
|
||||||
try
|
|
||||||
if s = "" then
|
|
||||||
Sfalse
|
|
||||||
else
|
|
||||||
string_to_num s r
|
|
||||||
with
|
|
||||||
_ -> Sfalse
|
|
||||||
end
|
|
||||||
| _ -> raise (Error "string->number: not a string")
|
|
||||||
end
|
|
||||||
| _ -> raise (Error "string->number: wrong number of args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_of_real_s r =
|
|
||||||
let rec loop n =
|
|
||||||
let s = Printf.sprintf "%.*g" n r in
|
|
||||||
if n >= 25 || r = float_of_string s then s
|
|
||||||
else loop (n + 1)
|
|
||||||
in
|
|
||||||
loop 14
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_of_real r =
|
|
||||||
let s = string_of_real_s r in
|
|
||||||
let n = String.length s in
|
|
||||||
let rec loop i =
|
|
||||||
if i >= n then s ^ ".0"
|
|
||||||
else if s.[i] = '.' || s.[i] = 'e' then s
|
|
||||||
else loop (i + 1)
|
|
||||||
in
|
|
||||||
loop 0
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_of_complex =
|
|
||||||
function { Complex.re = r; Complex.im = i } ->
|
|
||||||
(string_of_real_s r) ^
|
|
||||||
(if i < 0.0 then
|
|
||||||
begin
|
|
||||||
if i = -1.0 then
|
|
||||||
"-i"
|
|
||||||
else
|
|
||||||
(string_of_real_s i) ^ "i"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if i = 1.0 then
|
|
||||||
"+i"
|
|
||||||
else
|
|
||||||
"+" ^ (string_of_real_s i) ^ "i")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let ichr i =
|
|
||||||
if i < 10 then
|
|
||||||
char_of_int (int_of_char '0' + i)
|
|
||||||
else
|
|
||||||
char_of_int (int_of_char 'a' + i - 10)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_of_list l =
|
|
||||||
let n = List.length l in
|
|
||||||
let s = String.create n in
|
|
||||||
let rec loop i l =
|
|
||||||
if i < n then
|
|
||||||
begin
|
|
||||||
match l with
|
|
||||||
c::t -> s.[i] <- c; loop (i + 1) t
|
|
||||||
| _ -> assert false
|
|
||||||
end
|
|
||||||
else
|
|
||||||
()
|
|
||||||
in
|
|
||||||
loop 0 l; s
|
|
||||||
;;
|
|
||||||
|
|
||||||
let itostr base i =
|
|
||||||
if i = 0 then
|
|
||||||
"0"
|
|
||||||
else
|
|
||||||
let pf = if i < 0 then "-" else "" in
|
|
||||||
let rec loop i r =
|
|
||||||
if i = 0 then
|
|
||||||
r
|
|
||||||
else
|
|
||||||
loop (i / base) ((ichr (i mod base))::r)
|
|
||||||
in
|
|
||||||
pf ^ string_of_list (loop (abs i) [])
|
|
||||||
;;
|
|
||||||
|
|
||||||
let biqmi bi i =
|
|
||||||
let (q, r) = quomod_big_int bi (big_int_of_int i) in
|
|
||||||
(q, int_of_big_int r)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let bitostr base bi =
|
|
||||||
let pf = if sign_big_int bi < 0 then "-" else "" in
|
|
||||||
let rec loop bi r =
|
|
||||||
if sign_big_int bi = 0 then
|
|
||||||
begin
|
|
||||||
match r with
|
|
||||||
[] -> [ '0' ]
|
|
||||||
| _ -> r
|
|
||||||
end
|
|
||||||
else
|
|
||||||
let (q, m) = biqmi bi base in
|
|
||||||
loop q ((ichr m)::r)
|
|
||||||
in
|
|
||||||
pf ^ string_of_list (loop (abs_big_int bi) [])
|
|
||||||
;;
|
|
||||||
|
|
||||||
let ntostr base =
|
|
||||||
function
|
|
||||||
Sint i -> itostr base i
|
|
||||||
| Sbigint bi -> bitostr base bi
|
|
||||||
| Srational r -> bitostr base (numerator_ratio r) ^ "/" ^
|
|
||||||
bitostr base (denominator_ratio r)
|
|
||||||
| _ -> raise (Error "number->string: invalid radix for inexact number")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec snum_numtostr =
|
|
||||||
function
|
|
||||||
[| Sint i |] -> Sstring (string_of_int i)
|
|
||||||
| [| Sbigint bi |] -> Sstring (string_of_big_int bi)
|
|
||||||
| [| Srational r |] -> Sstring (string_of_ratio r)
|
|
||||||
| [| Sreal r |] -> Sstring (string_of_real r)
|
|
||||||
| [| Scomplex z |] -> Sstring (string_of_complex z)
|
|
||||||
| [| snum; Sint radix |] ->
|
|
||||||
if radix = 10 then
|
|
||||||
snum_numtostr [| snum |]
|
|
||||||
else if radix = 2 || radix = 8 || radix = 16 then
|
|
||||||
Sstring (ntostr radix snum)
|
|
||||||
else
|
|
||||||
raise (Error "number->string: invalid radix")
|
|
||||||
| _ -> raise (Error "number->string: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let init e =
|
|
||||||
set_pfn e snum_strtonum "string->number";
|
|
||||||
set_pfn e snum_numtostr "number->string";
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
(* Conversions between numbers and strings. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val string_of_real : float -> string
|
|
||||||
val string_of_complex : Complex.t -> string
|
|
||||||
|
|
||||||
val string_to_num : string -> int -> sval
|
|
||||||
|
|
||||||
val init : env -> unit
|
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
(* Buffered I/O, Scheme ports. *)
|
|
||||||
|
|
||||||
open Ocs_error
|
|
||||||
|
|
||||||
type port =
|
|
||||||
| Input_channel of in_channel * char option ref
|
|
||||||
| Output_channel of out_channel
|
|
||||||
| Input_string of (string * int ref) * char option ref
|
|
||||||
| Output_string of Buffer.t
|
|
||||||
|
|
||||||
let is_input p =
|
|
||||||
match p with
|
|
||||||
| Input_string _
|
|
||||||
| Input_channel _ -> true
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let is_output p =
|
|
||||||
match p with
|
|
||||||
| Output_string _
|
|
||||||
| Output_channel _ -> true
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let getc p =
|
|
||||||
match p with
|
|
||||||
| Input_channel (_, ({contents = Some c} as ungot))
|
|
||||||
| Input_string (_, ({contents = Some c} as ungot)) ->
|
|
||||||
ungot := None;
|
|
||||||
Some c
|
|
||||||
| Input_channel (chan, {contents = None}) ->
|
|
||||||
begin
|
|
||||||
try
|
|
||||||
Some (input_char chan)
|
|
||||||
with End_of_file ->
|
|
||||||
None
|
|
||||||
end
|
|
||||||
| Input_string ((str, pos), {contents = None}) ->
|
|
||||||
if !pos >= (String.length str) then
|
|
||||||
None
|
|
||||||
else
|
|
||||||
let c = str.[!pos] in
|
|
||||||
pos := !pos + 1;
|
|
||||||
Some c
|
|
||||||
| _ ->
|
|
||||||
None
|
|
||||||
|
|
||||||
let flush p =
|
|
||||||
match p with
|
|
||||||
| Output_channel chan ->
|
|
||||||
Pervasives.flush chan
|
|
||||||
| _ ->
|
|
||||||
()
|
|
||||||
|
|
||||||
let close p =
|
|
||||||
match p with
|
|
||||||
| Input_channel (chan, ungot) ->
|
|
||||||
ungot := None;
|
|
||||||
close_in chan
|
|
||||||
| Output_channel chan ->
|
|
||||||
close_out chan
|
|
||||||
| _ ->
|
|
||||||
()
|
|
||||||
|
|
||||||
let ungetc p c =
|
|
||||||
match p with
|
|
||||||
| Input_channel (_, ungot)
|
|
||||||
| Input_string (_, ungot) ->
|
|
||||||
ungot := Some c
|
|
||||||
| _ ->
|
|
||||||
()
|
|
||||||
|
|
||||||
let char_ready p =
|
|
||||||
match p with
|
|
||||||
| Input_string (_, {contents = Some _})
|
|
||||||
| Input_channel (_, {contents = Some _}) ->
|
|
||||||
true
|
|
||||||
| Input_string ((str, pos), {contents = None}) ->
|
|
||||||
!pos < (String.length str)
|
|
||||||
| Input_channel (chan, {contents = None}) ->
|
|
||||||
let fd = Unix.descr_of_in_channel chan in
|
|
||||||
let (r, _, _) = Unix.select [fd] [] [] 0.0 in
|
|
||||||
List.length r > 0
|
|
||||||
| _ ->
|
|
||||||
false
|
|
||||||
|
|
||||||
let putc p c =
|
|
||||||
match p with
|
|
||||||
| Output_string buf ->
|
|
||||||
Buffer.add_char buf c
|
|
||||||
| Output_channel chan ->
|
|
||||||
output_char chan c
|
|
||||||
| _ ->
|
|
||||||
()
|
|
||||||
|
|
||||||
let puts p s =
|
|
||||||
match p with
|
|
||||||
| Output_string buf ->
|
|
||||||
Buffer.add_string buf s
|
|
||||||
| Output_channel chan ->
|
|
||||||
output_string chan s
|
|
||||||
| _ ->
|
|
||||||
()
|
|
||||||
|
|
||||||
let input_port ch = Input_channel (ch, ref None)
|
|
||||||
|
|
||||||
let output_port ch = Output_channel ch
|
|
||||||
|
|
||||||
let open_input_port name =
|
|
||||||
try
|
|
||||||
input_port (open_in_bin name)
|
|
||||||
with Sys_error err ->
|
|
||||||
raise (Error ("unable to open '" ^ name ^ "' for input: " ^ err))
|
|
||||||
|
|
||||||
let open_output_port name =
|
|
||||||
try
|
|
||||||
output_port (open_out_bin name)
|
|
||||||
with Sys_error err ->
|
|
||||||
raise (Error ("unable to open '" ^ name ^ "' for output: " ^ err))
|
|
||||||
|
|
||||||
let open_input_string s = Input_string ((s, ref 0), ref None)
|
|
||||||
|
|
||||||
let open_output_string () =Output_string (Buffer.create 256)
|
|
||||||
|
|
||||||
let get_output_string p =
|
|
||||||
match p with
|
|
||||||
| Output_string buf ->
|
|
||||||
Buffer.contents buf
|
|
||||||
| _ ->
|
|
||||||
""
|
|
|
@ -1,26 +0,0 @@
|
||||||
(* Buffered I/O, Scheme ports. *)
|
|
||||||
|
|
||||||
type port
|
|
||||||
|
|
||||||
val input_port : in_channel -> port
|
|
||||||
val output_port : out_channel -> port
|
|
||||||
val open_input_port : string -> port
|
|
||||||
val open_output_port : string -> port
|
|
||||||
val open_input_string : string -> port
|
|
||||||
val open_output_string : unit -> port
|
|
||||||
val get_output_string : port -> string
|
|
||||||
|
|
||||||
val is_input : port -> bool
|
|
||||||
val is_output : port -> bool
|
|
||||||
|
|
||||||
val getc : port -> char option
|
|
||||||
val ungetc : port -> char -> unit
|
|
||||||
val char_ready : port -> bool
|
|
||||||
|
|
||||||
val putc : port -> char -> unit
|
|
||||||
val puts : port -> string -> unit
|
|
||||||
|
|
||||||
val flush : port -> unit
|
|
||||||
|
|
||||||
val close : port -> unit
|
|
||||||
|
|
|
@ -1,269 +0,0 @@
|
||||||
(* Various primitives *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_env
|
|
||||||
open Ocs_eval
|
|
||||||
open Ocs_misc
|
|
||||||
open Ocs_sym
|
|
||||||
open Ocs_io
|
|
||||||
open Ocs_compile
|
|
||||||
open Ocs_macro
|
|
||||||
|
|
||||||
let logical_not =
|
|
||||||
function
|
|
||||||
Sfalse -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Type predicates *)
|
|
||||||
|
|
||||||
let is_boolean =
|
|
||||||
function
|
|
||||||
Strue | Sfalse -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_string =
|
|
||||||
function
|
|
||||||
Sstring _ -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_char =
|
|
||||||
function
|
|
||||||
Schar _ -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_pair =
|
|
||||||
function
|
|
||||||
Spair _ -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_null =
|
|
||||||
function
|
|
||||||
Snull -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_vector =
|
|
||||||
function
|
|
||||||
Svector _ -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_proc =
|
|
||||||
function
|
|
||||||
Sproc (_, _) | Sprim _ -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_port =
|
|
||||||
function
|
|
||||||
Sport _ -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_symbol =
|
|
||||||
function
|
|
||||||
Ssymbol _ -> Strue
|
|
||||||
| _ -> Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let symbol_to_string =
|
|
||||||
function
|
|
||||||
Ssymbol s -> Sstring s
|
|
||||||
| _ -> raise (Error "symbol->string: not a symbol")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_to_symbol =
|
|
||||||
function
|
|
||||||
Sstring s -> get_symbol (String.copy s)
|
|
||||||
| _ -> raise (Error "string->symbol: not a string")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_eq a b =
|
|
||||||
if a == b then Strue else Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_eqv a b =
|
|
||||||
if test_eqv a b then Strue else Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let is_equal a b =
|
|
||||||
if test_equal a b then Strue else Sfalse
|
|
||||||
;;
|
|
||||||
|
|
||||||
let do_apply th cc av =
|
|
||||||
let n = Array.length av in
|
|
||||||
if n < 1 then
|
|
||||||
raise (Error "apply: bad args")
|
|
||||||
else
|
|
||||||
let f = av.(0) in
|
|
||||||
let rec loop i r =
|
|
||||||
if i = 0 then
|
|
||||||
r
|
|
||||||
else if i = n - 1 then (* r must be [] *)
|
|
||||||
loop (i - 1) (list_to_caml av.(i))
|
|
||||||
else
|
|
||||||
loop (i - 1) (av.(i)::r)
|
|
||||||
in
|
|
||||||
let args = Array.map (fun x -> Cval x)
|
|
||||||
(Array.of_list (loop (n - 1) []))
|
|
||||||
in
|
|
||||||
eval th cc (mkapply (Cval f) args)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let force _ cc =
|
|
||||||
function
|
|
||||||
[| Spromise ({ promise_code = c;
|
|
||||||
promise_val = None;
|
|
||||||
promise_th = Some th } as p) |] ->
|
|
||||||
eval th
|
|
||||||
(fun v ->
|
|
||||||
match p.promise_val with (* Computed before returning? *)
|
|
||||||
Some v -> cc v
|
|
||||||
| None ->
|
|
||||||
p.promise_val <- Some v;
|
|
||||||
p.promise_th <- None; (* Release reference for gc *)
|
|
||||||
cc v) c
|
|
||||||
| [| Spromise { promise_code = _;
|
|
||||||
promise_val = Some v;
|
|
||||||
promise_th = _ } |] ->
|
|
||||||
cc v
|
|
||||||
| _ -> raise (Error "force: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let map_for_each th cc av is_map =
|
|
||||||
let my_name = if is_map then "map" else "for-each"
|
|
||||||
and na = Array.length av - 1 in
|
|
||||||
if na <= 0 then
|
|
||||||
raise (Error (my_name ^ ": bad args"));
|
|
||||||
let proc = av.(0)
|
|
||||||
and get_cdr =
|
|
||||||
function
|
|
||||||
Spair { car = _; cdr = t } -> t
|
|
||||||
| _ -> raise (Error (my_name ^ ": list lengths don't match"))
|
|
||||||
and get_carc =
|
|
||||||
function
|
|
||||||
Spair { car = h; cdr = _ } -> Cval h
|
|
||||||
| _ -> raise (Error (my_name ^ ": list lengths don't match"))
|
|
||||||
and result = ref (if is_map then Snull else Sunspec)
|
|
||||||
and rtail = ref Snull in
|
|
||||||
let append v =
|
|
||||||
if !rtail == Snull then
|
|
||||||
begin
|
|
||||||
result := Spair { car = v; cdr = Snull };
|
|
||||||
rtail := !result;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
match !rtail with
|
|
||||||
Spair p ->
|
|
||||||
p.cdr <- Spair { car = v; cdr = Snull };
|
|
||||||
rtail := p.cdr
|
|
||||||
| _ -> assert false
|
|
||||||
end
|
|
||||||
in
|
|
||||||
let rec loop args =
|
|
||||||
match args.(0) with
|
|
||||||
Snull -> cc !result
|
|
||||||
| Spair _ ->
|
|
||||||
eval th
|
|
||||||
(fun v ->
|
|
||||||
if is_map then append v;
|
|
||||||
loop (Array.map get_cdr args))
|
|
||||||
(mkapply (Cval proc) (Array.map get_carc args))
|
|
||||||
| _ -> raise (Error (my_name ^ ": invalid argument lists"))
|
|
||||||
in
|
|
||||||
loop (Array.sub av 1 na)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let map th cc av =
|
|
||||||
map_for_each th cc av true
|
|
||||||
;;
|
|
||||||
|
|
||||||
let for_each th cc av =
|
|
||||||
map_for_each th cc av false
|
|
||||||
;;
|
|
||||||
|
|
||||||
let load_file e th name =
|
|
||||||
let th = { th with th_display = [| |]; th_depth = -1 }
|
|
||||||
and inp = Ocs_port.open_input_port name in
|
|
||||||
let lex = Ocs_lex.make_lexer inp name in
|
|
||||||
let rec loop () =
|
|
||||||
match Ocs_read.read_expr lex with
|
|
||||||
Seof -> ()
|
|
||||||
| v ->
|
|
||||||
let c = compile e v in
|
|
||||||
eval th (fun _ -> ()) c;
|
|
||||||
loop ()
|
|
||||||
in
|
|
||||||
loop ()
|
|
||||||
;;
|
|
||||||
|
|
||||||
let load_prim e th cc =
|
|
||||||
function
|
|
||||||
[| Sstring name |] -> load_file e th name; cc Sunspec
|
|
||||||
| _ -> raise (Error "load: invalid name argument")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let eval_prim th cc =
|
|
||||||
function
|
|
||||||
[| expr; Sesym (e, _) |] ->
|
|
||||||
eval { th with th_display = [| |]; th_depth = -1 } cc
|
|
||||||
(compile e expr)
|
|
||||||
| _ -> raise (Error "eval: invalid args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let report_env e _ =
|
|
||||||
Sesym (env_copy e, Ssymbol "")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let null_env _ =
|
|
||||||
let e = top_env () in
|
|
||||||
bind_lang e;
|
|
||||||
bind_macro e;
|
|
||||||
Sesym (e, Ssymbol "")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let interact_env e =
|
|
||||||
fun () -> Sesym (e, Ssymbol "")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let init e =
|
|
||||||
set_pf1 e logical_not "not";
|
|
||||||
set_pf1 e is_boolean "boolean?";
|
|
||||||
set_pf1 e is_string "string?";
|
|
||||||
set_pf1 e is_char "char?";
|
|
||||||
set_pf1 e is_vector "vector?";
|
|
||||||
set_pf1 e is_pair "pair?";
|
|
||||||
set_pf1 e is_null "null?";
|
|
||||||
set_pf1 e is_proc "procedure?";
|
|
||||||
set_pf1 e is_port "port?";
|
|
||||||
set_pf1 e is_symbol "symbol?";
|
|
||||||
|
|
||||||
set_pf1 e symbol_to_string "symbol->string";
|
|
||||||
set_pf1 e string_to_symbol "string->symbol";
|
|
||||||
|
|
||||||
set_pf2 e is_eq "eq?";
|
|
||||||
set_pf2 e is_eqv "eqv?";
|
|
||||||
set_pf2 e is_equal "equal?";
|
|
||||||
|
|
||||||
set_pfcn e do_apply "apply";
|
|
||||||
|
|
||||||
set_pfcn e force "force";
|
|
||||||
|
|
||||||
set_pfcn e map "map";
|
|
||||||
set_pfcn e for_each "for-each";
|
|
||||||
|
|
||||||
set_pfcn e (load_prim e) "load";
|
|
||||||
set_pfcn e eval_prim "eval";
|
|
||||||
|
|
||||||
set_pf1 e (report_env (env_copy e)) "scheme-report-environment";
|
|
||||||
set_pf1 e null_env "null-environment";
|
|
||||||
set_pf0 e (interact_env e) "interaction-environment";
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
(* Miscellaneous primitives. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val load_file : env -> thread -> string -> unit
|
|
||||||
|
|
||||||
val init : env -> unit
|
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
(* Print Scheme values *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_sym
|
|
||||||
open Ocs_numstr
|
|
||||||
|
|
||||||
let write_string p s =
|
|
||||||
Ocs_port.putc p '\"';
|
|
||||||
for i = 0 to String.length s - 1 do
|
|
||||||
match s.[i] with
|
|
||||||
'\n' -> Ocs_port.puts p "\\n"
|
|
||||||
| '\r' -> Ocs_port.puts p "\\r"
|
|
||||||
| '\t' -> Ocs_port.puts p "\\t"
|
|
||||||
| '\\' -> Ocs_port.puts p "\\\\"
|
|
||||||
| '\"' -> Ocs_port.puts p "\\\""
|
|
||||||
| '\032' .. '\126' as c -> Ocs_port.putc p c
|
|
||||||
| c -> Ocs_port.puts p (Printf.sprintf "\\x%02x" (int_of_char c))
|
|
||||||
done;
|
|
||||||
Ocs_port.putc p '\"'
|
|
||||||
;;
|
|
||||||
|
|
||||||
let write_char p c =
|
|
||||||
Ocs_port.puts p "#\\";
|
|
||||||
match c with
|
|
||||||
'\033' .. '\126' -> Ocs_port.putc p c
|
|
||||||
| _ -> Ocs_port.puts p (Ocs_char.char_to_name c)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec write_vector p disp v =
|
|
||||||
Ocs_port.puts p "#(";
|
|
||||||
for i = 0 to Array.length v - 1 do
|
|
||||||
if i <> 0 then Ocs_port.putc p ' ';
|
|
||||||
print p disp v.(i)
|
|
||||||
done;
|
|
||||||
Ocs_port.putc p ')'
|
|
||||||
|
|
||||||
and write_list p disp l =
|
|
||||||
Ocs_port.putc p '(';
|
|
||||||
let rec pit l =
|
|
||||||
print p disp l.car;
|
|
||||||
match l.cdr with
|
|
||||||
Snull -> ()
|
|
||||||
| Spair t -> Ocs_port.putc p ' '; pit t
|
|
||||||
| x -> Ocs_port.puts p " . "; print p disp x
|
|
||||||
in
|
|
||||||
pit l;
|
|
||||||
Ocs_port.putc p ')'
|
|
||||||
|
|
||||||
and print p disp =
|
|
||||||
function
|
|
||||||
Snull -> Ocs_port.puts p "()"
|
|
||||||
| Seof -> Ocs_port.puts p "#<eof>"
|
|
||||||
| Strue -> Ocs_port.puts p "#t"
|
|
||||||
| Sfalse -> Ocs_port.puts p "#f"
|
|
||||||
| Sstring s -> if disp then Ocs_port.puts p s else write_string p s
|
|
||||||
| Ssymbol s -> Ocs_port.puts p s
|
|
||||||
| Sint i -> Ocs_port.puts p (string_of_int i)
|
|
||||||
| Sreal r -> Ocs_port.puts p (string_of_real r)
|
|
||||||
| Scomplex z -> Ocs_port.puts p (string_of_complex z)
|
|
||||||
| Sbigint b -> Ocs_port.puts p (Big_int.string_of_big_int b)
|
|
||||||
| Srational r -> Ocs_port.puts p (Ratio.string_of_ratio r)
|
|
||||||
| Schar c -> if disp then Ocs_port.putc p c else write_char p c
|
|
||||||
| Spair l -> write_list p disp l
|
|
||||||
| Svector v -> write_vector p disp v
|
|
||||||
| Sport _ -> Ocs_port.puts p "#<port>"
|
|
||||||
| Sproc _ -> Ocs_port.puts p "#<procedure>"
|
|
||||||
| Sprim { prim_fun = _; prim_name = n } ->
|
|
||||||
Ocs_port.puts p "#<primitive:"; Ocs_port.puts p n; Ocs_port.putc p '>'
|
|
||||||
| Spromise _ -> Ocs_port.puts p "#<promise>"
|
|
||||||
| Sesym (_, s) -> print p disp s
|
|
||||||
| Swrapped _ -> Ocs_port.puts p "#<wrapped>"
|
|
||||||
| Sunspec -> Ocs_port.puts p "#<unspecified>"
|
|
||||||
| _ -> Ocs_port.puts p "#<unknown>"
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
(* Print Scheme values *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val write_string : Ocs_port.port -> string -> unit
|
|
||||||
val write_char : Ocs_port.port -> char -> unit
|
|
||||||
|
|
||||||
val print : Ocs_port.port -> bool -> sval -> unit
|
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
(* Reader of Scheme expressions. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_lex
|
|
||||||
open Ocs_sym
|
|
||||||
open Ocs_misc
|
|
||||||
|
|
||||||
let read_error lex err =
|
|
||||||
let (file, name) = get_loc lex in
|
|
||||||
if String.length file = 0 then
|
|
||||||
Error err
|
|
||||||
else
|
|
||||||
ErrorL ((file, name), err)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let show_token =
|
|
||||||
function
|
|
||||||
'"' -> "'\"'"
|
|
||||||
| '\032' .. '\126' as c -> Printf.sprintf "\"%c\"" c
|
|
||||||
| c -> Printf.sprintf "ascii %d" (int_of_char c)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec read_item lex =
|
|
||||||
function
|
|
||||||
Leof -> Seof
|
|
||||||
| Lident s -> get_symbol (String.lowercase s)
|
|
||||||
| Lstring s -> Sstring s
|
|
||||||
| Lnumber s | Lbool s | Lchar s -> s
|
|
||||||
| Ltoken '(' -> read_list lex ')'
|
|
||||||
| Ltoken '[' -> read_list lex ']'
|
|
||||||
| Lopenv -> read_vector lex
|
|
||||||
| Ltoken '\'' -> read_quoted lex sym_quote
|
|
||||||
| Ltoken '`' -> read_quoted lex sym_quasiquote
|
|
||||||
| Ltoken ',' -> read_quoted lex sym_unquote
|
|
||||||
| Lunqsplice -> read_quoted lex sym_unquote_splicing
|
|
||||||
| Ltoken c -> raise (read_error lex ("unexpected " ^ show_token c))
|
|
||||||
|
|
||||||
and read_list lex term =
|
|
||||||
let rec loop r =
|
|
||||||
match get_tok lex with
|
|
||||||
Leof -> raise (read_error lex "unexpected eof in list")
|
|
||||||
| Ltoken c when c = term -> make_slist Snull r
|
|
||||||
| Ltoken '.' ->
|
|
||||||
begin
|
|
||||||
let tl =
|
|
||||||
match get_tok lex with
|
|
||||||
Leof -> raise (read_error lex "unexpected eof in dotted tail")
|
|
||||||
| x -> read_item lex x
|
|
||||||
in
|
|
||||||
match get_tok lex with
|
|
||||||
Ltoken c when c = term -> make_slist tl r
|
|
||||||
| _ -> raise (read_error lex
|
|
||||||
"expected close paren after dotted tail")
|
|
||||||
end
|
|
||||||
| x -> loop ((read_item lex x)::r)
|
|
||||||
in
|
|
||||||
loop []
|
|
||||||
|
|
||||||
and read_vector lex =
|
|
||||||
let rec loop r =
|
|
||||||
match get_tok lex with
|
|
||||||
Leof -> raise (read_error lex "unexpected eof in vector")
|
|
||||||
| Ltoken ')' -> r
|
|
||||||
| x -> loop ((read_item lex x)::r)
|
|
||||||
in
|
|
||||||
Svector (Array.of_list (List.rev (loop [])))
|
|
||||||
|
|
||||||
and read_quoted lex sym =
|
|
||||||
match get_tok lex with
|
|
||||||
Leof -> raise (read_error lex "unexpected eof")
|
|
||||||
| x ->
|
|
||||||
let x = read_item lex x in
|
|
||||||
Spair { car = sym; cdr = Spair { car = x; cdr = Snull }}
|
|
||||||
;;
|
|
||||||
|
|
||||||
let read_expr lex =
|
|
||||||
read_item lex (get_tok lex)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let read_from_port p =
|
|
||||||
read_expr (make_lexer p "")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let read_from_string s =
|
|
||||||
read_from_port (Ocs_port.open_input_string s)
|
|
||||||
;;
|
|
|
@ -1,10 +0,0 @@
|
||||||
(* Reader of Scheme expressions. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_lex
|
|
||||||
|
|
||||||
val read_expr : lexer -> sval
|
|
||||||
|
|
||||||
val read_from_port : Ocs_port.port -> sval
|
|
||||||
val read_from_string : string -> sval
|
|
||||||
|
|
|
@ -1,153 +0,0 @@
|
||||||
(* String primitives *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_env
|
|
||||||
|
|
||||||
let make_string =
|
|
||||||
function
|
|
||||||
[| Sint k |] -> Sstring (String.create k)
|
|
||||||
| [| Sint k; Schar c |] -> Sstring (String.make k c)
|
|
||||||
| _ -> raise (Error "make-string: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_of av =
|
|
||||||
let n = Array.length av in
|
|
||||||
let s = String.create n in
|
|
||||||
for i = 0 to n - 1 do
|
|
||||||
match av.(i) with
|
|
||||||
Schar c -> s.[i] <- c
|
|
||||||
| _ -> raise (Error "string: bad args")
|
|
||||||
done;
|
|
||||||
Sstring s
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_length =
|
|
||||||
function
|
|
||||||
Sstring s -> Sint (String.length s)
|
|
||||||
| _ -> raise (Error "string-length: not a string")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_ref s k =
|
|
||||||
match (s, k) with
|
|
||||||
(Sstring s, Sint k) ->
|
|
||||||
if k >= 0 && k < String.length s then
|
|
||||||
Schar s.[k]
|
|
||||||
else
|
|
||||||
raise (Error "string-ref: out of bounds")
|
|
||||||
| _ -> raise (Error "string-ref: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_set s k c =
|
|
||||||
match (s, k, c) with
|
|
||||||
(Sstring s, Sint k, Schar c) ->
|
|
||||||
if k >= 0 && k < String.length s then
|
|
||||||
begin
|
|
||||||
s.[k] <- c; Sunspec
|
|
||||||
end
|
|
||||||
else
|
|
||||||
raise (Error "string-set!: out of bounds")
|
|
||||||
| _ -> raise (Error "string-set!: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_cmp op s1 s2 =
|
|
||||||
match (s1, s2) with
|
|
||||||
(Sstring s1, Sstring s2) -> if op s1 s2 then Strue else Sfalse
|
|
||||||
| _ -> raise (Error "bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_eq = string_cmp (=);;
|
|
||||||
let string_lt = string_cmp (<);;
|
|
||||||
let string_gt = string_cmp (>);;
|
|
||||||
let string_le = string_cmp (<=);;
|
|
||||||
let string_ge = string_cmp (>=);;
|
|
||||||
|
|
||||||
let string_ci_cmp op s1 s2 =
|
|
||||||
match (s1, s2) with
|
|
||||||
(Sstring s1, Sstring s2) ->
|
|
||||||
if op (String.lowercase s1) (String.lowercase s2) then Strue else Sfalse
|
|
||||||
| _ -> raise (Error "bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_ci_eq = string_ci_cmp (=);;
|
|
||||||
let string_ci_lt = string_ci_cmp (<);;
|
|
||||||
let string_ci_gt = string_ci_cmp (>);;
|
|
||||||
let string_ci_le = string_ci_cmp (<=);;
|
|
||||||
let string_ci_ge = string_ci_cmp (>=);;
|
|
||||||
|
|
||||||
let string_append av =
|
|
||||||
Sstring
|
|
||||||
(Array.fold_left (^) ""
|
|
||||||
(Array.map (function
|
|
||||||
Sstring s -> s
|
|
||||||
| _ -> raise (Error "string-append: bad args")) av))
|
|
||||||
;;
|
|
||||||
|
|
||||||
let substring s sp ep =
|
|
||||||
match (s, sp, ep) with
|
|
||||||
(Sstring s, Sint sp, Sint ep) ->
|
|
||||||
let n = String.length s in
|
|
||||||
if sp >= 0 && sp <= ep && ep <= n then
|
|
||||||
Sstring (String.sub s sp (ep - sp))
|
|
||||||
else
|
|
||||||
raise (Error "substring: out of bounds")
|
|
||||||
| _ -> raise (Error "substring: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_to_list =
|
|
||||||
function
|
|
||||||
Sstring s ->
|
|
||||||
begin
|
|
||||||
let rec loop i r =
|
|
||||||
if i < 0 then r
|
|
||||||
else loop (i - 1) (Spair { car = Schar s.[i]; cdr = r })
|
|
||||||
in
|
|
||||||
loop (String.length s - 1) Snull
|
|
||||||
end
|
|
||||||
| _ -> raise (Error "string->list: not a string")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_copy =
|
|
||||||
function
|
|
||||||
Sstring s -> Sstring (String.copy s)
|
|
||||||
| _ -> raise (Error "string-copy: not a string")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let string_fill s c =
|
|
||||||
match (s, c) with
|
|
||||||
(Sstring s, Schar c) ->
|
|
||||||
String.fill s 0 (String.length s) c; Sunspec
|
|
||||||
| _ -> raise (Error "string-fill!: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let init e =
|
|
||||||
set_pfn e make_string "make-string";
|
|
||||||
set_pfn e string_of "string";
|
|
||||||
|
|
||||||
set_pf1 e string_length "string-length";
|
|
||||||
|
|
||||||
set_pf2 e string_ref "string-ref";
|
|
||||||
set_pf3 e string_set "string-set!";
|
|
||||||
|
|
||||||
set_pf2 e string_eq "string=?";
|
|
||||||
set_pf2 e string_lt "string<?";
|
|
||||||
set_pf2 e string_gt "string>?";
|
|
||||||
set_pf2 e string_le "string<=?";
|
|
||||||
set_pf2 e string_ge "string>=?";
|
|
||||||
|
|
||||||
set_pf2 e string_ci_eq "string-ci=?";
|
|
||||||
set_pf2 e string_ci_lt "string-ci<?";
|
|
||||||
set_pf2 e string_ci_gt "string-ci>?";
|
|
||||||
set_pf2 e string_ci_le "string-ci<=?";
|
|
||||||
set_pf2 e string_ci_ge "string-ci>=?";
|
|
||||||
|
|
||||||
set_pf3 e substring "substring";
|
|
||||||
|
|
||||||
set_pfn e string_append "string-append";
|
|
||||||
|
|
||||||
set_pf1 e string_to_list "string->list";
|
|
||||||
|
|
||||||
set_pf1 e string_copy "string-copy";
|
|
||||||
|
|
||||||
set_pf2 e string_fill "string-fill!";
|
|
||||||
;;
|
|
|
@ -1,6 +0,0 @@
|
||||||
(* String primitives *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val init : env -> unit
|
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
(* Symbol table implementation. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
|
|
||||||
(* Symbols are stored in a hash table of weak references. This
|
|
||||||
guarantees that they are unique, but they needn't be permanent. *)
|
|
||||||
|
|
||||||
module HashSymbol =
|
|
||||||
struct
|
|
||||||
type t = sval
|
|
||||||
let equal a b =
|
|
||||||
match (a, b) with
|
|
||||||
(Ssymbol s1, Ssymbol s2) -> s1 = s2
|
|
||||||
| _ -> false
|
|
||||||
let hash = Hashtbl.hash
|
|
||||||
end
|
|
||||||
|
|
||||||
module SymTable = Weak.Make (HashSymbol)
|
|
||||||
|
|
||||||
let symt = SymTable.create 307
|
|
||||||
|
|
||||||
let get_symbol s =
|
|
||||||
SymTable.merge symt (Ssymbol s)
|
|
||||||
;;
|
|
||||||
|
|
||||||
let sym_name =
|
|
||||||
function
|
|
||||||
Ssymbol s -> s
|
|
||||||
| _ -> raise (Error "sym_name: not a symbol")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let sym_quote = get_symbol "quote"
|
|
||||||
let sym_lambda = get_symbol "lambda"
|
|
||||||
let sym_if = get_symbol "if"
|
|
||||||
let sym_set = get_symbol "set!"
|
|
||||||
let sym_begin = get_symbol "begin"
|
|
||||||
let sym_cond = get_symbol "cond"
|
|
||||||
let sym_and = get_symbol "and"
|
|
||||||
let sym_or = get_symbol "or"
|
|
||||||
let sym_case = get_symbol "case"
|
|
||||||
let sym_let = get_symbol "let"
|
|
||||||
let sym_letstar = get_symbol "let*"
|
|
||||||
let sym_letrec = get_symbol "letrec"
|
|
||||||
let sym_do = get_symbol "do"
|
|
||||||
let sym_delay = get_symbol "delay"
|
|
||||||
let sym_quasiquote = get_symbol "quasiquote"
|
|
||||||
let sym_else = get_symbol "else"
|
|
||||||
let sym_arrow = get_symbol "=>"
|
|
||||||
let sym_define = get_symbol "define"
|
|
||||||
let sym_unquote = get_symbol "unquote"
|
|
||||||
let sym_unquote_splicing = get_symbol "unquote-splicing"
|
|
||||||
|
|
||||||
let sym_define_syntax = get_symbol "define-syntax"
|
|
||||||
let sym_let_syntax = get_symbol "let-syntax"
|
|
||||||
let sym_letrec_syntax = get_symbol "letrec-syntax"
|
|
||||||
let sym_syntax_rules = get_symbol "syntax-rules"
|
|
||||||
let sym_ellipsis = get_symbol "..."
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
(* Symbol table interface. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
(* get_symbol returns a symbol corresponding to a string. It is
|
|
||||||
created if it doesn't exist. *)
|
|
||||||
val get_symbol : string -> sval
|
|
||||||
val sym_name : sval -> string
|
|
||||||
|
|
||||||
(* Keywords are globally defined for convenience. *)
|
|
||||||
val sym_quote : sval
|
|
||||||
val sym_lambda : sval
|
|
||||||
val sym_if : sval
|
|
||||||
val sym_set : sval
|
|
||||||
val sym_begin : sval
|
|
||||||
val sym_cond : sval
|
|
||||||
val sym_and : sval
|
|
||||||
val sym_or : sval
|
|
||||||
val sym_case : sval
|
|
||||||
val sym_let : sval
|
|
||||||
val sym_letstar : sval
|
|
||||||
val sym_letrec : sval
|
|
||||||
val sym_do : sval
|
|
||||||
val sym_delay : sval
|
|
||||||
val sym_quasiquote : sval
|
|
||||||
val sym_else : sval
|
|
||||||
val sym_arrow : sval
|
|
||||||
val sym_define : sval
|
|
||||||
val sym_unquote : sval
|
|
||||||
val sym_unquote_splicing : sval
|
|
||||||
|
|
||||||
val sym_define_syntax : sval
|
|
||||||
val sym_let_syntax : sval
|
|
||||||
val sym_letrec_syntax : sval
|
|
||||||
val sym_syntax_rules : sval
|
|
||||||
val sym_ellipsis : sval
|
|
|
@ -1,75 +0,0 @@
|
||||||
(* Top level, create and initialize the environment. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_env
|
|
||||||
open Ocs_compile
|
|
||||||
open Ocs_eval
|
|
||||||
open Ocs_print
|
|
||||||
open Ocs_macro
|
|
||||||
|
|
||||||
(* Create a top-level environment and bind standard primitives. *)
|
|
||||||
let make_env () =
|
|
||||||
let e = top_env () in
|
|
||||||
bind_lang e;
|
|
||||||
bind_macro e;
|
|
||||||
Ocs_num.init e;
|
|
||||||
Ocs_numstr.init e;
|
|
||||||
Ocs_prim.init e;
|
|
||||||
Ocs_vector.init e;
|
|
||||||
Ocs_list.init e;
|
|
||||||
Ocs_char.init e;
|
|
||||||
Ocs_string.init e;
|
|
||||||
Ocs_contin.init e;
|
|
||||||
Ocs_io.init e;
|
|
||||||
e
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Create a top-level thread. *)
|
|
||||||
let make_thread () =
|
|
||||||
{ th_display = [| |];
|
|
||||||
th_frame = [| |];
|
|
||||||
th_depth = -1;
|
|
||||||
th_stdin = Sport (Ocs_port.input_port stdin);
|
|
||||||
th_stdout = Sport (Ocs_port.output_port stdout);
|
|
||||||
th_dynext = None }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let get_port =
|
|
||||||
function
|
|
||||||
Sport p -> p
|
|
||||||
| _ -> failwith "expected port"
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Top-level loop for interaction. *)
|
|
||||||
let top_loop env th =
|
|
||||||
let inp = get_port th.th_stdin
|
|
||||||
and outp = get_port th.th_stdout
|
|
||||||
and errp = Ocs_port.output_port stderr in
|
|
||||||
let lex = Ocs_lex.make_lexer inp "" in
|
|
||||||
let rec loop () =
|
|
||||||
Ocs_port.puts outp "> ";
|
|
||||||
Ocs_port.flush outp;
|
|
||||||
try
|
|
||||||
match Ocs_read.read_expr lex with
|
|
||||||
Seof -> ()
|
|
||||||
| v ->
|
|
||||||
let c = compile env v in
|
|
||||||
eval th (function Sunspec -> ()
|
|
||||||
| r ->
|
|
||||||
print outp false r;
|
|
||||||
Ocs_port.putc outp '\n') c;
|
|
||||||
loop ()
|
|
||||||
with Error err | ErrorL (_, err) ->
|
|
||||||
Ocs_port.puts errp ("Error: " ^ err ^ "\n");
|
|
||||||
Ocs_port.flush errp;
|
|
||||||
loop ()
|
|
||||||
in
|
|
||||||
loop ()
|
|
||||||
;;
|
|
||||||
|
|
||||||
(* Simple interface to invoke the interactive Scheme environment. *)
|
|
||||||
let interactive () =
|
|
||||||
top_loop (make_env ()) (make_thread ())
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
(* Create and initialize top level environment. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val make_env : unit -> env
|
|
||||||
val make_thread : unit -> thread
|
|
||||||
val top_loop : env -> thread -> unit
|
|
||||||
|
|
||||||
val interactive : unit -> unit
|
|
||||||
|
|
|
@ -1,200 +0,0 @@
|
||||||
(* Main types used *)
|
|
||||||
|
|
||||||
open Ocs_vartable
|
|
||||||
|
|
||||||
(* We have to declare most types here to avoid cross-dependencies between
|
|
||||||
compilation units. *)
|
|
||||||
|
|
||||||
type sval =
|
|
||||||
(* Global variables are set to Sunbound when referenced but not assigned. *)
|
|
||||||
Sunbound
|
|
||||||
|
|
||||||
(* List terminator. *)
|
|
||||||
| Snull
|
|
||||||
|
|
||||||
(* End-of-file indicator. *)
|
|
||||||
| Seof
|
|
||||||
|
|
||||||
(* Boolean values. This is more compact than Sbool of bool. *)
|
|
||||||
| Strue
|
|
||||||
| Sfalse
|
|
||||||
|
|
||||||
(* String object. *)
|
|
||||||
| Sstring of string
|
|
||||||
|
|
||||||
(* Symbol type. Symbols should not be created directly, but using
|
|
||||||
Ocs_sym.get_symbol, which ensures that they are unique and can be
|
|
||||||
compared using ==. *)
|
|
||||||
| Ssymbol of string
|
|
||||||
|
|
||||||
(* Numeric types. *)
|
|
||||||
| Sint of int
|
|
||||||
| Sreal of float
|
|
||||||
| Scomplex of Complex.t
|
|
||||||
| Sbigint of Big_int.big_int
|
|
||||||
| Srational of Ratio.ratio
|
|
||||||
|
|
||||||
(* Character. *)
|
|
||||||
| Schar of char
|
|
||||||
|
|
||||||
(* A pair (list element). *)
|
|
||||||
| Spair of spair
|
|
||||||
|
|
||||||
(* Vector. *)
|
|
||||||
| Svector of sval array
|
|
||||||
|
|
||||||
(* Port object. *)
|
|
||||||
| Sport of Ocs_port.port
|
|
||||||
|
|
||||||
(* A closure created by combining the process reference with the
|
|
||||||
local environment at that point of execution. *)
|
|
||||||
| Sproc of sproc * sval array array
|
|
||||||
|
|
||||||
(* Primitive function. *)
|
|
||||||
| Sprim of sprim
|
|
||||||
|
|
||||||
(* Delayed expression. *)
|
|
||||||
| Spromise of spromise
|
|
||||||
|
|
||||||
(* A set of values returned by the 'values' primitive,
|
|
||||||
deconstructed into multiple parameters by call-with-values. *)
|
|
||||||
| Svalues of sval array
|
|
||||||
|
|
||||||
(* A symbol explicitly tied to an environment that defines its scope.
|
|
||||||
These symbols are generated by macro expansions and eliminated
|
|
||||||
prior to evaluation. *)
|
|
||||||
| Sesym of env * sval
|
|
||||||
|
|
||||||
(* Wrapped values are stub functions that encapsulate external values
|
|
||||||
of unknown types. *)
|
|
||||||
| Swrapped of (unit -> unit)
|
|
||||||
|
|
||||||
(* An unspecified value. *)
|
|
||||||
| Sunspec
|
|
||||||
|
|
||||||
(* The actual type of a pair (cons cell). *)
|
|
||||||
and spair =
|
|
||||||
{
|
|
||||||
mutable car : sval;
|
|
||||||
mutable cdr : sval
|
|
||||||
}
|
|
||||||
|
|
||||||
(* Primitive structure. *)
|
|
||||||
and sprim =
|
|
||||||
{
|
|
||||||
prim_fun : primf;
|
|
||||||
prim_name : string
|
|
||||||
}
|
|
||||||
|
|
||||||
(* Primitive function types. *)
|
|
||||||
and primf =
|
|
||||||
(* Simple functional interface to primitives with a small, constant
|
|
||||||
number of arguments. *)
|
|
||||||
Pf0 of (unit -> sval)
|
|
||||||
| Pf1 of (sval -> sval)
|
|
||||||
| Pf2 of (sval -> sval -> sval)
|
|
||||||
| Pf3 of (sval -> sval -> sval -> sval)
|
|
||||||
|
|
||||||
(* Functional interface to primitives with a variable number of arguments. *)
|
|
||||||
| Pfn of (sval array -> sval)
|
|
||||||
|
|
||||||
(* Continuation-based interface to primitives, also includes the thread
|
|
||||||
and supports a variable number of arguments. *)
|
|
||||||
| Pfcn of (thread -> (sval -> unit) -> sval array -> unit)
|
|
||||||
|
|
||||||
(* Procedure structure. *)
|
|
||||||
and sproc =
|
|
||||||
{
|
|
||||||
proc_body : code;
|
|
||||||
proc_nargs : int;
|
|
||||||
proc_has_rest : bool;
|
|
||||||
proc_frame_size : int;
|
|
||||||
mutable proc_name : string
|
|
||||||
}
|
|
||||||
|
|
||||||
(* Delayed expression. *)
|
|
||||||
and spromise =
|
|
||||||
{
|
|
||||||
promise_code : code;
|
|
||||||
mutable promise_val : sval option;
|
|
||||||
mutable promise_th : thread option (* Copy of the thread state *)
|
|
||||||
}
|
|
||||||
|
|
||||||
(* Code types are used to represent analyzed expressions prepared for
|
|
||||||
evaluation. *)
|
|
||||||
and code =
|
|
||||||
Cval of sval
|
|
||||||
| Cseq2 of code * code
|
|
||||||
| Cseq3 of code * code * code
|
|
||||||
| Cseqn of code array
|
|
||||||
| Cand2 of code * code
|
|
||||||
| Cand3 of code * code * code
|
|
||||||
| Candn of code array
|
|
||||||
| Cor2 of code * code
|
|
||||||
| Cor3 of code * code * code
|
|
||||||
| Corn of code array
|
|
||||||
| Cif of code * code * code
|
|
||||||
| Csetg of gvar * code
|
|
||||||
| Csetl of int * int * code
|
|
||||||
| Cdefine of gvar * code
|
|
||||||
| Cgetg of gvar
|
|
||||||
| Cgetl of int * int
|
|
||||||
| Capply0 of code
|
|
||||||
| Capply1 of code * code
|
|
||||||
| Capply2 of code * code * code
|
|
||||||
| Capply3 of code * code * code * code
|
|
||||||
| Capplyn of code * code array
|
|
||||||
| Clambda of sproc
|
|
||||||
| Cqqp of code * code
|
|
||||||
| Cqqv of code array
|
|
||||||
| Cqqvs of code list
|
|
||||||
| Cqqspl of code
|
|
||||||
| Ccond of (code * code) array
|
|
||||||
| Ccondspec of code
|
|
||||||
| Ccase of code * (sval array * code) array
|
|
||||||
| Cdelay of code
|
|
||||||
|
|
||||||
(* Global variable slot. *)
|
|
||||||
and gvar =
|
|
||||||
{
|
|
||||||
mutable g_sym : sval;
|
|
||||||
mutable g_val : sval
|
|
||||||
}
|
|
||||||
|
|
||||||
(* Thread state, used during evaluation. *)
|
|
||||||
and thread =
|
|
||||||
{
|
|
||||||
th_frame : sval array; (* Current local frame. *)
|
|
||||||
th_display : sval array array; (* Current display. *)
|
|
||||||
th_depth : int; (* Display depth. *)
|
|
||||||
th_stdin : sval; (* Default input port. *)
|
|
||||||
th_stdout : sval; (* Default output port. *)
|
|
||||||
th_dynext : dynext option (* Current dynamic extent. *)
|
|
||||||
}
|
|
||||||
|
|
||||||
(* Bindings, used during analysis. *)
|
|
||||||
and vbind =
|
|
||||||
Vglob of gvar
|
|
||||||
| Vloc of int * int
|
|
||||||
| Vsyntax of (env -> sval array -> code)
|
|
||||||
| Vmacro of (env -> sval array -> sval)
|
|
||||||
| Vkeyword of string
|
|
||||||
|
|
||||||
(* Environment, used during analysis. *)
|
|
||||||
and env =
|
|
||||||
{
|
|
||||||
env_depth : int;
|
|
||||||
env_vartable : vbind vartable;
|
|
||||||
env_frame_size : int ref;
|
|
||||||
mutable env_tagged : (env * sval * vbind) list
|
|
||||||
}
|
|
||||||
|
|
||||||
(* Dynamic extents are associated with threads and continuations. *)
|
|
||||||
and dynext =
|
|
||||||
{
|
|
||||||
dynext_parent : dynext option;
|
|
||||||
dynext_depth : int;
|
|
||||||
dynext_before : thread * code;
|
|
||||||
dynext_after : thread * code
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
(* Utility type for variable binding tables. *)
|
|
||||||
|
|
||||||
module VarTable = Map.Make (String)
|
|
||||||
|
|
||||||
type 'a vartable = {
|
|
||||||
vt_global : 'a vartable option;
|
|
||||||
mutable vt_bindings : 'a VarTable.t
|
|
||||||
}
|
|
||||||
|
|
||||||
let vt_create () =
|
|
||||||
{ vt_global = None;
|
|
||||||
vt_bindings = VarTable.empty }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let vt_inherit vt =
|
|
||||||
{ vt_global =
|
|
||||||
if vt.vt_global = None then Some vt
|
|
||||||
else vt.vt_global;
|
|
||||||
vt_bindings = vt.vt_bindings }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let vt_global vt =
|
|
||||||
vt.vt_global = None
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec vt_copy vt vc =
|
|
||||||
{ vt_global =
|
|
||||||
(match vt.vt_global with
|
|
||||||
Some t -> Some (vt_copy t vc)
|
|
||||||
| _ -> None);
|
|
||||||
vt_bindings =
|
|
||||||
VarTable.map vc vt.vt_bindings }
|
|
||||||
;;
|
|
||||||
|
|
||||||
let var_insert vt key r =
|
|
||||||
vt.vt_bindings <- VarTable.add key r vt.vt_bindings
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec var_find vt key =
|
|
||||||
try
|
|
||||||
Some (VarTable.find key vt.vt_bindings)
|
|
||||||
with
|
|
||||||
Not_found ->
|
|
||||||
begin
|
|
||||||
match vt.vt_global with
|
|
||||||
Some x -> var_find x key
|
|
||||||
| _ -> None
|
|
||||||
end
|
|
||||||
;;
|
|
||||||
|
|
||||||
let rec var_get vt key mkvar =
|
|
||||||
try
|
|
||||||
VarTable.find key vt.vt_bindings
|
|
||||||
with
|
|
||||||
Not_found ->
|
|
||||||
begin
|
|
||||||
match vt.vt_global with
|
|
||||||
Some x -> var_get x key mkvar
|
|
||||||
| _ ->
|
|
||||||
let r = mkvar () in
|
|
||||||
var_insert vt key r;
|
|
||||||
r
|
|
||||||
end
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
(* Utility type for variable binding tables. *)
|
|
||||||
|
|
||||||
type 'a vartable
|
|
||||||
|
|
||||||
val vt_create : unit -> 'a vartable
|
|
||||||
val vt_inherit : 'a vartable -> 'a vartable
|
|
||||||
val vt_global : 'a vartable -> bool
|
|
||||||
val vt_copy : 'a vartable -> ('a -> 'a) -> 'a vartable
|
|
||||||
|
|
||||||
val var_insert : 'a vartable -> string -> 'a -> unit
|
|
||||||
val var_find : 'a vartable -> string -> 'a option
|
|
||||||
val var_get : 'a vartable -> string -> (unit -> 'a) -> 'a
|
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
(* Vector primitives. *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
open Ocs_env
|
|
||||||
|
|
||||||
let get_int =
|
|
||||||
function
|
|
||||||
Sint i -> i
|
|
||||||
| _ -> raise (Error "bad arg types")
|
|
||||||
|
|
||||||
let make_vector av =
|
|
||||||
match Array.length av with
|
|
||||||
(1 | 2) as n ->
|
|
||||||
let size = get_int av.(0)
|
|
||||||
and fill = if n = 2 then av.(1) else Snull in
|
|
||||||
Svector (Array.make size fill)
|
|
||||||
| _ -> raise (Error "make-vector: wrong number of args")
|
|
||||||
|
|
||||||
let vector_of v =
|
|
||||||
Svector v
|
|
||||||
;;
|
|
||||||
|
|
||||||
let vector_length =
|
|
||||||
function
|
|
||||||
Svector v -> Sint (Array.length v)
|
|
||||||
| _ -> raise (Error "vector-length: not a vector")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let vector_ref sv i =
|
|
||||||
match (sv, i) with
|
|
||||||
(Svector vec, Sint i) -> vec.(i)
|
|
||||||
| _ -> raise (Error "vector-ref: bad arg types")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let vector_set sv i v =
|
|
||||||
match (sv, i) with
|
|
||||||
(Svector vec, Sint i) -> vec.(i) <- v; Sunspec
|
|
||||||
| _ -> raise (Error "vector-set!: bad arg types")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let vector_to_list =
|
|
||||||
function
|
|
||||||
Svector v ->
|
|
||||||
begin
|
|
||||||
let rec loop i r =
|
|
||||||
if i < 0 then r
|
|
||||||
else loop (i - 1) (Spair { car = v.(i); cdr = r })
|
|
||||||
in
|
|
||||||
loop (Array.length v - 1) Snull
|
|
||||||
end
|
|
||||||
| _ -> raise (Error "vector->list: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let vector_fill sv v =
|
|
||||||
match sv with
|
|
||||||
Svector vec ->
|
|
||||||
for i = 0 to Array.length vec - 1 do
|
|
||||||
vec.(i) <- v
|
|
||||||
done;
|
|
||||||
Sunspec
|
|
||||||
| _ -> raise (Error "vector-fill!: bad args")
|
|
||||||
;;
|
|
||||||
|
|
||||||
let init e =
|
|
||||||
set_pfn e make_vector "make-vector";
|
|
||||||
|
|
||||||
set_pfn e vector_of "vector";
|
|
||||||
|
|
||||||
set_pf1 e vector_length "vector-length";
|
|
||||||
|
|
||||||
set_pf2 e vector_ref "vector-ref";
|
|
||||||
set_pf3 e vector_set "vector-set!";
|
|
||||||
|
|
||||||
set_pf1 e vector_to_list "vector->list";
|
|
||||||
|
|
||||||
set_pf2 e vector_fill "vector-fill!";
|
|
||||||
;;
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
(* Vector primitives *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
|
|
||||||
val init : env -> unit
|
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
(* Functor for creating wrap/unwrap functions *)
|
|
||||||
|
|
||||||
open Ocs_types
|
|
||||||
open Ocs_error
|
|
||||||
|
|
||||||
module Make(T: sig type t end) =
|
|
||||||
struct
|
|
||||||
type t = T.t
|
|
||||||
|
|
||||||
exception E of t
|
|
||||||
|
|
||||||
let wrap v =
|
|
||||||
Swrapped (fun () -> raise (E v))
|
|
||||||
|
|
||||||
let unwrap =
|
|
||||||
function
|
|
||||||
Swrapped f ->
|
|
||||||
(try
|
|
||||||
f ();
|
|
||||||
raise (Error "unwrap: internal error")
|
|
||||||
with E v -> v
|
|
||||||
| _ -> raise (Error "unwrap: wrong wrapped type"))
|
|
||||||
| _ -> raise (Error "unwrap: not a wrapped type")
|
|
||||||
|
|
||||||
let try_unwrap =
|
|
||||||
function
|
|
||||||
Swrapped f ->
|
|
||||||
(try
|
|
||||||
f ();
|
|
||||||
None
|
|
||||||
with E v -> Some v
|
|
||||||
| _ -> None)
|
|
||||||
| _ -> None
|
|
||||||
end
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
type handler = Iobuf.t -> Command.t -> unit
|
||||||
|
|
||||||
|
let handlers = ref []
|
||||||
|
|
||||||
|
let register handler =
|
||||||
|
handlers := !handlers @ [handler]
|
||||||
|
|
||||||
|
let unregister handler =
|
||||||
|
handlers := List.filter ((<>) handler) !handlers
|
||||||
|
|
||||||
|
let handle_command iobuf cmd =
|
||||||
|
let rec loop h =
|
||||||
|
match h with
|
||||||
|
| [] -> ()
|
||||||
|
| handler :: tl ->
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
handler iobuf cmd
|
||||||
|
with _ ->
|
||||||
|
()
|
||||||
|
end;
|
||||||
|
loop tl
|
||||||
|
in
|
||||||
|
loop !handlers
|
|
@ -0,0 +1,5 @@
|
||||||
|
type handler = Iobuf.t -> Command.t -> unit
|
||||||
|
|
||||||
|
val register : handler -> unit
|
||||||
|
val unregister : handler -> unit
|
||||||
|
val handle_command : Iobuf.t -> Command.t -> unit
|
Loading…
Reference in New Issue