| Revision 26009 (by putter, 2009/03/27 03:29:37) |
[elf] elfish/on_sbcl renamed on_lisp to reflect added ccl support. Also renamed the old elfish/elfX to elfX_smop for greater clarity.
|
# This is sort of a hybrid Primitives and Prelude at the moment.
# Class graph
class Bit is Any {}
class Int is Any {}
class Str is Any {}
class Num is Any {}
class Complex is Any {}
class Bool is Any {}
class Code is Any {}
class Block is Code {}
class List is Any {}
class Seq is Any {}
class Range is Any {}
class Set is Any {}
class Bag is Any {}
class Pair is Any {}
class Mapping is Any {}
class Signature is Any {}
class Capture is Any {}
class Blob is Any {}
class Scalar is Any {}
class Array is List {}
class Hash is Any {}
class KeyHash is Any {}
class KeySet is Any {}
class KeyBag is Any {}
class Buf is Any {}
class IO is Any {}
class Routine is Code {}
class Sub is Routine {}
class Method is Routine {}
class Subethod is Routine {}
class Macro is Routine {}
class Regex is Routine {}
class Match is Any {}
class Package is Any {}
class Module is Package {}
class Class is Module {}
class Role is Module {}
class Grammar is Module {}
class Object {}; #XXX does Class
class Any is Object {}
class Junction is Object {}
package GLOBAL {
sub say(*@a) { for @a { print $_; }; print "\n";}
sub print(*@a) { for @a { primitive_print $_.Str }; }
sub primitive_print ($x) is cl {' (cl:write-string (S |$x|)) '}
sub primitive_write_to_string ($x) is cl {' (UP (write-to-string |$x|)) '};
sub undef () is cl {' (undef) '}
multi infix:<+> ($a,$b) is cl {' (UP (+ (N |$a|) (N |$b|))) '}
multi infix:<-> ($a,$b) is cl {' (UP (- (N |$a|) (N |$b|))) '}
multi infix:<*> ($a,$b) is cl {' (UP (* (N |$a|) (N |$b|))) '}
multi infix:</> ($a,$b) is cl {' (UP (/ (N |$a|) (N |$b|))) '}
multi infix:<<> ($a,$b) is cl {' (UP (< (N |$a|) (N |$b|))) '}
multi infix:«>» ($a,$b) is cl {' (UP (> (N |$a|) (N |$b|))) '}
multi infix:<<=> ($a,$b) is cl {' (UP (<= (N |$a|) (N |$b|))) '}
multi infix:«>=» ($a,$b) is cl {' (UP (>= (N |$a|) (N |$b|))) '}
multi infix:<==> ($a,$b) is cl {' (UP (equal (N |$a|) (N |$b|))) '}
multi infix:«!=» ($a,$b) is cl {' (UP (not (equal (N |$a|) (N |$b|)))) '}
multi infix:<eq> ($a,$b) is cl {' (UP (equal (S |$a|) (S |$b|))) '}
multi infix:<ne> ($a,$b) is cl {' (UP (not (equal (S |$a|) (S |$b|)))) '}
multi infix:<~> ($a,$b) { primitive_strcat($a.Str,$b.Str) }
multi primitive_strcat ($a,$b) is cl {' (UP (concatenate \'string (S |$a|) (S |$b|))) '}
multi prefix:<!> ($a) is cl {' (UP (not (to-b |$a|))) '}
multi prefix:<-> ($a) is cl {' (UP (- 0 (N |$a|))) '}
multi prefix:<?> ($a) is cl {' (UP (to-b |$a|)) '}
multi circumfix:«[ ]» (*@a) is cl {' |@a| '}
multi circumfix:«( )» ($a) is cl {' |$a| '}
multi slurp ($filename) is cl {'
(with-open-file (stream (S |$filename|))
(let* ((byte-length (file-length stream))
(buf (make-string byte-length)) ; likely too long
(char-length (read-sequence buf stream))
(str (subseq buf 0 char-length)))
(UP str)))
'}
multi unslurp ($string,$filename) is cl {'
(with-open-file (stream (S |$filename|) :direction :output :if-exists :supersede)
(write-sequence (S |$string|) stream))
'}
multi exit ($status) is cl {'
#+sbcl (sb-unix:unix-exit (N |$status|))
#+ccl (quit (N |$status|))
'}
# multi exit ($status) {}
multi die ($msg) { say $msg; exit(1); }
multi system ($cmd) is cl {'
#+sbcl
(let ((p (sb-ext:run-program "/bin/sh" (list "-c" (S |$cmd|)) :output t)))
(sb-ext:process-wait p)
(UP (sb-ext:process-exit-code p)))
#+ccl
(let ((p (ccl:run-program "/bin/sh" (list "-c" (S |$cmd|)) :wait t :output t)))
(UP (nth-value 1 (ccl:external-process-status p))))
'}
multi unlink (*@filenames) { @filenames.map(sub ($f){unlink_($f)}) }
multi unlink_ ($filename) is cl {'
#+sbcl (sb-unix:unix-unlink (S |$filename|))
#+(or :ccl :clisp) (delete-file (S |$filename|))
'}
multi not ($x) { if $x { undef } else { 1 } }
multi defined ($x) is cl {' (UP (defined-p |$x|)) '}
multi substr($s,$offset,$length) { $s.substr($offset,$length) }
}
# Elf
package GLOBAL {
our $compiler0;
our $compiler1;
our $parser0;
our $parser1;
our $ast2ir_0;
our $ast2ir_1;
our $emitter0;
our $emitter1;
sub fastundump ($dump_string) is cl {'
(let ((tree (read-from-string (S |$dump_string|))))
(labels
((undump (node)
(cond ((null node) nil)
((eq :false node) (undef))
((listp node)
(let ((args (mapcar #\'undump (cdr node))))
(ecase (car node)
(match (ap #\'|M::make_from_rsfth| (cons |Match::/co| args)))
(array (ap #\'|M::new| (cons |Array::/co| args)))
(hash (ap #\'|M::new| (cons |Hash::/co| args))))))
(t (UP node)))))
(undump tree)))
'}
sub parser_format () { "cl" }
sub parser_name () {
my $e = %*ENV{'ELF_STD_RED_RUN'};
if $e { $e }
else {
# XXX
# my $f = $0;
# $f =~ s/[^\/]+$//;
# # $f."elf_h_src/STD_red/STD_red_run"
# $f."../STD_red/STD_red_run"
"../../STD_red/STD_red_run"
}
}
sub private_tidy ($s) { $s }
sub eval_runtime_code($code,$env) is cl {'
(eval (read-from-string (concatenate \'string "(progn " (S |$code|) ")")))
'}
sub file_exists ($filename) is cl {'
(UP (if (probe-file (S |$filename|)) t nil))
'}
sub elf_main () {
Program.new().main(@*ARGS);
exit(0);
}
sub chmod_exe ($file) is cl {'
#+sbcl
(sb-posix:chmod (S |$file|)
(logior sb-posix::s-irusr sb-posix::s-iwusr sb-posix::s-ixusr))
#+ccl
(run-program "/bin/chmod" (list "a+x" (S |$file|)) :wait t :output t)
'}
sub module_require ($module) {
my $file = find_required_module($module);
$file || die("Cant locate $module in ( "~@*INC.join(" ")~" ).\n");
eval_file($file);
};
sub find_required_module ($module) {
my $names = [$module, $module~".pm", $module~".p6"];
for @*INC { my $dir = $_;
for $names { my $name = $_;
my $file = $dir~"/"~$name;
if file_exists($file) {
return $file;
}
}
}
return undef;
}
sub import ($module,*@args) {
undef
}
sub eval_file ($file) {
$*compiler0.eval_file($file);
}
sub eval_perl6 ($code,$env) {
$*compiler0.eval_perl6($code,$env);
}
sub eval ($code,$env) {
eval_perl6($code,$env);
}
}
# regexp elf bootstrap primitives
package Str {
method re_matchp ($re) is cl {' (UP (if (ppcre::scan (S |$re|) (S self)) t nil)) '}
method re_groups ($re) is cl {'
(multiple-value-bind (match_str a) (ppcre::scan-to-strings (S |$re|) (S self))
(declare (ignorable match_str))
(new-Array (mapcar #\'UP (coerce a \'list))))
'}
method re_gsub ($re,$replacement_str) is cl {'
(UP (ppcre::regex-replace-all (S |$re|) (S self) (list (S |$replacement_str|))))
'}
method re_gsub_pat ($re,$replacement_pat) is cl {'
(UP (ppcre::regex-replace-all (S |$re|) (S self)
(parse-re-replacement (S |$replacement_pat|))))
'}
}
# For the Elf P5.
package GLOBAL {
sub mangle_name ($name) is cl {'
; $name =~ s/([^\w])/"_".CORE::ord($1)/eg;
(UP (ppcre::regex-replace-all "([^\\\\w])" (S |$name|)
(lambda (match g1)
(concatenate \'string "_" (write-to-string (char-code (aref g1 0)))))
:simple-calls t))
'}
#sub quotemeta ($str) { $str.re_gsub_pat('([^\\w])','\\\\$1') }
sub quotemeta ($str) is cl {' ;#XXX flee backslash insanity
(UP (ppcre::regex-replace-all "([^\\\\w])" (S |$str|)
(lambda (match g1) (concatenate \'string "\\\\" g1))
:simple-calls t))
'}
}
package Main {
}
class Any {
method say() { say(self) }
method print() { say(self) }
method isa(Str $name) is cl {' (UP (typep self (find-class (pkg-clsname (S |$name|))))) '}
}
class Undef {
}
class Pair {
has $.key; has $.value;
method new ($k,$v) is cl {'
(let ((inst (make-instance \'|Pair/cls|)))
(setf (slot-value inst \'|Pair::.key|) |$k|)
(setf (slot-value inst \'|Pair::.value|) |$v|)
inst)
'}
}
class Int {
has $._native_;
method new ($n) is cl {'
(let ((inst (make-instance \'|Int/cls|)))
(setf (slot-value inst \'|Int::._native_|) (N |$n|))
inst)
'}
}
class Num {
has $._native_;
method new ($n) is cl {'
(let ((inst (make-instance \'|Num/cls|)))
(setf (slot-value inst \'|Num::._native_|) (N |$n|))
inst)
'}
}
class Str {
has $._native_;
method new ($s) is cl {'
(let ((inst (make-instance \'|Str/cls|)))
(setf (slot-value inst \'|Str::._native_|) (S |$s|))
inst)
'}
method split ($pat) is cl {'
(let ((s (slot-value self \'|Str::._native_|)))
(new-Array (mapcar (lambda (x) (UP x))
(ppcre::split (S |$pat|) s))))
'}
method substr ($offset,$length) is cl {'
(let* ((s (slot-value self \'|Str::._native_|))
(len (length s))
(off (wrapped-index len (N |$offset|))))
(UP (subseq s off (min len (+ off (N |$length|))))))
'}
method chars () is cl {'
(let* ((s (slot-value self \'|Str::._native_|))
(len (length s)))
(UP len))
'}
}
class Array {
has $._native_;
method flatten () is cl {'
(coerce (slot-value self \'|Array::._native_|) \'list)
'}
method elems () is cl {'
(UP (length (slot-value self \'|Array::._native_|)))
'}
method push (*@a) is cl {'
(setf (slot-value self \'|Array::._native_|)
(concatenate \'vector
(slot-value self \'|Array::._native_|)
(fc #\'|M::_native_| |@a|)))
self
'}
method unshift (*@a) is cl {'
(setf (slot-value self \'|Array::._native_|)
(concatenate \'vector
(fc #\'|M::_native_| |@a|)
(slot-value self \'|Array::._native_|)))
self
'}
method pop () is cl {'
(let* ((a (slot-value self \'|Array::._native_|))
(len (length a)))
(if (> len 0)
(let ((v (aref a (- len 1))))
(setf (slot-value self \'|Array::._native_|)
(subseq a 0 (- len 1)))
v)
(fc |M::undef|)))
'}
method shift () is cl {'
(let* ((a (slot-value self \'|Array::._native_|))
(len (length a)))
(if (> len 0)
(let ((v (aref a 0)))
(setf (slot-value self \'|Array::._native_|)
(subseq a 1 len))
v)
(fc |GLOBAL::&undef|)))
'}
method STORE ($k,$v) is cl {'
(let* ((a (slot-value self \'|Array::._native_|))
(idx (N |$k|))) ;XXX no wrapping, expansion, etc.
(setf (aref a idx) |$v|))
'}
method postcircumfix:<[ ]> ($k) is cl {'
(let* ((a (slot-value self \'|Array::._native_|))
(len (length a))
(idx (wrapped-index len (N |$k|))))
(rw-able (if idx (aref a idx) (undef)) #\'|M::STORE| self |$k|))
'}
method join ($join_str) is cl {'
(let* ((a (slot-value self \'|Array::._native_|))
(len (length a))
(strs (loop for v across a append (list (S (fc #\'|M::Str| v)) (S |$join_str|)))))
(UP (apply #\'concatenate (cons \'string (subseq strs 0 (max 0 (1- (* 2 len))))))))
'}
method map ($code) is cl {'
(let* ((a (slot-value self \'|Array::._native_|)))
(new-Array (loop for v across a collect (fc |$code| v))))
'}
method splice ($from,$to) is cl {'
(let* ((a (slot-value self \'|Array::._native_|))
(len (length a))
(from (wrapped-index len (N |$from|)))
(to (wrapped-index len (N |$to|))))
(new-Array (coerce (subseq a from to) \'list)))
'}
method reverse () is cl {'
(let* ((a (slot-value self \'|Array::._native_|)))
(new-Array (coerce (reverse a) \'list ))) ;X
'}
method clone () is cl {'
(let* ((a (slot-value self \'|Array::._native_|)))
(new-Array (coerce a \'list )))
'}
}
class Hash {
has $._values_;
has $._keys_;
method new (*@a) is cl {'
(let ((inst (make-instance \'|Hash/cls|))
(hk (make-hash-table :test #\'equal))
(hv (make-hash-table :test #\'equal))
(args (fc #\'|M::_native_| |@a|)))
(setf (slot-value inst \'|Hash::._keys_|) hk)
(setf (slot-value inst \'|Hash::._values_|) hv)
(loop for kv in (size-n-partition 2 args) do
(let* ((k (car kv))
(v (cadr kv))
(h (cl-hash k)))
(setf (gethash h hk) k)
(setf (gethash h hv) v)))
inst)
'}
method dup () is cl {'
(let ((hk (slot-value self \'|Hash::._keys_|))
(hv (slot-value self \'|Hash::._values_|))
(hk2 (make-hash-table :test #\'equal))
(hv2 (make-hash-table :test #\'equal))
(inst (make-instance \'|Hash/cls|)))
(setf (slot-value inst \'|Hash::._keys_|) hk)
(setf (slot-value inst \'|Hash::._values_|) hv)
(maphash #\'(lambda (k v) (setf (gethash k hk2) v)) hk)
(maphash #\'(lambda (k v) (setf (gethash k hv2) v)) hv)
inst)
'}
method kv () is cl {'
(let ((hk (slot-value self \'|Hash::._keys_|))
(hv (slot-value self \'|Hash::._values_|)))
(new-Array (loop for h being the hash-key of hk using (hash-value k)
append (list k (gethash h kv)))))
'}
method pairs () is cl {'
(let ((hk (slot-value self \'|Hash::._keys_|))
(hv (slot-value self \'|Hash::._values_|)))
(new-Array (loop for h being the hash-key of hk using (hash-value k)
collect (new-pair k (gethash h kv)))))
'}
method keys () is cl {'
(let ((hk (slot-value self \'|Hash::._keys_|))
(hv (slot-value self \'|Hash::._values_|)))
(new-Array (loop for k being the hash-value of hk collect k)))
'}
method values () is cl {'
(let ((hk (slot-value self \'|Hash::._keys_|))
(hv (slot-value self \'|Hash::._values_|)))
(new-Array (loop for v being the hash-value of hv collect v)))
'}
method exists ($key) is cl {'
(let ((hk (slot-value self \'|Hash::._keys_|))
(hv (slot-value self \'|Hash::._values_|)))
(UP (if (nth-value 1 (gethash (cl-hash |$key|) hk)) t nil)))
'}
method delete ($key) is cl {'
(let ((hk (slot-value self \'|Hash::._keys_|))
(hv (slot-value self \'|Hash::._values_|))
(h (cl-hash |$key|)))
(remhash h hk)
(remhash h hv))
'}
method clear () is cl {'
(let ((hk (slot-value self \'|Hash::._keys_|))
(hv (slot-value self \'|Hash::._values_|)))
(clrhash hk)
(clrhash hv)
self)
'}
method STORE ($k,$v) is cl {'
(let ((hk (slot-value self \'|Hash::._keys_|))
(hv (slot-value self \'|Hash::._values_|))
(h (cl-hash |$k|)))
(setf (gethash h hk) |$k|)
(setf (gethash h hv) |$v|))
'}
method postcircumfix:<{ }> ($k) is cl {'
(let ((hk (slot-value self \'|Hash::._keys_|))
(hv (slot-value self \'|Hash::._values_|))
(h (cl-hash |$k|)))
(multiple-value-bind (v exists) (gethash h hv)
(rw-able (if exists v (undef)) #\'|M::STORE| self |$k|)))
'}
#method postcircumfix:«< >» ($k) { self.{$k} }
method postcircumfix:«< >» ($k) is cl {'
(fc-preserving-rw #\'|M::postcircumfix:{ }| self |$k|)
'}
method clone () is cl {'
(let ((hk (slot-value self \'|Hash::._keys_|))
(hv (slot-value self \'|Hash::._values_|)))
(new-Hash (loop for h being the hash-key of hk using (hash-value k)
append (list k (gethash h hv)))))
'}
}
# true
class Any { method true() { self.Bool }}
# .Bool()
class Any { method Bool () { 0 == 0 } }
class Bool { method Bool () { self } }
class Int { method Bool () { self != 0 } }
class Num { method Bool () { self != 0 } }
class Str { method Bool () { self ne "" } }
class Array { method Bool () { self.elems != 0 } }
class Hash { method Bool () { self.keys.elems != 0 } }
# .Num()
class Undef { method Num () { 0 } }
class Int { method Num () { self } }
class Num { method Num () { self } }
class Str { method Num () { self.primitive_Num } }
class Array { method Num () { self.elems } }
class Hash { method Num () { self.keys.elems } } ;#X hash-table-count
class Pair { method Num () { 2 } }
# .Str()
class Any { method Str () { primitive_write_to_string(self) } }
class Undef { method Str () { "" } }
class Bool { method Str () { if self { "true" } else { "false " } } }
class True { method Str () { "true" } }
class False { method Str () { "false" } }
class Int { method Str () { primitive_write_to_string(self._native_) } }
class Num { method Str () { primitive_write_to_string(self._native_) } }
class Str { method Str () { self._native_ } }
class Array { method Str () { self.join('') } }
class Hash { method Str () { self.keys.map(sub ($k){$k~"\t"~self.{$k}}).join("\n") } }
class Pair { method Str () { $.key~"\t"~$.value } }
package GLOBAL {
sub _pid is cl {'
#+sbcl (UP (sb-posix:getpid))
#+ccl (UP (ccl::getpid))
'}
our $*PID = _pid();
our @*INC = ('.');
sub _init_ () is cl {'
(setq |GLOBAL::@ARGS|
(new-Array (mapcar #\'UP
#+sbcl (subseq sb-ext:*posix-argv* 1) ;skip "sbcl"
#+ccl ccl::*unprocessed-command-line-arguments*
)))
(defun env ()
(mapcan #\'copy-list
(mapcar (lambda (str)
(let ((pos (position #\= str :test #\'equal)))
(list (UP (subseq str 0 pos))
(UP (subseq str (1+ pos))))))
#+sbcl (posix-environ)
#+ccl (let ((envstr (with-output-to-string (stream)
(run-program "/usr/bin/printenv" nil
:wait t :output stream))))
(with-input-from-string (s envstr)
(loop for line = (read-line s nil nil)
while line collect line)))
)))
(setq |GLOBAL::%ENV| (ap #\'|M::new| (cons |Hash::/co| (env))))
(setq |GLOBAL::$lisp_name| (UP
#+sbcl "sbcl"
#+ccl "ccl"
#+clisp "clisp"
))
'}
_init_();
}