| @@ -26,7 +26,7 @@ | |||||
| (font-lock-add-keywords | (font-lock-add-keywords | ||||
| 'c++-mode | 'c++-mode | ||||
| '(("\\<\\(if_debug\\|if_windows\\|if_linux\\|defer\\|proc\\|try\\|try_void\\|for_array_list\\|for_lisp_vector\\|for_lisp_list\\|ignore_logging\\|dont_break_on_errors\\)\\>" . | |||||
| '(("\\<\\(if_debug\\|if_windows\\|if_linux\\|defer\\|proc\\|try\\|try_void\\|for_array_list\\|for_lisp_vector\\|in_caller_env\\|for_lisp_list\\|ignore_logging\\|dont_break_on_errors\\)\\>" . | |||||
| font-lock-keyword-face))))))) | font-lock-keyword-face))))))) | ||||
| (c++-mode . ((eval . (company-clang-set-prefix "slime.h")) | (c++-mode . ((eval . (company-clang-set-prefix "slime.h")) | ||||
| @@ -28,12 +28,12 @@ | |||||
| (define key-not-found-index -1) | (define key-not-found-index -1) | ||||
| (define (make-alist) | (define (make-alist) | ||||
| (set-type | |||||
| (set-type! | |||||
| '(()) | '(()) | ||||
| :alist)) | :alist)) | ||||
| (define (make-plist) | (define (make-plist) | ||||
| (set-type | |||||
| (set-type! | |||||
| '(()) | '(()) | ||||
| :plist)) | :plist)) | ||||
| @@ -41,9 +41,9 @@ | |||||
| (let ((associations (first alist))) | (let ((associations (first alist))) | ||||
| (define (pprint-intern associations) | (define (pprint-intern associations) | ||||
| (when associations | (when associations | ||||
| (printf " " | |||||
| (caar associations) "->" | |||||
| (cdar associations)) | |||||
| (print " " | |||||
| (caar associations) "->" | |||||
| (cdar associations)) | |||||
| (pprint-intern (rest associations)))) | (pprint-intern (rest associations)))) | ||||
| (print "(") | (print "(") | ||||
| (when associations | (when associations | ||||
| @@ -55,9 +55,9 @@ | |||||
| (let ((props (first plist))) | (let ((props (first plist))) | ||||
| (define (pprint-intern props) | (define (pprint-intern props) | ||||
| (when props | (when props | ||||
| (printf " " | |||||
| (car props) "->" | |||||
| (cadr props)) | |||||
| (print " " | |||||
| (car props) "->" | |||||
| (cadr props)) | |||||
| (pprint-intern (cddr props)))) | (pprint-intern (cddr props)))) | ||||
| (print "(") | (print "(") | ||||
| (when props | (when props | ||||
| @@ -113,7 +113,7 @@ | |||||
| (define (alist-set! alist key value) | (define (alist-set! alist key value) | ||||
| (mutate alist (set-type (pair (pair (pair key value) | |||||
| (mutate alist (set-type! (pair (pair (pair key value) | |||||
| (car alist)) | (car alist)) | ||||
| ()) | ()) | ||||
| :alist))) | :alist))) | ||||
| @@ -142,7 +142,7 @@ | |||||
| (plist-get-intern props prop))) | (plist-get-intern props prop))) | ||||
| (define (plist-set! plist prop value) | (define (plist-set! plist prop value) | ||||
| (mutate plist (set-type (pair (pair prop (pair value (first plist))) ()) | |||||
| (mutate plist (set-type! (pair (pair prop (pair value (first plist))) ()) | |||||
| :plist))) | :plist))) | ||||
| (define (plist-set-overwrite! plist prop value) | (define (plist-set-overwrite! plist prop value) | ||||
| @@ -1,10 +1,8 @@ | |||||
| (define-syntax (pe expr) | (define-syntax (pe expr) | ||||
| `(printf ',expr "evaluates to" ,expr)) | |||||
| `(print ',expr "evaluates to" ,expr)) | |||||
| (define-syntax (when condition :rest body) | |||||
| "Special form for when multiple actions should be done if a | |||||
| (define-syntax (when condition . body) | |||||
| :doc "Special form for when multiple actions should be done if a | |||||
| condition is true. | condition is true. | ||||
| {{{example_start}}} | {{{example_start}}} | ||||
| @@ -22,22 +20,23 @@ condition is true. | |||||
| `(if ,condition @body nil) | `(if ,condition @body nil) | ||||
| `(if ,condition (begin @body) nil))) | `(if ,condition (begin @body) nil))) | ||||
| (define-syntax (unless condition :rest body) | |||||
| "Special form for when multiple actions should be done if a | |||||
| (define-syntax (unless condition . body) | |||||
| :doc "Special form for when multiple actions should be done if a | |||||
| condition is false." | condition is false." | ||||
| (if (= (rest body) ()) | (if (= (rest body) ()) | ||||
| `(if ,condition nil @body) | `(if ,condition nil @body) | ||||
| `(if ,condition nil (begin @body)))) | `(if ,condition nil (begin @body)))) | ||||
| (define-syntax (n-times times action) | (define-syntax (n-times times action) | ||||
| "Executes action times times." | |||||
| :doc "Executes action times times." | |||||
| (define (repeat times elem) | (define (repeat times elem) | ||||
| (unless (> 1 times) | (unless (> 1 times) | ||||
| (pair elem (repeat (- times 1) elem)))) | (pair elem (repeat (- times 1) elem)))) | ||||
| `(begin @(repeat times action))) | `(begin @(repeat times action))) | ||||
| (define-syntax (let bindings :rest body) | |||||
| (define-syntax (let bindings . body) | |||||
| (define (unzip lists) | (define (unzip lists) | ||||
| (break) | |||||
| (when lists | (when lists | ||||
| (define (iter lists l1 l2) | (define (iter lists l1 l2) | ||||
| (define elem (first lists)) | (define elem (first lists)) | ||||
| @@ -51,9 +50,9 @@ condition is false." | |||||
| (define unzipped (unzip bindings)) | (define unzipped (unzip bindings)) | ||||
| `((lambda ,(first unzipped) @body) @(first (rest unzipped)))) | |||||
| `((,lambda ,(first unzipped) @body) @(first (rest unzipped)))) | |||||
| (define-syntax (cond :rest clauses) | |||||
| (define-syntax (cond . clauses) | |||||
| (define (rec clauses) | (define (rec clauses) | ||||
| (if (= nil clauses) | (if (= nil clauses) | ||||
| nil | nil | ||||
| @@ -68,7 +67,7 @@ condition is false." | |||||
| (rec clauses)) | (rec clauses)) | ||||
| (define-syntax (case var :rest clauses) | |||||
| (define-syntax (case var . clauses) | |||||
| (define (rec clauses) | (define (rec clauses) | ||||
| (if (= nil clauses) | (if (= nil clauses) | ||||
| nil | nil | ||||
| @@ -82,11 +81,11 @@ condition is false." | |||||
| ,(rec (rest clauses)))))) | ,(rec (rest clauses)))))) | ||||
| (rec clauses)) | (rec clauses)) | ||||
| (define-syntax (define-special name-and-args :rest body) | |||||
| (define-syntax (define-special name-and-args . body) | |||||
| `(define ,(first name-and-args) (special-lambda ,(rest name-and-args) @body))) | `(define ,(first name-and-args) (special-lambda ,(rest name-and-args) @body))) | ||||
| (define-syntax (construct-list :rest body) | |||||
| " | |||||
| (define-syntax (construct-list . body) | |||||
| :doc " | |||||
| {{{example_start}}} | {{{example_start}}} | ||||
| (construct-list | (construct-list | ||||
| i <- '(1 2 3 4 5) | i <- '(1 2 3 4 5) | ||||
| @@ -127,11 +126,11 @@ condition is false." | |||||
| (rec body)) | (rec body)) | ||||
| (define-syntax (apply fun seq) | (define-syntax (apply fun seq) | ||||
| "Applies the function to the sequence, as in calls the function with | |||||
| :doc "Applies the function to the sequence, as in calls the function with | |||||
| ithe sequence as arguemens." | ithe sequence as arguemens." | ||||
| `(eval (pair ,fun ,seq))) | `(eval (pair ,fun ,seq))) | ||||
| (define-syntax (define-typed args :rest body) | |||||
| (define-syntax (define-typed args . body) | |||||
| (define (get-arg-names args) | (define (get-arg-names args) | ||||
| (when args | (when args | ||||
| (pair (first args) | (pair (first args) | ||||
| @@ -144,7 +143,7 @@ ithe sequence as arguemens." | |||||
| @body))) | @body))) | ||||
| (define-syntax (define-module module-name :keys exports :rest body) | |||||
| (define-syntax (define-module module-name :exports . body) | |||||
| (let ((module-prefix (concat-strings (symbol->string module-name) "::"))) | (let ((module-prefix (concat-strings (symbol->string module-name) "::"))) | ||||
| (eval `(begin @body)) | (eval `(begin @body)) | ||||
| (pair 'begin | (pair 'begin | ||||
| @@ -159,14 +158,14 @@ ithe sequence as arguemens." | |||||
| (define (null? x) | (define (null? x) | ||||
| "Checks if the argument is =nil=." | |||||
| :doc "Checks if the argument is =nil=." | |||||
| (= x ())) | (= x ())) | ||||
| (define (type=? obj typ) | (define (type=? obj typ) | ||||
| "Checks if the argument =obj= is of type =typ=" | |||||
| :doc "Checks if the argument =obj= is of type =typ=" | |||||
| (= (type obj) typ)) | (= (type obj) typ)) | ||||
| (define (types=? :rest objs) | |||||
| (define (types=? . objs) | |||||
| (define (inner objs) | (define (inner objs) | ||||
| (if objs | (if objs | ||||
| (let ((actual-type (type (first objs))) | (let ((actual-type (type (first objs))) | ||||
| @@ -177,7 +176,7 @@ ithe sequence as arguemens." | |||||
| t)) | t)) | ||||
| (inner objs)) | (inner objs)) | ||||
| (define (assert-types= :rest objs) | |||||
| (define (assert-types= . objs) | |||||
| (define (inner objs) | (define (inner objs) | ||||
| (when objs | (when objs | ||||
| (let ((actual-type (type (first objs))) | (let ((actual-type (type (first objs))) | ||||
| @@ -188,39 +187,39 @@ ithe sequence as arguemens." | |||||
| (inner objs)) | (inner objs)) | ||||
| (define (number? x) | (define (number? x) | ||||
| "Checks if the argument is a number." | |||||
| :doc "Checks if the argument is a number." | |||||
| (type=? x :number)) | (type=? x :number)) | ||||
| (define (symbol? x) | (define (symbol? x) | ||||
| "Checks if the argument is a symbol." | |||||
| :doc "Checks if the argument is a symbol." | |||||
| (type=? x :symbol)) | (type=? x :symbol)) | ||||
| (define (keyword? x) | (define (keyword? x) | ||||
| "Checks if the argument is a keyword." | |||||
| :doc "Checks if the argument is a keyword." | |||||
| (type=? x :keyword)) | (type=? x :keyword)) | ||||
| (define (pair? x) | (define (pair? x) | ||||
| "Checks if the argument is a pair." | |||||
| :doc "Checks if the argument is a pair." | |||||
| (type=? x :pair)) | (type=? x :pair)) | ||||
| (define (string? x) | (define (string? x) | ||||
| "Checks if the argument is a string." | |||||
| :doc "Checks if the argument is a string." | |||||
| (type=? x :string)) | (type=? x :string)) | ||||
| (define (lambda? x) | (define (lambda? x) | ||||
| "Checks if the argument is a function." | |||||
| :doc "Checks if the argument is a function." | |||||
| (type=? x :lambda)) | (type=? x :lambda)) | ||||
| (define (macro? x) | (define (macro? x) | ||||
| "Checks if the argument is a macro." | |||||
| :doc "Checks if the argument is a macro." | |||||
| (type=? x :macro)) | (type=? x :macro)) | ||||
| (define (special-lambda? x) | (define (special-lambda? x) | ||||
| "Checks if the argument is a special-lambda." | |||||
| :doc "Checks if the argument is a special-lambda." | |||||
| (type=? x :dynamic-macro)) | (type=? x :dynamic-macro)) | ||||
| (define (built-in-function? x) | (define (built-in-function? x) | ||||
| "Checks if the argument is a built-in function." | |||||
| :doc "Checks if the argument is a built-in function." | |||||
| (type=? x :built-in-function)) | (type=? x :built-in-function)) | ||||
| (define (callable? x) | (define (callable? x) | ||||
| @@ -230,11 +229,11 @@ ithe sequence as arguemens." | |||||
| (built-in-function? x))) | (built-in-function? x))) | ||||
| (define (end seq) | (define (end seq) | ||||
| "Returns the last pair in the sqeuence. | |||||
| :doc "Returns the last pair in the sqeuence. | |||||
| {{{example_start}}} | {{{example_start}}} | ||||
| (define a (list 1 2 3 4)) | (define a (list 1 2 3 4)) | ||||
| (printf (end a)) | |||||
| (print (end a)) | |||||
| {{{example_end}}} | {{{example_end}}} | ||||
| " | " | ||||
| (if (or (null? seq) (not (pair? (rest seq)))) | (if (or (null? seq) (not (pair? (rest seq)))) | ||||
| @@ -242,17 +241,17 @@ ithe sequence as arguemens." | |||||
| (end (rest seq)))) | (end (rest seq)))) | ||||
| (define (last seq) | (define (last seq) | ||||
| "Returns the (first) of the last (pair) of the given sequence. | |||||
| :doc "Returns the (first) of the last (pair) of the given sequence. | |||||
| {{{example_start}}} | {{{example_start}}} | ||||
| (define a (list 1 2 3 4)) | (define a (list 1 2 3 4)) | ||||
| (printf (last a)) | |||||
| (print (last a)) | |||||
| {{{example_end}}} | {{{example_end}}} | ||||
| " | " | ||||
| (first (end seq))) | (first (end seq))) | ||||
| (define (extend seq elem) | (define (extend seq elem) | ||||
| "Extends a list with the given element, by putting it in | |||||
| :doc "Extends a list with the given element, by putting it in | |||||
| the (rest) of the last element of the sequence." | the (rest) of the last element of the sequence." | ||||
| (if (pair? seq) | (if (pair? seq) | ||||
| (begin | (begin | ||||
| @@ -262,23 +261,23 @@ the (rest) of the last element of the sequence." | |||||
| elem)) | elem)) | ||||
| (define (extend2 seq elem) | (define (extend2 seq elem) | ||||
| "Extends a list with the given element, by putting it in | |||||
| :doc "Extends a list with the given element, by putting it in | |||||
| the (rest) of the last element of the sequence." | the (rest) of the last element of the sequence." | ||||
| (printf "addr of (end seq)" (addr-of (end seq))) | |||||
| (print "addr of (end seq)" (addr-of (end seq))) | |||||
| (if (pair? seq) | (if (pair? seq) | ||||
| (let ((e (end seq))) | (let ((e (end seq))) | ||||
| (printf "addr if e inner" (addr-of e)) | |||||
| (print "addr if e inner" (addr-of e)) | |||||
| (mutate e (pair (first e) elem)) | (mutate e (pair (first e) elem)) | ||||
| seq)) | seq)) | ||||
| elem) | elem) | ||||
| (define (append seq elem) | (define (append seq elem) | ||||
| "Appends an element to a sequence, by extendeing the list | |||||
| :doc "Appends an element to a sequence, by extendeing the list | |||||
| with (pair elem nil)." | with (pair elem nil)." | ||||
| (extend seq (pair elem ()))) | (extend seq (pair elem ()))) | ||||
| (define (length seq) | (define (length seq) | ||||
| "Returns the length of the given sequence." | |||||
| :doc "Returns the length of the given sequence." | |||||
| (if (null? seq) | (if (null? seq) | ||||
| 0 | 0 | ||||
| (+ 1 (length (rest seq))))) | (+ 1 (length (rest seq))))) | ||||
| @@ -303,21 +302,21 @@ with (pair elem nil)." | |||||
| (else (pair (first seq) (list-without-index (rest seq) (- index 1)))))) | (else (pair (first seq) (list-without-index (rest seq) (- index 1)))))) | ||||
| (define (increment val) | (define (increment val) | ||||
| "Adds one to the argument." | |||||
| :doc "Adds one to the argument." | |||||
| (+ val 1)) | (+ val 1)) | ||||
| (define (decrement val) | (define (decrement val) | ||||
| "Subtracts one from the argument." | |||||
| :doc "Subtracts one from the argument." | |||||
| (- val 1)) | (- val 1)) | ||||
| (define (range :keys from :defaults-to 0 to) | |||||
| "Returns a sequence of numbers starting with the number defined by the | |||||
| key =from= and ends with the number defined in =to=." | |||||
| (define (range (:from 0) :to) | |||||
| :doc "Returns a sequence of numbers starting with the number defined | |||||
| by the key =from= and ends with the number defined in =to=." | |||||
| (when (< from to) | (when (< from to) | ||||
| (pair from (range :from (+ 1 from) :to to)))) | (pair from (range :from (+ 1 from) :to to)))) | ||||
| (define (range-while :keys from :defaults-to 0 to) | |||||
| "Returns a sequence of numbers starting with the number defined | |||||
| (define (range-while (:from 0) to) | |||||
| :doc "Returns a sequence of numbers starting with the number defined | |||||
| by the key 'from' and ends with the number defined in 'to'." | by the key 'from' and ends with the number defined in 'to'." | ||||
| (define result (list (copy from))) | (define result (list (copy from))) | ||||
| (define head result) | (define head result) | ||||
| @@ -330,7 +329,7 @@ by the key 'from' and ends with the number defined in 'to'." | |||||
| result) | result) | ||||
| (define (map fun seq) | (define (map fun seq) | ||||
| "Takes a function and a sequence as arguments and returns a new | |||||
| :doc "Takes a function and a sequence as arguments and returns a new | |||||
| sequence which contains the results of using the first sequences | sequence which contains the results of using the first sequences | ||||
| elemens as argument to that function." | elemens as argument to that function." | ||||
| (if (null? seq) | (if (null? seq) | ||||
| @@ -339,17 +338,17 @@ elemens as argument to that function." | |||||
| (map fun (rest seq))))) | (map fun (rest seq))))) | ||||
| (define (reduce fun seq) | (define (reduce fun seq) | ||||
| "Takes a function and a sequence as arguments and applies the | |||||
| function to the argument sequence. This only works correctly if the | |||||
| given function accepts a variable amount of parameters. If your | |||||
| funciton is limited to two arguments, use [[=reduce-binary=]] | |||||
| :doc "Takes a function and a sequence as arguments and applies the | |||||
| function to the argument sequence. This only works correctly if the | |||||
| given function accepts a variable amount of parameters. If your | |||||
| funciton is limited to two arguments, use [[=reduce-binary=]] | |||||
| instead." | instead." | ||||
| (apply fun seq)) | (apply fun seq)) | ||||
| (define (reduce-binary fun seq) | (define (reduce-binary fun seq) | ||||
| "Takes a function and a sequence as arguments and applies the | |||||
| :doc "Takes a function and a sequence as arguments and applies the | |||||
| function to the argument sequence. reduce-binary applies the arguments | function to the argument sequence. reduce-binary applies the arguments | ||||
| *pair-wise* which means it works with binary functions as compared to | |||||
| *pair-wise* which means it works with binary functions as compared to | |||||
| [[=reduce=]]." | [[=reduce=]]." | ||||
| (if (null? (rest seq)) | (if (null? (rest seq)) | ||||
| (first seq) | (first seq) | ||||
| @@ -357,7 +356,7 @@ function to the argument sequence. reduce-binary applies the arguments | |||||
| (reduce-binary fun (rest seq))))) | (reduce-binary fun (rest seq))))) | ||||
| (define (filter fun seq) | (define (filter fun seq) | ||||
| "Takes a function and a sequence as arguments and applies the | |||||
| :doc "Takes a function and a sequence as arguments and applies the | |||||
| function to every value in the sequence. If the result of that | function to every value in the sequence. If the result of that | ||||
| funciton application returns a truthy value, the original value is | funciton application returns a truthy value, the original value is | ||||
| added to a list, which in the end is returned." | added to a list, which in the end is returned." | ||||
| @@ -392,20 +391,20 @@ added to a list, which in the end is returned." | |||||
| (enumerate-inner (rest seq) (+ 1 next-num))))) | (enumerate-inner (rest seq) (+ 1 next-num))))) | ||||
| (enumerate-inner seq 0)) | (enumerate-inner seq 0)) | ||||
| (define (printf :keys sep :defaults-to " " end :defaults-to "\n" :rest args) | |||||
| "A wrapper for the built-in function [[=print=]] that accepts a | |||||
| variable number of arguments and also provides keywords for specifying | |||||
| the printed separators (=sep=) between the arguments and what should | |||||
| be printed after the last argument (=end=)." | |||||
| (define (printf-inner args) | |||||
| (if args | |||||
| (begin | |||||
| (print (first args)) | |||||
| (when (rest args) | |||||
| (print sep)) | |||||
| (printf-inner (rest args))) | |||||
| ; else | |||||
| (print end))) | |||||
| (printf-inner args) | |||||
| ()) | |||||
| ;; (define (print (:sep " ") (:end "\n") . args) | |||||
| ;; "A wrapper for the built-in function [[=print=]] that accepts a | |||||
| ;; variable number of arguments and also provides keywords for specifying | |||||
| ;; the printed separators (=sep=) between the arguments and what should | |||||
| ;; be printed after the last argument (=end=)." | |||||
| ;; (define (print-inner args) | |||||
| ;; (if args | |||||
| ;; (begin | |||||
| ;; (print (first args)) | |||||
| ;; (when (rest args) | |||||
| ;; (print sep)) | |||||
| ;; (print-inner (rest args))) | |||||
| ;; ; else | |||||
| ;; (print end))) | |||||
| ;; (print-inner args) | |||||
| ;; ()) | |||||
| @@ -1,42 +1,66 @@ | |||||
| (define (null? x) "Checks if the argument is =nil=." (= x ())) | |||||
| (define-syntax (pe expr) `(print ',expr "evaluates to" ,expr)) | |||||
| (define (type=? obj typ) "Checks if the argument =obj= is of type =typ=" (= (type obj) typ)) | |||||
| (define-syntax (when condition . body) :doc "Special form for when multiple actions should be done if a\ncondition is true.\n\n{{{example_start}}}\n(when (not ())\n (print "Hello ")\n (print "from ")\n (print "when!"))\n\n(when ()\n (print "Goodbye ")\n (print "World!"))\n{{{example_end}}}\n" (if (= (rest body) ()) `(if ,condition (unquote-splicing body) nil) `(if ,condition (begin (unquote-splicing body)) nil))) | |||||
| (define (types=? :rest objs) (define (inner objs) (if objs (let ((actual-type (type (first objs))) (desired-type (first (rest objs)))) (if (= actual-type desired-type) (inner (rest (rest objs))) ())) t)) (inner objs)) | |||||
| (define-syntax (unless condition . body) :doc "Special form for when multiple actions should be done if a\ncondition is false." (if (= (rest body) ()) `(if ,condition nil (unquote-splicing body)) `(if ,condition nil (begin (unquote-splicing body))))) | |||||
| (define (assert-types= :rest objs) (define (inner objs) (when objs (let ((actual-type (type (first objs))) (desired-type (first (rest objs)))) (if (= actual-type desired-type) (inner (rest (rest objs))) (error "type missmatch" actual-type desired-type))))) (inner objs)) | |||||
| (define-syntax (n-times times action) :doc "Executes action times times." (define (repeat times elem) (unless (> 1 times) (pair elem (repeat (- times 1) elem)))) `(begin (unquote-splicing (repeat times action)))) | |||||
| (define (number? x) "Checks if the argument is a number." (type=? x :number)) | |||||
| (define-syntax (let bindings . body) (define (unzip lists) (break) (when lists (define (iter lists l1 l2) (define elem (first lists)) (if elem (iter (rest lists) (pair (first elem) l1) (pair (first (rest elem)) l2)) (list l1 l2)))) (iter lists () ())) (define unzipped (unzip bindings)) `((,lambda ,(first unzipped) (unquote-splicing body)) (unquote-splicing (first (rest unzipped))))) | |||||
| (define (symbol? x) "Checks if the argument is a symbol." (type=? x :symbol)) | |||||
| (define-syntax (cond . clauses) (define (rec clauses) (if (= nil clauses) nil (if (= (first (first clauses)) 'else) (begin (if (not (= (rest clauses) ())) (error "There are additional clauses after the else clause!") (pair 'begin (rest (first clauses))))) `(if ,(first (first clauses)) (begin (unquote-splicing (rest (first clauses)))) ,(rec (rest clauses)))))) (rec clauses)) | |||||
| (define (keyword? x) "Checks if the argument is a keyword." (type=? x :keyword)) | |||||
| (define-syntax (case var . clauses) (define (rec clauses) (if (= nil clauses) nil (if (= (first (first clauses)) 'else) (begin (if (not (= (rest clauses) ())) (error "There are additional clauses after the else clause!") (pair 'begin (rest (first clauses))))) `(if (member? ,var ',(first (first clauses))) (begin (unquote-splicing (rest (first clauses)))) ,(rec (rest clauses)))))) (rec clauses)) | |||||
| (define (pair? x) "Checks if the argument is a pair." (type=? x :pair)) | |||||
| (define-syntax (define-special name-and-args . body) `(define ,(first name-and-args) (special-lambda ,(rest name-and-args) (unquote-splicing body)))) | |||||
| (define (string? x) "Checks if the argument is a string." (type=? x :string)) | |||||
| (define-syntax (construct-list . body) :doc "\n{{{example_start}}}\n(construct-list\n i <- '(1 2 3 4 5)\n yield (* i i))\n{{{example_end}}}\n\n(construct-list\n i <- '(1 2 3 4)\n j <- '(A B)\n yield (pair i j))\n\n(construct-list\n i <- '(1 2 3 4 5 6 7 8)\n if (= 0 (% i 2))\n yield i)\n" (define (append-map f ll) (unless (= ll ()) (define val (f (first ll))) (if (= (first val) ()) (append-map f (rest ll)) (extend val (append-map f (rest ll)))))) (define (rec body) (cond ((= () body) ()) ((= () (rest body)) (first body)) ((= (first (rest body)) '<-) `(,append-map (lambda (,(first body)) (list ,(rec (rest (rest (rest body)))))) ,(first (rest (rest body))))) ((= (first body) 'if) `(when ,(first (rest body)) ,(rec (rest (rest body))))) ((= (first (rest body)) 'yield) (first (rest body))) (else (error "Not a do-able expression")))) (rec body)) | |||||
| (define (lambda? x) "Checks if the argument is a function." (type=? x :lambda)) | |||||
| (define-syntax (apply fun seq) :doc "Applies the function to the sequence, as in calls the function with\nithe sequence as arguemens." `(eval (pair ,fun ,seq))) | |||||
| (define (macro? x) "Checks if the argument is a macro." (type=? x :macro)) | |||||
| (define-syntax (define-typed args . body) (define (get-arg-names args) (when args (pair (first args) (get-arg-names (rest (rest args)))))) (let ((name (first args)) (lambda-list (rest args)) (arg-names (get-arg-names (rest args)))) `(define (,name (unquote-splicing arg-names)) (assert-types= (unquote-splicing lambda-list)) (unquote-splicing body)))) | |||||
| (define (special-lambda? x) "Checks if the argument is a special-lambda." (type=? x :dynamic-macro)) | |||||
| (define-syntax (define-module module-name :exports . body) (let ((module-prefix (concat-strings (symbol->string module-name) "::"))) (eval `(begin (unquote-splicing body))) (pair 'begin (map (lambda (orig-export-name) (let ((export-name (string->symbol (concat-strings module-prefix (symbol->string orig-export-name))))) `(define ,export-name ,(try (eval orig-export-name) (error "The module does not contain" orig-export-name))))) exports)))) | |||||
| (define (built-in-function? x) "Checks if the argument is a built-in function." (type=? x :built-in-function)) | |||||
| (define (null? x) :doc "Checks if the argument is =nil=." (= x ())) | |||||
| (define (type=? obj typ) :doc "Checks if the argument =obj= is of type =typ=" (= (type obj) typ)) | |||||
| (define (types=? . objs) (define (inner objs) (if objs (let ((actual-type (type (first objs))) (desired-type (first (rest objs)))) (if (= actual-type desired-type) (inner (rest (rest objs))) ())) t)) (inner objs)) | |||||
| (define (assert-types= . objs) (define (inner objs) (when objs (let ((actual-type (type (first objs))) (desired-type (first (rest objs)))) (if (= actual-type desired-type) (inner (rest (rest objs))) (error "type missmatch" actual-type desired-type))))) (inner objs)) | |||||
| (define (number? x) :doc "Checks if the argument is a number." (type=? x :number)) | |||||
| (define (symbol? x) :doc "Checks if the argument is a symbol." (type=? x :symbol)) | |||||
| (define (keyword? x) :doc "Checks if the argument is a keyword." (type=? x :keyword)) | |||||
| (define (pair? x) :doc "Checks if the argument is a pair." (type=? x :pair)) | |||||
| (define (string? x) :doc "Checks if the argument is a string." (type=? x :string)) | |||||
| (define (lambda? x) :doc "Checks if the argument is a function." (type=? x :lambda)) | |||||
| (define (macro? x) :doc "Checks if the argument is a macro." (type=? x :macro)) | |||||
| (define (special-lambda? x) :doc "Checks if the argument is a special-lambda." (type=? x :dynamic-macro)) | |||||
| (define (built-in-function? x) :doc "Checks if the argument is a built-in function." (type=? x :built-in-function)) | |||||
| (define (callable? x) (or (lambda? x) (special-lambda? x) (macro? x) (built-in-function? x))) | (define (callable? x) (or (lambda? x) (special-lambda? x) (macro? x) (built-in-function? x))) | ||||
| (define (end seq) "Returns the last pair in the sqeuence.\n\n{{{example_start}}}\n(define a (list 1 2 3 4))\n(printf (end a))\n{{{example_end}}}\n" (if (or (null? seq) (not (pair? (rest seq)))) seq (end (rest seq)))) | |||||
| (define (end seq) :doc "Returns the last pair in the sqeuence.\n\n{{{example_start}}}\n(define a (list 1 2 3 4))\n(print (end a))\n{{{example_end}}}\n" (if (or (null? seq) (not (pair? (rest seq)))) seq (end (rest seq)))) | |||||
| (define (last seq) "Returns the (first) of the last (pair) of the given sequence.\n\n{{{example_start}}}\n(define a (list 1 2 3 4))\n(printf (last a))\n{{{example_end}}}\n" (first (end seq))) | |||||
| (define (last seq) :doc "Returns the (first) of the last (pair) of the given sequence.\n\n{{{example_start}}}\n(define a (list 1 2 3 4))\n(print (last a))\n{{{example_end}}}\n" (first (end seq))) | |||||
| (define (extend seq elem) "Extends a list with the given element, by putting it in\nthe (rest) of the last element of the sequence." (if (pair? seq) (begin (define e (end seq)) (mutate e (pair (first e) elem)) seq) elem)) | |||||
| (define (extend seq elem) :doc "Extends a list with the given element, by putting it in\nthe (rest) of the last element of the sequence." (if (pair? seq) (begin (define e (end seq)) (mutate e (pair (first e) elem)) seq) elem)) | |||||
| (define (extend2 seq elem) "Extends a list with the given element, by putting it in\nthe (rest) of the last element of the sequence." (printf "addr of (end seq)" (addr-of (end seq))) (if (pair? seq) (let ((e (end seq))) (printf "addr if e inner" (addr-of e)) (mutate e (pair (first e) elem)) seq)) elem) | |||||
| (define (extend2 seq elem) :doc "Extends a list with the given element, by putting it in\nthe (rest) of the last element of the sequence." (print "addr of (end seq)" (addr-of (end seq))) (if (pair? seq) (let ((e (end seq))) (print "addr if e inner" (addr-of e)) (mutate e (pair (first e) elem)) seq)) elem) | |||||
| (define (append seq elem) "Appends an element to a sequence, by extendeing the list\nwith (pair elem nil)." (extend seq (pair elem ()))) | |||||
| (define (append seq elem) :doc "Appends an element to a sequence, by extendeing the list\nwith (pair elem nil)." (extend seq (pair elem ()))) | |||||
| (define (length seq) "Returns the length of the given sequence." (if (null? seq) 0 (+ 1 (length (rest seq))))) | |||||
| (define (length seq) :doc "Returns the length of the given sequence." (if (null? seq) 0 (+ 1 (length (rest seq))))) | |||||
| (define (member? elem seq) (when (pair? seq) (if (= elem (first seq)) t (member? elem (rest seq))))) | (define (member? elem seq) (when (pair? seq) (if (= elem (first seq)) t (member? elem (rest seq))))) | ||||
| @@ -44,21 +68,21 @@ | |||||
| (define (list-without-index seq index) (cond ((or (< index 0) (null? seq)) (error "list-remove-index!: index out of range")) ((= 0 index) (rest seq)) (else (pair (first seq) (list-without-index (rest seq) (- index 1)))))) | (define (list-without-index seq index) (cond ((or (< index 0) (null? seq)) (error "list-remove-index!: index out of range")) ((= 0 index) (rest seq)) (else (pair (first seq) (list-without-index (rest seq) (- index 1)))))) | ||||
| (define (increment val) "Adds one to the argument." (+ val 1)) | |||||
| (define (increment val) :doc "Adds one to the argument." (+ val 1)) | |||||
| (define (decrement val) "Subtracts one from the argument." (- val 1)) | |||||
| (define (decrement val) :doc "Subtracts one from the argument." (- val 1)) | |||||
| (define (range :keys from :defaults-to 0 to) "Returns a sequence of numbers starting with the number defined by the\nkey =from= and ends with the number defined in =to=." (when (< from to) (pair from (range :from (+ 1 from) :to to)))) | |||||
| (define (range (:from 0) :to) :doc "Returns a sequence of numbers starting with the number defined\nby the key =from= and ends with the number defined in =to=." (when (< from to) (pair from (range :from (+ 1 from) :to to)))) | |||||
| (define (range-while :keys from :defaults-to 0 to) "Returns a sequence of numbers starting with the number defined\nby the key 'from' and ends with the number defined in 'to'." (define result (list (copy from))) (define head result) (mutate from (increment from)) (while (< from to) (begin (mutate head (pair (first head) (pair (copy from) nil))) (define head (rest head)) (mutate from (increment from)))) result) | |||||
| (define (range-while (:from 0) to) :doc "Returns a sequence of numbers starting with the number defined\nby the key 'from' and ends with the number defined in 'to'." (define result (list (copy from))) (define head result) (mutate from (increment from)) (while (< from to) (begin (mutate head (pair (first head) (pair (copy from) nil))) (define head (rest head)) (mutate from (increment from)))) result) | |||||
| (define (map fun seq) "Takes a function and a sequence as arguments and returns a new\nsequence which contains the results of using the first sequences\nelemens as argument to that function." (if (null? seq) seq (pair (fun (first seq)) (map fun (rest seq))))) | |||||
| (define (map fun seq) :doc "Takes a function and a sequence as arguments and returns a new\nsequence which contains the results of using the first sequences\nelemens as argument to that function." (if (null? seq) seq (pair (fun (first seq)) (map fun (rest seq))))) | |||||
| (define (reduce fun seq) "Takes a function and a sequence as arguments and applies the\nfunction to the argument sequence. This only works correctly if the\ngiven function accepts a variable amount of parameters. If your\nfunciton is limited to two arguments, use [[=reduce-binary=]]\ninstead." (apply fun seq)) | |||||
| (define (reduce fun seq) :doc "Takes a function and a sequence as arguments and applies the\nfunction to the argument sequence. This only works correctly if the\ngiven function accepts a variable amount of parameters. If your\nfunciton is limited to two arguments, use [[=reduce-binary=]]\ninstead." (apply fun seq)) | |||||
| (define (reduce-binary fun seq) "Takes a function and a sequence as arguments and applies the\nfunction to the argument sequence. reduce-binary applies the arguments\n*pair-wise* which means it works with binary functions as compared to\n[[=reduce=]]." (if (null? (rest seq)) (first seq) (fun (first seq) (reduce-binary fun (rest seq))))) | |||||
| (define (reduce-binary fun seq) :doc "Takes a function and a sequence as arguments and applies the\nfunction to the argument sequence. reduce-binary applies the arguments\n*pair-wise* which means it works with binary functions as compared to\n[[=reduce=]]." (if (null? (rest seq)) (first seq) (fun (first seq) (reduce-binary fun (rest seq))))) | |||||
| (define (filter fun seq) "Takes a function and a sequence as arguments and applies the\nfunction to every value in the sequence. If the result of that\nfunciton application returns a truthy value, the original value is\nadded to a list, which in the end is returned." (when seq (if (fun (first seq)) (pair (first seq) (filter fun (rest seq))) (filter fun (rest seq))))) | |||||
| (define (filter fun seq) :doc "Takes a function and a sequence as arguments and applies the\nfunction to every value in the sequence. If the result of that\nfunciton application returns a truthy value, the original value is\nadded to a list, which in the end is returned." (when seq (if (fun (first seq)) (pair (first seq) (filter fun (rest seq))) (filter fun (rest seq))))) | |||||
| (define (zip l1 l2) (unless (and (null? l1) (null? l2)) (pair (list (first l1) (first l2)) (zip (rest l1) (rest l2))))) | (define (zip l1 l2) (unless (and (null? l1) (null? l2)) (pair (list (first l1) (first l2)) (zip (rest l1) (rest l2))))) | ||||
| @@ -66,5 +90,3 @@ | |||||
| (define (enumerate seq) (define (enumerate-inner seq next-num) (when seq (pair (list (first seq) next-num) (enumerate-inner (rest seq) (+ 1 next-num))))) (enumerate-inner seq 0)) | (define (enumerate seq) (define (enumerate-inner seq next-num) (when seq (pair (list (first seq) next-num) (enumerate-inner (rest seq) (+ 1 next-num))))) (enumerate-inner seq 0)) | ||||
| (define (printf :keys sep :defaults-to " " end :defaults-to "\n" :rest args) "A wrapper for the built-in function [[=print=]] that accepts a\nvariable number of arguments and also provides keywords for specifying\nthe printed separators (=sep=) between the arguments and what should\nbe printed after the last argument (=end=)." (define (printf-inner args) (if args (begin (print (first args)) (when (rest args) (print sep)) (printf-inner (rest args))) (print end))) (printf-inner args) ()) | |||||
| @@ -1,14 +1,14 @@ | |||||
| (import "oo.slime") | |||||
| (define-class (vector3 x y z) (define (set-x new-x) (mutate x new-x)) (define (set-y new-y) (mutate y new-y)) (define (set-z new-z) (mutate z new-z)) (define (length) (** (+ (* x x) (* y y) (* z z)) 0.500000)) (define (scale fac) (mutate x (* fac x)) (mutate y (* fac y)) (mutate z (* fac z)) fac) (define (add other) (make-vector3 (+ (-> other x) x) (+ (-> other y) y) (+ (-> other z) z))) (define (subtract other) (make-vector3 (- (-> other x) x) (- (-> other y) y) (- (-> other z) z))) (define (equal? other) (and (= (-> other x) x) (= (-> other y) y) (= (-> other z) z))) (define (scalar-product other) (+ (* (-> other x) x) (* (-> other y) y) (* (-> other z) z))) (define (cross-product other) (make-vector3 (- (* (-> other z) y) (* (-> other y) z)) (- (* (-> other x) z) (* (-> other z) x)) (- (* (-> other y) x) (* (-> other x) y)))) (define (print) (printf :sep " " "[vector3] (" x y z ")"))) | |||||
| (define v1 (make-vector3 1 2 3)) | |||||
| (define v2 (make-vector3 3 2 1)) | |||||
| (assert (= (type v1) (type v2) :vector3)) | |||||
| (assert (= (v1 'scalar-product v2) 10)) | |||||
| (assert (-> (-> v1 cross-product v2) equal? (make-vector3 -4 8 -4))) | |||||
| (import "oo.slime") | |||||
| (define-class (vector3 x y z) (define (set-x new-x) (mutate x new-x)) (define (set-y new-y) (mutate y new-y)) (define (set-z new-z) (mutate z new-z)) (define (length) (** (+ (* x x) (* y y) (* z z)) 0.500000)) (define (scale fac) (mutate x (* fac x)) (mutate y (* fac y)) (mutate z (* fac z)) fac) (define (add other) (make-vector3 (+ (-> other x) x) (+ (-> other y) y) (+ (-> other z) z))) (define (subtract other) (make-vector3 (- (-> other x) x) (- (-> other y) y) (- (-> other z) z))) (define (equal? other) (and (= (-> other x) x) (= (-> other y) y) (= (-> other z) z))) (define (scalar-product other) (+ (* (-> other x) x) (* (-> other y) y) (* (-> other z) z))) (define (cross-product other) (make-vector3 (- (* (-> other z) y) (* (-> other y) z)) (- (* (-> other x) z) (* (-> other z) x)) (- (* (-> other y) x) (* (-> other x) y)))) (define (print) (printf :sep " " "[vector3] (" x y z ")"))) | |||||
| (define v1 (make-vector3 1 2 3)) | |||||
| (define v2 (make-vector3 3 2 1)) | |||||
| (assert (= (type v1) (type v2) :vector3)) | |||||
| (assert (= (v1 'scalar-product v2) 10)) | |||||
| (assert (-> (-> v1 cross-product v2) equal? (make-vector3 -4 8 -4))) | |||||
| @@ -1,54 +1,54 @@ | |||||
| (define (make-counter) (let ((var 0)) (lambda () (set! var (+ 1 var))))) | |||||
| (define counter1 (make-counter)) | |||||
| (assert (= (counter1) 1)) | |||||
| (define counter2 (make-counter)) | |||||
| (assert (= (counter2) 1)) | |||||
| (assert (= (counter2) 2)) | |||||
| (assert (= (counter1) 2)) | |||||
| (assert (= (counter1) 3)) | |||||
| (assert (= (counter2) 3)) | |||||
| (assert (= (counter2) 4)) | |||||
| (assert (= (counter2) 5)) | |||||
| (assert (= (counter1) 4)) | |||||
| (assert (= (counter1) 5)) | |||||
| (define (g) (define x 0) (lambda () (define temp x) (mutate x (+ x 1)) temp)) | |||||
| (define (make-key-counter) ((lambda (:keys var) (lambda () (mutate var (+ 1 var)) var)) :var 0)) | |||||
| (define key-counter1 (make-key-counter)) | |||||
| (assert (= (key-counter1) 1)) | |||||
| (define key-counter2 (make-key-counter)) | |||||
| (assert (= (key-counter2) 1)) | |||||
| (assert (= (key-counter2) 2)) | |||||
| (assert (= (key-counter1) 2)) | |||||
| (assert (= (key-counter1) 3)) | |||||
| (assert (= (key-counter2) 3)) | |||||
| (assert (= (key-counter2) 4)) | |||||
| (assert (= (key-counter2) 5)) | |||||
| (assert (= (key-counter1) 4)) | |||||
| (assert (= (key-counter1) 5)) | |||||
| (define (make-counter) (let ((var 0)) (lambda () (set! var (+ 1 var))))) | |||||
| (define counter1 (make-counter)) | |||||
| (assert (= (counter1) 1)) | |||||
| (define counter2 (make-counter)) | |||||
| (assert (= (counter2) 1)) | |||||
| (assert (= (counter2) 2)) | |||||
| (assert (= (counter1) 2)) | |||||
| (assert (= (counter1) 3)) | |||||
| (assert (= (counter2) 3)) | |||||
| (assert (= (counter2) 4)) | |||||
| (assert (= (counter2) 5)) | |||||
| (assert (= (counter1) 4)) | |||||
| (assert (= (counter1) 5)) | |||||
| (define (g) (define x 0) (lambda () (define temp x) (mutate x (+ x 1)) temp)) | |||||
| (define (make-key-counter) ((lambda (:keys var) (lambda () (mutate var (+ 1 var)) var)) :var 0)) | |||||
| (define key-counter1 (make-key-counter)) | |||||
| (assert (= (key-counter1) 1)) | |||||
| (define key-counter2 (make-key-counter)) | |||||
| (assert (= (key-counter2) 1)) | |||||
| (assert (= (key-counter2) 2)) | |||||
| (assert (= (key-counter1) 2)) | |||||
| (assert (= (key-counter1) 3)) | |||||
| (assert (= (key-counter2) 3)) | |||||
| (assert (= (key-counter2) 4)) | |||||
| (assert (= (key-counter2) 5)) | |||||
| (assert (= (key-counter1) 4)) | |||||
| (assert (= (key-counter1) 5)) | |||||
| @@ -10,10 +10,6 @@ echo "" | |||||
| pushd ./bin > /dev/null | pushd ./bin > /dev/null | ||||
| time ./slime --run-tests | time ./slime --run-tests | ||||
| echo "" | |||||
| echo "generating docs" | |||||
| time ./slime generate-docs.slime | |||||
| popd > /dev/null | popd > /dev/null | ||||
| popd > /dev/null | popd > /dev/null | ||||
| unset TIMEFORMAT | unset TIMEFORMAT | ||||
| @@ -84,6 +84,8 @@ inline proc get_current_environment() -> Environment* { | |||||
| } | } | ||||
| proc lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* { | proc lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* { | ||||
| assert_type(node, Lisp_Object_Type::Symbol); | |||||
| Lisp_Object* result = try_lookup_symbol(node, env); | Lisp_Object* result = try_lookup_symbol(node, env); | ||||
| if (result) | if (result) | ||||
| @@ -110,8 +112,8 @@ proc print_environment_indent(Environment* env, int indent) -> void { | |||||
| } | } | ||||
| for (int i = 0; i < env->next_index; ++i) { | for (int i = 0; i < env->next_index; ++i) { | ||||
| print_indent(indent); | print_indent(indent); | ||||
| printf("-> %s :: ", env->keys[i]); | |||||
| print(env->values[i]); | print(env->values[i]); | ||||
| printf(" %s", env->keys[i]); | |||||
| printf(" (%lld)", (long long)env->values[i]); | printf(" (%lld)", (long long)env->values[i]); | ||||
| puts(""); | puts(""); | ||||
| } | } | ||||
| @@ -9,10 +9,10 @@ proc delete_error() -> void { | |||||
| proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, String* message) -> void { | proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, String* message) -> void { | ||||
| if (Globals::log_level > Log_Level::None) { | |||||
| printf("Error created in:\n %s:%d\n", c_file_name, c_file_line); | |||||
| printf(" -> %s\n", Memory::get_c_str(message)); | |||||
| } | |||||
| if (Globals::log_level > Log_Level::None) { | |||||
| printf("Error created in:\n %s:%d\n", c_file_name, c_file_line); | |||||
| printf(" -> %s\n", Memory::get_c_str(message)); | |||||
| } | |||||
| delete_error(); | delete_error(); | ||||
| if (Globals::breaking_on_errors) { | if (Globals::breaking_on_errors) { | ||||
| @@ -1,30 +1,68 @@ | |||||
| proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> Lisp_Object* { | |||||
| proc create_extended_environment_for_function_application( | |||||
| Lisp_Object* unevaluated_arguments, | |||||
| Lisp_Object* function) -> Environment* | |||||
| { | |||||
| profile_this; | profile_this; | ||||
| bool is_c_function = Memory::get_type(function) == Lisp_Object_Type::CFunction; | |||||
| Environment* new_env; | Environment* new_env; | ||||
| try new_env = Memory::create_child_environment(function->parent_environment); | |||||
| Lisp_Object* arguments = unevaluated_arguments; | |||||
| Arguments* arg_spec; | |||||
| // NOTE(Felix): Step 1. | |||||
| // - setting the parent environment | |||||
| // - setting the arg_spec | |||||
| // - potentially evaluating the arguments | |||||
| if (is_c_function) { | |||||
| new_env = Memory::create_child_environment(get_root_environment()); | |||||
| arg_spec = &function->value.cFunction->args; | |||||
| // if it is not a special form, evaluate the arguments | |||||
| if (!function->value.cFunction->is_special_form) { | |||||
| try arguments = eval_arguments(arguments); | |||||
| } | |||||
| } else { | |||||
| new_env = Memory::create_child_environment(function->value.function.parent_environment); | |||||
| arg_spec = &function->value.function.args; | |||||
| // if it is a lambda | |||||
| if (function->value.function.type == Function_Type::Lambda) { | |||||
| try arguments = eval_arguments(arguments); | |||||
| } | |||||
| } | |||||
| // NOTE(Felix): Even though we will return the environment at the | |||||
| // end, for defining symbols here for the parameters, it has to be | |||||
| // on the envi stack. | |||||
| push_environment(new_env); | push_environment(new_env); | ||||
| defer { | defer { | ||||
| pop_environment(); | pop_environment(); | ||||
| }; | }; | ||||
| // NOTE(Felix): Step 2. | |||||
| // Reading the argument spec and fill in the environment | |||||
| // for the function call | |||||
| Lisp_Object* sym, *val; // used as temp storage to use `try` | Lisp_Object* sym, *val; // used as temp storage to use `try` | ||||
| String_Array_List read_in_keywords; | String_Array_List read_in_keywords; | ||||
| int obligatory_keywords_count = 0; | int obligatory_keywords_count = 0; | ||||
| int read_obligatory_keywords_count = 0; | int read_obligatory_keywords_count = 0; | ||||
| proc read_positional_args = [&]() -> void { | proc read_positional_args = [&]() -> void { | ||||
| for (int i = 0; i < function->args.positional.symbols.next_index; ++i) { | |||||
| for (int i = 0; i < arg_spec->positional.symbols.next_index; ++i) { | |||||
| if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) { | if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) { | ||||
| create_wrong_number_of_arguments_error(function->args.positional.symbols.next_index, i); | |||||
| create_wrong_number_of_arguments_error(arg_spec->positional.symbols.next_index, i); | |||||
| return; | return; | ||||
| } | } | ||||
| // NOTE(Felix): We have to copy all the arguments, otherwise | |||||
| // we change the program code. | |||||
| try_void sym = function->args.positional.symbols.data[i]; | |||||
| define_symbol( | |||||
| sym, | |||||
| Memory::copy_lisp_object_except_pairs(arguments->value.pair.first)); | |||||
| // NOTE(Felix): We have to copy all the arguments, | |||||
| // otherwise we change the program code. XXX(Felix): T C | |||||
| // functions we pass by reference... | |||||
| try_void sym = arg_spec->positional.symbols.data[i]; | |||||
| if (is_c_function) { | |||||
| define_symbol(sym, arguments->value.pair.first); | |||||
| } else { | |||||
| define_symbol( | |||||
| sym, | |||||
| Memory::copy_lisp_object_except_pairs(arguments->value.pair.first)); | |||||
| } | |||||
| arguments = arguments->value.pair.rest; | arguments = arguments->value.pair.rest; | ||||
| } | } | ||||
| @@ -41,8 +79,8 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| return; | return; | ||||
| // find out how many keyword args we /have/ to read | // find out how many keyword args we /have/ to read | ||||
| for (int i = 0; i < function->args.keyword.values.next_index; ++i) { | |||||
| if (function->args.keyword.values.data[i] == nullptr) | |||||
| for (int i = 0; i < arg_spec->keyword.values.next_index; ++i) { | |||||
| if (arg_spec->keyword.values.data[i] == nullptr) | |||||
| ++obligatory_keywords_count; | ++obligatory_keywords_count; | ||||
| else | else | ||||
| break; | break; | ||||
| @@ -52,10 +90,10 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| while (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) { | while (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) { | ||||
| // check if this one is even an accepted keyword | // check if this one is even an accepted keyword | ||||
| bool accepted = false; | bool accepted = false; | ||||
| for (int i = 0; i < function->args.keyword.values.next_index; ++i) { | |||||
| for (int i = 0; i < arg_spec->keyword.values.next_index; ++i) { | |||||
| if (string_equal( | if (string_equal( | ||||
| arguments->value.pair.first->value.symbol.identifier, | arguments->value.pair.first->value.symbol.identifier, | ||||
| function->args.keyword.keywords.data[i]->value.symbol.identifier)) | |||||
| arg_spec->keyword.keywords.data[i]->value.symbol.identifier)) | |||||
| { | { | ||||
| accepted = true; | accepted = true; | ||||
| break; | break; | ||||
| @@ -108,9 +146,13 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| // if not set it and then add it to the array list | // if not set it and then add it to the array list | ||||
| try_void sym = Memory::get_or_create_lisp_object_symbol(arguments->value.pair.first->value.symbol.identifier); | try_void sym = Memory::get_or_create_lisp_object_symbol(arguments->value.pair.first->value.symbol.identifier); | ||||
| // NOTE(Felix): It seems we do not need to evaluate the argument here... | // NOTE(Felix): It seems we do not need to evaluate the argument here... | ||||
| try_void define_symbol( | |||||
| sym, | |||||
| Memory::copy_lisp_object_except_pairs(arguments->value.pair.rest->value.pair.first)); | |||||
| if (is_c_function) { | |||||
| try_void define_symbol(sym, arguments->value.pair.rest->value.pair.first); | |||||
| } else { | |||||
| try_void define_symbol( | |||||
| sym, | |||||
| Memory::copy_lisp_object_except_pairs(arguments->value.pair.rest->value.pair.first)); | |||||
| } | |||||
| append_to_array_list(&read_in_keywords, arguments->value.pair.first->value.symbol.identifier); | append_to_array_list(&read_in_keywords, arguments->value.pair.first->value.symbol.identifier); | ||||
| ++read_obligatory_keywords_count; | ++read_obligatory_keywords_count; | ||||
| @@ -126,8 +168,8 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| proc check_keyword_args = [&]() -> void { | proc check_keyword_args = [&]() -> void { | ||||
| // check if all necessary keywords have been read in | // check if all necessary keywords have been read in | ||||
| for (int i = 0; i < function->args.keyword.values.next_index; ++i) { | |||||
| String* defined_keyword = function->args.keyword.keywords.data[i]->value.symbol.identifier; | |||||
| for (int i = 0; i < arg_spec->keyword.values.next_index; ++i) { | |||||
| String* defined_keyword = arg_spec->keyword.keywords.data[i]->value.symbol.identifier; | |||||
| bool was_set = false; | bool was_set = false; | ||||
| for (int j = 0; j < read_in_keywords.next_index; ++j) { | for (int j = 0; j < read_in_keywords.next_index; ++j) { | ||||
| // TODO(Felix): Later compare the keywords, not their strings!! | // TODO(Felix): Later compare the keywords, not their strings!! | ||||
| @@ -139,7 +181,7 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (function->args.keyword.values.data[i] == nullptr) { | |||||
| if (arg_spec->keyword.values.data[i] == nullptr) { | |||||
| // if this one does not have a default value | // if this one does not have a default value | ||||
| if (!was_set) { | if (!was_set) { | ||||
| create_generic_error( | create_generic_error( | ||||
| @@ -153,7 +195,11 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| // to use it or if the user supplied his own | // to use it or if the user supplied his own | ||||
| if (!was_set) { | if (!was_set) { | ||||
| try_void sym = Memory::get_or_create_lisp_object_symbol(defined_keyword); | try_void sym = Memory::get_or_create_lisp_object_symbol(defined_keyword); | ||||
| try_void val = Memory::copy_lisp_object_except_pairs(function->args.keyword.values.data[i]); | |||||
| if (is_c_function) { | |||||
| try_void val = arg_spec->keyword.values.data[i]; | |||||
| } else { | |||||
| try_void val = Memory::copy_lisp_object_except_pairs(arg_spec->keyword.values.data[i]); | |||||
| } | |||||
| define_symbol(sym, val); | define_symbol(sym, val); | ||||
| } | } | ||||
| } | } | ||||
| @@ -162,13 +208,13 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| proc read_rest_arg = [&]() -> void { | proc read_rest_arg = [&]() -> void { | ||||
| if (arguments == Memory::nil) { | if (arguments == Memory::nil) { | ||||
| if (function->args.rest) { | |||||
| define_symbol(function->args.rest, Memory::nil); | |||||
| if (arg_spec->rest) { | |||||
| define_symbol(arg_spec->rest, Memory::nil); | |||||
| } | } | ||||
| } else { | } else { | ||||
| if (function->args.rest) { | |||||
| if (arg_spec->rest) { | |||||
| define_symbol( | define_symbol( | ||||
| function->args.rest, | |||||
| arg_spec->rest, | |||||
| // NOTE(Felix): arguments will be a list, and I THINK | // NOTE(Felix): arguments will be a list, and I THINK | ||||
| // we do not need to copy it... | // we do not need to copy it... | ||||
| arguments); | arguments); | ||||
| @@ -187,157 +233,112 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> | |||||
| try check_keyword_args(); | try check_keyword_args(); | ||||
| try read_rest_arg(); | try read_rest_arg(); | ||||
| return new_env; | |||||
| } | |||||
| proc apply_arguments_to_function(Lisp_Object* arguments, Lisp_Object* function) -> Lisp_Object* { | |||||
| profile_this; | |||||
| Environment* new_env; | |||||
| try new_env = create_extended_environment_for_function_application(arguments, function); | |||||
| push_environment(new_env); | |||||
| defer { | |||||
| pop_environment(); | |||||
| }; | |||||
| Lisp_Object* result; | Lisp_Object* result; | ||||
| try result = eval_expr(function->body); | |||||
| // if c function: | |||||
| if (Memory::get_type(function) == Lisp_Object_Type::CFunction) | |||||
| try result = function->value.cFunction->body(); | |||||
| else // if lisp function | |||||
| try result = eval_expr(function->value.function.body); | |||||
| return result; | return result; | ||||
| } | } | ||||
| /** | /** | ||||
| This parses the argument specification of funcitons into their | This parses the argument specification of funcitons into their | ||||
| Function struct. It does this by allocating new | Function struct. It does this by allocating new | ||||
| positional_arguments, keyword_arguments and rest_argument and | positional_arguments, keyword_arguments and rest_argument and | ||||
| filling it in | filling it in | ||||
| */ | */ | ||||
| proc parse_argument_list(Lisp_Object* arguments, Function* function) -> void { | |||||
| proc create_arguments_from_lambda_list_and_inject(Lisp_Object* arguments, Lisp_Object* function) -> void { | |||||
| Arguments* result; | |||||
| if (Memory::get_type(function) == Lisp_Object_Type::CFunction) { | |||||
| result = &function->value.cFunction->args; | |||||
| } else { | |||||
| result = &function->value.function.args; | |||||
| } | |||||
| // first init the fields | // first init the fields | ||||
| function->args.positional = create_positional_argument_list(16); | |||||
| function->args.keyword = create_keyword_argument_list(16); | |||||
| function->args.rest = nullptr; | |||||
| result->positional = create_positional_argument_list(16); | |||||
| result->keyword = create_keyword_argument_list(16); | |||||
| result->rest = nullptr; | |||||
| // okay let's try to read some positional arguments | // okay let's try to read some positional arguments | ||||
| while (Memory::get_type(arguments) == Lisp_Object_Type::Pair) { | while (Memory::get_type(arguments) == Lisp_Object_Type::Pair) { | ||||
| if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) { | |||||
| if (string_equal(arguments->value.pair.first->value.symbol.identifier, "keys") || | |||||
| string_equal(arguments->value.pair.first->value.symbol.identifier, "rest")) | |||||
| // if we encounter a keyword or a list (for keywords with | |||||
| // defualt args), the positionals are done | |||||
| if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword || | |||||
| Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Pair) { | |||||
| break; | break; | ||||
| else { | |||||
| create_parsing_error("A non recognized marker was found " | |||||
| "in the lambda list: ':%s'", | |||||
| &arguments->value.pair.first->value.symbol.identifier->data); | |||||
| return; | |||||
| } | |||||
| } | } | ||||
| // if we encounter something that is neither a symbol nor a | |||||
| // keyword arg, it's an error | |||||
| if (Memory::get_type(arguments->value.pair.first) != Lisp_Object_Type::Symbol) { | if (Memory::get_type(arguments->value.pair.first) != Lisp_Object_Type::Symbol) { | ||||
| create_parsing_error("Only symbols and keywords can be " | |||||
| "parsed here, but found '%s'", | |||||
| create_parsing_error("Only symbols and keywords " | |||||
| "(with or without default args) " | |||||
| "can be parsed here, but found '%s'", | |||||
| Lisp_Object_Type_to_string(Memory::get_type(arguments->value.pair.first))); | Lisp_Object_Type_to_string(Memory::get_type(arguments->value.pair.first))); | ||||
| return; | return; | ||||
| } | } | ||||
| // okay wow we found an actual symbol | |||||
| // okay we found an actual symbol | |||||
| append_to_positional_argument_list( | append_to_positional_argument_list( | ||||
| &function->args.positional, | |||||
| &result->positional, | |||||
| arguments->value.pair.first); | arguments->value.pair.first); | ||||
| arguments = arguments->value.pair.rest; | arguments = arguments->value.pair.rest; | ||||
| } | } | ||||
| // okay we are done with positional arguments, lets check for | |||||
| // keywords, | |||||
| if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) { | |||||
| if (arguments != Memory::nil) | |||||
| create_parsing_error("The lambda list must be nil terminated."); | |||||
| return; | |||||
| } | |||||
| if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword && | |||||
| string_equal(arguments->value.pair.first->value.symbol.identifier, "keys")) | |||||
| { | |||||
| arguments = arguments->value.pair.rest; | |||||
| if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) { | |||||
| create_parsing_error("Actual keys have to follow the :keys indicator."); | |||||
| } | |||||
| // if (arguments->value.pair.first->type != Lisp_Object_Type::Symbol) { | |||||
| // create_parsing_error( | |||||
| // "Only symbols can be parsed here, but found '%s'.", | |||||
| // Lisp_Object_Type_to_string(arguments->value.pair.first->type)); | |||||
| // return; | |||||
| // } | |||||
| while (Memory::get_type(arguments) == Lisp_Object_Type::Pair) { | |||||
| if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) { | |||||
| if (string_equal(arguments->value.pair.first->value.symbol.identifier, "rest")) | |||||
| break; | |||||
| else { | |||||
| create_parsing_error( | |||||
| "Only the :rest keyword can be parsed here, but got ':%s'.", | |||||
| &arguments->value.pair.first->value.symbol.identifier->data); | |||||
| return; | |||||
| } | |||||
| } | |||||
| if (Memory::get_type(arguments->value.pair.first) != Lisp_Object_Type::Symbol) { | |||||
| create_parsing_error( | |||||
| "Only symbols can be parsed here, but found '%s'.", | |||||
| Lisp_Object_Type_to_string(Memory::get_type(arguments->value.pair.first))); | |||||
| return; | |||||
| // if we reach here, we are on a keyword or a pair wher a keyword | |||||
| // should be in first | |||||
| while (Memory::get_type(arguments) == Lisp_Object_Type::Pair) { | |||||
| if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) { | |||||
| // if we are on a actual keyword (with no default arg) | |||||
| auto keyword = arguments->value.pair.first; | |||||
| append_to_keyword_argument_list(&result->keyword, keyword, nullptr); | |||||
| } else if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Pair) { | |||||
| // if we are on a keyword with a default value | |||||
| auto keyword = arguments->value.pair.first->value.pair.first; | |||||
| if (Memory::get_type(keyword) != Lisp_Object_Type::Keyword) { | |||||
| create_parsing_error("Default args must be keywords"); | |||||
| } | } | ||||
| // we found a symbol (arguments->value.pair->first) for | |||||
| // the keyword args! Let's check if the next arguement is | |||||
| // :defaults-to | |||||
| Lisp_Object* next = arguments->value.pair.rest; | |||||
| if (Memory::get_type(next) == Lisp_Object_Type::Pair && | |||||
| Memory::get_type(next->value.pair.first) == Lisp_Object_Type::Keyword && | |||||
| string_equal(next->value.pair.first->value.symbol.identifier, | |||||
| "defaults-to")) | |||||
| if (Memory::get_type(arguments->value.pair.first->value.pair.rest) | |||||
| != Lisp_Object_Type::Pair) | |||||
| { | { | ||||
| // check if there is a next argument too, otherwise it | |||||
| // would be an error | |||||
| next = next->value.pair.rest; | |||||
| if (Memory::get_type(next) == Lisp_Object_Type::Pair) { | |||||
| Lisp_Object* ret; | |||||
| push_environment(function->parent_environment); | |||||
| defer { | |||||
| pop_environment(); | |||||
| }; | |||||
| try_void ret = eval_expr(next->value.pair.first); | |||||
| append_to_keyword_argument_list(&function->args.keyword, | |||||
| arguments->value.pair.first, | |||||
| ret); | |||||
| arguments = next->value.pair.rest; | |||||
| } else { | |||||
| create_parsing_error("Expecting a value after 'defaults-to'"); | |||||
| return; | |||||
| } | |||||
| } else { | |||||
| // No :defaults-to, so just add it to the list | |||||
| append_to_keyword_argument_list(&function->args.keyword, | |||||
| arguments->value.pair.first, | |||||
| nullptr); | |||||
| arguments = next; | |||||
| create_parsing_error("Default args must be a list of 2."); | |||||
| } | } | ||||
| auto value = arguments->value.pair.first->value.pair.rest->value.pair.first; | |||||
| if (arguments->value.pair.first->value.pair.rest->value.pair.rest != Memory::nil) { | |||||
| create_parsing_error("Default args must be a list of 2."); | |||||
| } | |||||
| append_to_keyword_argument_list(&result->keyword, keyword, value); | |||||
| } | } | ||||
| arguments = arguments->value.pair.rest; | |||||
| } | } | ||||
| // Now we are also done with keyword arguments, lets check for | // Now we are also done with keyword arguments, lets check for | ||||
| // if there is a rest argument | // if there is a rest argument | ||||
| if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) { | if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) { | ||||
| if (arguments != Memory::nil) | |||||
| create_parsing_error("The lambda list must be nil terminated."); | |||||
| return; | |||||
| } | |||||
| if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword && | |||||
| string_equal(arguments->value.pair.first->value.symbol.identifier, "rest")) | |||||
| { | |||||
| arguments = arguments->value.pair.rest; | |||||
| if (// arguments->type != Lisp_Object_Type::Pair || | |||||
| Memory::get_type(arguments->value.pair.first) != Lisp_Object_Type::Symbol) | |||||
| { | |||||
| create_parsing_error("After the 'rest' marker there must follow a symbol."); | |||||
| if (arguments == Memory::nil) | |||||
| return; | return; | ||||
| } | |||||
| function->args.rest = arguments->value.pair.first; | |||||
| if (arguments->value.pair.rest != Memory::nil) { | |||||
| create_parsing_error("The lambda list must end after the rest symbol"); | |||||
| } | |||||
| } else { | |||||
| printf("this should not happen?"); | |||||
| create_generic_error("What is happening?"); | |||||
| if (Memory::get_type(arguments) == Lisp_Object_Type::Symbol) | |||||
| result->rest = arguments; | |||||
| else | |||||
| create_parsing_error("The rest argument must be a symbol."); | |||||
| } | } | ||||
| } | } | ||||
| @@ -361,11 +362,11 @@ proc list_length(Lisp_Object* node) -> int { | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| proc eval_arguments(Lisp_Object* arguments, int *out_arguments_length) -> Lisp_Object* { | |||||
| proc eval_arguments(Lisp_Object* arguments) -> Lisp_Object* { | |||||
| profile_this; | profile_this; | ||||
| int my_out_arguments_length = 0; | |||||
| // int my_out_arguments_length = 0; | |||||
| if (arguments == Memory::nil) { | if (arguments == Memory::nil) { | ||||
| *(out_arguments_length) = 0; | |||||
| // *(out_arguments_length) = 0; | |||||
| return arguments; | return arguments; | ||||
| } | } | ||||
| @@ -390,9 +391,9 @@ proc eval_arguments(Lisp_Object* arguments, int *out_arguments_length) -> Lisp_O | |||||
| create_parsing_error("Attempting to evaluate ill formed argument list."); | create_parsing_error("Attempting to evaluate ill formed argument list."); | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| ++my_out_arguments_length; | |||||
| // ++my_out_arguments_length; | |||||
| } | } | ||||
| *(out_arguments_length) = my_out_arguments_length; | |||||
| // *(out_arguments_length) = my_out_arguments_length; | |||||
| return evaluated_arguments; | return evaluated_arguments; | ||||
| } | } | ||||
| @@ -435,12 +436,10 @@ proc eval_expr(Lisp_Object* node) -> Lisp_Object* { | |||||
| } | } | ||||
| Lisp_Object* arguments = node->value.pair.rest; | Lisp_Object* arguments = node->value.pair.rest; | ||||
| int arguments_length; | |||||
| // check for c function | // check for c function | ||||
| if (Memory::get_type(lispOperator) == Lisp_Object_Type::CFunction) { | if (Memory::get_type(lispOperator) == Lisp_Object_Type::CFunction) { | ||||
| Lisp_Object* result; | Lisp_Object* result; | ||||
| try result = lispOperator->value.cFunction->function(arguments); | |||||
| try result = apply_arguments_to_function(arguments, lispOperator); | |||||
| return result; | return result; | ||||
| } | } | ||||
| @@ -449,12 +448,9 @@ proc eval_expr(Lisp_Object* node) -> Lisp_Object* { | |||||
| // only for lambdas we evaluate the arguments before | // only for lambdas we evaluate the arguments before | ||||
| // apllying, for the other types, special-lambda and macro | // apllying, for the other types, special-lambda and macro | ||||
| // we do not need. | // we do not need. | ||||
| if (lispOperator->value.function.type == Function_Type::Lambda) { | |||||
| try arguments = eval_arguments(arguments, &arguments_length); | |||||
| } | |||||
| Lisp_Object* result; | Lisp_Object* result; | ||||
| try result = apply_arguments_to_function(arguments, &lispOperator->value.function); | |||||
| try result = apply_arguments_to_function(arguments, lispOperator); | |||||
| // NOTE(Felix): The parser does not understnad (import ..) | // NOTE(Felix): The parser does not understnad (import ..) | ||||
| // so it cannot expand imported macros at read time | // so it cannot expand imported macros at read time | ||||
| @@ -464,7 +460,9 @@ proc eval_expr(Lisp_Object* node) -> Lisp_Object* { | |||||
| // and bake them in, so they do not have to be expanded | // and bake them in, so they do not have to be expanded | ||||
| // later again. We will call this "lazy macro expansion" | // later again. We will call this "lazy macro expansion" | ||||
| if (lispOperator->value.function.type == Function_Type::Macro) { | if (lispOperator->value.function.type == Function_Type::Macro) { | ||||
| // bake in the macro expansion: | |||||
| *node = *result; | *node = *result; | ||||
| // eval again because macro | |||||
| try result = eval_expr(result); | try result = eval_expr(result); | ||||
| } | } | ||||
| @@ -4,12 +4,12 @@ proc built_in_import(String*) -> Lisp_Object*; | |||||
| proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, String* message) -> void; | proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, String* message) -> void; | ||||
| proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, const char* format, ...) -> void; | proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, const char* format, ...) -> void; | ||||
| proc create_error(Lisp_Object* type, const char* message, const char* c_file_name, int c_file_line) -> void; | proc create_error(Lisp_Object* type, const char* message, const char* c_file_name, int c_file_line) -> void; | ||||
| proc eval_arguments(Lisp_Object*, int*) -> Lisp_Object*; | |||||
| proc eval_arguments(Lisp_Object*) -> Lisp_Object*; | |||||
| proc eval_expr(Lisp_Object*) -> Lisp_Object*; | proc eval_expr(Lisp_Object*) -> Lisp_Object*; | ||||
| proc is_truthy (Lisp_Object*) -> bool; | proc is_truthy (Lisp_Object*) -> bool; | ||||
| proc list_length(Lisp_Object*) -> int; | proc list_length(Lisp_Object*) -> int; | ||||
| proc load_built_ins_into_environment() -> void; | proc load_built_ins_into_environment() -> void; | ||||
| proc parse_argument_list(Lisp_Object*, Function*) -> void; | |||||
| proc create_arguments_from_lambda_list_and_inject(Lisp_Object* formal_arguments, Lisp_Object* function) -> void; | |||||
| proc print_environment(Environment*) -> void; | proc print_environment(Environment*) -> void; | ||||
| @@ -36,6 +36,8 @@ namespace Parser { | |||||
| extern String* parser_file; | extern String* parser_file; | ||||
| extern int parser_line; | extern int parser_line; | ||||
| extern int parser_col; | extern int parser_col; | ||||
| proc parse_single_expression(char* text) -> Lisp_Object*; | |||||
| } | } | ||||
| namespace Globals { | namespace Globals { | ||||
| @@ -1,93 +1,94 @@ | |||||
| namespace GC { | |||||
| proc maybe_mark(Environment* env) -> void; | |||||
| int current_mark; | |||||
| Lisp_Object_Array_List marked_objects; | |||||
| String_Array_List marked_strings; | |||||
| Environment_Array_List marked_environments; | |||||
| Environment_Array_List protected_environments; | |||||
| proc marked(Lisp_Object* node) -> bool { | |||||
| return false; | |||||
| } | |||||
| proc marked(Environment* env) -> bool { | |||||
| return false; | |||||
| } | |||||
| proc maybe_mark(Lisp_Object* node) -> void { | |||||
| if (marked(node)) | |||||
| return; | |||||
| // mark object itself | |||||
| append_to_array_list(&marked_objects, node); | |||||
| // mark docstring | |||||
| if (node->docstring) | |||||
| append_to_array_list(&marked_strings, node->docstring); | |||||
| // mark type specific data | |||||
| switch (Memory::get_type(node)) { | |||||
| case Lisp_Object_Type::Pair: { | |||||
| for_lisp_list (node) { | |||||
| maybe_mark(it); | |||||
| } | |||||
| } break; | |||||
| case Lisp_Object_Type::Vector: { | |||||
| for_lisp_vector (node) { | |||||
| maybe_mark(it); | |||||
| } | |||||
| } break; | |||||
| case Lisp_Object_Type::String: { | |||||
| append_to_array_list(&marked_strings, node->value.string); | |||||
| } break; | |||||
| case Lisp_Object_Type::Function: { | |||||
| // NOTE(Felix): We dont have to mark the symbols, keywords | |||||
| // for parameter names, as symbols and keywords are never | |||||
| // garbage collected | |||||
| maybe_mark(node->value.function.parent_environment); | |||||
| maybe_mark(node->value.function.body); | |||||
| // mark the default arguemnt values: | |||||
| for_array_list (node->value.function.args.keyword.values) { | |||||
| if (it) maybe_mark(it); | |||||
| } | |||||
| } break; | |||||
| } | |||||
| } | |||||
| proc maybe_mark(Environment* env) -> void { | |||||
| if (marked(env)) | |||||
| return; | |||||
| append_to_array_list(&marked_environments, env); | |||||
| for_array_list (env->parents) { | |||||
| maybe_mark(it); | |||||
| } | |||||
| Lisp_Object* it = env->values[0]; | |||||
| for (int i = 0; i < env->next_index; it = env->values[++i]) { | |||||
| maybe_mark(it); | |||||
| } | |||||
| } | |||||
| proc garbage_collect() -> void { | |||||
| profile_this; | |||||
| ++current_mark; | |||||
| for_array_list (protected_environments) maybe_mark(it); | |||||
| for_array_list (Globals::Current_Execution::envi_stack) maybe_mark(it); | |||||
| } | |||||
| proc gc_init_and_go() -> void { | |||||
| current_mark = 0; | |||||
| marked_objects = create_Lisp_Object_array_list(1024); | |||||
| marked_environments = create_Environment_array_list(1024); | |||||
| while (1) { | |||||
| garbage_collect(); | |||||
| } | |||||
| } | |||||
| } | |||||
| namespace GC { | |||||
| proc maybe_mark(Environment* env) -> void; | |||||
| int current_mark; | |||||
| Lisp_Object_Array_List marked_objects; | |||||
| String_Array_List marked_strings; | |||||
| Environment_Array_List marked_environments; | |||||
| Environment_Array_List protected_environments; | |||||
| proc marked(Lisp_Object* node) -> bool { | |||||
| return false; | |||||
| } | |||||
| proc marked(Environment* env) -> bool { | |||||
| return false; | |||||
| } | |||||
| proc maybe_mark(Lisp_Object* node) -> void { | |||||
| if (marked(node)) | |||||
| return; | |||||
| // mark object itself | |||||
| append_to_array_list(&marked_objects, node); | |||||
| // mark docstring | |||||
| if (node->docstring) | |||||
| append_to_array_list(&marked_strings, node->docstring); | |||||
| // mark type specific data | |||||
| switch (Memory::get_type(node)) { | |||||
| case Lisp_Object_Type::Pair: { | |||||
| for_lisp_list (node) { | |||||
| maybe_mark(it); | |||||
| } | |||||
| } break; | |||||
| case Lisp_Object_Type::Vector: { | |||||
| for_lisp_vector (node) { | |||||
| maybe_mark(it); | |||||
| } | |||||
| } break; | |||||
| case Lisp_Object_Type::String: { | |||||
| append_to_array_list(&marked_strings, node->value.string); | |||||
| } break; | |||||
| case Lisp_Object_Type::Function: { | |||||
| // NOTE(Felix): We dont have to mark the symbols, keywords | |||||
| // for parameter names, as symbols and keywords are never | |||||
| // garbage collected | |||||
| maybe_mark(node->value.function.parent_environment); | |||||
| maybe_mark(node->value.function.body); | |||||
| // mark the default arguemnt values: | |||||
| for_array_list (node->value.function.args.keyword.values) { | |||||
| if (it) maybe_mark(it); | |||||
| } | |||||
| } break; | |||||
| default: break; | |||||
| } | |||||
| } | |||||
| proc maybe_mark(Environment* env) -> void { | |||||
| if (marked(env)) | |||||
| return; | |||||
| append_to_array_list(&marked_environments, env); | |||||
| for_array_list (env->parents) { | |||||
| maybe_mark(it); | |||||
| } | |||||
| Lisp_Object* it = env->values[0]; | |||||
| for (int i = 0; i < env->next_index; it = env->values[++i]) { | |||||
| maybe_mark(it); | |||||
| } | |||||
| } | |||||
| proc garbage_collect() -> void { | |||||
| profile_this; | |||||
| ++current_mark; | |||||
| for_array_list (protected_environments) maybe_mark(it); | |||||
| for_array_list (Globals::Current_Execution::envi_stack) maybe_mark(it); | |||||
| } | |||||
| proc gc_init_and_go() -> void { | |||||
| current_mark = 0; | |||||
| marked_objects = create_Lisp_Object_array_list(1024); | |||||
| marked_environments = create_Environment_array_list(1024); | |||||
| while (1) { | |||||
| garbage_collect(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -366,7 +366,7 @@ proc print(Lisp_Object* node, bool print_repr = false, FILE* file = stdout) -> v | |||||
| if (Memory::get_type(head) != Lisp_Object_Type::Nil) { | if (Memory::get_type(head) != Lisp_Object_Type::Nil) { | ||||
| fputs(" . ", file); | fputs(" . ", file); | ||||
| print(head); | |||||
| print(head, print_repr, file); | |||||
| } | } | ||||
| putc(')', file); | putc(')', file); | ||||
| @@ -376,7 +376,7 @@ proc print(Lisp_Object* node, bool print_repr = false, FILE* file = stdout) -> v | |||||
| proc print_single_call(Lisp_Object* obj) -> void { | proc print_single_call(Lisp_Object* obj) -> void { | ||||
| printf(console_cyan); | printf(console_cyan); | ||||
| print(obj); | |||||
| print(obj, true); | |||||
| printf(console_normal); | printf(console_normal); | ||||
| printf("\n at "); | printf("\n at "); | ||||
| if (obj->sourceCodeLocation) { | if (obj->sourceCodeLocation) { | ||||
| @@ -1,10 +1,11 @@ | |||||
| #include "slime.h" | #include "slime.h" | ||||
| int main(int argc, char* argv[]) { | int main(int argc, char* argv[]) { | ||||
| if (argc > 1) { | if (argc > 1) { | ||||
| if (Slime::string_equal(argv[1], "--run-tests")) { | if (Slime::string_equal(argv[1], "--run-tests")) { | ||||
| int res = Slime::run_all_tests(); | int res = Slime::run_all_tests(); | ||||
| Slime::interprete_file("generate-docs.slime"); | |||||
| Slime::interprete_file((char*)"generate-docs.slime"); | |||||
| return res ? 0 : 1; | return res ? 0 : 1; | ||||
| } | } | ||||
| @@ -184,8 +184,8 @@ namespace Memory { | |||||
| try_void Parser::standard_in = create_string("stdin"); | try_void Parser::standard_in = create_string("stdin"); | ||||
| try_void Globals::Current_Execution::envi_stack.data[0] = create_built_ins_environment(); | |||||
| try_void Globals::Current_Execution::envi_stack.next_index = 1; | |||||
| Globals::Current_Execution::envi_stack.next_index = 0; | |||||
| push_environment(create_built_ins_environment()); | |||||
| } | } | ||||
| proc reset() -> void { | proc reset() -> void { | ||||
| @@ -198,8 +198,8 @@ namespace Memory { | |||||
| next_index_in_environment_memory = 0; | next_index_in_environment_memory = 0; | ||||
| next_free_spot_in_string_memory = string_memory; | next_free_spot_in_string_memory = string_memory; | ||||
| try_void Globals::Current_Execution::envi_stack.data[0] = create_built_ins_environment(); | |||||
| try_void Globals::Current_Execution::envi_stack.next_index = 1; | |||||
| Globals::Current_Execution::envi_stack.next_index = 0; | |||||
| push_environment(create_built_ins_environment()); | |||||
| } | } | ||||
| proc create_lisp_object_number(double number) -> Lisp_Object* { | proc create_lisp_object_number(double number) -> Lisp_Object* { | ||||
| @@ -306,13 +306,14 @@ namespace Memory { | |||||
| Memory::create_string(keyword)); | Memory::create_string(keyword)); | ||||
| } | } | ||||
| proc create_lisp_object_cfunction(std::function<Lisp_Object* (Lisp_Object*)> function) -> Lisp_Object* { | |||||
| proc create_lisp_object_cfunction(bool is_special) -> Lisp_Object* { | |||||
| Lisp_Object* node; | Lisp_Object* node; | ||||
| try node = create_lisp_object(); | try node = create_lisp_object(); | ||||
| set_type(node, Lisp_Object_Type::CFunction); | set_type(node, Lisp_Object_Type::CFunction); | ||||
| // node->value.lambdaWrapper = new Lambda_Wrapper(function); | // node->value.lambdaWrapper = new Lambda_Wrapper(function); | ||||
| node->value.cFunction = new(cFunction); | node->value.cFunction = new(cFunction); | ||||
| node->value.cFunction->function = function; | |||||
| node->value.cFunction->args = {}; | |||||
| node->value.cFunction->is_special_form = is_special; | |||||
| return node; | return node; | ||||
| } | } | ||||
| @@ -402,17 +403,17 @@ namespace Memory { | |||||
| load_built_ins_into_environment(); | load_built_ins_into_environment(); | ||||
| // // save the current working directory | |||||
| // char* cwd = get_cwd(); | |||||
| // defer { | |||||
| // change_cwd(cwd); | |||||
| // free(cwd); | |||||
| // }; | |||||
| // // get the direction of the exe | |||||
| // char* exe_path = get_exe_dir(); | |||||
| // change_cwd(exe_path); | |||||
| // free(exe_path); | |||||
| // save the current working directory | |||||
| //char* cwd = get_cwd(); | |||||
| //defer { | |||||
| // change_cwd(cwd); | |||||
| // free(cwd); | |||||
| //}; | |||||
| //// get the direction of the exe | |||||
| //char* exe_path = get_exe_dir(); | |||||
| //change_cwd(exe_path); | |||||
| //free(exe_path); | |||||
| built_in_load(Memory::create_string("pre.slime")); | built_in_load(Memory::create_string("pre.slime")); | ||||
| @@ -366,118 +366,118 @@ namespace Parser { | |||||
| } | } | ||||
| // check if we have to create or delete or run macros | // check if we have to create or delete or run macros | ||||
| while (Memory::get_type(expression->value.pair.first) == Lisp_Object_Type::Symbol) { | |||||
| Lisp_Object* parsed_symbol = expression->value.pair.first; | |||||
| if (string_equal("define-syntax", parsed_symbol->value.symbol.identifier)) { | |||||
| // create a new macro | |||||
| Lisp_Object* arguments = expression->value.pair.rest; | |||||
| Lisp_Object* body; | |||||
| int arguments_length; | |||||
| // HACK(Felix): almost code duplicate from | |||||
| // `built_ins.cpp`: special-lambda | |||||
| try arguments_length = list_length(arguments); | |||||
| // (define-syntax (defun name args :rest body) (...)) | |||||
| if (arguments_length < 2) { | |||||
| create_wrong_number_of_arguments_error(3, arguments_length); | |||||
| return nullptr; | |||||
| } | |||||
| assert_type(arguments->value.pair.first, Lisp_Object_Type::Pair); | |||||
| // extract the name | |||||
| Lisp_Object* symbol_for_macro = arguments->value.pair.first->value.pair.first; | |||||
| body = arguments->value.pair.rest; | |||||
| arguments = arguments->value.pair.first->value.pair.rest; | |||||
| // Function* function = new(Function); | |||||
| Lisp_Object* macro; | |||||
| try macro = Memory::create_lisp_object(); | |||||
| Memory::set_type(macro, Lisp_Object_Type::Function); | |||||
| macro->value.function.parent_environment = get_current_environment(); | |||||
| macro->value.function.type = Function_Type::Macro; | |||||
| // if parameters were specified | |||||
| if (arguments != Memory::nil) { | |||||
| try assert_type(arguments, Lisp_Object_Type::Pair); | |||||
| try parse_argument_list(arguments, ¯o->value.function); | |||||
| } else { | |||||
| macro->value.function.args.positional = create_positional_argument_list(1); | |||||
| macro->value.function.args.keyword = create_keyword_argument_list(1); | |||||
| macro->value.function.args.rest = nullptr; | |||||
| } | |||||
| // arguments = arguments->value.pair.rest; | |||||
| // if there is a docstring, use it | |||||
| if (Memory::get_type(body->value.pair.first) == Lisp_Object_Type::String) { | |||||
| macro->docstring = body->value.pair.first->value.string; | |||||
| body = body->value.pair.rest; | |||||
| } else { | |||||
| macro->docstring = nullptr; | |||||
| } | |||||
| // we are now in the function body, just wrap it in an | |||||
| // implicit begin | |||||
| try macro->value.function.body = Memory::create_lisp_object_pair( | |||||
| Memory::get_or_create_lisp_object_symbol("begin"), | |||||
| body); | |||||
| inject_scl(macro); | |||||
| // macro->value.function = function; | |||||
| define_symbol(symbol_for_macro, macro); | |||||
| // print_environment(environment_for_macros); | |||||
| return Memory::nil; | |||||
| } else if (string_equal("delete-syntax", parsed_symbol->value.symbol.identifier)) { | |||||
| /* --- deleting an existing macro --- */ | |||||
| // TODO(Felix): this is a hard one because when | |||||
| // environments will be made from hashmaps, how can we | |||||
| // delete stuff from hashmaps? If we do probing on | |||||
| // collision and then delte the first colliding entry, | |||||
| // how can we find the second one? How many probes do | |||||
| // we have to do to know for sure that an elemenet is | |||||
| // not in the hashmap? It would be much easier if we | |||||
| // never deleted any elements from the hashmap, so | |||||
| // that, when an entry is not found immidiately, we | |||||
| // know for sure that it does not exist in the table. | |||||
| create_generic_error("deleting macros has not yet be implemented," | |||||
| "and I don't know if it is a good idea to do so."); | |||||
| return nullptr; | |||||
| } else { | |||||
| // if threre is a macro named like this, then macroexpand | |||||
| // if not it is regular code, dont touch. | |||||
| break; | |||||
| Lisp_Object* macro = try_lookup_symbol(parsed_symbol, get_current_environment()); | |||||
| if (macro && | |||||
| Memory::get_type(macro) == Lisp_Object_Type::Function && | |||||
| macro->value.function.type == Function_Type::Macro) | |||||
| { | |||||
| // printf("pretending to expand macro at %s %d %d: ", | |||||
| // Memory::get_c_str(parser_file), | |||||
| // parser_line, parser_col); | |||||
| // print(parsed_symbol); | |||||
| // printf("\n"); | |||||
| // NOTE(Felix): Execute it as a special lambda, | |||||
| // because if we keep it as a macro, the evaluator | |||||
| // will think it is a stray macro that was not yet | |||||
| // expanded, and attempt to evaluate it twice (1. | |||||
| // for expanding, and 2. for evaluating) | |||||
| macro->value.function.type = Function_Type::Special_Lambda; | |||||
| // NOTE(Felix): deferred so even if eval expr | |||||
| // fails, and returns, the type will be be | |||||
| // resetted to macro. | |||||
| defer { | |||||
| macro->value.function.type = Function_Type::Macro; | |||||
| }; | |||||
| try expression = eval_expr(expression); | |||||
| break; | |||||
| } else break; | |||||
| } | |||||
| } | |||||
| // while (Memory::get_type(expression->value.pair.first) == Lisp_Object_Type::Symbol) { | |||||
| // Lisp_Object* parsed_symbol = expression->value.pair.first; | |||||
| // if (string_equal("define-syntax", parsed_symbol->value.symbol.identifier)) { | |||||
| // // create a new macro | |||||
| // Lisp_Object* arguments = expression->value.pair.rest; | |||||
| // Lisp_Object* body; | |||||
| // int arguments_length; | |||||
| // // HACK(Felix): almost code duplicate from | |||||
| // // `built_ins.cpp`: special-lambda | |||||
| // try arguments_length = list_length(arguments); | |||||
| // // (define-syntax (defun name args :rest body) (...)) | |||||
| // if (arguments_length < 2) { | |||||
| // create_wrong_number_of_arguments_error(3, arguments_length); | |||||
| // return nullptr; | |||||
| // } | |||||
| // assert_type(arguments->value.pair.first, Lisp_Object_Type::Pair); | |||||
| // // extract the name | |||||
| // Lisp_Object* symbol_for_macro = arguments->value.pair.first->value.pair.first; | |||||
| // body = arguments->value.pair.rest; | |||||
| // arguments = arguments->value.pair.first->value.pair.rest; | |||||
| // // Function* function = new(Function); | |||||
| // Lisp_Object* macro; | |||||
| // try macro = Memory::create_lisp_object(); | |||||
| // Memory::set_type(macro, Lisp_Object_Type::Function); | |||||
| // macro->value.function.parent_environment = get_current_environment(); | |||||
| // macro->value.function.type = Function_Type::Macro; | |||||
| // // if parameters were specified | |||||
| // if (arguments != Memory::nil) { | |||||
| // try assert_type(arguments, Lisp_Object_Type::Pair); | |||||
| // try create_arguments_from_lambda_list_and_inject(arguments, macro); | |||||
| // } else { | |||||
| // macro->value.function.args.positional = create_positional_argument_list(1); | |||||
| // macro->value.function.args.keyword = create_keyword_argument_list(1); | |||||
| // macro->value.function.args.rest = nullptr; | |||||
| // } | |||||
| // // arguments = arguments->value.pair.rest; | |||||
| // // if there is a docstring, use it | |||||
| // if (Memory::get_type(body->value.pair.first) == Lisp_Object_Type::String) { | |||||
| // macro->docstring = body->value.pair.first->value.string; | |||||
| // body = body->value.pair.rest; | |||||
| // } else { | |||||
| // macro->docstring = nullptr; | |||||
| // } | |||||
| // // we are now in the function body, just wrap it in an | |||||
| // // implicit begin | |||||
| // try macro->value.function.body = Memory::create_lisp_object_pair( | |||||
| // Memory::get_or_create_lisp_object_symbol("begin"), | |||||
| // body); | |||||
| // inject_scl(macro); | |||||
| // // macro->value.function = function; | |||||
| // define_symbol(symbol_for_macro, macro); | |||||
| // // print_environment(environment_for_macros); | |||||
| // return Memory::nil; | |||||
| // } else if (string_equal("delete-syntax", parsed_symbol->value.symbol.identifier)) { | |||||
| // /* --- deleting an existing macro --- */ | |||||
| // // TODO(Felix): this is a hard one because when | |||||
| // // environments will be made from hashmaps, how can we | |||||
| // // delete stuff from hashmaps? If we do probing on | |||||
| // // collision and then delte the first colliding entry, | |||||
| // // how can we find the second one? How many probes do | |||||
| // // we have to do to know for sure that an elemenet is | |||||
| // // not in the hashmap? It would be much easier if we | |||||
| // // never deleted any elements from the hashmap, so | |||||
| // // that, when an entry is not found immidiately, we | |||||
| // // know for sure that it does not exist in the table. | |||||
| // create_generic_error("deleting macros has not yet be implemented," | |||||
| // "and I don't know if it is a good idea to do so."); | |||||
| // return nullptr; | |||||
| // } else { | |||||
| // // if threre is a macro named like this, then macroexpand | |||||
| // // if not it is regular code, dont touch. | |||||
| // break; | |||||
| // Lisp_Object* macro = try_lookup_symbol(parsed_symbol, get_current_environment()); | |||||
| // if (macro && | |||||
| // Memory::get_type(macro) == Lisp_Object_Type::Function && | |||||
| // macro->value.function.type == Function_Type::Macro) | |||||
| // { | |||||
| // // printf("pretending to expand macro at %s %d %d: ", | |||||
| // // Memory::get_c_str(parser_file), | |||||
| // // parser_line, parser_col); | |||||
| // // print(parsed_symbol); | |||||
| // // printf("\n"); | |||||
| // // NOTE(Felix): Execute it as a special lambda, | |||||
| // // because if we keep it as a macro, the evaluator | |||||
| // // will think it is a stray macro that was not yet | |||||
| // // expanded, and attempt to evaluate it twice (1. | |||||
| // // for expanding, and 2. for evaluating) | |||||
| // macro->value.function.type = Function_Type::Special_Lambda; | |||||
| // // NOTE(Felix): deferred so even if eval expr | |||||
| // // fails, and returns, the type will be be | |||||
| // // resetted to macro. | |||||
| // defer { | |||||
| // macro->value.function.type = Function_Type::Macro; | |||||
| // }; | |||||
| // try expression = eval_expr(expression); | |||||
| // break; | |||||
| // } else break; | |||||
| // } | |||||
| // } | |||||
| return expression; | return expression; | ||||
| } | } | ||||
| @@ -121,13 +121,15 @@ struct Environment { | |||||
| struct Function { | struct Function { | ||||
| Function_Type type; | Function_Type type; | ||||
| Arguments args; | |||||
| Lisp_Object* body; // implicit begin | |||||
| Arguments args; | |||||
| Lisp_Object* body; // maybe implicit begin | |||||
| Environment* parent_environment; // we are doing closures now!! | Environment* parent_environment; // we are doing closures now!! | ||||
| }; | }; | ||||
| struct cFunction { | struct cFunction { | ||||
| std::function<Lisp_Object* (Lisp_Object*)> function; | |||||
| std::function<Lisp_Object* ()> body; | |||||
| Arguments args; | |||||
| bool is_special_form; | |||||
| }; | }; | ||||
| struct Lisp_Object { | struct Lisp_Object { | ||||
| @@ -196,8 +196,7 @@ proc test_array_lists_searching() -> testresult { | |||||
| proc test_eval_operands() -> testresult { | proc test_eval_operands() -> testresult { | ||||
| char operands_string[] = "((eval 1) (+ 1 2) \"okay\" (eval :haha))"; | char operands_string[] = "((eval 1) (+ 1 2) \"okay\" (eval :haha))"; | ||||
| Lisp_Object* operands = Parser::parse_single_expression(operands_string); | Lisp_Object* operands = Parser::parse_single_expression(operands_string); | ||||
| int operands_length; | |||||
| try operands = eval_arguments(operands, &operands_length); | |||||
| try operands = eval_arguments(operands); | |||||
| assert_no_error(); | assert_no_error(); | ||||
| assert_equal_int(list_length(operands), 4); | assert_equal_int(list_length(operands), 4); | ||||
| @@ -504,7 +503,7 @@ proc test_built_in_type() -> testresult { | |||||
| assert_equal_string(result->value.symbol.identifier, "number"); | assert_equal_string(result->value.symbol.identifier, "number"); | ||||
| // setting user type | // setting user type | ||||
| char exp_string2[] = "(begin (set-type a :my-type)(type a))"; | |||||
| char exp_string2[] = "(begin (set-type! a :my-type)(type a))"; | |||||
| expression = Parser::parse_single_expression(exp_string2); | expression = Parser::parse_single_expression(exp_string2); | ||||
| result = eval_expr(expression); | result = eval_expr(expression); | ||||
| @@ -514,7 +513,7 @@ proc test_built_in_type() -> testresult { | |||||
| assert_equal_string(result->value.symbol.identifier, "my-type"); | assert_equal_string(result->value.symbol.identifier, "my-type"); | ||||
| // trying to set invalid user type | // trying to set invalid user type | ||||
| char exp_string3[] = "(begin (set-type a \"wrong tpye\")(type a))"; | |||||
| char exp_string3[] = "(begin (set-type! a \"wrong tpye\")(type a))"; | |||||
| expression = Parser::parse_single_expression(exp_string3); | expression = Parser::parse_single_expression(exp_string3); | ||||
| assert_no_error(); | assert_no_error(); | ||||
| @@ -528,7 +527,7 @@ proc test_built_in_type() -> testresult { | |||||
| delete_error(); | delete_error(); | ||||
| // deleting user type | // deleting user type | ||||
| char exp_string4[] = "(begin (delete-type a)(type a))"; | |||||
| char exp_string4[] = "(begin (delete-type! a)(type a))"; | |||||
| expression = Parser::parse_single_expression(exp_string4); | expression = Parser::parse_single_expression(exp_string4); | ||||
| result = eval_expr(expression); | result = eval_expr(expression); | ||||
| @@ -598,13 +597,19 @@ proc run_all_tests() -> bool { | |||||
| bool result = true; | bool result = true; | ||||
| Memory::init(4096 * 2000, 1024 * 32, 4096 * 16 * 10); | |||||
| Environment* root_env = get_root_environment(); | |||||
| Environment* user_env = Memory::create_child_environment(root_env); | |||||
| push_environment(user_env); | |||||
| defer{ | |||||
| pop_environment(); | |||||
| }; | |||||
| printf("-- Util --\n"); | printf("-- Util --\n"); | ||||
| invoke_test(test_array_lists_adding_and_removing); | invoke_test(test_array_lists_adding_and_removing); | ||||
| invoke_test(test_array_lists_sorting); | invoke_test(test_array_lists_sorting); | ||||
| invoke_test(test_array_lists_searching); | invoke_test(test_array_lists_searching); | ||||
| Memory::init(4096 * 2000, 1024 * 32, 4096 * 16 * 10); | |||||
| printf("\n -- Parsing --\n"); | printf("\n -- Parsing --\n"); | ||||
| invoke_test(test_parse_atom); | invoke_test(test_parse_atom); | ||||
| invoke_test(test_parse_expression); | invoke_test(test_parse_expression); | ||||
| @@ -18,3 +18,22 @@ | |||||
| ;; should output 6 | ;; should output 6 | ||||
| ;; outputs 0 | ;; outputs 0 | ||||
| #+END_SRC | #+END_SRC | ||||
| * TODO BUG 3: unnecessary copying? | |||||
| define((test val),"") { | |||||
| fetch(val) ; | |||||
| printf("addr of arg: %lld\n", (unsigned long long)&val); | |||||
| return Memory::nil; | |||||
| }; | |||||
| then: | |||||
| #+begin_src slime | |||||
| (define a "a") | |||||
| (test a) ;; will output an adress | |||||
| (if 1 (test a) 2) ;; will output a different adress | |||||
| #+end_src | |||||
| * TODO BUG 4: arg parsing | |||||
| #+begin_src slime | |||||
| (define (range (:from 0) to) ...) | |||||
| #+end_src | |||||
| should error since we can't have positional args after keywords. right now, 'to' is silently | |||||
| ignored.. | |||||
| @@ -1,182 +1,182 @@ | |||||
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
| <ItemGroup Label="ProjectConfigurations"> | |||||
| <ProjectConfiguration Include="Debug|Win32"> | |||||
| <Configuration>Debug</Configuration> | |||||
| <Platform>Win32</Platform> | |||||
| </ProjectConfiguration> | |||||
| <ProjectConfiguration Include="Release|Win32"> | |||||
| <Configuration>Release</Configuration> | |||||
| <Platform>Win32</Platform> | |||||
| </ProjectConfiguration> | |||||
| <ProjectConfiguration Include="Debug|x64"> | |||||
| <Configuration>Debug</Configuration> | |||||
| <Platform>x64</Platform> | |||||
| </ProjectConfiguration> | |||||
| <ProjectConfiguration Include="Release|x64"> | |||||
| <Configuration>Release</Configuration> | |||||
| <Platform>x64</Platform> | |||||
| </ProjectConfiguration> | |||||
| <ProjectConfiguration Include="run tests|Win32"> | |||||
| <Configuration>run tests</Configuration> | |||||
| <Platform>Win32</Platform> | |||||
| </ProjectConfiguration> | |||||
| <ProjectConfiguration Include="run tests|x64"> | |||||
| <Configuration>run tests</Configuration> | |||||
| <Platform>x64</Platform> | |||||
| </ProjectConfiguration> | |||||
| </ItemGroup> | |||||
| <PropertyGroup Label="Globals"> | |||||
| <VCProjectVersion>15.0</VCProjectVersion> | |||||
| <ProjectGuid>{1A47A3ED-871F-4CB4-875B-8CAA385B1771}</ProjectGuid> | |||||
| <RootNamespace>slime</RootNamespace> | |||||
| <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion> | |||||
| <ProjectName>slime</ProjectName> | |||||
| </PropertyGroup> | |||||
| <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>true</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='run tests|Win32'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>true</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>false</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <WholeProgramOptimization>true</WholeProgramOptimization> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>true</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='run tests|x64'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>true</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>false</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <WholeProgramOptimization>true</WholeProgramOptimization> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | |||||
| <ImportGroup Label="ExtensionSettings"> | |||||
| </ImportGroup> | |||||
| <ImportGroup Label="Shared"> | |||||
| </ImportGroup> | |||||
| <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <ImportGroup Condition="'$(Configuration)|$(Platform)'=='run tests|Win32'" Label="PropertySheets"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <ImportGroup Condition="'$(Configuration)|$(Platform)'=='run tests|x64'" Label="PropertySheets"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <PropertyGroup Label="UserMacros" /> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='run tests|x64'"> | |||||
| <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> | |||||
| </PropertyGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>Disabled</Optimization> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <Profile>true</Profile> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='run tests|Win32'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>Disabled</Optimization> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <Profile>true</Profile> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>Disabled</Optimization> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| <CompileAs>Default</CompileAs> | |||||
| <LanguageStandard>stdcpplatest</LanguageStandard> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <Profile>true</Profile> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='run tests|x64'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>Disabled</Optimization> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| <CompileAs>Default</CompileAs> | |||||
| <LanguageStandard>stdcpplatest</LanguageStandard> | |||||
| <PreprocessorDefinitions>_PROFILING;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <Profile>true</Profile> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>MaxSpeed</Optimization> | |||||
| <FunctionLevelLinking>true</FunctionLevelLinking> | |||||
| <IntrinsicFunctions>true</IntrinsicFunctions> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <EnableCOMDATFolding>true</EnableCOMDATFolding> | |||||
| <OptimizeReferences>true</OptimizeReferences> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>MaxSpeed</Optimization> | |||||
| <FunctionLevelLinking>true</FunctionLevelLinking> | |||||
| <IntrinsicFunctions>true</IntrinsicFunctions> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| <CompileAs>Default</CompileAs> | |||||
| <LanguageStandard>stdcpplatest</LanguageStandard> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <EnableCOMDATFolding>true</EnableCOMDATFolding> | |||||
| <OptimizeReferences>true</OptimizeReferences> | |||||
| <SubSystem>NotSet</SubSystem> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemGroup> | |||||
| <ClCompile Include="..\src\main.cpp" /> | |||||
| </ItemGroup> | |||||
| <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | |||||
| <ImportGroup Label="ExtensionTargets"> | |||||
| </ImportGroup> | |||||
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
| <ItemGroup Label="ProjectConfigurations"> | |||||
| <ProjectConfiguration Include="Debug|Win32"> | |||||
| <Configuration>Debug</Configuration> | |||||
| <Platform>Win32</Platform> | |||||
| </ProjectConfiguration> | |||||
| <ProjectConfiguration Include="Release|Win32"> | |||||
| <Configuration>Release</Configuration> | |||||
| <Platform>Win32</Platform> | |||||
| </ProjectConfiguration> | |||||
| <ProjectConfiguration Include="Debug|x64"> | |||||
| <Configuration>Debug</Configuration> | |||||
| <Platform>x64</Platform> | |||||
| </ProjectConfiguration> | |||||
| <ProjectConfiguration Include="Release|x64"> | |||||
| <Configuration>Release</Configuration> | |||||
| <Platform>x64</Platform> | |||||
| </ProjectConfiguration> | |||||
| <ProjectConfiguration Include="run tests|Win32"> | |||||
| <Configuration>run tests</Configuration> | |||||
| <Platform>Win32</Platform> | |||||
| </ProjectConfiguration> | |||||
| <ProjectConfiguration Include="run tests|x64"> | |||||
| <Configuration>run tests</Configuration> | |||||
| <Platform>x64</Platform> | |||||
| </ProjectConfiguration> | |||||
| </ItemGroup> | |||||
| <PropertyGroup Label="Globals"> | |||||
| <VCProjectVersion>15.0</VCProjectVersion> | |||||
| <ProjectGuid>{1A47A3ED-871F-4CB4-875B-8CAA385B1771}</ProjectGuid> | |||||
| <RootNamespace>slime</RootNamespace> | |||||
| <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion> | |||||
| <ProjectName>slime</ProjectName> | |||||
| </PropertyGroup> | |||||
| <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>true</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='run tests|Win32'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>true</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>false</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <WholeProgramOptimization>true</WholeProgramOptimization> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>true</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='run tests|x64'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>true</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | |||||
| <ConfigurationType>Application</ConfigurationType> | |||||
| <UseDebugLibraries>false</UseDebugLibraries> | |||||
| <PlatformToolset>v141</PlatformToolset> | |||||
| <WholeProgramOptimization>true</WholeProgramOptimization> | |||||
| <CharacterSet>MultiByte</CharacterSet> | |||||
| </PropertyGroup> | |||||
| <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | |||||
| <ImportGroup Label="ExtensionSettings"> | |||||
| </ImportGroup> | |||||
| <ImportGroup Label="Shared"> | |||||
| </ImportGroup> | |||||
| <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <ImportGroup Condition="'$(Configuration)|$(Platform)'=='run tests|Win32'" Label="PropertySheets"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <ImportGroup Condition="'$(Configuration)|$(Platform)'=='run tests|x64'" Label="PropertySheets"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||||
| </ImportGroup> | |||||
| <PropertyGroup Label="UserMacros" /> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='run tests|x64'"> | |||||
| <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir> | |||||
| </PropertyGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>Disabled</Optimization> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <Profile>true</Profile> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='run tests|Win32'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>Disabled</Optimization> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <Profile>true</Profile> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>Disabled</Optimization> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| <CompileAs>Default</CompileAs> | |||||
| <LanguageStandard>stdcpplatest</LanguageStandard> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <Profile>true</Profile> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='run tests|x64'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>Disabled</Optimization> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| <CompileAs>Default</CompileAs> | |||||
| <LanguageStandard>stdcpplatest</LanguageStandard> | |||||
| <PreprocessorDefinitions>_PROFILING;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <Profile>true</Profile> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>MaxSpeed</Optimization> | |||||
| <FunctionLevelLinking>true</FunctionLevelLinking> | |||||
| <IntrinsicFunctions>true</IntrinsicFunctions> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <EnableCOMDATFolding>true</EnableCOMDATFolding> | |||||
| <OptimizeReferences>true</OptimizeReferences> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||||
| <ClCompile> | |||||
| <WarningLevel>Level3</WarningLevel> | |||||
| <Optimization>MaxSpeed</Optimization> | |||||
| <FunctionLevelLinking>true</FunctionLevelLinking> | |||||
| <IntrinsicFunctions>true</IntrinsicFunctions> | |||||
| <SDLCheck>true</SDLCheck> | |||||
| <CompileAs>Default</CompileAs> | |||||
| <LanguageStandard>stdcpplatest</LanguageStandard> | |||||
| </ClCompile> | |||||
| <Link> | |||||
| <EnableCOMDATFolding>true</EnableCOMDATFolding> | |||||
| <OptimizeReferences>true</OptimizeReferences> | |||||
| <SubSystem>NotSet</SubSystem> | |||||
| </Link> | |||||
| </ItemDefinitionGroup> | |||||
| <ItemGroup> | |||||
| <ClCompile Include="..\src\main.cpp" /> | |||||
| </ItemGroup> | |||||
| <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | |||||
| <ImportGroup Label="ExtensionTargets"> | |||||
| </ImportGroup> | |||||
| </Project> | </Project> | ||||