2015-03-12 22:29:55 +00:00
|
|
|
(ero "initializing mu.. (takes ~5s)")
|
2015-01-02 19:34:24 +00:00
|
|
|
;; profiler (http://arclanguage.org/item?id=11556)
|
2015-01-02 19:52:58 +00:00
|
|
|
; Keeping this right on top as a reminder to profile before guessing at why my
|
|
|
|
; program is slow.
|
2015-01-02 19:34:24 +00:00
|
|
|
(mac proc (name params . body)
|
|
|
|
`(def ,name ,params ,@body nil))
|
|
|
|
|
2015-03-13 15:58:40 +00:00
|
|
|
(mac filter-log (msg f x)
|
|
|
|
`(ret x@ ,x
|
|
|
|
(prn ,msg (,f x@))))
|
|
|
|
|
2015-01-02 19:34:24 +00:00
|
|
|
(= times* (table))
|
|
|
|
|
2015-02-16 22:28:23 +00:00
|
|
|
(mac deftimed (name args . body)
|
2015-01-02 19:34:24 +00:00
|
|
|
`(do
|
|
|
|
(def ,(sym (string name "_core")) ,args
|
|
|
|
,@body)
|
|
|
|
(def ,name ,args
|
|
|
|
(let t0 (msec)
|
|
|
|
(ret ans ,(cons (sym (string name "_core")) args)
|
|
|
|
(update-time ,(string name) t0))))))
|
|
|
|
|
|
|
|
(proc update-time(name t0) ; call directly in recursive functions
|
|
|
|
(or= times*.name (list 0 0))
|
|
|
|
(with ((a b) times*.name
|
|
|
|
timing (- (msec) t0))
|
|
|
|
(= times*.name
|
|
|
|
(list
|
|
|
|
(+ a timing)
|
|
|
|
(+ b 1)))))
|
|
|
|
|
|
|
|
(def print-times()
|
2015-01-05 09:21:39 +00:00
|
|
|
(prn (current-process-milliseconds))
|
2015-01-02 19:34:24 +00:00
|
|
|
(prn "gc " (current-gc-milliseconds))
|
|
|
|
(each (name time) (tablist times*)
|
|
|
|
(prn name " " time)))
|
|
|
|
|
2014-10-10 22:09:16 +00:00
|
|
|
;; what happens when our virtual machine starts up
|
2014-08-19 17:31:58 +00:00
|
|
|
(= initialization-fns* (queue))
|
2015-02-16 22:28:23 +00:00
|
|
|
(def reset ()
|
2014-08-19 17:31:58 +00:00
|
|
|
(each f (as cons initialization-fns*)
|
|
|
|
(f)))
|
|
|
|
|
2014-08-29 02:53:41 +00:00
|
|
|
(mac on-init body
|
|
|
|
`(enq (fn () ,@body)
|
|
|
|
initialization-fns*))
|
|
|
|
|
2014-10-10 22:09:16 +00:00
|
|
|
;; persisting and checking traces for each test
|
2014-10-07 17:26:14 +00:00
|
|
|
(= traces* (queue))
|
|
|
|
(= trace-dir* ".traces/")
|
|
|
|
(ensure-dir trace-dir*)
|
|
|
|
(= curr-trace-file* nil)
|
2014-08-29 02:53:41 +00:00
|
|
|
(on-init
|
2014-10-07 17:26:14 +00:00
|
|
|
(awhen curr-trace-file*
|
|
|
|
(tofile (+ trace-dir* it)
|
|
|
|
(each (label trace) (as cons traces*)
|
|
|
|
(pr label ": " trace))))
|
|
|
|
(= curr-trace-file* nil)
|
2014-08-29 03:42:15 +00:00
|
|
|
(= traces* (queue)))
|
2014-10-07 17:26:14 +00:00
|
|
|
|
2015-02-16 22:28:23 +00:00
|
|
|
(def new-trace (filename)
|
2014-12-18 07:10:49 +00:00
|
|
|
(prn "== @filename")
|
2014-11-25 05:40:59 +00:00
|
|
|
;? )
|
2014-10-07 17:26:14 +00:00
|
|
|
(= curr-trace-file* filename))
|
|
|
|
|
2014-10-07 20:26:01 +00:00
|
|
|
(= dump-trace* nil)
|
2015-02-27 03:15:07 +00:00
|
|
|
(def trace (label . args)
|
|
|
|
(when (or (is dump-trace* t)
|
|
|
|
(and dump-trace* (is label "-"))
|
|
|
|
(and dump-trace* (pos label dump-trace*!whitelist))
|
|
|
|
(and dump-trace* (no dump-trace*!whitelist) (~pos label dump-trace*!blacklist)))
|
|
|
|
(apply prn label ": " args))
|
|
|
|
(enq (list label (apply tostring:prn args))
|
|
|
|
traces*)
|
|
|
|
(car args))
|
|
|
|
|
|
|
|
(on-init
|
|
|
|
(wipe dump-trace*))
|
|
|
|
|
|
|
|
(redef tr args ; why am I still returning to prn when debugging? Will this help?
|
|
|
|
(do1 nil
|
|
|
|
(apply trace "-" args)))
|
|
|
|
|
|
|
|
(def tr2 (msg arg)
|
|
|
|
(tr msg arg)
|
|
|
|
arg)
|
2014-11-22 02:21:15 +00:00
|
|
|
|
2015-02-16 22:28:23 +00:00
|
|
|
(def check-trace-contents (msg expected-contents)
|
2014-08-29 03:42:15 +00:00
|
|
|
(unless (trace-contents-match expected-contents)
|
|
|
|
(prn "F - " msg)
|
|
|
|
(prn " trace contents")
|
|
|
|
(print-trace-contents-mismatch expected-contents)))
|
|
|
|
|
2015-02-16 22:28:23 +00:00
|
|
|
(def trace-contents-match (expected-contents)
|
2014-08-29 03:42:15 +00:00
|
|
|
(each (label msg) (as cons traces*)
|
|
|
|
(when (and expected-contents
|
|
|
|
(is label expected-contents.0.0)
|
|
|
|
(posmatch expected-contents.0.1 msg))
|
|
|
|
(pop expected-contents)))
|
|
|
|
(no expected-contents))
|
|
|
|
|
2015-02-16 22:28:23 +00:00
|
|
|
(def print-trace-contents-mismatch (expected-contents)
|
2014-08-29 03:42:15 +00:00
|
|
|
(each (label msg) (as cons traces*)
|
|
|
|
(whenlet (expected-label expected-msg) expected-contents.0
|
|
|
|
(if (and (is label expected-label)
|
|
|
|
(posmatch expected-msg msg))
|
|
|
|
(do (pr " * ")
|
|
|
|
(pop expected-contents))
|
|
|
|
(pr " "))
|
|
|
|
(pr label ": " msg)))
|
|
|
|
(prn " couldn't find")
|
|
|
|
(each (expected-label expected-msg) expected-contents
|
|
|
|
(prn " ! " expected-label ": " expected-msg)))
|
2014-08-29 02:53:41 +00:00
|
|
|
|
2015-02-16 22:28:23 +00:00
|
|
|
(def check-trace-doesnt-contain (msg (label unexpected-contents))
|
2015-01-12 08:04:48 +00:00
|
|
|
(when (some (fn ((l s))
|
|
|
|
(and (is l label) (posmatch unexpected-contents msg)))
|
|
|
|
(as cons traces*))
|
|
|
|
(prn "F - " msg)
|
|
|
|
(prn " trace contents")
|
|
|
|
(each (l msg) (as cons traces*)
|
|
|
|
(if (and (is l label)
|
|
|
|
(posmatch unexpected-contents msg))
|
|
|
|
(pr " X ")
|
|
|
|
(pr " "))
|
|
|
|
(pr label ": " msg))))
|
|
|
|
|
2014-11-25 05:56:12 +00:00
|
|
|
;; virtual machine state
|
|
|
|
|
|
|
|
; things that a future assembler will need separate memory for:
|
|
|
|
; code; types; args channel
|
2014-12-31 03:04:01 +00:00
|
|
|
; at compile time: mapping names to locations
|
2015-01-10 21:10:23 +00:00
|
|
|
(on-init
|
2014-12-30 22:41:12 +00:00
|
|
|
(= type* (table)) ; name -> type info
|
2015-03-13 16:58:22 +00:00
|
|
|
(= memory* (table)) ; address -> value (make this a vector?)
|
2014-12-30 22:41:12 +00:00
|
|
|
(= function* (table)) ; name -> [instructions]
|
2015-01-29 07:28:56 +00:00
|
|
|
; transforming mu programs
|
2015-01-03 02:13:04 +00:00
|
|
|
(= location* (table)) ; function -> {name -> index into default-space}
|
|
|
|
(= next-space-generator* (table)) ; function -> name of function generating next space
|
|
|
|
; each function's next space will usually always come from a single function
|
2015-01-10 21:10:23 +00:00
|
|
|
(= next-routine-id* 0)
|
2015-01-29 07:28:56 +00:00
|
|
|
(= continuation* (table))
|
2014-11-27 13:24:24 +00:00
|
|
|
)
|
2014-11-25 05:56:12 +00:00
|
|
|
|
|
|
|
(on-init
|
2014-12-17 18:52:54 +00:00
|
|
|
(= type* (obj
|
2014-11-25 05:56:12 +00:00
|
|
|
; Each type must be scalar or array, sum or product or primitive
|
|
|
|
type (obj size 1) ; implicitly scalar and primitive
|
2014-12-17 22:03:34 +00:00
|
|
|
type-address (obj size 1 address t elem '(type))
|
|
|
|
type-array (obj array t elem '(type))
|
|
|
|
type-array-address (obj size 1 address t elem '(type-array))
|
|
|
|
location (obj size 1 address t elem '(location)) ; assume it points to an atom
|
2014-11-25 05:56:12 +00:00
|
|
|
integer (obj size 1)
|
|
|
|
boolean (obj size 1)
|
2014-12-17 22:03:34 +00:00
|
|
|
boolean-address (obj size 1 address t elem '(boolean))
|
2014-11-25 05:56:12 +00:00
|
|
|
byte (obj size 1)
|
2014-12-17 22:03:34 +00:00
|
|
|
byte-address (obj size 1 address t elem '(byte))
|
|
|
|
string (obj array t elem '(byte)) ; inspired by Go
|
2014-12-28 20:29:35 +00:00
|
|
|
; an address contains the location of a specific type
|
2014-12-17 22:03:34 +00:00
|
|
|
string-address (obj size 1 address t elem '(string))
|
2014-12-20 06:18:41 +00:00
|
|
|
string-address-address (obj size 1 address t elem '(string-address))
|
|
|
|
string-address-array (obj array t elem '(string-address))
|
|
|
|
string-address-array-address (obj size 1 address t elem '(string-address-array))
|
2015-02-08 08:42:07 +00:00
|
|
|
string-address-array-address-address (obj size 1 address t elem '(string-address-array-address))
|
2015-02-08 19:12:08 +00:00
|
|
|
; 'character' will be of larger size when mu supports unicode
|
|
|
|
; we're currently undisciplined about mixing 'byte' and 'character'
|
|
|
|
; realistic test of indiscipline in general
|
2014-11-25 05:56:12 +00:00
|
|
|
character (obj size 1) ; int32 like a Go rune
|
2014-12-17 22:03:34 +00:00
|
|
|
character-address (obj size 1 address t elem '(character))
|
2015-01-29 18:13:35 +00:00
|
|
|
; a buffer makes it easy to append to a string/array
|
|
|
|
; todo: make this generic
|
2015-01-30 07:19:22 +00:00
|
|
|
; data isn't a 'real' array: its length is stored outside it,
|
|
|
|
; so for example, 'print-string' won't work on it.
|
2015-01-17 23:41:24 +00:00
|
|
|
buffer (obj size 2 and-record t elems '((integer) (string-address)) fields '(length data))
|
|
|
|
buffer-address (obj size 1 address t elem '(buffer))
|
2015-02-08 08:42:07 +00:00
|
|
|
; a stream makes it easy to read from a string/array
|
|
|
|
stream (obj size 2 and-record t elems '((integer) (string-address)) fields '(pointer data))
|
|
|
|
stream-address (obj size 1 address t elem '(stream))
|
2014-11-25 05:56:12 +00:00
|
|
|
; isolating function calls
|
2015-01-03 02:13:04 +00:00
|
|
|
space (obj array t elem '(location)) ; by convention index 0 points to outer space
|
|
|
|
space-address (obj size 1 address t elem '(space))
|
2014-12-28 20:29:35 +00:00
|
|
|
; arrays consist of an integer length followed by that many
|
|
|
|
; elements, all of the same type
|
2014-12-17 22:03:34 +00:00
|
|
|
integer-array (obj array t elem '(integer))
|
|
|
|
integer-array-address (obj size 1 address t elem '(integer-array))
|
|
|
|
integer-array-address-address (obj size 1 address t elem '(integer-array-address))
|
|
|
|
integer-address (obj size 1 address t elem '(integer)) ; pointer to int
|
|
|
|
integer-address-address (obj size 1 address t elem '(integer-address))
|
2014-12-28 20:29:35 +00:00
|
|
|
; and-records consist of a multiple fields of different types
|
2014-12-17 22:03:34 +00:00
|
|
|
integer-boolean-pair (obj size 2 and-record t elems '((integer) (boolean)) fields '(int bool))
|
|
|
|
integer-boolean-pair-address (obj size 1 address t elem '(integer-boolean-pair))
|
|
|
|
integer-boolean-pair-array (obj array t elem '(integer-boolean-pair))
|
|
|
|
integer-boolean-pair-array-address (obj size 1 address t elem '(integer-boolean-pair-array))
|
|
|
|
integer-integer-pair (obj size 2 and-record t elems '((integer) (integer)))
|
2015-01-01 05:24:48 +00:00
|
|
|
integer-integer-pair-address (obj size 1 address t elem '(integer-integer-pair))
|
2014-12-17 22:03:34 +00:00
|
|
|
integer-point-pair (obj size 2 and-record t elems '((integer) (integer-integer-pair)))
|
|
|
|
integer-point-pair-address (obj size 1 address t elem '(integer-point-pair))
|
|
|
|
integer-point-pair-address-address (obj size 1 address t elem '(integer-point-pair-address))
|
2014-11-25 05:56:12 +00:00
|
|
|
; tagged-values are the foundation of dynamic types
|
2014-12-17 22:03:34 +00:00
|
|
|
tagged-value (obj size 2 and-record t elems '((type) (location)) fields '(type payload))
|
|
|
|
tagged-value-address (obj size 1 address t elem '(tagged-value))
|
|
|
|
tagged-value-array (obj array t elem '(tagged-value))
|
|
|
|
tagged-value-array-address (obj size 1 address t elem '(tagged-value-array))
|
|
|
|
tagged-value-array-address-address (obj size 1 address t elem '(tagged-value-array-address))
|
2014-11-25 05:56:12 +00:00
|
|
|
; heterogeneous lists
|
2014-12-17 22:03:34 +00:00
|
|
|
list (obj size 2 and-record t elems '((tagged-value) (list-address)) fields '(car cdr))
|
|
|
|
list-address (obj size 1 address t elem '(list))
|
|
|
|
list-address-address (obj size 1 address t elem '(list-address))
|
2014-11-25 05:56:12 +00:00
|
|
|
; parallel routines use channels to synchronize
|
2014-12-17 22:03:34 +00:00
|
|
|
channel (obj size 3 and-record t elems '((integer) (integer) (tagged-value-array-address)) fields '(first-full first-free circular-buffer))
|
2014-12-28 23:57:55 +00:00
|
|
|
; be careful of accidental copies to channels
|
2014-12-17 22:03:34 +00:00
|
|
|
channel-address (obj size 1 address t elem '(channel))
|
2015-01-29 07:28:56 +00:00
|
|
|
; opaque pointer to a call stack
|
|
|
|
; todo: save properly in allocated memory
|
|
|
|
continuation (obj size 1)
|
2014-11-25 05:56:12 +00:00
|
|
|
; editor
|
2014-12-17 22:03:34 +00:00
|
|
|
line (obj array t elem '(character))
|
|
|
|
line-address (obj size 1 address t elem '(line))
|
|
|
|
line-address-address (obj size 1 address t elem '(line-address))
|
|
|
|
screen (obj array t elem '(line-address))
|
|
|
|
screen-address (obj size 1 address t elem '(screen))
|
2015-01-23 02:01:45 +00:00
|
|
|
; fake screen
|
2015-01-18 02:50:32 +00:00
|
|
|
terminal (obj size 5 and-record t elems '((integer) (integer) (integer) (integer) (string-address)) fields '(num-rows num-cols cursor-row cursor-col data))
|
2015-01-15 08:00:46 +00:00
|
|
|
terminal-address (obj size 1 address t elem '(terminal))
|
2015-01-23 02:01:45 +00:00
|
|
|
; fake keyboard
|
|
|
|
keyboard (obj size 2 and-record t elems '((integer) (string-address)) fields '(index data))
|
|
|
|
keyboard-address (obj size 1 address t elem '(keyboard))
|
2014-11-25 05:56:12 +00:00
|
|
|
)))
|
2014-07-06 07:07:03 +00:00
|
|
|
|
2014-11-06 18:22:33 +00:00
|
|
|
;; managing concurrent routines
|
2014-11-06 23:24:00 +00:00
|
|
|
|
2014-12-29 17:15:42 +00:00
|
|
|
(on-init
|
2015-01-21 09:23:57 +00:00
|
|
|
;? (prn "-- resetting memory allocation")
|
2015-01-26 10:40:35 +00:00
|
|
|
(= Memory-allocated-until 1000)
|
|
|
|
(= Allocation-chunk 100000))
|
2014-12-29 17:15:42 +00:00
|
|
|
|
2014-11-06 23:24:00 +00:00
|
|
|
; routine = runtime state for a serial thread of execution
|
2014-11-19 08:19:57 +00:00
|
|
|
(def make-routine (fn-name . args)
|
2015-01-18 00:15:25 +00:00
|
|
|
(let curr-alloc Memory-allocated-until
|
2015-01-21 09:23:57 +00:00
|
|
|
;? (prn "-- allocating routine: @curr-alloc")
|
2015-01-26 10:40:35 +00:00
|
|
|
(++ Memory-allocated-until Allocation-chunk)
|
2015-01-18 00:15:25 +00:00
|
|
|
(annotate 'routine (obj alloc curr-alloc alloc-max Memory-allocated-until
|
2015-01-10 11:32:14 +00:00
|
|
|
call-stack
|
|
|
|
(list (obj fn-name fn-name pc 0 args args caller-arg-idx 0))))
|
|
|
|
; other fields we use in routine:
|
|
|
|
; sleep: conditions
|
|
|
|
; limit: number of cycles this routine can use
|
|
|
|
; running-since: start of the clock for counting cycles this routine has used
|
|
|
|
|
2014-12-29 17:17:12 +00:00
|
|
|
; todo: do memory management in mu
|
2015-01-18 00:15:25 +00:00
|
|
|
))
|
2014-11-06 23:24:00 +00:00
|
|
|
|
|
|
|
(defextend empty (x) (isa x 'routine)
|
|
|
|
(no rep.x!call-stack))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def stack (routine)
|
2014-11-06 23:24:00 +00:00
|
|
|
((rep routine) 'call-stack))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def push-stack (routine op)
|
2015-02-16 20:40:25 +00:00
|
|
|
(push (obj fn-name op pc 0 caller-arg-idx 0 t0 (msec))
|
2015-02-16 20:10:54 +00:00
|
|
|
rep.routine!call-stack))
|
2014-11-06 23:24:00 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def pop-stack (routine)
|
2015-02-16 22:24:38 +00:00
|
|
|
;? (update-time label.routine (msec)) ;? 1
|
2015-02-16 20:10:54 +00:00
|
|
|
(pop rep.routine!call-stack))
|
2014-11-06 23:24:00 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def top (routine)
|
2014-11-06 23:24:00 +00:00
|
|
|
stack.routine.0)
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def label (routine)
|
2015-02-16 22:24:38 +00:00
|
|
|
(whenlet stack stack.routine
|
|
|
|
(or= stack.0!label
|
|
|
|
(label2 stack))))
|
2015-02-27 03:15:07 +00:00
|
|
|
(def label2 (stack)
|
2015-02-16 22:24:38 +00:00
|
|
|
(string:intersperse "/" (map [_ 'fn-name] stack)));))
|
2015-01-24 21:43:20 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def body (routine)
|
2015-01-02 19:34:24 +00:00
|
|
|
(function* stack.routine.0!fn-name))
|
2014-11-06 23:24:00 +00:00
|
|
|
|
|
|
|
(mac pc (routine (o idx 0)) ; assignable
|
|
|
|
`((((rep ,routine) 'call-stack) ,idx) 'pc))
|
|
|
|
|
|
|
|
(mac caller-arg-idx (routine (o idx 0)) ; assignable
|
|
|
|
`((((rep ,routine) 'call-stack) ,idx) 'caller-arg-idx))
|
|
|
|
|
|
|
|
(mac caller-args (routine) ; assignable
|
|
|
|
`((((rep ,routine) 'call-stack) 0) 'args))
|
2014-12-24 09:00:36 +00:00
|
|
|
(mac caller-operands (routine) ; assignable
|
|
|
|
`((((rep ,routine) 'call-stack) 0) 'caller-operands))
|
|
|
|
(mac caller-results (routine) ; assignable
|
|
|
|
`((((rep ,routine) 'call-stack) 0) 'caller-results))
|
2014-11-06 23:24:00 +00:00
|
|
|
|
|
|
|
(mac results (routine) ; assignable
|
|
|
|
`((((rep ,routine) 'call-stack) 0) 'results))
|
2015-01-26 06:56:53 +00:00
|
|
|
(mac reply-args (routine) ; assignable
|
2015-01-26 00:40:11 +00:00
|
|
|
`((((rep ,routine) 'call-stack) 0) 'reply-args))
|
2014-11-06 23:24:00 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def waiting-for-exact-cycle? (routine)
|
2015-01-10 21:20:13 +00:00
|
|
|
(is 'until rep.routine!sleep.0))
|
2014-11-22 03:29:37 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def ready-to-wake-up (routine)
|
2014-11-22 04:25:41 +00:00
|
|
|
(assert no.routine*)
|
2015-01-09 07:21:56 +00:00
|
|
|
(case rep.routine!sleep.0
|
2015-01-10 21:20:13 +00:00
|
|
|
until
|
2015-01-09 07:21:56 +00:00
|
|
|
(> curr-cycle* rep.routine!sleep.1)
|
|
|
|
until-location-changes
|
|
|
|
(~is rep.routine!sleep.2 (memory* rep.routine!sleep.1))
|
2015-01-10 21:49:16 +00:00
|
|
|
until-routine-done
|
|
|
|
(find [and _ (is rep._!id rep.routine!sleep.1)]
|
|
|
|
completed-routines*)
|
2015-01-09 08:48:13 +00:00
|
|
|
))
|
2014-11-22 04:25:41 +00:00
|
|
|
|
2014-11-06 18:22:33 +00:00
|
|
|
(on-init
|
2014-11-21 22:36:22 +00:00
|
|
|
(= running-routines* (queue)) ; simple round-robin scheduler
|
2014-11-06 23:38:00 +00:00
|
|
|
; set of sleeping routines; don't modify routines while they're in this table
|
|
|
|
(= sleeping-routines* (table))
|
2014-11-21 22:36:22 +00:00
|
|
|
(= completed-routines* nil) ; audit trail
|
2014-11-06 18:22:33 +00:00
|
|
|
(= routine* nil)
|
2014-11-06 19:36:16 +00:00
|
|
|
(= abort-routine* (parameter nil))
|
2014-11-06 23:24:16 +00:00
|
|
|
(= curr-cycle* 0)
|
|
|
|
(= scheduling-interval* 500)
|
2015-02-04 05:05:49 +00:00
|
|
|
(= scheduler-switch-table* nil) ; hook into scheduler for debugging
|
2014-11-06 23:24:16 +00:00
|
|
|
)
|
2014-11-06 18:22:33 +00:00
|
|
|
|
|
|
|
; like arc's 'point' but you can also call ((abort-routine*)) in nested calls
|
|
|
|
(mac routine-mark body
|
|
|
|
(w/uniq (g p)
|
|
|
|
`(ccc (fn (,g)
|
|
|
|
(parameterize abort-routine* (fn ((o ,p)) (,g ,p))
|
|
|
|
,@body)))))
|
|
|
|
|
|
|
|
(def run fn-names
|
2014-12-30 23:13:51 +00:00
|
|
|
(freeze function*)
|
2015-02-11 19:52:56 +00:00
|
|
|
;? (prn function*!main) ;? 1
|
2014-12-30 23:13:51 +00:00
|
|
|
(load-system-functions)
|
2015-02-11 09:09:07 +00:00
|
|
|
(apply run-more fn-names))
|
|
|
|
|
|
|
|
; assume we've already frozen; throw on a few more routines and continue scheduling
|
|
|
|
(def run-more fn-names
|
2014-11-06 19:36:16 +00:00
|
|
|
(each it fn-names
|
|
|
|
(enq make-routine.it running-routines*))
|
2014-11-21 22:36:22 +00:00
|
|
|
(while (~empty running-routines*)
|
2014-11-06 19:36:16 +00:00
|
|
|
(= routine* deq.running-routines*)
|
2015-01-10 11:32:14 +00:00
|
|
|
(when rep.routine*!limit
|
|
|
|
; start the clock if it wasn't already running
|
|
|
|
(or= rep.routine*!running-since curr-cycle*))
|
2015-01-25 04:30:25 +00:00
|
|
|
(trace "schedule" label.routine*)
|
2014-11-21 22:36:22 +00:00
|
|
|
(routine-mark
|
|
|
|
(run-for-time-slice scheduling-interval*))
|
2015-02-11 09:09:07 +00:00
|
|
|
(update-scheduler-state)))
|
2014-11-21 22:36:22 +00:00
|
|
|
|
|
|
|
; prepare next iteration of round-robin scheduler
|
|
|
|
;
|
|
|
|
; state before: routine* running-routines* sleeping-routines*
|
|
|
|
; state after: running-routines* (with next routine to run at head) sleeping-routines*
|
|
|
|
;
|
|
|
|
; responsibilities:
|
|
|
|
; add routine* to either running-routines* or sleeping-routines* or completed-routines*
|
2014-12-28 23:57:55 +00:00
|
|
|
; wake up any necessary sleeping routines (which might be waiting for a
|
|
|
|
; particular time or for a particular memory location to change)
|
2015-01-12 08:04:48 +00:00
|
|
|
; detect termination: all non-helper routines completed
|
2014-11-21 22:36:22 +00:00
|
|
|
; detect deadlock: kill all sleeping routines when none can be woken
|
2015-02-27 03:15:07 +00:00
|
|
|
(def update-scheduler-state ()
|
2014-11-22 02:31:48 +00:00
|
|
|
(when routine*
|
2015-01-21 20:33:36 +00:00
|
|
|
;? (prn "update scheduler state: " routine*)
|
2014-11-22 02:31:48 +00:00
|
|
|
(if
|
|
|
|
rep.routine*!sleep
|
2015-01-24 21:43:20 +00:00
|
|
|
(do (trace "schedule" "pushing " label.routine* " to sleep queue")
|
2015-01-10 11:32:14 +00:00
|
|
|
; keep the clock ticking at rep.routine*!running-since
|
2015-01-21 10:01:54 +00:00
|
|
|
(set sleeping-routines*.routine*))
|
2015-01-12 02:44:32 +00:00
|
|
|
rep.routine*!error
|
2015-01-24 21:43:20 +00:00
|
|
|
(do (trace "schedule" "done with dead routine " label.routine*)
|
2015-01-12 07:36:10 +00:00
|
|
|
;? (tr rep.routine*)
|
2015-01-12 02:44:32 +00:00
|
|
|
(push routine* completed-routines*))
|
2015-01-21 20:33:36 +00:00
|
|
|
empty.routine*
|
2015-01-24 21:43:20 +00:00
|
|
|
(do (trace "schedule" "done with routine " label.routine*)
|
2015-01-21 20:33:36 +00:00
|
|
|
(push routine* completed-routines*))
|
2015-01-12 02:41:23 +00:00
|
|
|
(no rep.routine*!limit)
|
2015-01-24 21:43:20 +00:00
|
|
|
(do (trace "schedule" "scheduling " label.routine* " for further processing")
|
2014-11-22 02:31:48 +00:00
|
|
|
(enq routine* running-routines*))
|
2015-01-12 02:41:23 +00:00
|
|
|
(> rep.routine*!limit 0)
|
2015-01-24 21:43:20 +00:00
|
|
|
(do (trace "schedule" "scheduling " label.routine* " for further processing (limit)")
|
2015-01-10 11:32:14 +00:00
|
|
|
; stop the clock and debit the time on it from the routine
|
|
|
|
(-- rep.routine*!limit (- curr-cycle* rep.routine*!running-since))
|
|
|
|
(wipe rep.routine*!running-since)
|
|
|
|
(if (<= rep.routine*!limit 0)
|
|
|
|
(do (trace "schedule" "routine ran out of time")
|
|
|
|
(push routine* completed-routines*))
|
|
|
|
(enq routine* running-routines*)))
|
2014-11-22 02:31:48 +00:00
|
|
|
:else
|
2015-01-12 02:41:23 +00:00
|
|
|
(err "illegal scheduler state"))
|
2014-11-22 02:31:48 +00:00
|
|
|
(= routine* nil))
|
2015-01-25 07:36:30 +00:00
|
|
|
(each (routine _) routine-canon.sleeping-routines*
|
2015-01-10 11:32:14 +00:00
|
|
|
(when (aand rep.routine!limit (<= it (- curr-cycle* rep.routine!running-since)))
|
|
|
|
(trace "schedule" "routine timed out")
|
|
|
|
(wipe sleeping-routines*.routine)
|
|
|
|
(push routine completed-routines*)
|
|
|
|
;? (tr completed-routines*)
|
|
|
|
))
|
2015-01-25 07:36:30 +00:00
|
|
|
(each (routine _) routine-canon.sleeping-routines*
|
2014-11-22 04:25:41 +00:00
|
|
|
(when (ready-to-wake-up routine)
|
2015-01-24 21:43:20 +00:00
|
|
|
(trace "schedule" "waking up " label.routine)
|
2014-11-22 04:25:41 +00:00
|
|
|
(wipe sleeping-routines*.routine) ; do this before modifying routine
|
|
|
|
(wipe rep.routine!sleep)
|
|
|
|
(++ pc.routine)
|
|
|
|
(enq routine running-routines*)))
|
2015-01-10 11:32:14 +00:00
|
|
|
; optimization for simulated time
|
2014-11-22 03:29:37 +00:00
|
|
|
(when (empty running-routines*)
|
|
|
|
(whenlet exact-sleeping-routines (keep waiting-for-exact-cycle? keys.sleeping-routines*)
|
2015-01-09 07:21:56 +00:00
|
|
|
(let next-wakeup-cycle (apply min (map [rep._!sleep 1] exact-sleeping-routines))
|
2015-01-12 07:37:19 +00:00
|
|
|
(= curr-cycle* (+ 1 next-wakeup-cycle)))
|
|
|
|
(trace "schedule" "skipping to cycle " curr-cycle*)
|
|
|
|
(update-scheduler-state)))
|
2015-01-12 08:04:48 +00:00
|
|
|
(when (and (or (~empty running-routines*)
|
|
|
|
(~empty sleeping-routines*))
|
|
|
|
(all [rep._ 'helper] (as cons running-routines*))
|
2015-01-12 06:54:51 +00:00
|
|
|
(all [rep._ 'helper] keys.sleeping-routines*))
|
2015-01-12 08:04:48 +00:00
|
|
|
(trace "schedule" "just helpers left; stopping everything")
|
2015-01-12 06:54:51 +00:00
|
|
|
(until (empty running-routines*)
|
2015-01-21 10:01:54 +00:00
|
|
|
(push (deq running-routines*) completed-routines*))
|
2015-01-12 08:04:48 +00:00
|
|
|
(each (routine _) sleeping-routines*
|
2015-01-25 04:30:25 +00:00
|
|
|
;? (prn " " label.routine) ;? 0
|
2015-01-12 08:04:48 +00:00
|
|
|
(wipe sleeping-routines*.routine)
|
|
|
|
(push routine completed-routines*)))
|
2014-12-04 10:50:33 +00:00
|
|
|
(detect-deadlock)
|
|
|
|
)
|
2014-11-21 22:36:22 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def detect-deadlock ()
|
2014-11-22 07:43:27 +00:00
|
|
|
(when (and (empty running-routines*)
|
|
|
|
(~empty sleeping-routines*)
|
2014-11-08 05:39:00 +00:00
|
|
|
(~some 'literal (map (fn(_) rep._!sleep.1)
|
|
|
|
keys.sleeping-routines*)))
|
|
|
|
(each (routine _) sleeping-routines*
|
|
|
|
(wipe sleeping-routines*.routine)
|
|
|
|
(= rep.routine!error "deadlock detected")
|
2014-11-22 04:47:48 +00:00
|
|
|
(push routine completed-routines*))))
|
2014-11-08 05:39:00 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def die (msg)
|
2014-11-29 09:38:54 +00:00
|
|
|
(tr "die: " msg)
|
2014-11-06 18:22:33 +00:00
|
|
|
(= rep.routine*!error msg)
|
2014-11-29 01:43:33 +00:00
|
|
|
(iflet abort-continuation (abort-routine*)
|
|
|
|
(abort-continuation)))
|
2014-11-06 18:22:33 +00:00
|
|
|
|
|
|
|
;; running a single routine
|
2014-11-29 02:02:16 +00:00
|
|
|
|
2014-12-14 20:36:42 +00:00
|
|
|
; value of an arg or oarg, stripping away all metadata
|
|
|
|
; wish I could have this flag an error when arg is incorrectly formed
|
2014-10-29 07:18:58 +00:00
|
|
|
(mac v (operand) ; for value
|
2014-12-13 10:07:48 +00:00
|
|
|
`((,operand 0) 0))
|
2014-07-31 08:53:14 +00:00
|
|
|
|
2014-12-14 17:46:49 +00:00
|
|
|
; routines consist of instrs
|
|
|
|
; instrs consist of oargs, op and args
|
2015-02-27 03:15:07 +00:00
|
|
|
(def parse-instr (instr)
|
2014-12-14 17:46:49 +00:00
|
|
|
(iflet delim (pos '<- instr)
|
2015-02-24 08:29:26 +00:00
|
|
|
(do (when (atom (instr (+ delim 1)))
|
|
|
|
(err "operator not tokenized in @instr; maybe you need to freeze functions*?"))
|
|
|
|
(list (cut instr 0 delim) ; oargs
|
|
|
|
(v (instr (+ delim 1))) ; op
|
|
|
|
(cut instr (+ delim 2)))) ; args
|
2014-12-14 17:46:49 +00:00
|
|
|
(list nil (v car.instr) cdr.instr)))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def metadata (operand)
|
2014-08-21 02:49:05 +00:00
|
|
|
cdr.operand)
|
2014-07-31 09:27:41 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def ty (operand)
|
2014-12-13 10:07:48 +00:00
|
|
|
(cdr operand.0))
|
2014-07-31 08:53:14 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def literal? (operand)
|
2015-01-30 07:19:22 +00:00
|
|
|
(unless (acons ty.operand)
|
|
|
|
(err "no type in operand @operand"))
|
2014-12-28 22:07:30 +00:00
|
|
|
(in ty.operand.0 'literal 'offset 'fn))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def typeinfo (operand)
|
2014-12-17 18:52:54 +00:00
|
|
|
(or (type* ty.operand.0)
|
2014-11-07 08:59:23 +00:00
|
|
|
(err "unknown type @(tostring prn.operand)")))
|
2014-08-22 02:55:16 +00:00
|
|
|
|
2014-12-14 20:36:42 +00:00
|
|
|
; operand accessors
|
2015-02-27 03:15:07 +00:00
|
|
|
(def nondummy (operand) ; precondition for helpers below
|
2014-12-14 20:36:42 +00:00
|
|
|
(~is '_ operand))
|
|
|
|
|
|
|
|
; just for convenience, 'new' instruction sometimes takes a raw string and
|
|
|
|
; allocates just enough space to store it
|
2015-02-27 03:15:07 +00:00
|
|
|
(def not-raw-string (operand)
|
2014-12-14 20:36:42 +00:00
|
|
|
(~isa operand 'string))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def address? (operand)
|
2014-12-18 07:14:58 +00:00
|
|
|
(or (is ty.operand.0 'location)
|
|
|
|
typeinfo.operand!address))
|
|
|
|
|
2014-10-05 03:18:55 +00:00
|
|
|
($:require "charterm/main.rkt")
|
2014-12-24 07:38:16 +00:00
|
|
|
($:require graphics/graphics)
|
2015-01-27 09:21:29 +00:00
|
|
|
;? ($:require "terminal-color/terminal-color/main.rkt") ;? 1
|
2014-12-24 07:38:16 +00:00
|
|
|
(= Viewport nil)
|
2015-01-27 09:21:29 +00:00
|
|
|
; http://rosettacode.org/wiki/Terminal_control/Coloured_text#Racket
|
|
|
|
($:define (tput . xs) (system (apply ~a 'tput " " (add-between xs " "))) (void))
|
|
|
|
($:define (foreground color) (tput 'setaf color))
|
|
|
|
($:define (background color) (tput 'setab color))
|
|
|
|
($:define (reset) (tput 'sgr0))
|
2014-10-05 03:18:55 +00:00
|
|
|
|
2015-03-13 15:58:40 +00:00
|
|
|
(= new-string-foo* nil)
|
|
|
|
|
2014-11-29 02:02:16 +00:00
|
|
|
; run instructions from 'routine*' for 'time-slice'
|
2015-02-27 03:15:07 +00:00
|
|
|
(def run-for-time-slice (time-slice)
|
2014-08-28 23:40:28 +00:00
|
|
|
(point return
|
2014-08-28 23:47:09 +00:00
|
|
|
(for ninstrs 0 (< ninstrs time-slice) (++ ninstrs)
|
2014-10-29 20:05:08 +00:00
|
|
|
(if (empty body.routine*) (err "@stack.routine*.0!fn-name not defined"))
|
2014-12-26 03:39:32 +00:00
|
|
|
; falling out of end of function = implicit reply
|
2014-10-29 20:05:08 +00:00
|
|
|
(while (>= pc.routine* (len body.routine*))
|
|
|
|
(pop-stack routine*)
|
|
|
|
(if empty.routine* (return ninstrs))
|
2014-12-31 02:51:34 +00:00
|
|
|
(when (pos '<- (body.routine* pc.routine*))
|
2015-01-14 05:14:52 +00:00
|
|
|
(die "No results returned: @(tostring:pr (body.routine* pc.routine*))"))
|
2014-10-29 20:05:08 +00:00
|
|
|
(++ pc.routine*))
|
2014-11-06 19:36:16 +00:00
|
|
|
(++ curr-cycle*)
|
2015-01-25 19:38:13 +00:00
|
|
|
;? (trace "run" "-- " int-canon.memory*) ;? 1
|
2015-02-04 05:05:49 +00:00
|
|
|
;? (trace "run" curr-cycle*)
|
|
|
|
(trace "run" label.routine* " " pc.routine* ": " (body.routine* pc.routine*))
|
2014-11-01 00:35:24 +00:00
|
|
|
;? (trace "run" routine*)
|
2014-11-23 06:26:11 +00:00
|
|
|
(when (atom (body.routine* pc.routine*)) ; label
|
2015-02-23 08:45:35 +00:00
|
|
|
;? (tr "label") ;? 1
|
2014-11-23 15:19:14 +00:00
|
|
|
(when (aand scheduler-switch-table*
|
|
|
|
(alref it (body.routine* pc.routine*)))
|
|
|
|
(++ pc.routine*)
|
2015-02-04 05:05:49 +00:00
|
|
|
(trace "run" label.routine* " " pc.routine* ": " "context-switch forced " abort-routine*)
|
2014-11-23 15:19:14 +00:00
|
|
|
((abort-routine*)))
|
2014-11-23 06:26:11 +00:00
|
|
|
(++ pc.routine*)
|
|
|
|
(continue))
|
2014-10-29 20:05:08 +00:00
|
|
|
(let (oarg op arg) (parse-instr (body.routine* pc.routine*))
|
2015-02-23 08:45:35 +00:00
|
|
|
;? (tr op) ;? 1
|
2014-11-18 18:53:33 +00:00
|
|
|
(let results
|
2014-07-31 10:46:05 +00:00
|
|
|
(case op
|
2014-10-10 22:04:14 +00:00
|
|
|
; arithmetic
|
2014-07-31 10:46:05 +00:00
|
|
|
add
|
|
|
|
(+ (m arg.0) (m arg.1))
|
2014-12-13 01:54:31 +00:00
|
|
|
subtract
|
2014-07-31 10:46:05 +00:00
|
|
|
(- (m arg.0) (m arg.1))
|
2014-12-13 01:54:31 +00:00
|
|
|
multiply
|
2014-07-31 10:46:05 +00:00
|
|
|
(* (m arg.0) (m arg.1))
|
2014-12-13 01:54:31 +00:00
|
|
|
divide
|
2014-07-31 10:46:05 +00:00
|
|
|
(/ (real (m arg.0)) (m arg.1))
|
2014-12-13 01:54:31 +00:00
|
|
|
divide-with-remainder
|
2014-08-27 05:00:23 +00:00
|
|
|
(list (trunc:/ (m arg.0) (m arg.1))
|
|
|
|
(mod (m arg.0) (m arg.1)))
|
2014-10-10 22:04:14 +00:00
|
|
|
|
|
|
|
; boolean
|
2014-07-31 10:46:05 +00:00
|
|
|
and
|
|
|
|
(and (m arg.0) (m arg.1))
|
|
|
|
or
|
|
|
|
(or (m arg.0) (m arg.1))
|
|
|
|
not
|
|
|
|
(not (m arg.0))
|
2014-10-10 22:04:14 +00:00
|
|
|
|
|
|
|
; comparison
|
2014-12-13 01:54:31 +00:00
|
|
|
equal
|
2015-01-12 06:03:16 +00:00
|
|
|
;? (do (prn (m arg.0) " vs " (m arg.1))
|
2014-07-31 10:46:05 +00:00
|
|
|
(is (m arg.0) (m arg.1))
|
2015-01-12 06:03:16 +00:00
|
|
|
;? )
|
2014-12-13 01:54:31 +00:00
|
|
|
not-equal
|
2014-07-31 10:46:05 +00:00
|
|
|
(~is (m arg.0) (m arg.1))
|
2014-12-13 01:54:31 +00:00
|
|
|
less-than
|
2014-07-31 10:46:05 +00:00
|
|
|
(< (m arg.0) (m arg.1))
|
2014-12-13 01:54:31 +00:00
|
|
|
greater-than
|
2014-07-31 10:46:05 +00:00
|
|
|
(> (m arg.0) (m arg.1))
|
2014-12-13 01:54:31 +00:00
|
|
|
lesser-or-equal
|
2014-07-31 10:46:05 +00:00
|
|
|
(<= (m arg.0) (m arg.1))
|
2014-12-13 01:54:31 +00:00
|
|
|
greater-or-equal
|
2014-07-31 10:46:05 +00:00
|
|
|
(>= (m arg.0) (m arg.1))
|
2014-10-10 22:04:14 +00:00
|
|
|
|
|
|
|
; control flow
|
2014-10-15 00:51:30 +00:00
|
|
|
jump
|
2014-10-29 20:05:08 +00:00
|
|
|
(do (= pc.routine* (+ 1 pc.routine* (v arg.0)))
|
2014-07-31 10:46:05 +00:00
|
|
|
(continue))
|
2014-10-15 00:51:30 +00:00
|
|
|
jump-if
|
2015-01-10 18:36:59 +00:00
|
|
|
(when (m arg.0)
|
|
|
|
(= pc.routine* (+ 1 pc.routine* (v arg.1)))
|
|
|
|
(continue))
|
2014-10-15 01:24:46 +00:00
|
|
|
jump-unless ; convenient helper
|
2015-01-10 18:36:59 +00:00
|
|
|
(unless (m arg.0)
|
|
|
|
(= pc.routine* (+ 1 pc.routine* (v arg.1)))
|
|
|
|
(continue))
|
2014-10-10 22:04:14 +00:00
|
|
|
|
2014-12-17 18:39:58 +00:00
|
|
|
; data management: scalars, arrays, and-records (structs)
|
2014-07-31 10:46:05 +00:00
|
|
|
copy
|
|
|
|
(m arg.0)
|
2014-08-20 04:33:48 +00:00
|
|
|
get
|
2014-11-29 04:08:24 +00:00
|
|
|
(with (operand (canonize arg.0)
|
|
|
|
idx (v arg.1))
|
2014-12-14 17:46:49 +00:00
|
|
|
(assert (iso '(offset) (ty arg.1)) "record index @arg.1 must have type 'offset'")
|
2014-11-29 04:08:24 +00:00
|
|
|
(assert (< -1 idx (len typeinfo.operand!elems)) "@idx is out of bounds of record @operand")
|
2014-12-14 17:46:49 +00:00
|
|
|
(m `((,(apply + v.operand
|
2014-12-17 22:03:34 +00:00
|
|
|
(map (fn(x) (sizeof `((_ ,@x))))
|
|
|
|
(firstn idx typeinfo.operand!elems)))
|
|
|
|
,@typeinfo.operand!elems.idx)
|
2014-12-27 06:21:25 +00:00
|
|
|
(raw))))
|
2014-10-05 18:34:23 +00:00
|
|
|
get-address
|
2014-11-29 04:08:24 +00:00
|
|
|
(with (operand (canonize arg.0)
|
|
|
|
idx (v arg.1))
|
2014-12-14 17:46:49 +00:00
|
|
|
(assert (iso '(offset) (ty arg.1)) "record index @arg.1 must have type 'offset'")
|
2014-11-29 04:08:24 +00:00
|
|
|
(assert (< -1 idx (len typeinfo.operand!elems)) "@idx is out of bounds of record @operand")
|
|
|
|
(apply + v.operand
|
2014-12-17 22:03:34 +00:00
|
|
|
(map (fn(x) (sizeof `((_ ,@x))))
|
|
|
|
(firstn idx typeinfo.operand!elems))))
|
2014-10-06 03:03:03 +00:00
|
|
|
index
|
2014-11-29 04:08:24 +00:00
|
|
|
(withs (operand (canonize arg.0)
|
|
|
|
elemtype typeinfo.operand!elem
|
|
|
|
idx (m arg.1))
|
2015-01-01 19:11:02 +00:00
|
|
|
;? (write arg.0)
|
|
|
|
;? (pr " => ")
|
|
|
|
;? (write operand)
|
|
|
|
;? (prn)
|
2014-11-29 04:08:24 +00:00
|
|
|
(unless (< -1 idx array-len.operand)
|
|
|
|
(die "@idx is out of bounds of array @operand"))
|
2014-12-14 17:46:49 +00:00
|
|
|
(m `((,(+ v.operand
|
|
|
|
1 ; for array size
|
2014-12-17 22:03:34 +00:00
|
|
|
(* idx (sizeof `((_ ,@elemtype)))))
|
|
|
|
,@elemtype)
|
2014-12-27 06:21:25 +00:00
|
|
|
(raw))))
|
2014-10-06 03:03:03 +00:00
|
|
|
index-address
|
2014-11-29 04:08:24 +00:00
|
|
|
(withs (operand (canonize arg.0)
|
|
|
|
elemtype typeinfo.operand!elem
|
|
|
|
idx (m arg.1))
|
|
|
|
(unless (< -1 idx array-len.operand)
|
|
|
|
(die "@idx is out of bounds of array @operand"))
|
|
|
|
(+ v.operand
|
|
|
|
1 ; for array size
|
2014-12-17 22:03:34 +00:00
|
|
|
(* idx (sizeof `((_ ,@elemtype))))))
|
2014-08-31 18:20:28 +00:00
|
|
|
new
|
2014-11-27 06:43:51 +00:00
|
|
|
(if (isa arg.0 'string)
|
|
|
|
; special-case: allocate space for a literal string
|
|
|
|
(new-string arg.0)
|
|
|
|
(let type (v arg.0)
|
2014-12-14 17:46:49 +00:00
|
|
|
(assert (iso '(literal) (ty arg.0)) "new: second arg @arg.0 must be literal")
|
2014-12-17 18:52:54 +00:00
|
|
|
(if (no type*.type) (err "no such type @type"))
|
2014-11-27 06:43:51 +00:00
|
|
|
; todo: initialize memory. currently racket does it for us
|
2014-12-17 18:52:54 +00:00
|
|
|
(if type*.type!array
|
2014-11-27 06:43:51 +00:00
|
|
|
(new-array type (m arg.1))
|
|
|
|
(new-scalar type))))
|
2014-10-05 18:32:25 +00:00
|
|
|
sizeof
|
2014-12-17 22:03:34 +00:00
|
|
|
(sizeof `((_ ,(m arg.0))))
|
2014-12-13 01:54:31 +00:00
|
|
|
length
|
2014-10-05 18:32:25 +00:00
|
|
|
(let base arg.0
|
2014-12-18 07:14:58 +00:00
|
|
|
(if (or typeinfo.base!array address?.base)
|
2014-10-05 18:32:25 +00:00
|
|
|
array-len.base
|
|
|
|
-1))
|
2014-10-05 03:19:12 +00:00
|
|
|
|
2014-10-24 18:38:02 +00:00
|
|
|
; tagged-values require one primitive
|
|
|
|
save-type
|
2014-12-14 20:36:42 +00:00
|
|
|
(annotate 'record `(,((ty arg.0) 0) ,(m arg.0)))
|
2014-10-24 18:38:02 +00:00
|
|
|
|
2015-01-01 05:24:48 +00:00
|
|
|
; code points for characters
|
|
|
|
character-to-integer
|
|
|
|
($.char->integer (m arg.0))
|
2015-01-02 23:30:33 +00:00
|
|
|
integer-to-character
|
|
|
|
($.integer->char (m arg.0))
|
2015-01-01 05:24:48 +00:00
|
|
|
|
2014-10-05 03:19:12 +00:00
|
|
|
; multiprocessing
|
|
|
|
fork
|
2014-12-29 00:42:18 +00:00
|
|
|
; args: fn globals-table args ...
|
2015-01-10 20:38:14 +00:00
|
|
|
(let routine (apply make-routine (m arg.0) (map m (nthcdr 3 arg)))
|
2015-01-10 21:10:23 +00:00
|
|
|
(= rep.routine!id ++.next-routine-id*)
|
2014-12-28 23:57:55 +00:00
|
|
|
(= rep.routine!globals (when (len> arg 1) (m arg.1)))
|
2015-01-10 20:38:14 +00:00
|
|
|
(= rep.routine!limit (when (len> arg 2) (m arg.2)))
|
2015-01-10 21:10:23 +00:00
|
|
|
(enq routine running-routines*)
|
|
|
|
rep.routine!id)
|
2015-01-12 06:54:51 +00:00
|
|
|
fork-helper
|
|
|
|
; args: fn globals-table args ...
|
|
|
|
(let routine (apply make-routine (m arg.0) (map m (nthcdr 3 arg)))
|
|
|
|
(= rep.routine!id ++.next-routine-id*)
|
|
|
|
(set rep.routine!helper)
|
|
|
|
(= rep.routine!globals (when (len> arg 1) (m arg.1)))
|
|
|
|
(= rep.routine!limit (when (len> arg 2) (m arg.2)))
|
|
|
|
(enq routine running-routines*)
|
|
|
|
rep.routine!id)
|
2014-11-06 23:38:00 +00:00
|
|
|
sleep
|
2015-01-09 07:21:56 +00:00
|
|
|
(do
|
|
|
|
(case (v arg.0)
|
|
|
|
for-some-cycles
|
|
|
|
(let wakeup-time (+ curr-cycle* (v arg.1))
|
2015-02-04 05:05:49 +00:00
|
|
|
(trace "run" label.routine* " " pc.routine* ": " "sleeping until " wakeup-time)
|
2015-01-10 21:20:13 +00:00
|
|
|
(= rep.routine*!sleep `(until ,wakeup-time)))
|
2015-01-09 07:21:56 +00:00
|
|
|
until-location-changes
|
|
|
|
(= rep.routine*!sleep `(until-location-changes ,(addr arg.1) ,(m arg.1)))
|
2015-01-10 21:49:16 +00:00
|
|
|
until-routine-done
|
|
|
|
(= rep.routine*!sleep `(until-routine-done ,(m arg.1)))
|
2015-01-10 20:28:00 +00:00
|
|
|
; else
|
|
|
|
(die "badly formed 'sleep' call @(tostring:prn (body.routine* pc.routine*))")
|
2015-01-09 08:48:13 +00:00
|
|
|
)
|
2014-11-07 03:05:20 +00:00
|
|
|
((abort-routine*)))
|
2015-01-10 21:15:10 +00:00
|
|
|
assert
|
|
|
|
(unless (m arg.0)
|
|
|
|
(die (v arg.1))) ; other routines will be able to look at the error status
|
2015-02-01 09:26:08 +00:00
|
|
|
assert-false
|
|
|
|
(when (m arg.0)
|
|
|
|
(die (v arg.1)))
|
2014-10-05 03:19:12 +00:00
|
|
|
|
2015-01-04 08:34:14 +00:00
|
|
|
; cursor-based (text mode) interaction
|
2015-01-15 04:21:52 +00:00
|
|
|
cursor-mode
|
2015-02-10 01:49:10 +00:00
|
|
|
;(do1 nil (system "/bin/stty -F /dev/tty raw"))
|
2015-01-15 04:21:52 +00:00
|
|
|
(do1 nil (if (no ($.current-charterm)) ($.open-charterm)))
|
|
|
|
retro-mode
|
2015-02-10 01:49:10 +00:00
|
|
|
;(do1 nil (system "/bin/stty -F /dev/tty sane"))
|
2015-01-15 04:21:52 +00:00
|
|
|
(do1 nil (if ($.current-charterm) ($.close-charterm)))
|
2015-01-15 04:43:23 +00:00
|
|
|
clear-host-screen
|
2015-02-10 01:49:10 +00:00
|
|
|
(do1 nil (pr "\e[m\e[2J\e[;H"))
|
2015-02-01 07:25:44 +00:00
|
|
|
clear-line-on-host
|
2015-02-10 01:49:10 +00:00
|
|
|
(do1 nil (pr "\e[2K"))
|
2015-01-15 04:43:23 +00:00
|
|
|
cursor-on-host
|
2015-02-10 01:49:10 +00:00
|
|
|
(do1 nil (pr (+ "\e[" (m arg.0) ";" (m arg.1) "H")))
|
2015-01-15 04:43:23 +00:00
|
|
|
cursor-on-host-to-next-line
|
2015-02-10 01:49:10 +00:00
|
|
|
(do1 nil (pr "\r\n"))
|
2015-02-10 01:58:35 +00:00
|
|
|
cursor-up-on-host
|
|
|
|
(do1 nil (pr (+ "\e[" (aif (len> arg 0) (or m arg.0) 1) "A")))
|
|
|
|
cursor-down-on-host
|
|
|
|
(do1 nil (pr (+ "\e[" (aif (len> arg 0) (or m arg.0) 1) "B")))
|
|
|
|
cursor-right-on-host
|
|
|
|
(do1 nil (pr (+ "\e[" (aif (len> arg 0) (or m arg.0) 1) "C")))
|
|
|
|
cursor-left-on-host
|
|
|
|
(do1 nil (pr (+ "\e[" (aif (len> arg 0) (or m arg.0) 1) "D")))
|
2015-02-01 08:15:43 +00:00
|
|
|
print-character-to-host
|
2015-01-18 02:50:32 +00:00
|
|
|
(do1 nil
|
2015-02-01 09:03:42 +00:00
|
|
|
(assert (in (type:m arg.0) 'char 'sym) (rep (m arg.0)))
|
2015-01-21 09:23:57 +00:00
|
|
|
;? (write (m arg.0)) (pr " => ") (prn (type (m arg.0)))
|
2015-01-25 06:23:21 +00:00
|
|
|
(if (no ($.current-charterm))
|
2015-01-25 07:00:22 +00:00
|
|
|
(pr (m arg.0))
|
2015-01-25 06:19:17 +00:00
|
|
|
(caselet x (m arg.0)
|
2015-01-25 07:30:23 +00:00
|
|
|
; todo: test these exceptions
|
2015-01-25 06:19:17 +00:00
|
|
|
#\newline
|
2015-02-10 01:49:10 +00:00
|
|
|
(pr "\r\n")
|
2015-01-25 07:18:02 +00:00
|
|
|
#\backspace
|
|
|
|
; backspace doesn't clear after moving the cursor
|
2015-02-10 02:09:41 +00:00
|
|
|
(pr "\b \b")
|
2015-01-25 07:26:02 +00:00
|
|
|
ctrl-c
|
|
|
|
(do ($.close-charterm)
|
|
|
|
(die "interrupted"))
|
2015-01-25 06:19:17 +00:00
|
|
|
;else
|
2015-02-01 09:03:42 +00:00
|
|
|
(if (and (len> arg 2)
|
|
|
|
(m arg.2))
|
2015-02-01 08:15:43 +00:00
|
|
|
(do
|
|
|
|
($.foreground (m arg.1))
|
|
|
|
($.background (m arg.2))
|
|
|
|
(pr x)
|
|
|
|
($.reset))
|
2015-02-01 09:03:42 +00:00
|
|
|
(and (len> arg 1)
|
|
|
|
(m arg.1))
|
2015-02-01 08:15:43 +00:00
|
|
|
(do
|
|
|
|
($.foreground (m arg.1))
|
|
|
|
(pr x)
|
|
|
|
($.reset))
|
|
|
|
:else
|
2015-02-10 01:49:10 +00:00
|
|
|
(pr x))))
|
2015-01-18 02:50:32 +00:00
|
|
|
)
|
2015-01-23 02:01:45 +00:00
|
|
|
read-key-from-host
|
2015-01-06 07:28:21 +00:00
|
|
|
(if ($.current-charterm)
|
2015-01-25 06:26:43 +00:00
|
|
|
(and ($.charterm-byte-ready?)
|
|
|
|
(ret result ($.charterm-read-key)
|
|
|
|
(case result
|
|
|
|
; charterm exceptions
|
|
|
|
return
|
|
|
|
(= result #\newline)
|
2015-01-25 07:18:02 +00:00
|
|
|
backspace
|
|
|
|
(= result #\backspace)
|
2015-01-25 06:26:43 +00:00
|
|
|
)))
|
2015-01-06 07:28:21 +00:00
|
|
|
($.graphics-open?)
|
|
|
|
($.ready-key-press Viewport))
|
2014-10-05 06:00:19 +00:00
|
|
|
|
2014-12-24 07:38:16 +00:00
|
|
|
; graphics
|
2015-01-12 18:45:08 +00:00
|
|
|
window-on
|
2014-12-24 07:38:16 +00:00
|
|
|
(do1 nil
|
|
|
|
($.open-graphics)
|
2015-01-05 09:21:39 +00:00
|
|
|
(= Viewport ($.open-viewport (m arg.0) ; name
|
|
|
|
(m arg.1) (m arg.2)))) ; width height
|
2015-01-12 18:45:08 +00:00
|
|
|
window-off
|
2014-12-24 07:38:16 +00:00
|
|
|
(do1 nil
|
2015-01-04 08:34:14 +00:00
|
|
|
($.close-viewport Viewport) ; why doesn't this close the window? works in naked racket. not racket vs arc.
|
2014-12-24 07:38:16 +00:00
|
|
|
($.close-graphics)
|
|
|
|
(= Viewport nil))
|
|
|
|
mouse-position
|
|
|
|
(aif ($.ready-mouse-click Viewport)
|
|
|
|
(let posn ($.mouse-click-posn it)
|
|
|
|
(list (annotate 'record (list ($.posn-x posn) ($.posn-y posn))) t))
|
|
|
|
(list nil nil))
|
2015-01-04 08:34:14 +00:00
|
|
|
wait-for-mouse
|
|
|
|
(let posn ($.mouse-click-posn ($.get-mouse-click Viewport))
|
|
|
|
(list (annotate 'record (list ($.posn-x posn) ($.posn-y posn))) t))
|
|
|
|
; clear-screen in cursor mode above
|
|
|
|
rectangle
|
|
|
|
(do1 nil
|
|
|
|
(($.draw-solid-rectangle Viewport)
|
|
|
|
($.make-posn (m arg.0) (m arg.1)) ; origin
|
|
|
|
(m arg.2) (m arg.3) ; width height
|
|
|
|
(m arg.4))) ; color
|
2015-01-05 09:21:39 +00:00
|
|
|
point
|
|
|
|
(do1 nil
|
|
|
|
(($.draw-pixel Viewport) ($.make-posn (m arg.0) (m arg.1))
|
2015-01-06 07:28:21 +00:00
|
|
|
(m arg.2))) ; color
|
2015-01-05 09:21:39 +00:00
|
|
|
|
|
|
|
image
|
|
|
|
(do1 nil
|
|
|
|
(($.draw-pixmap Viewport) (m arg.0) ; filename
|
|
|
|
($.make-posn (m arg.1) (m arg.2))))
|
|
|
|
color-at
|
|
|
|
(let pixel (($.get-color-pixel Viewport) ($.make-posn (m arg.0) (m arg.1)))
|
|
|
|
(prn ($.rgb-red pixel) " " ($.rgb-blue pixel) " " ($.rgb-green pixel))
|
|
|
|
($:rgb-red pixel))
|
2014-12-24 07:38:16 +00:00
|
|
|
|
2015-01-25 10:25:50 +00:00
|
|
|
; debugging aides
|
|
|
|
$dump-memory
|
2015-01-25 09:41:40 +00:00
|
|
|
(do1 nil
|
|
|
|
(prn:repr int-canon.memory*))
|
2015-02-01 07:25:44 +00:00
|
|
|
$dump-trace
|
|
|
|
(tofile arg.0
|
|
|
|
(each (label trace) (as cons traces*)
|
|
|
|
(pr label ": " trace)))
|
2015-01-25 10:25:50 +00:00
|
|
|
$start-tracing
|
|
|
|
(do1 nil
|
|
|
|
(set dump-trace*))
|
|
|
|
$stop-tracing
|
|
|
|
(do1 nil
|
|
|
|
(wipe dump-trace*))
|
2015-02-01 07:25:44 +00:00
|
|
|
$dump-routine
|
|
|
|
(do1 nil
|
|
|
|
($.close-charterm)
|
|
|
|
(prn routine*)
|
|
|
|
($.open-charterm)
|
|
|
|
)
|
2015-01-25 10:25:50 +00:00
|
|
|
$dump-channel
|
|
|
|
(do1 nil
|
2015-01-25 19:38:13 +00:00
|
|
|
($.close-charterm) ;? 1
|
2015-01-25 10:25:50 +00:00
|
|
|
(withs (x (m arg.0)
|
|
|
|
y (memory* (+ x 2)))
|
|
|
|
(prn label.routine* " -- " x " -- " (list (memory* x)
|
|
|
|
(memory* (+ x 1))
|
|
|
|
(memory* (+ x 2)))
|
|
|
|
" -- " (list (memory* y)
|
|
|
|
(memory* (+ y 1))
|
|
|
|
(repr:memory* (+ y 2))
|
|
|
|
(memory* (+ y 3))
|
|
|
|
(repr:memory* (+ y 4)))))
|
2015-01-25 19:38:13 +00:00
|
|
|
($.open-charterm) ;? 1
|
|
|
|
)
|
2015-01-25 10:25:50 +00:00
|
|
|
$quit
|
|
|
|
(quit)
|
2015-01-26 18:13:34 +00:00
|
|
|
$wait-for-key-from-host
|
2015-01-27 09:21:29 +00:00
|
|
|
(when ($.current-charterm)
|
|
|
|
(ret result ($.charterm-read-key)
|
|
|
|
(case result
|
|
|
|
; charterm exceptions
|
|
|
|
return
|
|
|
|
(= result #\newline)
|
|
|
|
backspace
|
|
|
|
(= result #\backspace)
|
|
|
|
)))
|
2015-02-01 08:15:43 +00:00
|
|
|
$print
|
2015-01-27 09:21:29 +00:00
|
|
|
(do1 nil
|
|
|
|
;? (write (m arg.0)) (pr " => ") (prn (type (m arg.0)))
|
|
|
|
(if (no ($.current-charterm))
|
|
|
|
(pr (m arg.0))
|
2015-03-10 04:26:13 +00:00
|
|
|
(unless disable-debug-prints-in-console-mode*
|
|
|
|
(caselet x (m arg.0)
|
|
|
|
#\newline
|
|
|
|
(pr "\r\n")
|
|
|
|
#\backspace
|
|
|
|
; backspace doesn't clear after moving the cursor
|
|
|
|
(pr "\b \b")
|
|
|
|
ctrl-c
|
|
|
|
(do ($.close-charterm)
|
|
|
|
(die "interrupted"))
|
|
|
|
;else
|
|
|
|
(pr x)))
|
|
|
|
))
|
2015-03-12 04:02:33 +00:00
|
|
|
$write
|
|
|
|
(do1 nil
|
|
|
|
(write (m arg.0)))
|
2015-01-26 18:13:34 +00:00
|
|
|
$eval
|
|
|
|
(new-string:repr:eval:read:to-arc-string (m arg.0))
|
2015-01-28 10:31:54 +00:00
|
|
|
;? (let x (to-arc-string (m arg.0)) ;? 1
|
|
|
|
;? (prn x) ;? 1
|
|
|
|
;? (new-string:repr:eval x)) ;? 1
|
2015-01-25 09:41:40 +00:00
|
|
|
|
2015-02-24 08:35:56 +00:00
|
|
|
$clear-trace
|
|
|
|
(do1 nil (wipe interactive-traces*))
|
|
|
|
$save-trace
|
2015-03-13 15:58:40 +00:00
|
|
|
(let x (filter-log "CCC: " len
|
|
|
|
(string
|
|
|
|
(filter-log "BBB: " len
|
|
|
|
(map [string:intersperse ": " _]
|
|
|
|
(filter-log "AAA: " len
|
|
|
|
(as cons (interactive-traces* (m arg.0)))))
|
|
|
|
)))
|
2015-02-24 08:35:56 +00:00
|
|
|
;? (let x (string:map [string:intersperse ": " _]
|
2015-03-13 15:58:40 +00:00
|
|
|
;? (apply join
|
|
|
|
;? (map [as cons _] rev.interactive-traces*)))
|
|
|
|
(prn "computed trace; now saving to memory\n")
|
2015-02-24 08:35:56 +00:00
|
|
|
;? (write x)(write #\newline) ;? 1
|
|
|
|
;? (prn x) ;? 1
|
2015-03-13 15:58:40 +00:00
|
|
|
(set new-string-foo*)
|
|
|
|
(do1 (new-string x)
|
|
|
|
(wipe new-string-foo*)))
|
2015-02-24 08:35:56 +00:00
|
|
|
|
2015-01-29 07:28:56 +00:00
|
|
|
; first-class continuations
|
|
|
|
current-continuation
|
|
|
|
(w/uniq continuation-name
|
|
|
|
(trace "continuation" "saving @(repr rep.routine*!call-stack) to @continuation-name")
|
|
|
|
(= continuation*.continuation-name (copy rep.routine*!call-stack))
|
|
|
|
continuation-name)
|
|
|
|
continue-from
|
|
|
|
(let continuation-name (m arg.0)
|
|
|
|
(trace "continuation" "restoring @continuation-name")
|
|
|
|
(trace "continuation" continuation*.continuation-name)
|
|
|
|
(= rep.routine*!call-stack continuation*.continuation-name)
|
|
|
|
(trace "continuation" "call stack is now @(repr rep.routine*!call-stack)")
|
|
|
|
;? (++ pc.routine*) ;? 1
|
|
|
|
(continue))
|
|
|
|
;? ((abort-routine*))) ;? 1
|
2015-01-29 04:48:51 +00:00
|
|
|
|
2014-10-10 22:04:14 +00:00
|
|
|
; user-defined functions
|
2014-12-13 01:54:31 +00:00
|
|
|
next-input
|
|
|
|
(let idx caller-arg-idx.routine*
|
|
|
|
(++ caller-arg-idx.routine*)
|
2015-01-24 21:49:21 +00:00
|
|
|
(trace "arg" repr.arg " " idx " " (repr caller-args.routine*))
|
2014-12-13 01:54:31 +00:00
|
|
|
(if (len> caller-args.routine* idx)
|
|
|
|
(list caller-args.routine*.idx t)
|
|
|
|
(list nil nil)))
|
|
|
|
input
|
2014-12-14 17:46:49 +00:00
|
|
|
(do (assert (iso '(literal) (ty arg.0)))
|
2014-12-13 01:54:31 +00:00
|
|
|
(= caller-arg-idx.routine* (v arg.0))
|
2014-11-27 14:16:02 +00:00
|
|
|
(let idx caller-arg-idx.routine*
|
|
|
|
(++ caller-arg-idx.routine*)
|
2015-01-24 21:49:21 +00:00
|
|
|
(trace "arg" repr.arg " " idx " " (repr caller-args.routine*))
|
2014-11-27 14:16:02 +00:00
|
|
|
(if (len> caller-args.routine* idx)
|
|
|
|
(list caller-args.routine*.idx t)
|
|
|
|
(list nil nil))))
|
2014-12-24 09:00:36 +00:00
|
|
|
; type and otype won't always easily compile. be careful.
|
|
|
|
type
|
|
|
|
(ty (caller-operands.routine* (v arg.0)))
|
|
|
|
otype
|
|
|
|
(ty (caller-results.routine* (v arg.0)))
|
2014-10-31 23:22:21 +00:00
|
|
|
prepare-reply
|
2014-10-31 23:24:17 +00:00
|
|
|
(prepare-reply arg)
|
2014-07-31 10:46:05 +00:00
|
|
|
reply
|
2014-10-31 23:24:17 +00:00
|
|
|
(do (when arg
|
|
|
|
(prepare-reply arg))
|
2015-01-26 00:40:11 +00:00
|
|
|
(with (results results.routine*
|
|
|
|
reply-args reply-args.routine*)
|
2014-10-29 20:05:08 +00:00
|
|
|
(pop-stack routine*)
|
2014-10-31 23:18:13 +00:00
|
|
|
(if empty.routine* (return ninstrs))
|
2015-01-26 06:56:53 +00:00
|
|
|
(let (call-oargs _ call-args) (parse-instr (body.routine* pc.routine*))
|
2015-02-04 05:05:49 +00:00
|
|
|
;? (trace "reply" repr.arg " " repr.call-oargs) ;? 1
|
2015-01-26 06:56:53 +00:00
|
|
|
(each (dest reply-arg val) (zip call-oargs reply-args results)
|
2015-02-04 05:05:49 +00:00
|
|
|
(trace "run" label.routine* " " pc.routine* ": " repr.val " => " dest)
|
2014-11-07 19:56:34 +00:00
|
|
|
(when nondummy.dest
|
2015-01-26 06:56:53 +00:00
|
|
|
(whenlet argidx (alref metadata.reply-arg 'same-as-arg)
|
|
|
|
(unless (is v.dest (v call-args.argidx))
|
|
|
|
(die "'same-as-arg' output arg in @repr.reply-args can't bind to @repr.call-oargs")))
|
2014-11-07 19:50:41 +00:00
|
|
|
(setm dest val))))
|
2014-10-31 23:18:13 +00:00
|
|
|
(++ pc.routine*)
|
|
|
|
(while (>= pc.routine* (len body.routine*))
|
|
|
|
(pop-stack routine*)
|
|
|
|
(when empty.routine* (return ninstrs))
|
|
|
|
(++ pc.routine*))
|
|
|
|
(continue)))
|
2014-10-10 22:04:14 +00:00
|
|
|
; else try to call as a user-defined function
|
2014-10-05 18:33:25 +00:00
|
|
|
(do (if function*.op
|
2014-12-24 09:00:36 +00:00
|
|
|
(with (callee-args (accum yield
|
|
|
|
(each a arg
|
|
|
|
(yield (m a))))
|
|
|
|
callee-operands (accum yield
|
|
|
|
(each a arg
|
|
|
|
(yield a)))
|
|
|
|
callee-results (accum yield
|
|
|
|
(each a oarg
|
|
|
|
(yield a))))
|
2014-11-01 00:35:24 +00:00
|
|
|
(push-stack routine* op)
|
2014-12-24 09:00:36 +00:00
|
|
|
(= caller-args.routine* callee-args)
|
|
|
|
(= caller-operands.routine* callee-operands)
|
|
|
|
(= caller-results.routine* callee-results))
|
2014-10-05 18:33:25 +00:00
|
|
|
(err "no such op @op"))
|
2014-08-28 19:44:01 +00:00
|
|
|
(continue))
|
2014-07-31 10:46:05 +00:00
|
|
|
)
|
2014-11-18 18:53:33 +00:00
|
|
|
; opcode generated some 'results'
|
2014-10-10 22:04:14 +00:00
|
|
|
; copy to output args
|
2014-11-18 18:53:33 +00:00
|
|
|
(if (acons results)
|
|
|
|
(each (dest val) (zip oarg results)
|
2014-11-07 19:57:45 +00:00
|
|
|
(unless (is dest '_)
|
2015-02-04 05:05:49 +00:00
|
|
|
(trace "run" label.routine* " " pc.routine* ": " repr.val " => " dest)
|
2014-11-07 19:57:45 +00:00
|
|
|
(setm dest val)))
|
2014-07-31 10:46:05 +00:00
|
|
|
(when oarg ; must be a list
|
2015-02-04 05:05:49 +00:00
|
|
|
(trace "run" label.routine* " " pc.routine* ": " repr.results " => " oarg.0)
|
2014-11-18 18:53:33 +00:00
|
|
|
(setm oarg.0 results)))
|
2014-08-28 19:44:01 +00:00
|
|
|
)
|
2014-10-29 20:05:08 +00:00
|
|
|
(++ pc.routine*)))
|
2014-08-28 23:47:09 +00:00
|
|
|
(return time-slice)))
|
2014-07-06 07:07:03 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def prepare-reply (args)
|
2014-10-31 23:24:17 +00:00
|
|
|
(= results.routine*
|
|
|
|
(accum yield
|
|
|
|
(each a args
|
2015-01-26 00:40:11 +00:00
|
|
|
(yield (m a)))))
|
|
|
|
(= reply-args.routine* args))
|
2014-10-31 23:24:17 +00:00
|
|
|
|
2014-11-29 02:02:16 +00:00
|
|
|
; helpers for memory access respecting
|
|
|
|
; immediate addressing - 'literal' and 'offset'
|
|
|
|
; direct addressing - default
|
|
|
|
; indirect addressing - 'deref'
|
2015-01-03 02:13:04 +00:00
|
|
|
; relative addressing - if routine* has 'default-space'
|
2014-11-27 06:43:51 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def m (loc) ; read memory, respecting metadata
|
2014-11-29 02:02:16 +00:00
|
|
|
(point return
|
2014-12-28 22:07:30 +00:00
|
|
|
(when (literal? loc)
|
2014-11-29 02:02:16 +00:00
|
|
|
(return v.loc))
|
2015-01-03 02:13:04 +00:00
|
|
|
(when (is v.loc 'default-space)
|
|
|
|
(return rep.routine*!call-stack.0!default-space))
|
2015-02-04 05:05:49 +00:00
|
|
|
;? (trace "mem" loc) ;? 1
|
2015-02-01 07:25:44 +00:00
|
|
|
(assert (isa v.loc 'int) "addresses must be numeric (problem in convert-names?): @repr.loc")
|
2015-02-04 05:05:49 +00:00
|
|
|
(ret result
|
|
|
|
(with (n sizeof.loc
|
|
|
|
addr addr.loc)
|
|
|
|
;? (trace "mem" "reading " n " locations starting at " addr) ;? 1
|
|
|
|
(if (is 1 n)
|
|
|
|
memory*.addr
|
|
|
|
:else
|
|
|
|
(annotate 'record
|
|
|
|
(map memory* (addrs addr n)))))
|
|
|
|
(trace "mem" loc " => " result))))
|
2014-08-26 19:20:08 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def setm (loc val) ; set memory, respecting metadata
|
2015-01-15 05:51:27 +00:00
|
|
|
;? (tr 111)
|
2014-11-29 02:02:16 +00:00
|
|
|
(point return
|
2015-01-15 05:51:27 +00:00
|
|
|
;? (tr 112)
|
2015-01-03 02:13:04 +00:00
|
|
|
(when (is v.loc 'default-space)
|
|
|
|
(assert (is 1 sizeof.loc) "can't store compounds in default-space @loc")
|
|
|
|
(= rep.routine*!call-stack.0!default-space val)
|
2014-11-29 02:02:16 +00:00
|
|
|
(return))
|
2015-01-15 05:51:27 +00:00
|
|
|
;? (tr 120)
|
2014-11-29 02:02:16 +00:00
|
|
|
(assert (isa v.loc 'int) "can't store to non-numeric address (problem in convert-names?)")
|
2015-02-04 05:05:49 +00:00
|
|
|
;? (trace "mem" loc " <= " repr.val) ;? 1
|
2014-11-29 02:52:34 +00:00
|
|
|
(with (n (if (isa val 'record) (len rep.val) 1)
|
2014-12-17 22:03:34 +00:00
|
|
|
addr addr.loc
|
|
|
|
typ typeof.loc)
|
2015-02-04 05:05:49 +00:00
|
|
|
;? (trace "mem" "size of " loc " is " n) ;? 1
|
2014-11-29 02:02:16 +00:00
|
|
|
(assert n "setm: can't compute type of @loc")
|
|
|
|
(assert addr "setm: null pointer @loc")
|
|
|
|
(if (is 1 n)
|
|
|
|
(do (assert (~isa val 'record) "setm: record of size 1 @(tostring prn.val)")
|
2015-02-04 05:05:49 +00:00
|
|
|
(trace "mem" loc ": " addr " <= " repr.val)
|
2014-11-29 02:19:09 +00:00
|
|
|
(= memory*.addr val))
|
2014-12-17 22:03:34 +00:00
|
|
|
(do (if type*.typ!array
|
2014-11-29 02:58:38 +00:00
|
|
|
; size check for arrays
|
2014-11-29 08:57:06 +00:00
|
|
|
(when (~is n
|
|
|
|
(+ 1 ; array length
|
2014-12-17 22:03:34 +00:00
|
|
|
(* rep.val.0 (sizeof `((_ ,@type*.typ!elem))))))
|
2014-11-29 02:58:38 +00:00
|
|
|
(die "writing invalid array @(tostring prn.val)"))
|
|
|
|
; size check for non-arrays
|
2014-11-29 02:52:34 +00:00
|
|
|
(when (~is sizeof.loc n)
|
2015-01-12 06:03:16 +00:00
|
|
|
(die "writing to incorrect size @(tostring pr.val) => @loc")))
|
2014-11-29 02:40:47 +00:00
|
|
|
(let addrs (addrs addr n)
|
|
|
|
(each (dest src) (zip addrs rep.val)
|
2015-02-04 05:05:49 +00:00
|
|
|
(trace "mem" loc ": " dest " <= " repr.src)
|
2014-11-29 02:40:47 +00:00
|
|
|
(= memory*.dest src))))))))
|
2014-08-26 19:20:08 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def typeof (operand)
|
2014-11-29 02:52:34 +00:00
|
|
|
(let loc absolutize.operand
|
2014-12-13 10:07:48 +00:00
|
|
|
(while (pos '(deref) metadata.loc)
|
2014-11-29 02:52:34 +00:00
|
|
|
(zap deref loc))
|
2014-12-13 10:07:48 +00:00
|
|
|
ty.loc.0))
|
2014-11-29 02:52:34 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def addr (operand)
|
2014-12-28 02:20:13 +00:00
|
|
|
(v canonize.operand))
|
2014-11-29 02:02:16 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def addrs (n sz)
|
2014-11-29 02:02:16 +00:00
|
|
|
(accum yield
|
|
|
|
(repeat sz
|
|
|
|
(yield n)
|
|
|
|
(++ n))))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def canonize (operand)
|
2015-01-01 19:11:02 +00:00
|
|
|
;? (tr "0: @operand")
|
2014-11-29 04:08:24 +00:00
|
|
|
(ret operand
|
2015-01-01 19:11:02 +00:00
|
|
|
;? (prn "1: " operand)
|
|
|
|
;? (tr "1: " operand) ; todo: why does this die?
|
2014-11-29 04:08:24 +00:00
|
|
|
(zap absolutize operand)
|
2015-01-26 11:11:04 +00:00
|
|
|
;? (tr "2: @repr.operand")
|
2014-12-13 10:07:48 +00:00
|
|
|
(while (pos '(deref) metadata.operand)
|
2015-01-01 19:11:02 +00:00
|
|
|
(zap deref operand)
|
2015-01-26 11:11:04 +00:00
|
|
|
;? (tr "3: @repr.operand")
|
2015-01-01 19:11:02 +00:00
|
|
|
)))
|
2014-11-29 02:02:16 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def array-len (operand)
|
2014-11-29 02:02:16 +00:00
|
|
|
(trace "array-len" operand)
|
2014-11-29 09:05:39 +00:00
|
|
|
(zap canonize operand)
|
2014-11-29 02:02:16 +00:00
|
|
|
(if typeinfo.operand!array
|
2014-12-13 10:07:48 +00:00
|
|
|
(m `((,v.operand integer) ,@metadata.operand))
|
2014-11-29 02:02:16 +00:00
|
|
|
:else
|
|
|
|
(err "can't take len of non-array @operand")))
|
2014-11-27 06:43:51 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def sizeof (x)
|
2015-02-04 05:05:49 +00:00
|
|
|
;? (trace "sizeof" x) ;? 1
|
2014-12-17 22:03:34 +00:00
|
|
|
(assert acons.x)
|
|
|
|
(zap canonize x)
|
2014-11-29 00:13:28 +00:00
|
|
|
(point return
|
2014-12-17 22:03:34 +00:00
|
|
|
;? (tr "sizeof: checking @x for array")
|
|
|
|
(when typeinfo.x!array
|
|
|
|
;? (tr "sizeof: @x is an array")
|
|
|
|
(assert (~is '_ v.x) "sizeof: arrays require a specific variable")
|
|
|
|
(return (+ 1 (* array-len.x (sizeof `((_ ,@typeinfo.x!elem)))))))
|
|
|
|
;? (tr "sizeof: not an array")
|
|
|
|
(when typeinfo.x!and-record
|
|
|
|
;? (tr "sizeof: @x is an and-record")
|
|
|
|
(return (sum idfn
|
|
|
|
(accum yield
|
|
|
|
(each elem typeinfo.x!elems
|
|
|
|
(yield (sizeof `((_ ,@elem)))))))))
|
|
|
|
;? (tr "sizeof: @x is a primitive")
|
|
|
|
(return typeinfo.x!size)))
|
2014-08-26 19:20:08 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def absolutize (operand)
|
2014-11-29 01:43:33 +00:00
|
|
|
(if (no routine*)
|
|
|
|
operand
|
2015-01-15 05:51:27 +00:00
|
|
|
(in v.operand '_ 'default-space)
|
2014-12-17 22:03:34 +00:00
|
|
|
operand
|
2014-12-27 06:21:25 +00:00
|
|
|
(pos '(raw) metadata.operand)
|
2014-11-29 01:43:33 +00:00
|
|
|
operand
|
2014-12-29 17:24:11 +00:00
|
|
|
(is 'global space.operand)
|
2014-12-28 02:27:54 +00:00
|
|
|
(aif rep.routine*!globals
|
2014-12-29 17:20:51 +00:00
|
|
|
`((,(+ it 1 v.operand) ,@(cdr operand.0))
|
2014-12-28 02:27:54 +00:00
|
|
|
,@(rem [caris _ 'space] metadata.operand)
|
|
|
|
(raw))
|
|
|
|
(die "routine has no globals: @operand"))
|
2014-11-29 01:43:33 +00:00
|
|
|
:else
|
2015-01-03 02:13:04 +00:00
|
|
|
(iflet base rep.routine*!call-stack.0!default-space
|
2014-12-30 09:27:26 +00:00
|
|
|
(lookup-space (rem [caris _ 'space] operand)
|
|
|
|
base
|
|
|
|
space.operand)
|
2014-11-29 01:43:33 +00:00
|
|
|
operand)))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def lookup-space (operand base space)
|
2015-02-28 21:13:39 +00:00
|
|
|
;? (prn operand " " base) ;? 1
|
2014-12-30 09:27:26 +00:00
|
|
|
(if (is 0 space)
|
|
|
|
; base case
|
|
|
|
(if (< v.operand memory*.base)
|
|
|
|
`((,(+ base 1 v.operand) ,@(cdr operand.0))
|
|
|
|
,@metadata.operand
|
|
|
|
(raw))
|
|
|
|
(die "no room for var @operand in routine of size @memory*.base"))
|
|
|
|
; recursive case
|
2015-01-03 02:13:04 +00:00
|
|
|
(lookup-space operand (memory* (+ base 1)) ; location 0 points to next space
|
2014-12-30 09:27:26 +00:00
|
|
|
(- space 1))))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def space (operand)
|
2015-01-29 20:33:57 +00:00
|
|
|
(or (alref metadata.operand 'space)
|
2014-12-28 02:27:54 +00:00
|
|
|
0))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def deref (operand)
|
2014-12-13 10:07:48 +00:00
|
|
|
(assert (pos '(deref) metadata.operand))
|
2014-12-18 07:14:58 +00:00
|
|
|
(assert address?.operand)
|
2015-03-13 16:58:22 +00:00
|
|
|
(cons `(,(memory* v.operand) ,@typeinfo.operand!elem)
|
|
|
|
(drop-one '(deref) metadata.operand)))
|
2014-11-29 00:49:11 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def drop-one (f x)
|
2014-11-29 00:49:11 +00:00
|
|
|
(when acons.x ; proper lists only
|
|
|
|
(if (testify.f car.x)
|
|
|
|
cdr.x
|
2014-12-18 04:49:23 +00:00
|
|
|
(cons car.x (drop-one f cdr.x)))))
|
2014-11-29 00:49:11 +00:00
|
|
|
|
2014-11-29 02:02:16 +00:00
|
|
|
; memory allocation
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def alloc (sz)
|
2015-01-26 10:56:08 +00:00
|
|
|
(when (> sz (- rep.routine*!alloc-max rep.routine*!alloc))
|
|
|
|
(let curr-alloc Memory-allocated-until
|
|
|
|
(= rep.routine*!alloc curr-alloc)
|
|
|
|
(++ Memory-allocated-until Allocation-chunk)
|
|
|
|
(= rep.routine*!alloc-max Memory-allocated-until)))
|
|
|
|
(ret result rep.routine*!alloc
|
|
|
|
(++ rep.routine*!alloc sz)))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def new-scalar (type)
|
2014-12-04 10:50:33 +00:00
|
|
|
;? (tr "new scalar: @type")
|
2015-01-26 10:56:08 +00:00
|
|
|
(alloc (sizeof `((_ ,type)))))
|
2014-11-29 02:02:16 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def new-array (type size)
|
2014-12-04 10:50:33 +00:00
|
|
|
;? (tr "new array: @type @size")
|
2015-01-26 10:56:08 +00:00
|
|
|
(ret result (alloc (+ 1 (* (sizeof `((_ ,@type*.type!elem))) size)))
|
|
|
|
(= memory*.result size)))
|
2014-11-29 02:02:16 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def new-string (literal-string)
|
2014-12-04 10:50:33 +00:00
|
|
|
;? (tr "new string: @literal-string")
|
2015-01-26 11:11:04 +00:00
|
|
|
(ret result (alloc (+ 1 len.literal-string))
|
|
|
|
(= memory*.result len.literal-string)
|
|
|
|
(on c literal-string
|
2015-03-13 15:58:40 +00:00
|
|
|
(when (and new-string-foo* (is 0 (mod index 100)))
|
|
|
|
(prn index " " repr.c))
|
2015-01-26 11:11:04 +00:00
|
|
|
(= (memory* (+ result 1 index)) c))))
|
2014-11-29 02:02:16 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def to-arc-string (string-address)
|
2015-01-26 18:13:34 +00:00
|
|
|
(let len (memory* string-address)
|
|
|
|
(string:map memory* (range (+ string-address 1)
|
|
|
|
(+ string-address len)))))
|
|
|
|
|
2014-10-10 22:09:16 +00:00
|
|
|
;; desugar structured assembly based on blocks
|
2014-10-10 22:04:14 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def convert-braces (instrs)
|
2014-12-14 20:36:42 +00:00
|
|
|
;? (prn "convert-braces " instrs)
|
2014-07-17 16:02:43 +00:00
|
|
|
(let locs () ; list of information on each brace: (open/close pc)
|
|
|
|
(let pc 0
|
|
|
|
(loop (instrs instrs)
|
|
|
|
(each instr instrs
|
2014-12-14 17:46:49 +00:00
|
|
|
;? (tr instr)
|
2014-11-23 06:26:11 +00:00
|
|
|
(if (or atom.instr (~is 'begin instr.0)) ; label or regular instruction
|
|
|
|
(do
|
|
|
|
(trace "c{0" pc " " instr " -- " locs)
|
|
|
|
(++ pc))
|
2014-11-27 16:48:38 +00:00
|
|
|
; hack: racket replaces braces with parens, so we need the
|
2014-11-25 02:52:15 +00:00
|
|
|
; keyword 'begin' to delimit blocks.
|
2014-11-27 16:48:38 +00:00
|
|
|
; ultimately there'll be no nesting and braces will just be
|
2014-11-25 02:52:15 +00:00
|
|
|
; in an instr by themselves.
|
2014-11-23 06:26:11 +00:00
|
|
|
:else ; brace
|
|
|
|
(do
|
|
|
|
(push `(open ,pc) locs)
|
|
|
|
(recur cdr.instr)
|
|
|
|
(push `(close ,pc) locs))))))
|
2014-07-17 16:02:43 +00:00
|
|
|
(zap rev locs)
|
2014-12-14 17:46:49 +00:00
|
|
|
;? (tr "-")
|
2014-07-17 16:02:43 +00:00
|
|
|
(with (pc 0
|
|
|
|
stack ()) ; elems are pcs
|
|
|
|
(accum yield
|
|
|
|
(loop (instrs instrs)
|
|
|
|
(each instr instrs
|
2014-12-14 17:46:49 +00:00
|
|
|
;? (tr "- " instr)
|
2014-10-07 20:26:01 +00:00
|
|
|
(point continue
|
2014-11-23 06:26:11 +00:00
|
|
|
(when (atom instr) ; label
|
|
|
|
(yield instr)
|
2014-11-23 14:06:04 +00:00
|
|
|
(++ pc)
|
2014-11-23 06:26:11 +00:00
|
|
|
(continue))
|
2014-12-14 17:46:49 +00:00
|
|
|
(when (is car.instr 'begin)
|
|
|
|
(push pc stack)
|
|
|
|
(recur cdr.instr)
|
|
|
|
(pop stack)
|
|
|
|
(continue))
|
2015-01-10 19:16:57 +00:00
|
|
|
(with ((oarg op arg) (parse-instr instr)
|
|
|
|
yield-new-instr (fn (new-instr)
|
|
|
|
(trace "c{1" "@pc X " instr " => " new-instr)
|
|
|
|
(yield new-instr))
|
|
|
|
yield-unchanged (fn ()
|
2015-01-10 21:54:21 +00:00
|
|
|
(trace "c{1" "@pc ✓ " instr)
|
2015-01-10 19:16:57 +00:00
|
|
|
(yield instr)))
|
|
|
|
(when (in op 'break 'break-if 'break-unless 'loop 'loop-if 'loop-unless)
|
|
|
|
(assert (is oarg nil) "@op: can't take oarg in @instr"))
|
2014-12-14 17:50:10 +00:00
|
|
|
(case op
|
|
|
|
break
|
2015-01-10 19:16:57 +00:00
|
|
|
(yield-new-instr `(((jump)) ((,(close-offset pc locs (and arg (v arg.0))) offset))))
|
2014-12-14 17:50:10 +00:00
|
|
|
break-if
|
2015-01-10 19:16:57 +00:00
|
|
|
(yield-new-instr `(((jump-if)) ,arg.0 ((,(close-offset pc locs (and cdr.arg (v arg.1))) offset))))
|
2014-12-14 17:50:10 +00:00
|
|
|
break-unless
|
2015-01-10 19:16:57 +00:00
|
|
|
(yield-new-instr `(((jump-unless)) ,arg.0 ((,(close-offset pc locs (and cdr.arg (v arg.1))) offset))))
|
2014-12-14 17:50:10 +00:00
|
|
|
loop
|
2015-01-10 19:16:57 +00:00
|
|
|
(yield-new-instr `(((jump)) ((,(open-offset pc stack (and arg (v arg.0))) offset))))
|
2014-12-14 17:50:10 +00:00
|
|
|
loop-if
|
2015-01-10 19:16:57 +00:00
|
|
|
(yield-new-instr `(((jump-if)) ,arg.0 ((,(open-offset pc stack (and cdr.arg (v arg.1))) offset))))
|
2014-12-14 17:50:10 +00:00
|
|
|
loop-unless
|
2015-01-10 19:16:57 +00:00
|
|
|
(yield-new-instr `(((jump-unless)) ,arg.0 ((,(open-offset pc stack (and cdr.arg (v arg.1))) offset))))
|
2014-12-14 17:50:10 +00:00
|
|
|
;else
|
2015-01-10 19:16:57 +00:00
|
|
|
(yield-unchanged)))
|
2014-10-07 20:26:01 +00:00
|
|
|
(++ pc))))))))
|
2014-07-17 16:02:43 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def close-offset (pc locs nblocks)
|
2014-11-27 17:30:43 +00:00
|
|
|
(or= nblocks 1)
|
|
|
|
;? (tr nblocks)
|
2014-11-23 14:12:15 +00:00
|
|
|
(point return
|
2014-11-23 14:06:04 +00:00
|
|
|
;? (tr "close " pc " " locs)
|
2014-11-23 14:12:15 +00:00
|
|
|
(let stacksize 0
|
|
|
|
(each (state loc) locs
|
|
|
|
(point continue
|
|
|
|
;? (tr stacksize "/" done " " state " " loc)
|
|
|
|
(when (<= loc pc)
|
|
|
|
(continue))
|
|
|
|
;? (tr "process " stacksize loc)
|
|
|
|
(if (is 'open state) (++ stacksize) (-- stacksize))
|
|
|
|
; last time
|
|
|
|
;? (tr "process2 " stacksize loc)
|
2014-11-27 17:30:43 +00:00
|
|
|
(when (is stacksize (* -1 nblocks))
|
2014-11-23 14:12:15 +00:00
|
|
|
;? (tr "close now " loc)
|
|
|
|
(return (- loc pc 1))))))))
|
2014-07-17 16:02:43 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def open-offset (pc stack nblocks)
|
2014-11-27 17:30:43 +00:00
|
|
|
(or= nblocks 1)
|
|
|
|
(- (stack (- nblocks 1)) 1 pc))
|
|
|
|
|
2014-11-27 16:49:18 +00:00
|
|
|
;; convert jump targets to offsets
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def convert-labels (instrs)
|
2014-11-27 16:49:18 +00:00
|
|
|
;? (tr "convert-labels " instrs)
|
|
|
|
(let labels (table)
|
|
|
|
(let pc 0
|
|
|
|
(each instr instrs
|
|
|
|
(when (~acons instr)
|
|
|
|
;? (tr "label " pc)
|
|
|
|
(= labels.instr pc))
|
|
|
|
(++ pc)))
|
|
|
|
(let pc 0
|
|
|
|
(each instr instrs
|
|
|
|
(when (and acons.instr
|
2014-12-14 17:46:49 +00:00
|
|
|
(acons car.instr)
|
|
|
|
(in (v car.instr) 'jump 'jump-if 'jump-unless))
|
2014-11-27 16:49:18 +00:00
|
|
|
(each arg cdr.instr
|
|
|
|
;? (tr "trying " arg " " ty.arg ": " v.arg " => " (labels v.arg))
|
2014-12-14 17:46:49 +00:00
|
|
|
(when (and (is ty.arg.0 'offset)
|
2014-11-27 16:49:18 +00:00
|
|
|
(isa v.arg 'sym)
|
|
|
|
(labels v.arg))
|
|
|
|
(= v.arg (- (labels v.arg) pc 1)))))
|
|
|
|
(++ pc))))
|
|
|
|
instrs)
|
|
|
|
|
2014-11-07 19:59:22 +00:00
|
|
|
;; convert symbolic names to raw memory locations
|
2014-10-29 07:18:58 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def add-next-space-generator (instrs name)
|
2014-12-30 22:52:58 +00:00
|
|
|
;? (prn "== @name")
|
|
|
|
(each instr instrs
|
|
|
|
(when acons.instr
|
|
|
|
(let (oargs op args) (parse-instr instr)
|
|
|
|
(each oarg oargs
|
|
|
|
(when (and (nondummy oarg)
|
|
|
|
(is v.oarg 0)
|
2015-01-03 02:13:04 +00:00
|
|
|
(iso ty.oarg '(space-address)))
|
2015-02-11 09:09:07 +00:00
|
|
|
(assert (or (no next-space-generator*.name)
|
|
|
|
(is next-space-generator*.name (alref oarg 'names)))
|
|
|
|
"function can have only one next-space-generator environment")
|
2015-01-03 02:13:04 +00:00
|
|
|
(tr "next-space-generator of @name is @(alref oarg 'names)")
|
|
|
|
(= next-space-generator*.name (alref oarg 'names))))))))
|
2014-12-30 22:52:58 +00:00
|
|
|
|
|
|
|
; just a helper for testing; in practice we unbundle assign-names-to-location
|
|
|
|
; and replace-names-with-location.
|
|
|
|
(def convert-names (instrs (o name))
|
2014-12-13 22:00:14 +00:00
|
|
|
;? (tr "convert-names " instrs)
|
2015-01-29 20:13:24 +00:00
|
|
|
(= location*.name (assign-names-to-location instrs name))
|
|
|
|
;? (tr "save names for function @name: @(tostring:pr location*.name)") ;? 1
|
2014-12-30 22:52:58 +00:00
|
|
|
(replace-names-with-location instrs name))
|
|
|
|
|
2015-02-23 08:22:45 +00:00
|
|
|
(def assign-names-to-location (instrs name (o init-locations))
|
2015-02-11 09:09:07 +00:00
|
|
|
(trace "cn0" "convert-names in @name")
|
2015-01-29 20:33:57 +00:00
|
|
|
;? (prn name ": " location*) ;? 1
|
2015-01-29 21:47:30 +00:00
|
|
|
(point return
|
2015-02-23 08:22:45 +00:00
|
|
|
(ret location (or init-locations (table))
|
2015-01-29 20:33:57 +00:00
|
|
|
; if default-space in first instruction has a name, begin with its bindings
|
|
|
|
(when (acons instrs.0) ; not a label
|
|
|
|
(let first-oarg-of-first-instr instrs.0.0 ; hack: assumes the standard default-space boilerplate
|
|
|
|
(when (and (nondummy first-oarg-of-first-instr)
|
|
|
|
(is 'default-space (v first-oarg-of-first-instr))
|
|
|
|
(assoc 'names metadata.first-oarg-of-first-instr))
|
|
|
|
(let old-names (location*:alref metadata.first-oarg-of-first-instr 'names)
|
|
|
|
(unless old-names
|
2015-01-29 21:47:30 +00:00
|
|
|
;? (prn "@name requires bindings for @(alref metadata.first-oarg-of-first-instr 'names) which aren't computed yet. Waiting.") ;? 1
|
|
|
|
(return nil))
|
2015-01-29 20:33:57 +00:00
|
|
|
(= location copy.old-names))))) ; assumption: we've already converted names for 'it'
|
2015-01-29 21:47:30 +00:00
|
|
|
;? (unless empty.location (prn location)) ;? 2
|
2014-12-30 22:52:58 +00:00
|
|
|
(with (isa-field (table)
|
2015-01-29 21:47:30 +00:00
|
|
|
idx (+ 1 ; 0 always reserved for next space
|
|
|
|
(or (apply max vals.location) ; skip past bindings already shared from elsewhere
|
|
|
|
0))
|
|
|
|
already-location (copy location)
|
|
|
|
)
|
2014-10-29 07:18:58 +00:00
|
|
|
(each instr instrs
|
2014-11-23 06:26:11 +00:00
|
|
|
(point continue
|
|
|
|
(when atom.instr
|
|
|
|
(continue))
|
2014-11-07 19:59:22 +00:00
|
|
|
(trace "cn0" instr " " canon.location " " canon.isa-field)
|
2014-10-29 07:18:58 +00:00
|
|
|
(let (oargs op args) (parse-instr instr)
|
2015-01-01 05:24:48 +00:00
|
|
|
;? (tr "about to rename args: @op")
|
2015-01-28 04:50:21 +00:00
|
|
|
(when (in op 'get 'get-address)
|
2014-12-30 22:41:12 +00:00
|
|
|
; special case: map field offset by looking up type table
|
2014-12-17 22:03:34 +00:00
|
|
|
(with (basetype (typeof args.0)
|
2014-11-04 06:34:58 +00:00
|
|
|
field (v args.1))
|
2015-01-01 05:24:48 +00:00
|
|
|
;? (tr 111 " " args.0 " " basetype)
|
2014-12-17 22:03:34 +00:00
|
|
|
(assert type*.basetype!and-record "get on non-record @args.0")
|
2015-01-01 05:24:48 +00:00
|
|
|
;? (tr 112)
|
2014-12-17 22:03:34 +00:00
|
|
|
(trace "cn0" "field-access @field in @args.0 of type @basetype")
|
2014-11-04 06:34:58 +00:00
|
|
|
(when (isa field 'sym)
|
2015-01-29 21:47:30 +00:00
|
|
|
(unless (already-location field)
|
|
|
|
(assert (or (~location field) isa-field.field) "field @args.1 is also a variable"))
|
2014-11-07 19:59:22 +00:00
|
|
|
(when (~location field)
|
|
|
|
(trace "cn0" "new field; computing location")
|
2014-12-17 22:03:34 +00:00
|
|
|
;? (tr "aa " type*.basetype)
|
|
|
|
(assert type*.basetype!fields "no field names available for @instr")
|
|
|
|
;? (tr "bb")
|
|
|
|
(iflet idx (pos field type*.basetype!fields)
|
2014-11-07 08:56:42 +00:00
|
|
|
(do (set isa-field.field)
|
2014-11-07 20:01:20 +00:00
|
|
|
(trace "cn0" "field location @idx")
|
2014-11-07 19:59:22 +00:00
|
|
|
(= location.field idx))
|
2015-01-28 04:50:21 +00:00
|
|
|
(assert nil "couldn't find field in @instr"))))))
|
|
|
|
; map args to location indices
|
|
|
|
(each arg args
|
|
|
|
(trace "cn0" "checking arg " arg)
|
|
|
|
(when (and nondummy.arg not-raw-string.arg (~literal? arg))
|
|
|
|
(assert (~isa-field v.arg) "arg @arg is also a field name")
|
|
|
|
(when (maybe-add arg location idx)
|
|
|
|
; todo: test this
|
|
|
|
(err "use before set: @arg"))))
|
2014-12-17 22:03:34 +00:00
|
|
|
;? (tr "about to rename oargs")
|
2014-12-30 22:41:12 +00:00
|
|
|
; map oargs to location indices
|
2014-10-29 07:18:58 +00:00
|
|
|
(each arg oargs
|
2015-01-01 05:18:22 +00:00
|
|
|
(trace "cn0" "checking oarg " arg)
|
2014-12-14 20:36:42 +00:00
|
|
|
(when (and nondummy.arg not-raw-string.arg)
|
2014-11-07 19:50:41 +00:00
|
|
|
(assert (~isa-field v.arg) "oarg @arg is also a field name")
|
2014-11-07 19:59:22 +00:00
|
|
|
(when (maybe-add arg location idx)
|
2015-01-01 05:18:22 +00:00
|
|
|
(trace "cn0" "location for oarg " arg ": " idx)
|
2014-11-27 08:34:29 +00:00
|
|
|
; todo: can't allocate arrays on the stack
|
2015-01-29 21:47:30 +00:00
|
|
|
(++ idx (sizeof `((_ ,@ty.arg))))))))))))))
|
2014-12-30 22:52:58 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def replace-names-with-location (instrs name)
|
2014-12-30 22:52:58 +00:00
|
|
|
(each instr instrs
|
|
|
|
(when (acons instr)
|
|
|
|
(let (oargs op args) (parse-instr instr)
|
|
|
|
(each arg args
|
|
|
|
(convert-name arg name))
|
|
|
|
(each arg oargs
|
|
|
|
(convert-name arg name)))))
|
2015-01-10 21:53:00 +00:00
|
|
|
(each instr instrs
|
|
|
|
(trace "cn1" instr))
|
2014-12-30 22:52:58 +00:00
|
|
|
instrs)
|
2014-10-29 07:18:58 +00:00
|
|
|
|
2015-02-08 21:24:10 +00:00
|
|
|
(= allow-raw-addresses* nil)
|
2015-02-27 03:15:07 +00:00
|
|
|
(def check-default-space (instrs name)
|
2015-02-08 21:24:10 +00:00
|
|
|
(unless allow-raw-addresses*
|
|
|
|
(let oarg-names (accum yield
|
|
|
|
(each (oargs _ _) (map parse-instr (keep acons ; non-label
|
|
|
|
instrs))
|
|
|
|
(each oarg oargs
|
|
|
|
(when nondummy.oarg
|
|
|
|
(yield v.oarg)))))
|
|
|
|
(when (~pos 'default-space oarg-names)
|
|
|
|
(prn "function @name has no default-space")))))
|
2015-02-08 19:55:28 +00:00
|
|
|
|
2014-12-30 22:52:58 +00:00
|
|
|
; assign an index to an arg
|
2015-02-27 03:15:07 +00:00
|
|
|
(def maybe-add (arg location idx)
|
2014-11-07 19:50:41 +00:00
|
|
|
(trace "maybe-add" arg)
|
2014-11-07 19:56:34 +00:00
|
|
|
(when (and nondummy.arg
|
2014-12-30 22:52:58 +00:00
|
|
|
;? (prn arg " " (assoc 'space arg))
|
|
|
|
(~assoc 'space arg)
|
2014-12-28 22:07:30 +00:00
|
|
|
(~literal? arg)
|
2014-11-07 19:59:22 +00:00
|
|
|
(~location v.arg)
|
2014-11-04 06:38:28 +00:00
|
|
|
(isa v.arg 'sym)
|
2015-01-03 02:13:04 +00:00
|
|
|
(~in v.arg 'nil 'default-space)
|
2014-12-27 06:21:25 +00:00
|
|
|
(~pos '(raw) metadata.arg))
|
2014-11-07 19:59:22 +00:00
|
|
|
(= (location v.arg) idx)))
|
2014-10-29 07:18:58 +00:00
|
|
|
|
2014-12-30 22:52:58 +00:00
|
|
|
; convert the arg to corresponding index
|
2015-02-27 03:15:07 +00:00
|
|
|
(def convert-name (arg default-name)
|
2014-12-30 22:52:58 +00:00
|
|
|
;? (prn "111 @arg @default-name")
|
2015-01-01 05:15:26 +00:00
|
|
|
(when (and nondummy.arg not-raw-string.arg
|
|
|
|
(~is ty.arg.0 'literal)) ; can't use 'literal?' because we want to rename offsets
|
2014-12-30 22:52:58 +00:00
|
|
|
;? (prn "112 @arg")
|
|
|
|
(let name (space-to-name arg default-name)
|
|
|
|
;? (prn "113 @arg @name @keys.location* @(tostring:pr location*.name)")
|
|
|
|
;? (when (is arg '((y integer) (space 1)))
|
|
|
|
;? (prn "@arg => @name"))
|
|
|
|
(when (aand location*.name (it v.arg))
|
|
|
|
;? (prn 114)
|
|
|
|
(zap location*.name v.arg))
|
|
|
|
;? (prn 115)
|
|
|
|
)))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def space-to-name (arg default-name)
|
2014-12-30 22:52:58 +00:00
|
|
|
(ret name default-name
|
|
|
|
(when (~is space.arg 'global)
|
|
|
|
(repeat space.arg
|
2015-01-03 02:13:04 +00:00
|
|
|
(zap next-space-generator* name)))))
|
2014-12-30 22:52:58 +00:00
|
|
|
|
2015-03-12 23:44:27 +00:00
|
|
|
(proc check-numeric-address (instrs name)
|
|
|
|
;? (prn name) ;? 2
|
|
|
|
(on instr instrs
|
|
|
|
;? (prn instr) ;? 2
|
|
|
|
(when acons.instr ; not a label
|
|
|
|
(let (oargs op args) (parse-instr instr)
|
|
|
|
(each arg oargs
|
|
|
|
;? (prn " " arg) ;? 2
|
|
|
|
(when (and acons.arg ; not dummy _ or raw string
|
|
|
|
(isa v.arg 'int)
|
|
|
|
(~is v.arg 0)
|
|
|
|
(~pos '(raw) metadata.arg)
|
|
|
|
(~literal? arg))
|
|
|
|
(prn "using a raw integer address @arg in @name (instruction #@index)")))
|
|
|
|
(each arg args
|
|
|
|
;? (prn " " arg) ;? 2
|
|
|
|
(when (and acons.arg ; not dummy _ or raw string
|
|
|
|
(isa v.arg 'int)
|
|
|
|
(~is v.arg 0)
|
|
|
|
(~pos '(raw) metadata.arg)
|
|
|
|
(~literal? arg))
|
|
|
|
(prn "using a raw integer address @arg in @name (instruction #@index)")))))))
|
|
|
|
|
2014-10-29 15:55:00 +00:00
|
|
|
;; literate tangling system for reordering code
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def convert-quotes (instrs)
|
2014-10-29 15:55:00 +00:00
|
|
|
(let deferred (queue)
|
|
|
|
(each instr instrs
|
2014-11-25 02:56:15 +00:00
|
|
|
(when (acons instr)
|
|
|
|
(case instr.0
|
|
|
|
defer
|
|
|
|
(let (q qinstrs) instr.1
|
|
|
|
(assert (is 'make-br-fn q) "defer: first arg must be [quoted]")
|
|
|
|
(each qinstr qinstrs
|
|
|
|
(enq qinstr deferred))))))
|
2014-10-29 15:55:00 +00:00
|
|
|
(accum yield
|
|
|
|
(each instr instrs
|
2014-12-04 02:12:44 +00:00
|
|
|
(if atom.instr ; label
|
|
|
|
(yield instr)
|
|
|
|
(is instr.0 'defer)
|
|
|
|
nil ; skip
|
|
|
|
(is instr.0 'reply)
|
|
|
|
(do
|
2014-12-04 02:19:40 +00:00
|
|
|
(when cdr.instr ; return values
|
|
|
|
(= instr.0 'prepare-reply)
|
|
|
|
(yield instr))
|
2014-12-04 02:12:44 +00:00
|
|
|
(each instr (as cons deferred)
|
|
|
|
(yield instr))
|
2014-12-04 02:19:40 +00:00
|
|
|
(yield '(reply)))
|
2014-12-04 02:12:44 +00:00
|
|
|
:else
|
|
|
|
(yield instr)))
|
2014-10-29 15:55:00 +00:00
|
|
|
(each instr (as cons deferred)
|
|
|
|
(yield instr)))))
|
|
|
|
|
2014-11-25 03:27:52 +00:00
|
|
|
(on-init
|
|
|
|
(= before* (table)) ; label -> queue of fragments
|
|
|
|
(= after* (table))) ; label -> list of fragments
|
|
|
|
|
2014-11-25 05:40:59 +00:00
|
|
|
; see add-code below for adding to before* and after*
|
2014-11-25 03:27:52 +00:00
|
|
|
|
2014-11-27 05:36:14 +00:00
|
|
|
(def insert-code (instrs (o name))
|
2014-12-13 22:00:14 +00:00
|
|
|
;? (tr "insert-code " instrs)
|
2014-11-25 06:05:56 +00:00
|
|
|
(loop (instrs instrs)
|
|
|
|
(accum yield
|
|
|
|
(each instr instrs
|
|
|
|
(if (and (acons instr) (~is 'begin car.instr))
|
|
|
|
; simple instruction
|
|
|
|
(yield instr)
|
|
|
|
(and (acons instr) (is 'begin car.instr))
|
|
|
|
; block
|
|
|
|
(yield `{begin ,@(recur cdr.instr)})
|
|
|
|
(atom instr)
|
|
|
|
; label
|
|
|
|
(do
|
|
|
|
;? (prn "tangling " instr)
|
2014-11-27 05:36:14 +00:00
|
|
|
(each fragment (as cons (or (and name (before* (sym:string name '/ instr)))
|
|
|
|
before*.instr))
|
2014-11-25 06:05:56 +00:00
|
|
|
(each instr fragment
|
|
|
|
(yield instr)))
|
|
|
|
(yield instr)
|
2014-11-27 05:36:14 +00:00
|
|
|
(each fragment (or (and name (after* (sym:string name '/ instr)))
|
|
|
|
after*.instr)
|
2014-11-25 06:05:56 +00:00
|
|
|
(each instr fragment
|
|
|
|
(yield instr)))))))))
|
2014-11-25 03:27:52 +00:00
|
|
|
|
2014-12-15 10:00:18 +00:00
|
|
|
;; loading code into the virtual machine
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def add-code (forms)
|
2014-12-15 10:00:18 +00:00
|
|
|
(each (op . rest) forms
|
|
|
|
(case op
|
2014-12-17 18:41:43 +00:00
|
|
|
; function <name> [ <instructions> ]
|
2014-12-15 10:00:18 +00:00
|
|
|
; don't apply our lightweight tools just yet
|
|
|
|
function!
|
|
|
|
(let (name (_make-br-fn body)) rest
|
|
|
|
(assert (is 'make-br-fn _make-br-fn))
|
2015-02-08 19:33:29 +00:00
|
|
|
(= name (v tokenize-arg.name))
|
2014-12-15 10:00:18 +00:00
|
|
|
(= function*.name body))
|
|
|
|
function
|
|
|
|
(let (name (_make-br-fn body)) rest
|
|
|
|
(assert (is 'make-br-fn _make-br-fn))
|
2015-02-08 19:33:29 +00:00
|
|
|
(= name (v tokenize-arg.name))
|
2015-01-15 06:29:16 +00:00
|
|
|
(when function*.name
|
|
|
|
(prn "adding new clause to @name"))
|
2014-12-15 10:00:18 +00:00
|
|
|
(= function*.name (join body function*.name)))
|
|
|
|
|
2014-12-17 19:01:38 +00:00
|
|
|
; and-record <type> [ <name:types> ]
|
|
|
|
and-record
|
|
|
|
(let (name (_make-br-fn fields)) rest
|
|
|
|
(assert (is 'make-br-fn _make-br-fn))
|
2015-02-08 19:33:29 +00:00
|
|
|
(= name (v tokenize-arg.name))
|
2014-12-17 19:01:38 +00:00
|
|
|
(let fields (map tokenize-arg fields)
|
|
|
|
(= type*.name (obj size len.fields
|
|
|
|
and-record t
|
2014-12-17 22:03:34 +00:00
|
|
|
; dump all metadata for now except field name and type
|
2014-12-17 19:01:38 +00:00
|
|
|
elems (map cdar fields)
|
|
|
|
fields (map caar fields)))))
|
|
|
|
|
2015-01-02 23:30:11 +00:00
|
|
|
; primitive <type>
|
|
|
|
primitive
|
|
|
|
(let (name) rest
|
2015-02-08 19:33:29 +00:00
|
|
|
(= name (v tokenize-arg.name))
|
2015-01-02 23:30:11 +00:00
|
|
|
(= type*.name (obj size 1)))
|
|
|
|
|
2015-01-01 05:24:48 +00:00
|
|
|
; address <type> <elem-type>
|
|
|
|
address
|
|
|
|
(let (name types) rest
|
2015-02-08 19:33:29 +00:00
|
|
|
(= name (v tokenize-arg.name))
|
2015-01-01 05:24:48 +00:00
|
|
|
(= type*.name (obj size 1
|
|
|
|
address t
|
|
|
|
elem types)))
|
|
|
|
|
|
|
|
; array <type> <elem-type>
|
|
|
|
array
|
|
|
|
(let (name types) rest
|
2015-02-08 19:33:29 +00:00
|
|
|
(= name (v tokenize-arg.name))
|
2015-01-01 05:24:48 +00:00
|
|
|
(= type*.name (obj array t
|
|
|
|
elem types)))
|
|
|
|
|
2014-12-17 18:41:43 +00:00
|
|
|
; before <label> [ <instructions> ]
|
2014-12-15 10:00:18 +00:00
|
|
|
;
|
|
|
|
; multiple before directives => code in order
|
|
|
|
before
|
|
|
|
(let (label (_make-br-fn fragment)) rest
|
|
|
|
(assert (is 'make-br-fn _make-br-fn))
|
2015-02-08 19:33:29 +00:00
|
|
|
; todo: stop using '/' in non-standard manner
|
|
|
|
;(= label (v tokenize-arg.label))
|
2014-12-15 10:00:18 +00:00
|
|
|
(or= before*.label (queue))
|
|
|
|
(enq fragment before*.label))
|
|
|
|
|
2014-12-17 18:41:43 +00:00
|
|
|
; after <label> [ <instructions> ]
|
2014-12-15 10:00:18 +00:00
|
|
|
;
|
|
|
|
; multiple after directives => code in *reverse* order
|
|
|
|
; (if initialization order in a function is A B, corresponding
|
|
|
|
; finalization order should be B A)
|
|
|
|
after
|
|
|
|
(let (label (_make-br-fn fragment)) rest
|
|
|
|
(assert (is 'make-br-fn _make-br-fn))
|
2015-02-08 19:33:29 +00:00
|
|
|
; todo: stop using '/' in non-standard manner
|
|
|
|
;(= label (v tokenize-arg.label))
|
2014-12-15 10:00:18 +00:00
|
|
|
(push fragment after*.label))
|
2015-01-15 05:27:03 +00:00
|
|
|
|
|
|
|
;else
|
|
|
|
(prn "unrecognized top-level " (cons op rest))
|
2014-12-15 10:00:18 +00:00
|
|
|
)))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def freeze (function-table)
|
2014-12-30 23:13:51 +00:00
|
|
|
(each (name body) canon.function-table
|
|
|
|
;? (prn "freeze " name)
|
|
|
|
(= function-table.name (convert-labels:convert-braces:tokenize-args:insert-code body name)))
|
2015-02-08 19:55:28 +00:00
|
|
|
(each (name body) canon.function-table
|
|
|
|
(check-default-space body name))
|
2015-03-12 23:44:27 +00:00
|
|
|
(each (name body) canon.function-table
|
|
|
|
(check-numeric-address body name))
|
2014-12-30 23:13:51 +00:00
|
|
|
(each (name body) canon.function-table
|
2015-01-03 02:13:04 +00:00
|
|
|
(add-next-space-generator body name))
|
2015-02-08 19:55:28 +00:00
|
|
|
; keep converting names until none remain
|
|
|
|
; (we need to skip unrecognized spaces)
|
2015-01-29 21:47:30 +00:00
|
|
|
(let change t
|
|
|
|
(while change
|
|
|
|
(= change nil)
|
|
|
|
(each (name body) canon.function-table
|
2015-03-13 16:58:22 +00:00
|
|
|
;? (prn name) ;? 1
|
2015-01-29 21:47:30 +00:00
|
|
|
(when (no location*.name)
|
|
|
|
(= change t))
|
|
|
|
(or= location*.name (assign-names-to-location body name)))))
|
|
|
|
;? (each (name body) canon.function-table ;? 1
|
|
|
|
;? (or= location*.name (assign-names-to-location body name))) ;? 1
|
2014-12-30 23:13:51 +00:00
|
|
|
(each (name body) canon.function-table
|
|
|
|
(= function-table.name (replace-names-with-location body name)))
|
2014-12-30 22:52:58 +00:00
|
|
|
; we could clear location* at this point, but maybe we'll find a use for it
|
|
|
|
)
|
2014-12-15 10:00:18 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def freeze-another (fn-name)
|
2015-02-11 09:09:07 +00:00
|
|
|
(= function*.fn-name (convert-labels:convert-braces:tokenize-args:insert-code function*.fn-name fn-name))
|
|
|
|
(check-default-space function*.fn-name fn-name)
|
|
|
|
(add-next-space-generator function*.fn-name fn-name)
|
2015-02-23 08:22:45 +00:00
|
|
|
(= location*.fn-name (assign-names-to-location function*.fn-name fn-name location*.fn-name))
|
|
|
|
(replace-names-with-location function*.fn-name fn-name))
|
2015-02-11 09:09:07 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def tokenize-arg (arg)
|
2014-12-15 10:00:18 +00:00
|
|
|
;? (tr "tokenize-arg " arg)
|
|
|
|
(if (in arg '<- '_)
|
|
|
|
arg
|
|
|
|
(isa arg 'sym)
|
|
|
|
(map [map [fromstring _ (read)] _]
|
|
|
|
(map [tokens _ #\:]
|
|
|
|
(tokens string.arg #\/)))
|
|
|
|
:else
|
|
|
|
arg))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def tokenize-args (instrs)
|
2014-12-15 10:00:18 +00:00
|
|
|
;? (tr "tokenize-args " instrs)
|
|
|
|
;? (prn2 "@(tostring prn.instrs) => "
|
|
|
|
(accum yield
|
|
|
|
(each instr instrs
|
|
|
|
(if atom.instr
|
|
|
|
(yield instr)
|
|
|
|
(is 'begin instr.0)
|
|
|
|
(yield `{begin ,@(tokenize-args cdr.instr)})
|
|
|
|
:else
|
|
|
|
(yield (map tokenize-arg instr))))))
|
|
|
|
;? )
|
|
|
|
|
|
|
|
(def prn2 (msg . args)
|
|
|
|
(pr msg)
|
|
|
|
(apply prn args))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def canon (table)
|
2014-12-15 10:00:18 +00:00
|
|
|
(sort (compare < [tostring (prn:car _)]) (as cons table)))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def int-canon (table)
|
2014-12-15 10:00:18 +00:00
|
|
|
(sort (compare < car) (as cons table)))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def routine-canon (routine-table)
|
2015-01-25 07:36:30 +00:00
|
|
|
(sort (compare < label:car) (as cons routine-table)))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def repr (val)
|
2015-01-24 21:49:21 +00:00
|
|
|
(tostring write.val))
|
|
|
|
|
2014-12-15 10:00:18 +00:00
|
|
|
;; test helpers
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def memory-contains (addr value)
|
2014-12-15 10:00:18 +00:00
|
|
|
;? (prn "Looking for @value starting at @addr")
|
|
|
|
(loop (addr addr
|
|
|
|
idx 0)
|
|
|
|
;? (prn "@idx vs @addr")
|
|
|
|
(if (>= idx len.value)
|
|
|
|
t
|
|
|
|
(~is memory*.addr value.idx)
|
|
|
|
(do1 nil
|
|
|
|
(prn "@addr should contain @value.idx but contains @memory*.addr"))
|
|
|
|
:else
|
|
|
|
(recur (+ addr 1) (+ idx 1)))))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def memory-contains-array (addr value)
|
2015-02-16 06:48:58 +00:00
|
|
|
(and (>= memory*.addr len.value)
|
|
|
|
(loop (addr (+ addr 1) ; skip count
|
|
|
|
idx 0)
|
|
|
|
(if (>= idx len.value)
|
|
|
|
t
|
|
|
|
(~is memory*.addr value.idx)
|
|
|
|
nil
|
|
|
|
:else
|
|
|
|
(recur (+ addr 1) (+ idx 1))))))
|
2015-02-11 19:52:56 +00:00
|
|
|
|
2015-02-16 07:13:13 +00:00
|
|
|
; like memory-contains-array but shows diffs
|
2015-02-27 03:15:07 +00:00
|
|
|
(def memory-contains-array-verbose (addr value)
|
2015-02-11 19:52:56 +00:00
|
|
|
(prn "Mismatch when looking at @addr, size @memory*.addr vs @len.value")
|
2014-12-15 10:00:18 +00:00
|
|
|
(and (>= memory*.addr len.value)
|
2015-02-16 05:34:02 +00:00
|
|
|
(loop (addr (+ addr 1) ; skip count
|
2014-12-15 10:00:18 +00:00
|
|
|
idx 0)
|
2015-02-11 19:52:56 +00:00
|
|
|
(and (< idx len.value) (prn "comparing @idx: @memory*.addr and @value.idx"))
|
2014-12-15 10:00:18 +00:00
|
|
|
(if (>= idx len.value)
|
|
|
|
t
|
|
|
|
(~is memory*.addr value.idx)
|
|
|
|
(do1 nil
|
2015-01-26 11:11:04 +00:00
|
|
|
(prn "@addr should contain @(repr value.idx) but contains @(repr memory*.addr)")
|
2015-02-11 19:52:56 +00:00
|
|
|
(recur (+ addr 1) (+ idx 1)))
|
2014-12-15 10:00:18 +00:00
|
|
|
:else
|
|
|
|
(recur (+ addr 1) (+ idx 1))))))
|
|
|
|
|
2015-02-16 07:13:13 +00:00
|
|
|
; like memory-contains-array but shows diffs in 2D
|
2015-02-27 03:15:07 +00:00
|
|
|
(def screen-contains (addr width value)
|
2015-02-16 05:34:02 +00:00
|
|
|
(or (memory-contains-array addr value)
|
2015-02-28 03:09:49 +00:00
|
|
|
(do1 nil
|
2015-02-16 07:00:25 +00:00
|
|
|
(prn "Mismatch detected. Screen contents:")
|
2015-02-16 05:34:02 +00:00
|
|
|
(with (row-start-addr (+ addr 1) ; skip count
|
|
|
|
idx 0)
|
|
|
|
(for row 0 (< row (/ len.value width)) (do ++.row (++ row-start-addr width))
|
|
|
|
(pr ". ")
|
|
|
|
(for col 0 (< col width) ++.col
|
|
|
|
(with (expected value.idx
|
|
|
|
got (memory* (+ col row-start-addr)))
|
2015-02-16 07:00:25 +00:00
|
|
|
(pr got)
|
|
|
|
(pr (if (is expected got) " " "X")))
|
2015-02-16 05:34:02 +00:00
|
|
|
++.idx)
|
|
|
|
(prn " .")
|
|
|
|
)))))
|
|
|
|
|
2015-02-11 09:09:07 +00:00
|
|
|
; run code in tests
|
2015-01-21 10:01:54 +00:00
|
|
|
(mac run-code (name . body)
|
2015-02-11 09:09:07 +00:00
|
|
|
; careful to avoid re-processing functions and adding noise to traces
|
2015-01-21 10:01:54 +00:00
|
|
|
`(do
|
2015-02-16 12:24:21 +00:00
|
|
|
(prn "-- " ',name)
|
2015-03-02 04:46:24 +00:00
|
|
|
(trace "===" ',name)
|
2015-02-11 19:52:56 +00:00
|
|
|
(wipe (function* ',name))
|
2015-01-21 10:01:54 +00:00
|
|
|
(add-code '((function ,name [ ,@body ])))
|
2015-02-11 09:09:07 +00:00
|
|
|
(freeze-another ',name)
|
2015-03-02 01:09:06 +00:00
|
|
|
;? (set dump-trace*) ;? 1
|
2015-02-11 09:09:07 +00:00
|
|
|
(run-more ',name)))
|
2015-01-21 10:01:54 +00:00
|
|
|
|
2015-03-02 04:37:03 +00:00
|
|
|
; kludge to prevent reloading functions in .mu files for every test
|
|
|
|
(def reset2 ()
|
|
|
|
(= memory* (table))
|
|
|
|
(= Memory-allocated-until 1000)
|
|
|
|
(awhen curr-trace-file*
|
|
|
|
(tofile (+ trace-dir* it)
|
|
|
|
(each (label trace) (as cons traces*)
|
|
|
|
(pr label ": " trace))))
|
|
|
|
(= curr-trace-file* nil)
|
|
|
|
(= traces* (queue))
|
|
|
|
(wipe dump-trace*)
|
|
|
|
(wipe function*!main)
|
|
|
|
(wipe location*!main)
|
|
|
|
(= running-routines* (queue))
|
|
|
|
(= sleeping-routines* (table))
|
|
|
|
(wipe completed-routines*)
|
|
|
|
(wipe routine*)
|
|
|
|
(= abort-routine* (parameter nil))
|
|
|
|
(= curr-cycle* 0)
|
|
|
|
(= scheduling-interval* 500)
|
|
|
|
(= scheduler-switch-table* nil)
|
|
|
|
)
|
|
|
|
|
2015-03-10 04:26:13 +00:00
|
|
|
(= disable-debug-prints-in-console-mode* nil)
|
|
|
|
(def test-only-settings ()
|
|
|
|
(set allow-raw-addresses*)
|
|
|
|
(set disable-debug-prints-in-console-mode*))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def routine-that-ran (f)
|
2015-01-15 00:06:53 +00:00
|
|
|
(find [some [is f _!fn-name] stack._]
|
|
|
|
completed-routines*))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def routine-running (f)
|
2015-01-21 09:23:57 +00:00
|
|
|
(or
|
|
|
|
(find [some [is f _!fn-name] stack._]
|
|
|
|
completed-routines*)
|
|
|
|
(find [some [is f _!fn-name] stack._]
|
|
|
|
(as cons running-routines*))
|
|
|
|
(find [some [is f _!fn-name] stack._]
|
|
|
|
(keys sleeping-routines*))
|
|
|
|
(and routine*
|
|
|
|
(some [is f _!fn-name] stack.routine*)
|
|
|
|
routine*)))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def ran-to-completion (f)
|
2015-01-10 11:32:14 +00:00
|
|
|
; if a routine calling f ran to completion there'll be no sign of it in any
|
|
|
|
; completed call-stacks.
|
2015-01-21 10:01:54 +00:00
|
|
|
(~routine-that-ran f))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def restart (routine)
|
2015-01-21 10:01:54 +00:00
|
|
|
(while (in top.routine!fn-name 'read 'write)
|
|
|
|
(pop-stack routine))
|
|
|
|
(wipe rep.routine!sleep)
|
2015-01-21 20:33:36 +00:00
|
|
|
(wipe rep.routine!error)
|
2015-01-21 10:01:54 +00:00
|
|
|
(enq routine running-routines*))
|
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def dump (msg routine)
|
2015-01-21 10:01:54 +00:00
|
|
|
(prn "= @msg " rep.routine!sleep)
|
|
|
|
(prn:rem [in car._ 'sleep 'call-stack] (as cons rep.routine))
|
|
|
|
(each frame rep.routine!call-stack
|
|
|
|
(prn " @frame!fn-name")
|
|
|
|
(each (key val) frame
|
|
|
|
(unless (is key 'fn-name)
|
|
|
|
(prn " " key " " val)))))
|
2015-01-10 11:32:14 +00:00
|
|
|
|
2014-10-11 17:09:41 +00:00
|
|
|
;; system software
|
2014-12-15 10:00:18 +00:00
|
|
|
; create once, load before every test
|
|
|
|
|
|
|
|
(reset)
|
|
|
|
(= system-function* (table))
|
|
|
|
|
|
|
|
(mac init-fn (name . body)
|
2015-02-08 19:33:29 +00:00
|
|
|
(let real-name (v tokenize-arg.name)
|
|
|
|
`(= (system-function* ',real-name) ',body)))
|
2014-12-15 10:00:18 +00:00
|
|
|
|
2015-02-27 03:15:07 +00:00
|
|
|
(def load-system-functions ()
|
2014-12-15 10:00:18 +00:00
|
|
|
(each (name f) system-function*
|
|
|
|
(= (function* name)
|
|
|
|
(system-function* name))))
|
2014-10-11 17:09:41 +00:00
|
|
|
|
2015-02-23 07:54:14 +00:00
|
|
|
; allow running mu.arc without load.arc
|
|
|
|
(unless bound!section (= section do))
|
|
|
|
|
2014-12-13 08:33:20 +00:00
|
|
|
(section 100
|
|
|
|
|
2014-10-11 17:09:41 +00:00
|
|
|
(init-fn maybe-coerce
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
(x:tagged-value-address <- new tagged-value:literal)
|
|
|
|
(x:tagged-value-address/deref <- next-input)
|
|
|
|
(p:type <- next-input)
|
2014-12-31 07:38:50 +00:00
|
|
|
(xtype:type <- get x:tagged-value-address/deref type:offset)
|
2014-12-14 20:36:42 +00:00
|
|
|
(match?:boolean <- equal xtype:type p:type)
|
2014-10-11 17:09:41 +00:00
|
|
|
{ begin
|
2014-12-14 20:36:42 +00:00
|
|
|
(break-if match?:boolean)
|
|
|
|
(reply 0:literal nil:literal)
|
2014-10-11 17:09:41 +00:00
|
|
|
}
|
2014-12-31 07:38:50 +00:00
|
|
|
(xvalue:location <- get x:tagged-value-address/deref payload:offset)
|
2014-12-14 20:36:42 +00:00
|
|
|
(reply xvalue:location match?:boolean))
|
2014-10-11 17:09:41 +00:00
|
|
|
|
2014-12-28 21:03:50 +00:00
|
|
|
(init-fn init-tagged-value
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
; assert sizeof:arg.0 == 1
|
|
|
|
(xtype:type <- next-input)
|
|
|
|
(xtypesize:integer <- sizeof xtype:type)
|
|
|
|
(xcheck:boolean <- equal xtypesize:integer 1:literal)
|
|
|
|
(assert xcheck:boolean)
|
2014-10-12 19:01:04 +00:00
|
|
|
; todo: check that arg 0 matches the type? or is that for the future typechecker?
|
2014-12-14 20:36:42 +00:00
|
|
|
(result:tagged-value-address <- new tagged-value:literal)
|
2014-11-18 12:35:39 +00:00
|
|
|
; result->type = arg 0
|
2014-12-14 20:36:42 +00:00
|
|
|
(resulttype:location <- get-address result:tagged-value-address/deref type:offset)
|
|
|
|
(resulttype:location/deref <- copy xtype:type)
|
2014-11-18 12:35:39 +00:00
|
|
|
; result->payload = arg 1
|
2014-12-14 20:36:42 +00:00
|
|
|
(locaddr:location <- get-address result:tagged-value-address/deref payload:offset)
|
|
|
|
(locaddr:location/deref <- next-input)
|
|
|
|
(reply result:tagged-value-address))
|
2014-10-12 19:01:04 +00:00
|
|
|
|
2014-10-13 01:04:29 +00:00
|
|
|
(init-fn list-next ; list-address -> list-address
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
(base:list-address <- next-input)
|
|
|
|
(result:list-address <- get base:list-address/deref cdr:offset)
|
|
|
|
(reply result:list-address))
|
2014-10-13 01:04:29 +00:00
|
|
|
|
|
|
|
(init-fn list-value-address ; list-address -> tagged-value-address
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
(base:list-address <- next-input)
|
|
|
|
(result:tagged-value-address <- get-address base:list-address/deref car:offset)
|
|
|
|
(reply result:tagged-value-address))
|
2014-10-12 21:27:26 +00:00
|
|
|
|
2015-01-06 07:57:19 +00:00
|
|
|
; create a list out of a list of args
|
|
|
|
; only integers for now
|
2014-12-28 21:03:50 +00:00
|
|
|
(init-fn init-list
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-11-18 12:35:39 +00:00
|
|
|
; new-list = curr = new list
|
2014-12-28 21:03:50 +00:00
|
|
|
(result:list-address <- new list:literal)
|
|
|
|
(curr:list-address <- copy result:list-address)
|
2014-10-25 09:32:30 +00:00
|
|
|
{ begin
|
2014-11-18 12:35:39 +00:00
|
|
|
; while read curr-value
|
2014-12-14 20:36:42 +00:00
|
|
|
(curr-value:integer exists?:boolean <- next-input)
|
|
|
|
(break-unless exists?:boolean)
|
2014-11-18 12:35:39 +00:00
|
|
|
; curr.cdr = new list
|
2014-12-14 20:36:42 +00:00
|
|
|
(next:list-address-address <- get-address curr:list-address/deref cdr:offset)
|
|
|
|
(next:list-address-address/deref <- new list:literal)
|
2014-11-18 12:35:39 +00:00
|
|
|
; curr = curr.cdr
|
2014-12-14 20:36:42 +00:00
|
|
|
(curr:list-address <- list-next curr:list-address)
|
|
|
|
; curr.car = type:curr-value
|
|
|
|
(dest:tagged-value-address <- list-value-address curr:list-address)
|
|
|
|
(dest:tagged-value-address/deref <- save-type curr-value:integer)
|
2014-11-27 06:09:23 +00:00
|
|
|
(loop)
|
2014-10-25 09:32:30 +00:00
|
|
|
}
|
2014-11-18 12:35:39 +00:00
|
|
|
; return new-list.cdr
|
2014-12-28 21:03:50 +00:00
|
|
|
(result:list-address <- list-next result:list-address) ; memory leak
|
|
|
|
(reply result:list-address))
|
2014-10-25 09:32:30 +00:00
|
|
|
|
2014-12-31 06:36:36 +00:00
|
|
|
(init-fn list-length
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-12-31 06:36:36 +00:00
|
|
|
(curr:list-address <- next-input)
|
|
|
|
;? ; recursive
|
|
|
|
;? { begin
|
|
|
|
;? ; if empty list return 0
|
|
|
|
;? (t1:tagged-value-address <- list-value-address curr:list-address)
|
2015-01-17 21:29:43 +00:00
|
|
|
;? (break-if t1:tagged-value-address)
|
2014-12-31 06:36:36 +00:00
|
|
|
;? (reply 0:literal)
|
|
|
|
;? }
|
|
|
|
;? ; else return 1+length(curr.cdr)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ;? ($print (("recurse\n" literal)))
|
2014-12-31 06:36:36 +00:00
|
|
|
;? (next:list-address <- list-next curr:list-address)
|
|
|
|
;? (sub:integer <- list-length next:list-address)
|
|
|
|
;? (result:integer <- add sub:integer 1:literal)
|
|
|
|
;? (reply result:integer))
|
|
|
|
; iterative solution
|
|
|
|
(result:integer <- copy 0:literal)
|
|
|
|
{ begin
|
|
|
|
; while curr
|
|
|
|
(t1:tagged-value-address <- list-value-address curr:list-address)
|
2015-01-17 21:29:43 +00:00
|
|
|
(break-unless t1:tagged-value-address)
|
2014-12-31 06:36:36 +00:00
|
|
|
; ++result
|
|
|
|
(result:integer <- add result:integer 1:literal)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print result:integer)
|
|
|
|
;? ($print (("\n" literal)))
|
2014-12-31 06:36:36 +00:00
|
|
|
; curr = curr.cdr
|
|
|
|
(curr:list-address <- list-next curr:list-address)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
(reply result:integer))
|
|
|
|
|
2014-12-28 21:03:50 +00:00
|
|
|
(init-fn init-channel
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-11-18 12:35:39 +00:00
|
|
|
; result = new channel
|
2014-12-14 20:36:42 +00:00
|
|
|
(result:channel-address <- new channel:literal)
|
2014-11-18 12:35:39 +00:00
|
|
|
; result.first-full = 0
|
2014-12-14 20:36:42 +00:00
|
|
|
(full:integer-address <- get-address result:channel-address/deref first-full:offset)
|
|
|
|
(full:integer-address/deref <- copy 0:literal)
|
2014-11-18 12:35:39 +00:00
|
|
|
; result.first-free = 0
|
2014-12-14 20:36:42 +00:00
|
|
|
(free:integer-address <- get-address result:channel-address/deref first-free:offset)
|
|
|
|
(free:integer-address/deref <- copy 0:literal)
|
2014-11-18 12:35:39 +00:00
|
|
|
; result.circular-buffer = new tagged-value[arg+1]
|
2014-12-14 20:36:42 +00:00
|
|
|
(capacity:integer <- next-input)
|
|
|
|
(capacity:integer <- add capacity:integer 1:literal) ; unused slot for full? below
|
|
|
|
(channel-buffer-address:tagged-value-array-address-address <- get-address result:channel-address/deref circular-buffer:offset)
|
|
|
|
(channel-buffer-address:tagged-value-array-address-address/deref <- new tagged-value-array:literal capacity:integer)
|
|
|
|
(reply result:channel-address))
|
2014-11-04 08:01:57 +00:00
|
|
|
|
2014-11-18 12:39:24 +00:00
|
|
|
(init-fn capacity
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
(chan:channel <- next-input)
|
|
|
|
(q:tagged-value-array-address <- get chan:channel circular-buffer:offset)
|
|
|
|
(qlen:integer <- length q:tagged-value-array-address/deref)
|
|
|
|
(reply qlen:integer))
|
2014-11-18 12:39:24 +00:00
|
|
|
|
2014-11-04 21:46:31 +00:00
|
|
|
(init-fn write
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
(chan:channel-address <- next-input)
|
|
|
|
(val:tagged-value <- next-input)
|
2014-11-08 05:39:00 +00:00
|
|
|
{ begin
|
2014-11-08 18:31:37 +00:00
|
|
|
; block if chan is full
|
2014-12-14 20:36:42 +00:00
|
|
|
(full:boolean <- full? chan:channel-address/deref)
|
|
|
|
(break-unless full:boolean)
|
|
|
|
(full-address:integer-address <- get-address chan:channel-address/deref first-full:offset)
|
2015-01-09 07:21:56 +00:00
|
|
|
(sleep until-location-changes:literal full-address:integer-address/deref)
|
2014-11-08 05:39:00 +00:00
|
|
|
}
|
2014-11-23 03:50:21 +00:00
|
|
|
; store val
|
2014-12-14 20:36:42 +00:00
|
|
|
(q:tagged-value-array-address <- get chan:channel-address/deref circular-buffer:offset)
|
|
|
|
(free:integer-address <- get-address chan:channel-address/deref first-free:offset)
|
|
|
|
(dest:tagged-value-address <- index-address q:tagged-value-array-address/deref free:integer-address/deref)
|
|
|
|
(dest:tagged-value-address/deref <- copy val:tagged-value)
|
2014-11-23 03:50:21 +00:00
|
|
|
; increment free
|
2014-12-14 20:36:42 +00:00
|
|
|
(free:integer-address/deref <- add free:integer-address/deref 1:literal)
|
2014-11-07 20:33:12 +00:00
|
|
|
{ begin
|
2014-11-23 03:50:21 +00:00
|
|
|
; wrap free around to 0 if necessary
|
2014-12-14 20:36:42 +00:00
|
|
|
(qlen:integer <- length q:tagged-value-array-address/deref)
|
|
|
|
(remaining?:boolean <- less-than free:integer-address/deref qlen:integer)
|
|
|
|
(break-if remaining?:boolean)
|
|
|
|
(free:integer-address/deref <- copy 0:literal)
|
2014-11-07 20:33:12 +00:00
|
|
|
}
|
2015-01-26 06:56:53 +00:00
|
|
|
(reply chan:channel-address/deref/same-as-arg:0))
|
2014-11-04 21:46:31 +00:00
|
|
|
|
2014-11-05 02:35:13 +00:00
|
|
|
(init-fn read
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
(chan:channel-address <- next-input)
|
2015-01-25 19:38:13 +00:00
|
|
|
;? ($dump-channel chan:channel-address) ;? 2
|
2014-11-08 05:39:00 +00:00
|
|
|
{ begin
|
2014-11-08 18:31:37 +00:00
|
|
|
; block if chan is empty
|
2014-12-14 20:36:42 +00:00
|
|
|
(empty:boolean <- empty? chan:channel-address/deref)
|
|
|
|
(break-unless empty:boolean)
|
|
|
|
(free-address:integer-address <- get-address chan:channel-address/deref first-free:offset)
|
2015-01-09 07:21:56 +00:00
|
|
|
(sleep until-location-changes:literal free-address:integer-address/deref)
|
2014-11-08 05:39:00 +00:00
|
|
|
}
|
2014-11-23 03:50:21 +00:00
|
|
|
; read result
|
2014-12-14 20:36:42 +00:00
|
|
|
(full:integer-address <- get-address chan:channel-address/deref first-full:offset)
|
|
|
|
(q:tagged-value-array-address <- get chan:channel-address/deref circular-buffer:offset)
|
|
|
|
(result:tagged-value <- index q:tagged-value-array-address/deref full:integer-address/deref)
|
2014-11-23 03:50:21 +00:00
|
|
|
; increment full
|
2014-12-14 20:36:42 +00:00
|
|
|
(full:integer-address/deref <- add full:integer-address/deref 1:literal)
|
2014-11-07 20:33:12 +00:00
|
|
|
{ begin
|
2014-11-23 03:50:21 +00:00
|
|
|
; wrap full around to 0 if necessary
|
2014-12-14 20:36:42 +00:00
|
|
|
(qlen:integer <- length q:tagged-value-array-address/deref)
|
|
|
|
(remaining?:boolean <- less-than full:integer-address/deref qlen:integer)
|
|
|
|
(break-if remaining?:boolean)
|
|
|
|
(full:integer-address/deref <- copy 0:literal)
|
2014-11-07 20:33:12 +00:00
|
|
|
}
|
2015-01-26 06:56:53 +00:00
|
|
|
(reply result:tagged-value chan:channel-address/deref/same-as-arg:0))
|
2014-11-05 02:35:13 +00:00
|
|
|
|
2014-11-07 22:09:59 +00:00
|
|
|
; An empty channel has first-empty and first-full both at the same value.
|
|
|
|
(init-fn empty?
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-11-18 12:35:39 +00:00
|
|
|
; return arg.first-full == arg.first-free
|
2014-12-14 20:36:42 +00:00
|
|
|
(chan:channel <- next-input)
|
|
|
|
(full:integer <- get chan:channel first-full:offset)
|
|
|
|
(free:integer <- get chan:channel first-free:offset)
|
|
|
|
(result:boolean <- equal full:integer free:integer)
|
|
|
|
(reply result:boolean))
|
2014-11-07 22:09:59 +00:00
|
|
|
|
2014-11-08 18:31:37 +00:00
|
|
|
; A full channel has first-empty just before first-full, wasting one slot.
|
|
|
|
; (Other alternatives: https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)
|
2014-11-07 22:09:59 +00:00
|
|
|
(init-fn full?
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
(chan:channel <- next-input)
|
2014-11-18 12:35:39 +00:00
|
|
|
; curr = chan.first-free + 1
|
2014-12-14 20:36:42 +00:00
|
|
|
(curr:integer <- get chan:channel first-free:offset)
|
|
|
|
(curr:integer <- add curr:integer 1:literal)
|
2014-11-07 22:09:59 +00:00
|
|
|
{ begin
|
2014-11-18 12:35:39 +00:00
|
|
|
; if (curr == chan.capacity) curr = 0
|
2014-12-14 20:36:42 +00:00
|
|
|
(qlen:integer <- capacity chan:channel)
|
|
|
|
(remaining?:boolean <- less-than curr:integer qlen:integer)
|
|
|
|
(break-if remaining?:boolean)
|
|
|
|
(curr:integer <- copy 0:literal)
|
2014-11-07 22:09:59 +00:00
|
|
|
}
|
2014-11-18 12:35:39 +00:00
|
|
|
; return chan.first-full == curr
|
2014-12-14 20:36:42 +00:00
|
|
|
(full:integer <- get chan:channel first-full:offset)
|
|
|
|
(result:boolean <- equal full:integer curr:integer)
|
|
|
|
(reply result:boolean))
|
2014-11-07 22:09:59 +00:00
|
|
|
|
2015-02-05 07:28:50 +00:00
|
|
|
(init-fn string-equal
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(a:string-address <- next-input)
|
|
|
|
(a-len:integer <- length a:string-address/deref)
|
|
|
|
(b:string-address <- next-input)
|
|
|
|
(b-len:integer <- length b:string-address/deref)
|
|
|
|
; compare lengths
|
|
|
|
{ begin
|
|
|
|
(length-equal?:boolean <- equal a-len:integer b-len:integer)
|
|
|
|
(break-if length-equal?:boolean)
|
|
|
|
(reply nil:literal)
|
|
|
|
}
|
|
|
|
; compare each corresponding byte
|
|
|
|
(i:integer <- copy 0:literal)
|
|
|
|
{ begin
|
|
|
|
(done?:boolean <- greater-or-equal i:integer a-len:integer)
|
|
|
|
(break-if done?:boolean)
|
2015-02-08 19:12:08 +00:00
|
|
|
(a2:byte <- index a:string-address/deref i:integer)
|
|
|
|
(b2:byte <- index b:string-address/deref i:integer)
|
2015-02-05 07:28:50 +00:00
|
|
|
{ begin
|
2015-02-08 19:12:08 +00:00
|
|
|
(chars-match?:boolean <- equal a2:byte b2:byte)
|
2015-02-05 07:28:50 +00:00
|
|
|
(break-if chars-match?:boolean)
|
|
|
|
(reply nil:literal)
|
|
|
|
}
|
|
|
|
(i:integer <- add i:integer 1:literal)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
(reply t:literal)
|
|
|
|
)
|
|
|
|
|
2014-11-27 08:34:29 +00:00
|
|
|
(init-fn strcat
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-11-27 08:34:29 +00:00
|
|
|
; result = new string[a.length + b.length]
|
2014-12-14 20:36:42 +00:00
|
|
|
(a:string-address <- next-input)
|
|
|
|
(a-len:integer <- length a:string-address/deref)
|
|
|
|
(b:string-address <- next-input)
|
|
|
|
(b-len:integer <- length b:string-address/deref)
|
|
|
|
(result-len:integer <- add a-len:integer b-len:integer)
|
|
|
|
(result:string-address <- new string:literal result-len:integer)
|
2014-11-27 08:34:29 +00:00
|
|
|
; copy a into result
|
2014-12-14 20:36:42 +00:00
|
|
|
(result-idx:integer <- copy 0:literal)
|
|
|
|
(i:integer <- copy 0:literal)
|
2014-11-27 08:34:29 +00:00
|
|
|
{ begin
|
|
|
|
; while (i < a.length)
|
2015-01-17 21:29:43 +00:00
|
|
|
(a-done?:boolean <- greater-or-equal i:integer a-len:integer)
|
|
|
|
(break-if a-done?:boolean)
|
2014-11-27 08:34:29 +00:00
|
|
|
; result[result-idx] = a[i]
|
2014-12-14 20:36:42 +00:00
|
|
|
(out:byte-address <- index-address result:string-address/deref result-idx:integer)
|
|
|
|
(in:byte <- index a:string-address/deref i:integer)
|
|
|
|
(out:byte-address/deref <- copy in:byte)
|
2014-11-27 08:34:29 +00:00
|
|
|
; ++i
|
2014-12-14 20:36:42 +00:00
|
|
|
(i:integer <- add i:integer 1:literal)
|
2014-11-27 08:34:29 +00:00
|
|
|
; ++result-idx
|
2014-12-14 20:36:42 +00:00
|
|
|
(result-idx:integer <- add result-idx:integer 1:literal)
|
2014-11-27 08:34:29 +00:00
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
; copy b into result
|
2014-12-14 20:36:42 +00:00
|
|
|
(i:integer <- copy 0:literal)
|
2014-11-27 08:34:29 +00:00
|
|
|
{ begin
|
|
|
|
; while (i < b.length)
|
2015-01-17 21:29:43 +00:00
|
|
|
(b-done?:boolean <- greater-or-equal i:integer b-len:integer)
|
|
|
|
(break-if b-done?:boolean)
|
2014-11-27 08:34:29 +00:00
|
|
|
; result[result-idx] = a[i]
|
2014-12-14 20:36:42 +00:00
|
|
|
(out:byte-address <- index-address result:string-address/deref result-idx:integer)
|
|
|
|
(in:byte <- index b:string-address/deref i:integer)
|
|
|
|
(out:byte-address/deref <- copy in:byte)
|
2014-11-27 08:34:29 +00:00
|
|
|
; ++i
|
2014-12-14 20:36:42 +00:00
|
|
|
(i:integer <- add i:integer 1:literal)
|
2014-11-27 08:34:29 +00:00
|
|
|
; ++result-idx
|
2014-12-14 20:36:42 +00:00
|
|
|
(result-idx:integer <- add result-idx:integer 1:literal)
|
2014-11-27 08:34:29 +00:00
|
|
|
(loop)
|
|
|
|
}
|
2014-12-14 20:36:42 +00:00
|
|
|
(reply result:string-address))
|
2014-11-27 08:34:29 +00:00
|
|
|
|
2014-11-27 18:14:03 +00:00
|
|
|
; replace underscores in first with remaining args
|
2014-11-29 09:38:54 +00:00
|
|
|
(init-fn interpolate ; string-address template, string-address a..
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 60:literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
(template:string-address <- next-input)
|
2014-11-29 09:54:46 +00:00
|
|
|
; compute result-len, space to allocate for result
|
2014-12-14 20:36:42 +00:00
|
|
|
(tem-len:integer <- length template:string-address/deref)
|
|
|
|
(result-len:integer <- copy tem-len:integer)
|
2014-11-29 09:38:54 +00:00
|
|
|
{ begin
|
|
|
|
; while arg received
|
2014-12-14 20:36:42 +00:00
|
|
|
(a:string-address arg-received?:boolean <- next-input)
|
|
|
|
(break-unless arg-received?:boolean)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print ("arg now: " literal))
|
|
|
|
;? ($print a:string-address)
|
|
|
|
;? ($print "@":literal)
|
|
|
|
;? ($print a:string-address/deref) ; todo: test (m on scoped array)
|
|
|
|
;? ($print "\n":literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
;? ;? (assert nil:literal)
|
2014-11-29 09:38:54 +00:00
|
|
|
; result-len = result-len + arg.length - 1 (for the 'underscore' being replaced)
|
2014-12-14 20:36:42 +00:00
|
|
|
(a-len:integer <- length a:string-address/deref)
|
|
|
|
(result-len:integer <- add result-len:integer a-len:integer)
|
|
|
|
(result-len:integer <- subtract result-len:integer 1:literal)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print ("result-len now: " literal))
|
|
|
|
;? ($print result-len:integer)
|
|
|
|
;? ($print "\n":literal)
|
2014-11-29 09:38:54 +00:00
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
; rewind to start of non-template args
|
2014-12-14 20:36:42 +00:00
|
|
|
(_ <- input 0:literal)
|
2014-11-27 18:14:03 +00:00
|
|
|
; result = new string[result-len]
|
2014-12-14 20:36:42 +00:00
|
|
|
(result:string-address <- new string:literal result-len:integer)
|
2014-11-29 09:54:46 +00:00
|
|
|
; repeatedly copy sections of template and 'holes' into result
|
2014-12-14 20:36:42 +00:00
|
|
|
(result-idx:integer <- copy 0:literal)
|
|
|
|
(i:integer <- copy 0:literal)
|
2014-11-27 18:14:03 +00:00
|
|
|
{ begin
|
2014-11-29 09:38:54 +00:00
|
|
|
; while arg received
|
2014-12-14 20:36:42 +00:00
|
|
|
(a:string-address arg-received?:boolean <- next-input)
|
|
|
|
(break-unless arg-received?:boolean)
|
2014-11-27 18:14:03 +00:00
|
|
|
; copy template into result until '_'
|
|
|
|
{ begin
|
|
|
|
; while (i < template.length)
|
2015-01-17 21:29:43 +00:00
|
|
|
(tem-done?:boolean <- greater-or-equal i:integer tem-len:integer)
|
|
|
|
(break-if tem-done?:boolean 2:blocks)
|
2014-11-27 18:14:03 +00:00
|
|
|
; while template[i] != '_'
|
2014-12-14 20:36:42 +00:00
|
|
|
(in:byte <- index template:string-address/deref i:integer)
|
|
|
|
(underscore?:boolean <- equal in:byte ((#\_ literal)))
|
|
|
|
(break-if underscore?:boolean)
|
2014-11-27 18:14:03 +00:00
|
|
|
; result[result-idx] = template[i]
|
2014-12-14 20:36:42 +00:00
|
|
|
(out:byte-address <- index-address result:string-address/deref result-idx:integer)
|
|
|
|
(out:byte-address/deref <- copy in:byte)
|
2014-11-27 18:14:03 +00:00
|
|
|
; ++i
|
2014-12-14 20:36:42 +00:00
|
|
|
(i:integer <- add i:integer 1:literal)
|
2014-11-27 18:14:03 +00:00
|
|
|
; ++result-idx
|
2014-12-14 20:36:42 +00:00
|
|
|
(result-idx:integer <- add result-idx:integer 1:literal)
|
2014-11-27 18:14:03 +00:00
|
|
|
(loop)
|
|
|
|
}
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print ("i now: " literal))
|
|
|
|
;? ($print i:integer)
|
|
|
|
;? ($print "\n":literal)
|
2014-11-27 18:14:03 +00:00
|
|
|
; copy 'a' into result
|
2014-12-14 20:36:42 +00:00
|
|
|
(j:integer <- copy 0:literal)
|
2014-11-27 18:14:03 +00:00
|
|
|
{ begin
|
|
|
|
; while (j < a.length)
|
2015-01-17 21:29:43 +00:00
|
|
|
(arg-done?:boolean <- greater-or-equal j:integer a-len:integer)
|
|
|
|
(break-if arg-done?:boolean)
|
2014-11-27 18:14:03 +00:00
|
|
|
; result[result-idx] = a[j]
|
2014-12-14 20:36:42 +00:00
|
|
|
(in:byte <- index a:string-address/deref j:integer)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print ("copying: " literal))
|
|
|
|
;? ($print in:byte)
|
|
|
|
;? ($print (" at: " literal))
|
|
|
|
;? ($print result-idx:integer)
|
|
|
|
;? ($print "\n":literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
(out:byte-address <- index-address result:string-address/deref result-idx:integer)
|
|
|
|
(out:byte-address/deref <- copy in:byte)
|
2014-11-27 18:14:03 +00:00
|
|
|
; ++j
|
2014-12-14 20:36:42 +00:00
|
|
|
(j:integer <- add j:integer 1:literal)
|
2014-11-27 18:14:03 +00:00
|
|
|
; ++result-idx
|
2014-12-14 20:36:42 +00:00
|
|
|
(result-idx:integer <- add result-idx:integer 1:literal)
|
2014-11-27 18:14:03 +00:00
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
; skip '_' in template
|
2014-12-14 20:36:42 +00:00
|
|
|
(i:integer <- add i:integer 1:literal)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print ("i now: " literal))
|
|
|
|
;? ($print i:integer)
|
|
|
|
;? ($print "\n":literal)
|
2014-11-29 09:38:54 +00:00
|
|
|
(loop) ; interpolate next arg
|
|
|
|
}
|
2014-11-29 09:54:46 +00:00
|
|
|
; done with holes; copy rest of template directly into result
|
|
|
|
{ begin
|
|
|
|
; while (i < template.length)
|
2015-01-17 21:29:43 +00:00
|
|
|
(tem-done?:boolean <- greater-or-equal i:integer tem-len:integer)
|
|
|
|
(break-if tem-done?:boolean)
|
2014-11-29 09:54:46 +00:00
|
|
|
; result[result-idx] = template[i]
|
2014-12-14 20:36:42 +00:00
|
|
|
(in:byte <- index template:string-address/deref i:integer)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print ("copying: " literal))
|
|
|
|
;? ($print in:byte)
|
|
|
|
;? ($print (" at: " literal))
|
|
|
|
;? ($print result-idx:integer)
|
|
|
|
;? ($print "\n":literal)
|
2014-12-14 20:36:42 +00:00
|
|
|
(out:byte-address <- index-address result:string-address/deref result-idx:integer)
|
|
|
|
(out:byte-address/deref <- copy in:byte)
|
2014-11-29 09:54:46 +00:00
|
|
|
; ++i
|
2014-12-14 20:36:42 +00:00
|
|
|
(i:integer <- add i:integer 1:literal)
|
2014-11-29 09:54:46 +00:00
|
|
|
; ++result-idx
|
2014-12-14 20:36:42 +00:00
|
|
|
(result-idx:integer <- add result-idx:integer 1:literal)
|
2014-11-29 09:54:46 +00:00
|
|
|
(loop)
|
|
|
|
}
|
2014-12-14 20:36:42 +00:00
|
|
|
(reply result:string-address))
|
2014-11-27 18:14:03 +00:00
|
|
|
|
2014-12-20 02:57:11 +00:00
|
|
|
(init-fn find-next ; string, character, index -> next index
|
2015-02-08 19:55:28 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2015-02-08 21:26:16 +00:00
|
|
|
(text:string-address <- next-input)
|
|
|
|
(pattern:character <- next-input)
|
2014-12-20 02:57:11 +00:00
|
|
|
(idx:integer <- next-input)
|
2015-02-08 21:26:16 +00:00
|
|
|
(len:integer <- length text:string-address/deref)
|
2014-12-20 02:57:11 +00:00
|
|
|
{ begin
|
|
|
|
(eof?:boolean <- greater-or-equal idx:integer len:integer)
|
|
|
|
(break-if eof?:boolean)
|
2015-02-08 21:26:16 +00:00
|
|
|
(curr:byte <- index text:string-address/deref idx:integer)
|
|
|
|
(found?:boolean <- equal curr:byte pattern:character)
|
2014-12-20 02:57:11 +00:00
|
|
|
(break-if found?:boolean)
|
|
|
|
(idx:integer <- add idx:integer 1:literal)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
(reply idx:integer))
|
|
|
|
|
2015-02-08 21:26:16 +00:00
|
|
|
(init-fn find-substring/variant:find-next
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
; fairly dumb algorithm; used for parsing code and traces
|
|
|
|
(text:string-address <- next-input)
|
|
|
|
(pattern:string-address <- next-input)
|
|
|
|
(idx:integer <- next-input)
|
|
|
|
(first:character <- index pattern:string-address/deref 0:literal)
|
|
|
|
; repeatedly check for match at current idx
|
|
|
|
(len:integer <- length text:string-address/deref)
|
|
|
|
{ begin
|
|
|
|
; does some unnecessary work checking for substrings even when there isn't enough of text left
|
|
|
|
(eof?:boolean <- greater-or-equal idx:integer len:integer)
|
|
|
|
(break-if eof?:boolean)
|
|
|
|
(found?:boolean <- match-at text:string-address pattern:string-address idx:integer)
|
|
|
|
(break-if found?:boolean)
|
|
|
|
(idx:integer <- add idx:integer 1:literal)
|
|
|
|
; optimization: skip past indices that definitely won't match
|
|
|
|
(idx:integer <- find-next text:string-address first:character idx:integer)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
(reply idx:integer)
|
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn match-at
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
; fairly dumb algorithm; used for parsing code and traces
|
|
|
|
(text:string-address <- next-input)
|
|
|
|
(pattern:string-address <- next-input)
|
|
|
|
(idx:integer <- next-input)
|
|
|
|
(pattern-len:integer <- length pattern:string-address/deref)
|
|
|
|
; check that there's space left for the pattern
|
|
|
|
{ begin
|
|
|
|
(x:integer <- length text:string-address/deref)
|
|
|
|
(x:integer <- subtract x:integer pattern-len:integer)
|
|
|
|
(enough-room?:boolean <- lesser-or-equal idx:integer x:integer)
|
|
|
|
(break-if enough-room?:boolean)
|
|
|
|
(reply nil:literal)
|
|
|
|
}
|
|
|
|
; check each character of pattern
|
|
|
|
(pattern-idx:integer <- copy 0:literal)
|
|
|
|
{ begin
|
|
|
|
(done?:boolean <- greater-or-equal pattern-idx:integer pattern-len:integer)
|
|
|
|
(break-if done?:boolean)
|
|
|
|
(c:character <- index text:string-address/deref idx:integer)
|
|
|
|
(exp:character <- index pattern:string-address/deref pattern-idx:integer)
|
|
|
|
{ begin
|
|
|
|
(match?:boolean <- equal c:character exp:character)
|
|
|
|
(break-if match?:boolean)
|
|
|
|
(reply nil:literal)
|
|
|
|
}
|
|
|
|
(idx:integer <- add idx:integer 1:literal)
|
|
|
|
(pattern-idx:integer <- add pattern-idx:integer 1:literal)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
(reply t:literal)
|
|
|
|
)
|
|
|
|
|
2014-12-20 06:18:41 +00:00
|
|
|
(init-fn split ; string, character -> string-address-array-address
|
2015-01-03 02:13:04 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2014-12-20 06:18:41 +00:00
|
|
|
(s:string-address <- next-input)
|
2015-02-08 19:12:08 +00:00
|
|
|
(delim:character <- next-input)
|
2014-12-20 06:18:41 +00:00
|
|
|
; empty string? return empty array
|
|
|
|
(len:integer <- length s:string-address/deref)
|
|
|
|
{ begin
|
|
|
|
(empty?:boolean <- equal len:integer 0:literal)
|
|
|
|
(break-unless empty?:boolean)
|
|
|
|
(result:string-address-array-address <- new string-address-array:literal 0:literal)
|
|
|
|
(reply result:string-address-array-address)
|
|
|
|
}
|
|
|
|
; count #pieces we need room for
|
|
|
|
(count:integer <- copy 1:literal) ; n delimiters = n+1 pieces
|
|
|
|
(idx:integer <- copy 0:literal)
|
|
|
|
{ begin
|
|
|
|
(idx:integer <- find-next s:string-address delim:character idx:integer)
|
|
|
|
(done?:boolean <- greater-or-equal idx:integer len:integer)
|
|
|
|
(break-if done?:boolean)
|
|
|
|
(idx:integer <- add idx:integer 1:literal)
|
|
|
|
(count:integer <- add count:integer 1:literal)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
; allocate space
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("alloc: " literal)))
|
|
|
|
;? ($print count:integer)
|
|
|
|
;? ($print (("\n" literal)))
|
2014-12-20 06:18:41 +00:00
|
|
|
(result:string-address-array-address <- new string-address-array:literal count:integer)
|
|
|
|
; repeatedly copy slices (start..end) until delimiter into result[curr-result]
|
|
|
|
(curr-result:integer <- copy 0:literal)
|
|
|
|
(start:integer <- copy 0:literal)
|
|
|
|
{ begin
|
|
|
|
; while next delim exists
|
|
|
|
(done?:boolean <- greater-or-equal start:integer len:integer)
|
|
|
|
(break-if done?:boolean)
|
|
|
|
(end:integer <- find-next s:string-address delim:character start:integer)
|
2015-02-08 05:21:42 +00:00
|
|
|
;? ($print start:integer) ;? 1
|
|
|
|
;? ($print ((" " literal))) ;? 1
|
|
|
|
;? ($print end:integer) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
2014-12-20 06:18:41 +00:00
|
|
|
; copy start..end into result[curr-result]
|
2015-02-08 05:21:42 +00:00
|
|
|
(dest:string-address-address <- index-address result:string-address-array-address/deref curr-result:integer)
|
|
|
|
(dest:string-address-address/deref <- string-copy s:string-address start:integer end:integer)
|
2014-12-20 06:18:41 +00:00
|
|
|
; slide over to next slice
|
|
|
|
(start:integer <- add end:integer 1:literal)
|
|
|
|
(curr-result:integer <- add curr-result:integer 1:literal)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
(reply result:string-address-array-address)
|
|
|
|
)
|
|
|
|
|
2015-02-08 23:02:33 +00:00
|
|
|
(init-fn split-first-at-substring/variant:split-first ; string text, string delim -> string first, string rest
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(text:string-address <- next-input)
|
|
|
|
(delim:string-address <- next-input)
|
|
|
|
; empty string? return empty strings
|
|
|
|
(len:integer <- length text:string-address/deref)
|
|
|
|
{ begin
|
|
|
|
(empty?:boolean <- equal len:integer 0:literal)
|
|
|
|
(break-unless empty?:boolean)
|
|
|
|
(x:string-address <- new "")
|
|
|
|
(y:string-address <- new "")
|
|
|
|
(reply x:string-address y:string-address)
|
|
|
|
}
|
|
|
|
(idx:integer <- find-substring text:string-address delim:string-address 0:literal)
|
|
|
|
(x:string-address <- string-copy text:string-address 0:literal idx:integer)
|
|
|
|
(k:integer <- length delim:string-address/deref)
|
|
|
|
(idx:integer <- add idx:integer k:integer)
|
|
|
|
(y:string-address <- string-copy text:string-address idx:integer len:integer)
|
|
|
|
(reply x:string-address y:string-address)
|
|
|
|
)
|
|
|
|
|
2015-02-08 21:29:01 +00:00
|
|
|
(init-fn split-first ; string text, character delim -> string first, string rest
|
2015-02-08 05:31:35 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2015-02-08 21:29:01 +00:00
|
|
|
(text:string-address <- next-input)
|
2015-02-08 19:12:08 +00:00
|
|
|
(delim:character <- next-input)
|
2015-02-08 23:02:33 +00:00
|
|
|
; empty string? return empty strings
|
2015-02-08 21:29:01 +00:00
|
|
|
(len:integer <- length text:string-address/deref)
|
2015-02-08 05:31:35 +00:00
|
|
|
{ begin
|
|
|
|
(empty?:boolean <- equal len:integer 0:literal)
|
|
|
|
(break-unless empty?:boolean)
|
|
|
|
(x:string-address <- new "")
|
|
|
|
(y:string-address <- new "")
|
|
|
|
(reply x:string-address y:string-address)
|
|
|
|
}
|
2015-02-08 21:29:01 +00:00
|
|
|
(idx:integer <- find-next text:string-address delim:character 0:literal)
|
|
|
|
(x:string-address <- string-copy text:string-address 0:literal idx:integer)
|
2015-02-08 05:31:35 +00:00
|
|
|
(idx:integer <- add idx:integer 1:literal)
|
2015-02-08 21:29:01 +00:00
|
|
|
(y:string-address <- string-copy text:string-address idx:integer len:integer)
|
2015-02-08 05:31:35 +00:00
|
|
|
(reply x:string-address y:string-address)
|
|
|
|
)
|
|
|
|
|
2015-02-08 05:21:42 +00:00
|
|
|
; todo: make this generic
|
|
|
|
(init-fn string-copy ; buf start end -> address of new array
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(buf:string-address <- next-input)
|
|
|
|
(start:integer <- next-input)
|
|
|
|
(end:integer <- next-input)
|
|
|
|
;? ($print ((" copy: " literal))) ;? 1
|
|
|
|
;? ($print start:integer) ;? 1
|
|
|
|
;? ($print (("-" literal))) ;? 1
|
|
|
|
;? ($print end:integer) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
2015-02-08 23:02:33 +00:00
|
|
|
; if end is out of bounds, trim it
|
|
|
|
(len:integer <- length buf:string-address/deref)
|
|
|
|
(end:integer <- min len:integer end:integer)
|
|
|
|
; allocate space for result
|
2015-02-08 05:21:42 +00:00
|
|
|
(len:integer <- subtract end:integer start:integer)
|
|
|
|
(result:string-address <- new string:literal len:integer)
|
|
|
|
; copy start..end into result[curr-result]
|
|
|
|
(src-idx:integer <- copy start:integer)
|
|
|
|
(dest-idx:integer <- copy 0:literal)
|
|
|
|
{ begin
|
|
|
|
(done?:boolean <- greater-or-equal src-idx:integer end:integer)
|
|
|
|
(break-if done?:boolean)
|
|
|
|
(src:character <- index buf:string-address/deref src-idx:integer)
|
|
|
|
;? ($print ((" copying " literal))) ;? 1
|
|
|
|
;? ($print src:character) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
|
|
|
(dest:character-address <- index-address result:string-address/deref dest-idx:integer)
|
|
|
|
(dest:character-address/deref <- copy src:character)
|
|
|
|
(src-idx:integer <- add src-idx:integer 1:literal)
|
|
|
|
(dest-idx:integer <- add dest-idx:integer 1:literal)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
(reply result:string-address)
|
|
|
|
)
|
|
|
|
|
2015-02-08 23:02:33 +00:00
|
|
|
(init-fn min
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:integer <- next-input)
|
|
|
|
(y:integer <- next-input)
|
|
|
|
{ begin
|
|
|
|
(return-x?:boolean <- less-than x:integer y:integer)
|
|
|
|
(break-if return-x?:boolean)
|
|
|
|
(reply y:integer)
|
|
|
|
}
|
|
|
|
(reply x:integer)
|
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn max
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:integer <- next-input)
|
|
|
|
(y:integer <- next-input)
|
|
|
|
{ begin
|
|
|
|
(return-x?:boolean <- greater-than x:integer y:integer)
|
|
|
|
(break-if return-x?:boolean)
|
|
|
|
(reply y:integer)
|
|
|
|
}
|
|
|
|
(reply x:integer)
|
|
|
|
)
|
|
|
|
|
2015-02-08 08:42:07 +00:00
|
|
|
(init-fn init-stream
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(in:string-address <- next-input)
|
|
|
|
(result:stream-address <- new stream:literal)
|
|
|
|
(x:integer-address <- get-address result:stream-address/deref pointer:offset)
|
|
|
|
(x:integer-address/deref <- copy 0:literal)
|
|
|
|
(y:string-address-address <- get-address result:stream-address/deref data:offset)
|
|
|
|
(y:string-address-address/deref <- copy in:string-address)
|
|
|
|
(reply result:stream-address)
|
|
|
|
)
|
|
|
|
|
2015-03-13 00:03:29 +00:00
|
|
|
(init-fn rewind-stream
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(in:stream-address <- next-input)
|
|
|
|
(x:integer-address <- get-address in:stream-address/deref pointer:offset)
|
|
|
|
(x:integer-address/deref <- copy 0:literal)
|
|
|
|
(reply in:stream-address/same-as-arg:0)
|
|
|
|
)
|
|
|
|
|
2015-02-08 08:42:07 +00:00
|
|
|
(init-fn read-line
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(in:stream-address <- next-input)
|
|
|
|
(idx:integer-address <- get-address in:stream-address/deref pointer:offset)
|
|
|
|
(s:string-address <- get in:stream-address/deref data:offset)
|
|
|
|
;? ($print (("idx before: " literal))) ;? 1
|
|
|
|
;? ($print idx:integer-address/deref) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
|
|
|
(next-idx:integer <- find-next s:string-address ((#\newline literal)) idx:integer-address/deref)
|
|
|
|
;? ($print (("next-idx: " literal))) ;? 1
|
|
|
|
;? ($print next-idx:integer) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
|
|
|
(result:string-address <- string-copy s:string-address idx:integer-address/deref next-idx:integer)
|
|
|
|
(idx:integer-address/deref <- add next-idx:integer 1:literal) ; skip newline
|
|
|
|
;? ($print (("idx now: " literal))) ;? 1
|
|
|
|
;? ($print idx:integer-address/deref) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
|
|
|
(reply result:string-address)
|
|
|
|
)
|
|
|
|
|
2015-03-13 00:03:29 +00:00
|
|
|
(init-fn read-character
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(in:stream-address <- next-input)
|
|
|
|
(idx:integer-address <- get-address in:stream-address/deref pointer:offset)
|
|
|
|
(s:string-address <- get in:stream-address/deref data:offset)
|
|
|
|
(c:character <- index s:string-address/deref idx:integer-address/deref)
|
|
|
|
(idx:integer-address/deref <- add idx:integer-address/deref 1:literal)
|
|
|
|
(reply c:character)
|
|
|
|
)
|
|
|
|
|
2015-02-08 08:42:07 +00:00
|
|
|
(init-fn end-of-stream?
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(in:stream-address <- next-input)
|
|
|
|
(idx:integer <- get in:stream-address/deref pointer:offset)
|
|
|
|
(s:string-address <- get in:stream-address/deref data:offset)
|
|
|
|
(len:integer <- length s:string-address/deref)
|
|
|
|
;? ($print (("eos: " literal))) ;? 1
|
|
|
|
;? ($print len:integer) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
|
|
|
;? ($print (("idx: " literal))) ;? 1
|
|
|
|
;? ($print idx:integer) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
|
|
|
(result:boolean <- greater-or-equal idx:integer len:integer)
|
|
|
|
(reply result:boolean)
|
|
|
|
)
|
|
|
|
|
2015-01-23 02:01:45 +00:00
|
|
|
(init-fn init-keyboard
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(result:keyboard-address <- new keyboard:literal)
|
|
|
|
(buf:string-address-address <- get-address result:keyboard-address/deref data:offset)
|
|
|
|
(buf:string-address-address/deref <- next-input)
|
|
|
|
(idx:integer-address <- get-address result:keyboard-address/deref index:offset)
|
|
|
|
(idx:integer-address/deref <- copy 0:literal)
|
|
|
|
(reply result:keyboard-address)
|
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn read-key
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:keyboard-address <- next-input)
|
2015-02-01 09:03:42 +00:00
|
|
|
(screen:terminal-address <- next-input)
|
2015-01-23 02:01:45 +00:00
|
|
|
{ begin
|
|
|
|
(break-unless x:keyboard-address)
|
|
|
|
(idx:integer-address <- get-address x:keyboard-address/deref index:offset)
|
|
|
|
(buf:string-address <- get x:keyboard-address/deref data:offset)
|
2015-01-25 04:30:25 +00:00
|
|
|
(max:integer <- length buf:string-address/deref)
|
|
|
|
{ begin
|
|
|
|
(done?:boolean <- greater-or-equal idx:integer-address/deref max:integer)
|
|
|
|
(break-unless done?:boolean)
|
|
|
|
(reply ((#\null literal)))
|
|
|
|
}
|
2015-01-23 02:01:45 +00:00
|
|
|
(c:character <- index buf:string-address/deref idx:integer-address/deref)
|
|
|
|
(idx:integer-address/deref <- add idx:integer-address/deref 1:literal)
|
|
|
|
(reply c:character)
|
|
|
|
}
|
2015-01-25 04:30:25 +00:00
|
|
|
; real keyboard input is infrequent; avoid polling it too much
|
|
|
|
(sleep for-some-cycles:literal 1:literal)
|
2015-01-23 02:01:45 +00:00
|
|
|
(c:character <- read-key-from-host)
|
2015-01-25 05:26:26 +00:00
|
|
|
; when we read from a real keyboard we print to screen as well
|
|
|
|
{ begin
|
|
|
|
(break-unless c:character)
|
2015-02-01 09:03:42 +00:00
|
|
|
(silent?:boolean <- equal screen:terminal-address ((silent literal)))
|
|
|
|
(break-if silent?:boolean)
|
|
|
|
;? ($print (("aaaa\n" literal))) ;? 1
|
2015-02-01 08:15:43 +00:00
|
|
|
(print-character-to-host c:character)
|
2015-01-25 05:26:26 +00:00
|
|
|
}
|
2015-01-23 02:01:45 +00:00
|
|
|
(reply c:character)
|
|
|
|
)
|
|
|
|
|
2015-02-01 09:03:42 +00:00
|
|
|
(init-fn wait-for-key
|
2015-02-08 19:55:28 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2015-02-01 09:03:42 +00:00
|
|
|
(k:keyboard-address <- next-input)
|
|
|
|
(screen:terminal-address <- next-input)
|
|
|
|
{ begin
|
|
|
|
(result:character <- read-key k:keyboard-address screen:terminal-address)
|
|
|
|
(loop-unless result:character)
|
|
|
|
}
|
|
|
|
(reply result:character)
|
|
|
|
)
|
|
|
|
|
2015-01-12 06:03:16 +00:00
|
|
|
(init-fn send-keys-to-stdin
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2015-01-24 20:00:40 +00:00
|
|
|
(k:keyboard-address <- next-input)
|
2015-01-12 06:03:16 +00:00
|
|
|
(stdin:channel-address <- next-input)
|
2015-01-25 19:38:13 +00:00
|
|
|
;? (c:character <- copy ((#\a literal))) ;? 1
|
|
|
|
;? (curr:tagged-value <- save-type c:character) ;? 1
|
2015-01-26 06:56:53 +00:00
|
|
|
;? (stdin:channel-address/deref <- write stdin:channel-address curr:tagged-value) ;? 1
|
2015-01-25 19:38:13 +00:00
|
|
|
;? (c:character <- copy ((#\newline literal))) ;? 1
|
|
|
|
;? (curr:tagged-value <- save-type c:character) ;? 1
|
2015-01-26 06:56:53 +00:00
|
|
|
;? (stdin:channel-address/deref <- write stdin:channel-address curr:tagged-value) ;? 1
|
2015-01-25 19:38:13 +00:00
|
|
|
{ begin ;? 1
|
|
|
|
(c:character <- read-key k:keyboard-address) ;? 1
|
|
|
|
(loop-unless c:character) ;? 1
|
|
|
|
(curr:tagged-value <- save-type c:character) ;? 1
|
2015-01-26 06:56:53 +00:00
|
|
|
(stdin:channel-address/deref <- write stdin:channel-address curr:tagged-value) ;? 1
|
2015-01-25 19:38:13 +00:00
|
|
|
(eof?:boolean <- equal c:character ((#\null literal))) ;? 1
|
|
|
|
(break-if eof?:boolean) ;? 1
|
|
|
|
(loop) ;? 1
|
|
|
|
} ;? 1
|
2015-01-25 04:30:25 +00:00
|
|
|
)
|
|
|
|
|
2015-02-06 04:54:00 +00:00
|
|
|
; collect characters until newline before sending out
|
|
|
|
(init-fn buffer-lines
|
2015-01-25 04:30:25 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(stdin:channel-address <- next-input)
|
|
|
|
(buffered-stdin:channel-address <- next-input)
|
|
|
|
; repeat forever
|
|
|
|
{ begin
|
2015-01-25 09:41:40 +00:00
|
|
|
(line:buffer-address <- init-buffer 30:literal)
|
2015-01-25 10:25:50 +00:00
|
|
|
;? ($dump-channel 1093:literal) ;? 1
|
2015-01-25 04:30:25 +00:00
|
|
|
; read characters from stdin until newline, copy into line
|
|
|
|
{ begin
|
2015-01-26 06:56:53 +00:00
|
|
|
(x:tagged-value stdin:channel-address/deref <- read stdin:channel-address)
|
2015-01-25 04:30:25 +00:00
|
|
|
(c:character <- maybe-coerce x:tagged-value character:literal)
|
|
|
|
(assert c:character)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print line:buffer-address) ;? 2
|
|
|
|
;? ($print (("\n" literal))) ;? 2
|
|
|
|
;? ($print c:character) ;? 2
|
|
|
|
;? ($print (("\n" literal))) ;? 2
|
2015-01-27 04:10:43 +00:00
|
|
|
; handle backspace
|
2015-01-25 08:09:52 +00:00
|
|
|
{ begin
|
|
|
|
(backspace?:boolean <- equal c:character ((#\backspace literal)))
|
|
|
|
(break-unless backspace?:boolean)
|
|
|
|
(len:integer-address <- get-address line:buffer-address/deref length:offset)
|
2015-01-27 04:10:43 +00:00
|
|
|
; but only if we need to
|
|
|
|
{ begin
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("backspace: " literal))) ;? 1
|
|
|
|
;? ($print len:integer-address/deref) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
2015-01-27 04:10:43 +00:00
|
|
|
(zero?:boolean <- lesser-or-equal len:integer-address/deref 0:literal)
|
|
|
|
(break-if zero?:boolean)
|
|
|
|
(len:integer-address/deref <- subtract len:integer-address/deref 1:literal)
|
|
|
|
}
|
2015-01-25 08:09:52 +00:00
|
|
|
(loop 2:blocks)
|
|
|
|
}
|
2015-01-25 04:30:25 +00:00
|
|
|
(line:buffer-address <- append line:buffer-address c:character)
|
|
|
|
(line-done?:boolean <- equal c:character ((#\newline literal)))
|
|
|
|
(break-if line-done?:boolean)
|
|
|
|
(eof?:boolean <- equal c:character ((#\null literal)))
|
2015-01-25 10:25:50 +00:00
|
|
|
(break-if eof?:boolean 2:blocks)
|
2015-01-25 04:30:25 +00:00
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
; copy line into buffered-stdout
|
|
|
|
(i:integer <- copy 0:literal)
|
|
|
|
(line-contents:string-address <- get line:buffer-address/deref data:offset)
|
|
|
|
(max:integer <- get line:buffer-address/deref length:offset)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("len: " literal))) ;? 1
|
|
|
|
;? ($print max:integer) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
2015-01-25 04:30:25 +00:00
|
|
|
{ begin
|
|
|
|
(done?:boolean <- greater-or-equal i:integer max:integer)
|
|
|
|
(break-if done?:boolean)
|
|
|
|
(c:character <- index line-contents:string-address/deref i:integer)
|
|
|
|
(curr:tagged-value <- save-type c:character)
|
2015-01-25 10:25:50 +00:00
|
|
|
;? ($dump-channel 1093:literal) ;? 1
|
|
|
|
;? ($start-tracing) ;? 1
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("bufferout: " literal))) ;? 2
|
|
|
|
;? ($print c:character) ;? 1
|
2015-01-27 04:29:55 +00:00
|
|
|
;? (x:integer <- character-to-integer c:character) ;? 1
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print x:integer) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 2
|
2015-01-26 06:56:53 +00:00
|
|
|
(buffered-stdin:channel-address/deref <- write buffered-stdin:channel-address curr:tagged-value)
|
2015-01-25 10:25:50 +00:00
|
|
|
;? ($stop-tracing) ;? 1
|
|
|
|
;? ($dump-channel 1093:literal) ;? 1
|
|
|
|
;? ($quit) ;? 1
|
2015-01-25 04:30:25 +00:00
|
|
|
(i:integer <- add i:integer 1:literal)
|
|
|
|
(loop)
|
|
|
|
}
|
2015-01-12 06:03:16 +00:00
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2015-01-15 04:43:23 +00:00
|
|
|
(init-fn clear-screen
|
2015-01-15 08:00:46 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:terminal-address <- next-input)
|
|
|
|
{ begin
|
|
|
|
(break-unless x:terminal-address)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("AAA" literal)))
|
2015-01-18 02:50:32 +00:00
|
|
|
(buf:string-address <- get x:terminal-address/deref data:offset)
|
|
|
|
(max:integer <- length buf:string-address/deref)
|
|
|
|
(i:integer <- copy 0:literal)
|
|
|
|
{ begin
|
|
|
|
(done?:boolean <- greater-or-equal i:integer max:integer)
|
|
|
|
(break-if done?:boolean)
|
|
|
|
(x:byte-address <- index-address buf:string-address/deref i:integer)
|
|
|
|
(x:byte-address/deref <- copy ((#\space literal)))
|
|
|
|
(i:integer <- add i:integer 1:literal)
|
|
|
|
(loop)
|
|
|
|
}
|
2015-01-15 08:00:46 +00:00
|
|
|
(reply)
|
|
|
|
}
|
2015-01-15 04:43:23 +00:00
|
|
|
(clear-host-screen)
|
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn cursor
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2015-01-15 08:00:46 +00:00
|
|
|
(x:terminal-address <- next-input)
|
2015-01-18 02:50:32 +00:00
|
|
|
(newrow:integer <- next-input)
|
|
|
|
(newcol:integer <- next-input)
|
2015-01-15 08:00:46 +00:00
|
|
|
{ begin
|
|
|
|
(break-unless x:terminal-address)
|
2015-01-18 02:50:32 +00:00
|
|
|
(row:integer-address <- get-address x:terminal-address/deref cursor-row:offset)
|
|
|
|
(row:integer-address/deref <- copy newrow:integer)
|
|
|
|
(col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
|
|
|
|
(col:integer-address/deref <- copy newcol:integer)
|
2015-01-15 08:00:46 +00:00
|
|
|
(reply)
|
|
|
|
}
|
2015-01-15 04:43:23 +00:00
|
|
|
(cursor-on-host row:integer col:integer)
|
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn cursor-to-next-line
|
2015-01-15 08:00:46 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:terminal-address <- next-input)
|
|
|
|
{ begin
|
|
|
|
(break-unless x:terminal-address)
|
2015-01-18 02:50:32 +00:00
|
|
|
(row:integer-address <- get-address x:terminal-address/deref cursor-row:offset)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print row:integer-address/deref)
|
|
|
|
;? ($print (("\n" literal)))
|
2015-01-18 02:50:32 +00:00
|
|
|
(row:integer-address/deref <- add row:integer-address/deref 1:literal)
|
|
|
|
(col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print col:integer-address/deref)
|
|
|
|
;? ($print (("\n" literal)))
|
2015-01-18 02:50:32 +00:00
|
|
|
(col:integer-address/deref <- copy 0:literal)
|
2015-01-15 08:00:46 +00:00
|
|
|
(reply)
|
|
|
|
}
|
2015-01-15 04:43:23 +00:00
|
|
|
(cursor-on-host-to-next-line)
|
|
|
|
)
|
|
|
|
|
2015-02-11 01:51:57 +00:00
|
|
|
(init-fn cursor-down
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:terminal-address <- next-input)
|
2015-02-11 06:53:29 +00:00
|
|
|
;? ($print ((#\# literal))) ;? 1
|
2015-02-11 01:51:57 +00:00
|
|
|
(height:integer-address <- get-address x:terminal-address/deref num-rows:offset)
|
2015-02-11 06:53:29 +00:00
|
|
|
;? ($print height:integer-address/deref) ;? 1
|
2015-02-11 01:51:57 +00:00
|
|
|
{ begin
|
|
|
|
(break-unless x:terminal-address)
|
2015-02-11 06:53:29 +00:00
|
|
|
;? ($print ((#\% literal))) ;? 1
|
2015-02-11 01:51:57 +00:00
|
|
|
(row:integer-address <- get-address x:terminal-address/deref cursor-row:offset)
|
2015-03-11 06:20:16 +00:00
|
|
|
;? ($print (("cursor down: " literal))) ;? 1
|
|
|
|
;? ($print row:integer-address/deref) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
2015-02-11 01:51:57 +00:00
|
|
|
{ begin
|
2015-02-11 06:53:29 +00:00
|
|
|
(bottom?:boolean <- greater-or-equal row:integer-address/deref height:integer-address/deref)
|
2015-02-11 01:51:57 +00:00
|
|
|
(break-if bottom?:boolean)
|
|
|
|
(row:integer-address/deref <- add row:integer-address/deref 1:literal)
|
2015-02-11 06:53:29 +00:00
|
|
|
;? ($print ((#\* literal))) ;? 1
|
|
|
|
;? ($print row:integer-address/deref) ;? 1
|
2015-02-11 01:51:57 +00:00
|
|
|
}
|
|
|
|
(reply)
|
|
|
|
}
|
|
|
|
(cursor-down-on-host)
|
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn cursor-up
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:terminal-address <- next-input)
|
|
|
|
{ begin
|
|
|
|
(break-unless x:terminal-address)
|
|
|
|
(row:integer-address <- get-address x:terminal-address/deref cursor-row:offset)
|
2015-03-11 06:20:16 +00:00
|
|
|
;? ($print (("cursor up: " literal))) ;? 1
|
|
|
|
;? ($print row:integer-address/deref) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
2015-02-11 01:51:57 +00:00
|
|
|
{ begin
|
|
|
|
(top?:boolean <- lesser-or-equal row:integer-address/deref 0:literal)
|
|
|
|
(break-if top?:boolean)
|
|
|
|
(row:integer-address/deref <- subtract row:integer-address/deref 1:literal)
|
|
|
|
}
|
|
|
|
(reply)
|
|
|
|
}
|
|
|
|
(cursor-up-on-host)
|
|
|
|
)
|
|
|
|
|
2015-02-11 19:52:56 +00:00
|
|
|
(init-fn cursor-left
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:terminal-address <- next-input)
|
|
|
|
{ begin
|
|
|
|
(break-unless x:terminal-address)
|
|
|
|
(col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
|
|
|
|
{ begin
|
|
|
|
(edge?:boolean <- lesser-or-equal col:integer-address/deref 0:literal)
|
|
|
|
(break-if edge?:boolean)
|
|
|
|
(col:integer-address/deref <- subtract col:integer-address/deref 1:literal)
|
|
|
|
}
|
|
|
|
(reply)
|
|
|
|
}
|
|
|
|
(cursor-left-on-host)
|
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn cursor-right
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:terminal-address <- next-input)
|
|
|
|
(width:integer-address <- get-address x:terminal-address/deref num-cols:offset)
|
|
|
|
{ begin
|
|
|
|
(break-unless x:terminal-address)
|
|
|
|
(col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
|
|
|
|
{ begin
|
|
|
|
(edge?:boolean <- lesser-or-equal col:integer-address/deref width:integer-address/deref)
|
|
|
|
(break-if edge?:boolean)
|
|
|
|
(col:integer-address/deref <- add col:integer-address/deref 1:literal)
|
|
|
|
}
|
|
|
|
(reply)
|
|
|
|
}
|
|
|
|
(cursor-right-on-host)
|
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn replace-character
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:terminal-address <- next-input)
|
|
|
|
(c:character <- next-input)
|
|
|
|
(print-character x:terminal-address c:character)
|
|
|
|
(cursor-left x:terminal-address)
|
|
|
|
)
|
|
|
|
|
2015-02-16 05:34:02 +00:00
|
|
|
(init-fn clear-line
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:terminal-address <- next-input)
|
|
|
|
{ begin
|
|
|
|
(break-unless x:terminal-address)
|
|
|
|
(n:integer <- get x:terminal-address/deref num-cols:offset)
|
|
|
|
(col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
|
|
|
|
(orig-col:integer <- copy col:integer-address/deref)
|
|
|
|
; space over the entire line
|
|
|
|
{ begin
|
|
|
|
(done?:boolean <- greater-or-equal col:integer-address/deref n:integer)
|
|
|
|
(break-if done?:boolean)
|
|
|
|
(print-character x:terminal-address ((#\space literal))) ; implicitly updates 'col'
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
; now back to where the cursor was
|
2015-02-16 20:40:25 +00:00
|
|
|
(col:integer-address/deref <- copy orig-col:integer)
|
2015-02-16 05:34:02 +00:00
|
|
|
(reply)
|
|
|
|
}
|
|
|
|
(clear-line-on-host)
|
|
|
|
)
|
|
|
|
|
2015-01-18 01:00:44 +00:00
|
|
|
(init-fn print-character
|
2015-01-15 04:43:23 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2015-01-15 08:00:46 +00:00
|
|
|
(x:terminal-address <- next-input)
|
2015-01-18 01:00:44 +00:00
|
|
|
(c:character <- next-input)
|
2015-02-01 09:03:42 +00:00
|
|
|
(fg:integer/color <- next-input)
|
|
|
|
(bg:integer/color <- next-input)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("printing character to screen " literal)))
|
|
|
|
;? ($print c:character)
|
2015-01-18 02:50:32 +00:00
|
|
|
;? (reply)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("\n" literal)))
|
2015-01-15 08:00:46 +00:00
|
|
|
{ begin
|
|
|
|
(break-unless x:terminal-address)
|
2015-01-18 02:50:32 +00:00
|
|
|
(row:integer-address <- get-address x:terminal-address/deref cursor-row:offset)
|
2015-03-07 09:19:46 +00:00
|
|
|
;? ($print row:integer-address/deref) ;? 2
|
|
|
|
;? ($print ((", " literal))) ;? 1
|
2015-01-18 02:50:32 +00:00
|
|
|
(col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
|
2015-03-07 09:19:46 +00:00
|
|
|
;? ($print col:integer-address/deref) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
2015-01-18 02:50:32 +00:00
|
|
|
(width:integer <- get x:terminal-address/deref num-cols:offset)
|
|
|
|
(t1:integer <- multiply row:integer-address/deref width:integer)
|
|
|
|
(idx:integer <- add t1:integer col:integer-address/deref)
|
|
|
|
(buf:string-address <- get x:terminal-address/deref data:offset)
|
|
|
|
(cursor:byte-address <- index-address buf:string-address/deref idx:integer)
|
2015-01-25 04:30:25 +00:00
|
|
|
(cursor:byte-address/deref <- copy c:character) ; todo: newline, etc.
|
2015-01-18 02:50:32 +00:00
|
|
|
(col:integer-address/deref <- add col:integer-address/deref 1:literal)
|
|
|
|
; we don't rely on any auto-wrap functionality
|
|
|
|
; maybe die if we go out of screen bounds?
|
2015-01-15 08:00:46 +00:00
|
|
|
(reply)
|
|
|
|
}
|
2015-02-01 09:03:42 +00:00
|
|
|
(print-character-to-host c:character fg:integer/color bg:integer/color)
|
2015-01-18 01:00:44 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn print-string
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:terminal-address <- next-input)
|
|
|
|
(s:string-address <- next-input)
|
|
|
|
(len:integer <- length s:string-address/deref)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("print/string: len: " literal)))
|
|
|
|
;? ($print len:integer)
|
|
|
|
;? ($print (("\n" literal)))
|
2015-01-18 01:00:44 +00:00
|
|
|
(i:integer <- copy 0:literal)
|
|
|
|
{ begin
|
|
|
|
(done?:boolean <- greater-or-equal i:integer len:integer)
|
|
|
|
(break-if done?:boolean)
|
2015-02-08 19:12:08 +00:00
|
|
|
(c:character <- index s:string-address/deref i:integer)
|
2015-01-18 01:00:44 +00:00
|
|
|
(print-character x:terminal-address c:character)
|
|
|
|
(i:integer <- add i:integer 1:literal)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn print-integer
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(x:terminal-address <- next-input)
|
|
|
|
(n:integer <- next-input)
|
|
|
|
; todo: other bases besides decimal
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("AAA " literal)))
|
|
|
|
;? ($print n:integer)
|
2015-01-18 01:00:44 +00:00
|
|
|
(s:string-address <- integer-to-decimal-string n:integer)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print s:string-address)
|
2015-01-18 01:00:44 +00:00
|
|
|
(print-string x:terminal-address s:string-address)
|
2015-01-15 04:43:23 +00:00
|
|
|
)
|
|
|
|
|
2015-01-17 23:41:24 +00:00
|
|
|
(init-fn init-buffer
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(result:buffer-address <- new buffer:literal)
|
|
|
|
(len:integer-address <- get-address result:buffer-address/deref length:offset)
|
|
|
|
(len:integer-address/deref <- copy 0:literal)
|
|
|
|
(s:string-address-address <- get-address result:buffer-address/deref data:offset)
|
|
|
|
(capacity:integer <- next-input)
|
|
|
|
(s:string-address-address/deref <- new string:literal capacity:integer)
|
|
|
|
(reply result:buffer-address)
|
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn grow-buffer
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(in:buffer-address <- next-input)
|
|
|
|
; double buffer size
|
|
|
|
(x:string-address-address <- get-address in:buffer-address/deref data:offset)
|
|
|
|
(oldlen:integer <- length x:string-address-address/deref/deref)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print oldlen:integer) ;? 1
|
2015-01-17 23:41:24 +00:00
|
|
|
(newlen:integer <- multiply oldlen:integer 2:literal)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print newlen:integer) ;? 1
|
2015-01-17 23:41:24 +00:00
|
|
|
(olddata:string-address <- copy x:string-address-address/deref)
|
|
|
|
(x:string-address-address/deref <- new string:literal newlen:integer)
|
|
|
|
; copy old contents
|
|
|
|
(i:integer <- copy 0:literal)
|
|
|
|
{ begin
|
|
|
|
(done?:boolean <- greater-or-equal i:integer oldlen:integer)
|
|
|
|
(break-if done?:boolean)
|
|
|
|
(src:byte <- index olddata:string-address/deref i:integer)
|
|
|
|
(dest:byte-address <- index-address x:string-address-address/deref/deref i:integer)
|
2015-01-28 10:31:54 +00:00
|
|
|
(dest:byte-address/deref <- copy src:byte)
|
2015-01-28 10:13:20 +00:00
|
|
|
(i:integer <- add i:integer 1:literal)
|
2015-01-17 23:41:24 +00:00
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
(reply in:buffer-address)
|
|
|
|
)
|
|
|
|
|
|
|
|
(init-fn buffer-full?
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(in:buffer-address <- next-input)
|
|
|
|
(len:integer <- get in:buffer-address/deref length:offset)
|
|
|
|
(s:string-address <- get in:buffer-address/deref data:offset)
|
|
|
|
(capacity:integer <- length s:string-address/deref)
|
|
|
|
(result:boolean <- greater-or-equal len:integer capacity:integer)
|
|
|
|
(reply result:boolean)
|
|
|
|
)
|
|
|
|
|
2015-02-01 07:36:48 +00:00
|
|
|
(init-fn buffer-index
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(in:buffer-address <- next-input)
|
|
|
|
(idx:integer <- next-input)
|
|
|
|
{ begin
|
|
|
|
(len:integer <- get in:buffer-address/deref length:offset)
|
|
|
|
(not-too-high?:boolean <- less-than idx:integer len:integer)
|
|
|
|
(not-too-low?:boolean <- greater-or-equal idx:integer 0:literal)
|
|
|
|
(in-bounds?:boolean <- and not-too-low?:boolean not-too-high?:boolean)
|
|
|
|
(break-if in-bounds?:boolean)
|
|
|
|
(assert nil:literal (("buffer-index out of bounds" literal)))
|
|
|
|
}
|
|
|
|
(s:string-address <- get in:buffer-address/deref data:offset)
|
|
|
|
(result:character <- index s:string-address/deref idx:integer)
|
|
|
|
(reply result:character)
|
|
|
|
)
|
|
|
|
|
2015-01-30 07:19:22 +00:00
|
|
|
(init-fn to-array ; from buffer
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(in:buffer-address <- next-input)
|
|
|
|
(len:integer <- get in:buffer-address/deref length:offset)
|
|
|
|
(s:string-address <- get in:buffer-address/deref data:offset)
|
|
|
|
{ begin
|
|
|
|
; test: ctrl-d -> s is nil -> to-array returns nil -> read-expression returns t -> exit repl
|
|
|
|
(break-if s:string-address)
|
|
|
|
(reply nil:literal)
|
|
|
|
}
|
|
|
|
; we can't just return s because it is usually the wrong length
|
|
|
|
(result:string-address <- new string:literal len:integer)
|
|
|
|
(i:integer <- copy 0:literal)
|
|
|
|
{ begin
|
|
|
|
(done?:boolean <- greater-or-equal i:integer len:integer)
|
|
|
|
(break-if done?:boolean)
|
|
|
|
(src:byte <- index s:string-address/deref i:integer)
|
|
|
|
;? (foo:integer <- character-to-integer src:byte) ;? 1
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("a: " literal))) ;? 1
|
|
|
|
;? ($print foo:integer) ;? 1
|
|
|
|
;? ($print ((#\newline literal))) ;? 1
|
2015-01-30 07:19:22 +00:00
|
|
|
(dest:byte-address <- index-address result:string-address/deref i:integer)
|
|
|
|
(dest:byte-address/deref <- copy src:byte)
|
|
|
|
(i:integer <- add i:integer 1:literal)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
(reply result:string-address)
|
|
|
|
)
|
|
|
|
|
2015-01-17 23:41:24 +00:00
|
|
|
(init-fn append
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(in:buffer-address <- next-input)
|
|
|
|
(c:character <- next-input)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print c:character) ;? 1
|
2015-01-17 23:41:24 +00:00
|
|
|
{ begin
|
|
|
|
; grow buffer if necessary
|
|
|
|
(full?:boolean <- buffer-full? in:buffer-address)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("aa\n" literal))) ;? 1
|
2015-01-17 23:41:24 +00:00
|
|
|
(break-unless full?:boolean)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("bb\n" literal))) ;? 1
|
2015-01-17 23:41:24 +00:00
|
|
|
(in:buffer-address <- grow-buffer in:buffer-address)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("cc\n" literal))) ;? 1
|
2015-01-17 23:41:24 +00:00
|
|
|
}
|
|
|
|
(len:integer-address <- get-address in:buffer-address/deref length:offset)
|
|
|
|
(s:string-address <- get in:buffer-address/deref data:offset)
|
|
|
|
(dest:byte-address <- index-address s:string-address/deref len:integer-address/deref)
|
2015-02-08 19:12:08 +00:00
|
|
|
(dest:byte-address/deref <- copy c:character)
|
2015-01-17 23:41:24 +00:00
|
|
|
(len:integer-address/deref <- add len:integer-address/deref 1:literal)
|
2015-01-27 02:12:46 +00:00
|
|
|
(reply in:buffer-address/same-as-arg:0)
|
2015-01-17 23:41:24 +00:00
|
|
|
)
|
|
|
|
|
2015-01-28 08:24:28 +00:00
|
|
|
(init-fn last
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
|
|
|
(in:buffer-address <- next-input)
|
|
|
|
(n:integer <- get in:buffer-address/deref length:offset)
|
|
|
|
{ begin
|
|
|
|
; if empty return nil
|
|
|
|
(empty?:boolean <- equal n:integer 0:literal)
|
|
|
|
(break-unless empty?:boolean)
|
|
|
|
(reply nil:literal)
|
|
|
|
}
|
|
|
|
(n:integer <- subtract n:integer 1:literal)
|
|
|
|
(s:string-address <- get in:buffer-address/deref data:offset)
|
|
|
|
(result:character <- index s:string-address/deref n:integer)
|
|
|
|
(reply result:character)
|
|
|
|
)
|
|
|
|
|
2015-01-17 23:41:24 +00:00
|
|
|
(init-fn integer-to-decimal-string
|
2015-01-18 01:00:44 +00:00
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2015-01-17 23:41:24 +00:00
|
|
|
(n:integer <- next-input)
|
|
|
|
; is it zero?
|
|
|
|
{ begin
|
|
|
|
(zero?:boolean <- equal n:integer 0:literal)
|
|
|
|
(break-unless zero?:boolean)
|
|
|
|
(s:string-address <- new "0")
|
|
|
|
(reply s:string-address)
|
|
|
|
}
|
|
|
|
; save sign
|
|
|
|
(negate-result:boolean <- copy nil:literal)
|
|
|
|
{ begin
|
|
|
|
(negative?:boolean <- less-than n:integer 0:literal)
|
|
|
|
(break-unless negative?:boolean)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("is negative " literal)))
|
2015-01-17 23:41:24 +00:00
|
|
|
(negate-result:boolean <- copy t:literal)
|
|
|
|
(n:integer <- multiply n:integer -1:literal)
|
|
|
|
}
|
|
|
|
; add digits from right to left into intermediate buffer
|
|
|
|
(tmp:buffer-address <- init-buffer 30:literal)
|
|
|
|
(zero:character <- copy ((#\0 literal)))
|
|
|
|
(digit-base:integer <- character-to-integer zero:character)
|
|
|
|
{ begin
|
|
|
|
(done?:boolean <- equal n:integer 0:literal)
|
|
|
|
(break-if done?:boolean)
|
|
|
|
(n:integer digit:integer <- divide-with-remainder n:integer 10:literal)
|
|
|
|
(digit-codepoint:integer <- add digit-base:integer digit:integer)
|
|
|
|
(c:character <- integer-to-character digit-codepoint:integer)
|
|
|
|
(tmp:buffer-address <- append tmp:buffer-address c:character)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
; add sign
|
|
|
|
{ begin
|
|
|
|
(break-unless negate-result:boolean)
|
|
|
|
(tmp:buffer-address <- append tmp:buffer-address ((#\- literal)))
|
|
|
|
}
|
|
|
|
; reverse buffer into string result
|
|
|
|
(len:integer <- get tmp:buffer-address/deref length:offset)
|
|
|
|
(buf:string-address <- get tmp:buffer-address/deref data:offset)
|
|
|
|
(result:string-address <- new string:literal len:integer)
|
|
|
|
(i:integer <- subtract len:integer 1:literal)
|
|
|
|
(j:integer <- copy 0:literal)
|
|
|
|
{ begin
|
|
|
|
; while (i >= 0)
|
|
|
|
(done?:boolean <- less-than i:integer 0:literal)
|
|
|
|
(break-if done?:boolean)
|
|
|
|
; result[j] = tmp[i]
|
|
|
|
(src:byte <- index buf:string-address/deref i:integer)
|
|
|
|
(dest:byte-address <- index-address result:string-address/deref j:integer)
|
|
|
|
(dest:byte-address/deref <- copy src:byte)
|
|
|
|
; ++i
|
|
|
|
(i:integer <- subtract i:integer 1:literal)
|
|
|
|
; --j
|
|
|
|
(j:integer <- add j:integer 1:literal)
|
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
(reply result:string-address)
|
|
|
|
)
|
|
|
|
|
2015-01-14 03:38:53 +00:00
|
|
|
(init-fn send-prints-to-stdout
|
|
|
|
(default-space:space-address <- new space:literal 30:literal)
|
2015-01-25 04:30:25 +00:00
|
|
|
(screen:terminal-address <- next-input)
|
2015-01-14 03:38:53 +00:00
|
|
|
(stdout:channel-address <- next-input)
|
2015-01-27 04:29:55 +00:00
|
|
|
;? (i:integer <- copy 0:literal) ;? 1
|
2015-01-14 03:38:53 +00:00
|
|
|
{ begin
|
2015-01-26 06:56:53 +00:00
|
|
|
(x:tagged-value stdout:channel-address/deref <- read stdout:channel-address)
|
2015-01-14 03:38:53 +00:00
|
|
|
(c:character <- maybe-coerce x:tagged-value character:literal)
|
2015-01-25 04:30:25 +00:00
|
|
|
(done?:boolean <- equal c:character ((#\null literal)))
|
|
|
|
(break-if done?:boolean)
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print (("printing " literal))) ;? 1
|
|
|
|
;? ($print i:integer) ;? 1
|
|
|
|
;? ($print ((" -- " literal))) ;? 1
|
2015-01-27 04:29:55 +00:00
|
|
|
;? (x:integer <- character-to-integer c:character) ;? 1
|
2015-02-01 08:15:43 +00:00
|
|
|
;? ($print x:integer) ;? 1
|
|
|
|
;? ($print (("\n" literal))) ;? 1
|
2015-01-27 04:29:55 +00:00
|
|
|
;? (i:integer <- add i:integer 1:literal) ;? 1
|
2015-01-25 04:30:25 +00:00
|
|
|
(print-character screen:terminal-address c:character)
|
2015-01-14 03:38:53 +00:00
|
|
|
(loop)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2015-01-18 09:32:56 +00:00
|
|
|
; remember to call this before you clear the screen or at any other milestone
|
|
|
|
; in an interactive program
|
2015-01-14 03:53:30 +00:00
|
|
|
(init-fn flush-stdout
|
2015-02-08 19:55:28 +00:00
|
|
|
(default-space:boolean <- copy nil:literal) ; silence warning, but die if locals used
|
2015-01-14 03:53:30 +00:00
|
|
|
(sleep for-some-cycles:literal 1:literal)
|
|
|
|
)
|
|
|
|
|
2015-01-18 02:50:32 +00:00
|
|
|
(init-fn init-fake-terminal
|
|
|
|
(default-space:space-address <- new space:literal 30:literal/capacity)
|
|
|
|
(result:terminal-address <- new terminal:literal)
|
|
|
|
(width:integer-address <- get-address result:terminal-address/deref num-cols:offset)
|
|
|
|
(width:integer-address/deref <- next-input)
|
|
|
|
(height:integer-address <- get-address result:terminal-address/deref num-rows:offset)
|
|
|
|
(height:integer-address/deref <- next-input)
|
|
|
|
(row:integer-address <- get-address result:terminal-address/deref cursor-row:offset)
|
|
|
|
(row:integer-address/deref <- copy 0:literal)
|
|
|
|
(col:integer-address <- get-address result:terminal-address/deref cursor-col:offset)
|
|
|
|
(col:integer-address/deref <- copy 0:literal)
|
|
|
|
(bufsize:integer <- multiply width:integer-address/deref height:integer-address/deref)
|
|
|
|
(buf:string-address-address <- get-address result:terminal-address/deref data:offset)
|
|
|
|
(buf:string-address-address/deref <- new string:literal bufsize:integer)
|
|
|
|
(clear-screen result:terminal-address)
|
|
|
|
(reply result:terminal-address)
|
|
|
|
)
|
|
|
|
|
2015-03-14 18:22:15 +00:00
|
|
|
(init-fn divides?
|
|
|
|
(default-space:space-address <- new space:literal 30:literal/capacity)
|
|
|
|
(x:integer <- next-input)
|
|
|
|
(y:integer <- next-input)
|
|
|
|
(_ remainder:integer <- divide-with-remainder x:integer y:integer)
|
|
|
|
(result:boolean <- equal remainder:integer 0:literal)
|
|
|
|
(reply result:boolean)
|
|
|
|
)
|
|
|
|
|
2014-12-30 23:13:51 +00:00
|
|
|
; after all system software is loaded:
|
2015-01-17 23:41:24 +00:00
|
|
|
;? (= dump-trace* (obj whitelist '("cn0" "cn1")))
|
2014-12-30 23:13:51 +00:00
|
|
|
(freeze system-function*)
|
2014-12-13 08:33:20 +00:00
|
|
|
) ; section 100 for system software
|
|
|
|
|
2015-02-23 08:45:35 +00:00
|
|
|
;; initialization
|
|
|
|
|
2014-08-22 18:05:51 +00:00
|
|
|
(reset)
|
2014-12-13 08:33:20 +00:00
|
|
|
(awhen (pos "--" argv)
|
2015-02-23 08:45:35 +00:00
|
|
|
; batch mode: load all provided files and start at 'main'
|
2014-12-13 08:33:20 +00:00
|
|
|
(map add-code:readfile (cut argv (+ it 1)))
|
2015-02-23 08:45:35 +00:00
|
|
|
;? (set dump-trace*)
|
2014-08-28 19:44:01 +00:00
|
|
|
(run 'main)
|
2015-01-02 19:39:22 +00:00
|
|
|
(if ($.current-charterm) ($.close-charterm))
|
2015-01-12 06:03:16 +00:00
|
|
|
(when ($.graphics-open?) ($.close-viewport Viewport) ($.close-graphics))
|
2015-01-29 06:06:19 +00:00
|
|
|
;? (pr "\nmemory: ")
|
|
|
|
;? (write int-canon.memory*)
|
2015-01-18 01:00:44 +00:00
|
|
|
(prn)
|
2015-01-01 19:11:02 +00:00
|
|
|
(each routine completed-routines*
|
2015-01-18 00:15:25 +00:00
|
|
|
(awhen rep.routine!error
|
|
|
|
(prn "error - " it)
|
2015-01-18 01:00:44 +00:00
|
|
|
;? (prn routine)
|
|
|
|
))
|
2014-11-01 23:34:33 +00:00
|
|
|
)
|
2015-02-24 08:32:23 +00:00
|
|
|
|
|
|
|
; repl
|
2015-02-27 03:15:07 +00:00
|
|
|
(def run-interactive (stmt)
|
2015-02-24 08:32:23 +00:00
|
|
|
; careful to avoid re-processing functions and adding noise to traces
|
|
|
|
(= function*!interactive (convert-labels:convert-braces:tokenize-args (list stmt)))
|
|
|
|
(add-next-space-generator function*!interactive 'interactive)
|
|
|
|
(= location*!interactive (assign-names-to-location function*!interactive 'interactive location*!interactive))
|
|
|
|
(replace-names-with-location function*!interactive 'interactive)
|
2015-02-24 08:35:56 +00:00
|
|
|
(= traces* (queue)) ; skip preprocessing
|
2015-02-24 08:32:23 +00:00
|
|
|
(run-more 'interactive))
|
2015-02-24 08:35:56 +00:00
|
|
|
|
2015-02-23 08:45:35 +00:00
|
|
|
(when (no cdr.argv)
|
2015-02-24 08:35:56 +00:00
|
|
|
(add-code:readfile "trace.mu")
|
2015-03-13 00:03:19 +00:00
|
|
|
(wipe function*!main)
|
2015-03-14 18:22:15 +00:00
|
|
|
(add-code:readfile "factorial.mu")
|
|
|
|
;? (add-code:readfile "chessboard.mu") ; takes too long
|
2015-03-13 00:03:19 +00:00
|
|
|
(wipe function*!main)
|
2015-02-24 08:35:56 +00:00
|
|
|
(freeze function*)
|
|
|
|
(load-system-functions)
|
|
|
|
(wipe interactive-commands*)
|
|
|
|
(wipe interactive-traces*)
|
|
|
|
(= interactive-cmdidx* 0)
|
|
|
|
(= traces* (queue))
|
|
|
|
;? (set dump-trace*) ;? 2
|
2015-02-23 08:45:35 +00:00
|
|
|
; interactive mode
|
2015-02-24 08:35:56 +00:00
|
|
|
(point break
|
|
|
|
(while t
|
|
|
|
(pr interactive-cmdidx*)(pr "> ")
|
|
|
|
(let expr (read)
|
|
|
|
(unless expr (break))
|
|
|
|
(push expr interactive-commands*)
|
|
|
|
(run-interactive expr))
|
|
|
|
(push traces* interactive-traces*)
|
|
|
|
(++ interactive-cmdidx*)
|
|
|
|
)))
|
|
|
|
|
|
|
|
(if ($.current-charterm) ($.close-charterm))
|
2015-01-02 19:39:22 +00:00
|
|
|
(reset)
|
2015-01-06 07:28:21 +00:00
|
|
|
;? (print-times)
|