From ba64276630454ceec1953af2debeb84be44980ad Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Tue, 8 Sep 2020 00:25:41 -0400 Subject: [PATCH] Begin object/struct syntax & semantics --- k_prime.krak | 2 +- k_prime_stdlib/prelude.kp | 20 +++++++++++++-- method.kp | 52 +++++++++++++++++++++++++++++++++------ 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/k_prime.krak b/k_prime.krak index 7090ade..49e024a 100644 --- a/k_prime.krak +++ b/k_prime.krak @@ -751,7 +751,7 @@ fun main(argc: int, argv: **char): int { var parameter_objects = params[1].get_array_rc() for (var i = 0; i < parameter_objects.get().size; i++;) { if !parameter_objects.get()[i].is_symbol() { - return make_pair(null(), KPResult::Err(kpString(str("second param to vau has a not symbol member")))) + return make_pair(null(), KPResult::Err(kpString(str("second param to vau has a not symbol member: ") + pr_str(parameter_objects.get()[i], true)))) } var parameter = parameter_objects.get()[i].get_symbol_text() if parameter == "&" { diff --git a/k_prime_stdlib/prelude.kp b/k_prime_stdlib/prelude.kp index cd42962..af96259 100644 --- a/k_prime_stdlib/prelude.kp +++ b/k_prime_stdlib/prelude.kp @@ -6,7 +6,7 @@ ; do_helper is basically mapping eval over statements, but the last one is in TCO position ; a bit of a hack, using cond to sequence (note the repitition of the eval in TCO position if it's last, -; otherwise the same eval in cond position, and wheather or not it returns a truthy value, it recurses in TCO position +; otherwise the same eval in cond position, and wheather or not it returns a truthy value, it recurses in TCO position) (fun do_helper (s i se) (cond (= i (len s)) nil (= i (- (len s) 1)) (eval (idx s i) se) (eval (idx s i) se) (do_helper s (+ i 1) se) @@ -23,14 +23,30 @@ (fun vapply (f p ede) (eval (concat [f] p) ede)) (fun lapply (f p) (eval (concat [(unwrap f)] p) (current-env))) + (set! let1 (vau de (s v b) (eval [[vau '_ [s] b] (eval v de)] de))) (set! let (vau de (vs b) (cond (= (len vs) 0) (eval b de) true (vapply let1 [(idx vs 0) (idx vs 1) [let (slice vs 2 -1) b]] de)))) + (set! if (vau de (con than & else) (cond (eval con de) (eval than de) (> (len else) 0) (eval (idx else 0) de) true nil))) +(fun map (f l) + (let (helper (lambda (f l n i recurse) + (if (= i (len l)) + n + (do (set-idx! n i (f (idx l i))) + (recurse f l n (+ i 1) recurse))))) + (helper f l (array-with-len (len l)) 0 helper))) +(fun map_with_idx (f l) + (let (helper (lambda (f l n i recurse) + (if (= i (len l)) + n + (do (set-idx! n i (f i (idx l i))) + (recurse f l n (+ i 1) recurse))))) + (helper f l (array-with-len (len l)) 0 helper))) -(fun print_through (x) (let (_ (println x)) x)) +(fun print_through (x) (do (println x) x)) (fun is_pair? (x) (and (array? x) (> (len x) 0))) (set! quasiquote (vau de (x) diff --git a/method.kp b/method.kp index 26b3b51..10d5d2c 100644 --- a/method.kp +++ b/method.kp @@ -1,9 +1,9 @@ ; First quick lookup function, since maps are not built in (fun get-value-helper (dict key i) (if (>= i (len dict)) nil - (if (= key (idx dict i)) - (idx dict (+ i 1)) - (get-value-helper dict key (+ i 2))))) + (if (= key (idx (idx dict i) 0)) + (idx (idx dict i) 1) + (get-value-helper dict key (+ i 1))))) (fun get-value (dict key) (get-value-helper dict key 0)) ; Our actual method call function @@ -12,16 +12,54 @@ (println "no method " method) (do (println "applying" method_fn (concat [object] arguments) ) (lapply method_fn (concat [object] arguments)))))) ; Some nice syntactic sugar for method calls +; No params +(add_grammar_rule 'form ['form "\\." 'atom] + (lambda (o _ m) `(method-call ~o '~m))) +; params (add_grammar_rule 'form ['form "\\." 'atom 'optional_WS "\\(" 'optional_WS 'space_forms 'optional_WS "\\)"] (lambda (o _ m _ _ _ p _ _) `(method-call ~o '~m ,p))) +; object creation +(set! make_object (vau de (name members) + (eval (print_through `(fun ~name ~members + (with-meta [,members] + [,(map_with_idx (lambda (i x) [array `'~x (lambda (o) (idx o i))]) members)]))) de))) + +; object syntax +(add_grammar_rule 'form ["obj" 'WS 'atom "\\(" ['optional_WS 'atom] * 'optional_WS "\\)" 'optional_WS "{" "}"] (lambda (_ _ name _ members _ _ _ _ _) + `(make_object ~name ~(map (lambda (x) (idx x 1)) members)))) + ; Ok, let's create our object by hand for this example (set! actual_obj (with-meta [0] [ - 'inc (lambda (o) (set-idx! o 0 (+ (idx o 0) 1))) - 'dec (lambda (o) (set-idx! o 0 (- (idx o 0) 1))) - 'set (lambda (o n) (set-idx! o 0 n)) - 'get (lambda (o) (idx o 0)) + ['inc (lambda (o) (set-idx! o 0 (+ (idx o 0) 1)))] + ['dec (lambda (o) (set-idx! o 0 (- (idx o 0) 1)))] + ['set (lambda (o n) (set-idx! o 0 n))] + ['get (lambda (o) (idx o 0))] ])) + +(println "asdf") +(println (make_object Wooo ( a b c ))) +(println "fdsa") + +obj MyConstructor() {} +(println '(obj MyConstructor() {})) +(println MyConstructor) +(println (MyConstructor)) + +(println "done with first") + +(println '(obj MyConstructor2( mem1 mem2 ) {})) + +obj MyConstructor2( mem1 mem2 ) {} +(println "made") +(println MyConstructor2) +(println (MyConstructor2 1 2)) +(println (meta (MyConstructor2 1 2))) +(println "it will be " (MyConstructor2 1337 266).mem1()) +(println "it will be " (MyConstructor2 1337 266).mem2()) +(println "it will be " (MyConstructor2 1337 777).mem2) +(println "it was") + (do (println (meta actual_obj)) ; Use our new sugar