1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-19 09:38:28 +03:00
mal/logo/types.lg
Dov Murik 4eb88ef295 Logo implementation
Tested on UCBLogo 6.0 with some minor tweaks (for performance and adding
a `timems` function).  The tweaks are performed during Docker image
creation (see Dockerfile).

Tests of step 5 are skipped because UCBLogo is too slow.

Interop is available via `(logo-eval "logo code to run")`.

The `examples` directory contains a Mal example of drawing a tree using
turtle graphics.
2016-06-17 16:36:09 -04:00

176 lines
3.2 KiB
Plaintext

; Make Logo's string-comparison case sensitive
make "caseignoredp "false
; Load the 'case' library macro
case "dummy []
; Redefine 'case' macro to not override caseignoredp
.macro case :case.value :case.clauses
catch "case.error [output case.helper :case.value :case.clauses]
(throw "error [Empty CASE clause])
end
to obj_new :type :val
output list :type :val
end
to obj_new_with_meta :type :val :meta
output (list :type :val :meta)
end
to obj_type :obj
output first :obj
end
to obj_val :obj
output item 2 :obj
end
to obj_meta :obj
if (count :obj) < 3 [output []]
output item 3 :obj
end
make "global_nil obj_new "nil []
to nil_new
output :global_nil
end
make "global_true obj_new "true []
to true_new
output :global_true
end
make "global_false obj_new "false []
to false_new
output :global_false
end
to symbol_new :name
output obj_new "symbol :name
end
to hashmap_get :h :key
localmake "i 1
while [:i < count :h] [
if equal_q item :i :h :key [
output item (:i + 1) :h
]
make "i (:i + 2)
]
output []
end
; Returns a new list with the key-val pair set
to hashmap_put :h :key :val
localmake "res hashmap_delete :h :key
make "res lput :key :res
make "res lput :val :res
output :res
end
; Returns a new list without the key-val pair set
to hashmap_delete :h :key
localmake "res []
localmake "i 1
while [:i < count :h] [
if (item :i :h) <> :key [
make "res lput item :i :h :res
make "res lput item (:i + 1) :h :res
]
make "i (:i + 2)
]
output :res
end
to fn_new :args :env :body
output obj_new "fn (list :args :env :body "false)
end
to fn_args :fn
output item 1 obj_val :fn
end
to fn_env :fn
output item 2 obj_val :fn
end
to fn_body :fn
output item 3 obj_val :fn
end
to fn_is_macro :fn
output item 4 obj_val :fn
end
to fn_set_macro :fn
.setfirst butfirst butfirst butfirst obj_val :fn "true
end
; zero-based sequence addressing
to nth :seq :index
output item (:index + 1) obj_val :seq
end
to _count :seq
output count obj_val :seq
end
to rest :seq
output obj_new obj_type :seq butfirst obj_val :seq
end
to drop :seq :num
if or :num = 0 (_count :seq) = 0 [output :seq]
foreach obj_val :seq [
if # >= :num [output obj_new obj_type :seq ?rest]
]
end
to sequentialp :obj
output or ((obj_type :obj) = "list) ((obj_type :obj) = "vector)
end
to equal_sequential_q :a :b
if (_count :a) <> (_count :b) [output "false]
(foreach obj_val :a obj_val :b [
if not equal_q ?1 ?2 [output "false]
])
output "true
end
to equal_hashmap_q :a :b
if (_count :a) <> (_count :b) [output "false]
localmake "a_keys obj_val mal_keys :a
foreach :a_keys [
localmake "a_val hashmap_get obj_val :a ?
localmake "b_val hashmap_get obj_val :b ?
if emptyp :b_val [output "false]
if not equal_q :a_val :b_val [output "false]
]
output "true
end
to equal_q :a :b
output cond [
[[and sequentialp :a sequentialp :b]
equal_sequential_q :a :b]
[[((obj_type :a) = (obj_type :b))]
case obj_type :a [
[[true false nil] "true]
[[number string keyword symbol] ((obj_val :a) = (obj_val :b))]
[[hashmap] equal_hashmap_q :a :b]
[[atom] equal_q obj_val :a obj_val :b]
[else "false]
]]
[else "false]
]
end
to symbolnamedp :name :obj
output and ((obj_type :obj) = "symbol) ((obj_val :obj) = :name)
end