1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-11 21:57:38 +03:00
mal/impls/elisp/step8_macros.el

192 lines
6.4 KiB
EmacsLisp
Raw Permalink Normal View History

2016-02-29 23:01:13 +03:00
;; -*- lexical-binding: t; -*-
(require 'cl-lib)
(require 'mal/types)
(require 'mal/env)
(require 'mal/reader)
(require 'mal/printer)
(require 'mal/core)
2016-02-29 23:01:13 +03:00
(defun qq-reducer (elt acc)
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(let ((value (mal-list-value elt)))
(mal-list (if (eq 'splice-unquote (mal-symbol-value (car value)))
(list (mal-symbol 'concat) (cadr value) acc)
(list (mal-symbol 'cons) (quasiquote elt) acc)))))
(defun qq-iter (elts)
(cl-reduce 'qq-reducer elts :from-end t :initial-value (mal-list nil)))
2016-02-29 23:01:13 +03:00
(defun quasiquote (ast)
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(let (value)
(cond
((setq value (mal-list-value ast)) ; not empty
(if (eq 'unquote (mal-symbol-value (car value)))
(cadr value)
(qq-iter value)))
((setq value (mal-vector-value ast))
(mal-list (list (mal-symbol 'vec) (qq-iter value))))
((or (mal-map-value ast)
(mal-symbol-value ast))
(mal-list (list (mal-symbol 'quote) ast)))
(t ; including the empty list case
ast))))
2016-02-29 23:01:13 +03:00
(defun READ (input)
(read-str input))
(defun EVAL (ast env)
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(let (return a)
(while (not return)
2016-02-29 23:01:13 +03:00
Merge eval-ast and macro expansion into EVAL, add DEBUG-EVAL See issue #587. * Merge eval-ast and eval into a single conditional. * Expand macros during the apply phase, removing lots of duplicate tests, and increasing the overall consistency by allowing the macro to be computed instead of referenced by name (`((defmacro! cond (...)))` is currently illegal for example). * Print "EVAL: $ast" at the top of EVAL if DEBUG-EVAL exists in the MAL environment. * Remove macroexpand and quasiquoteexpand special forms. * Use pattern-matching style in process/step*.txt. Unresolved issues: c.2: unable to reproduce with gcc 11.12.0. elm: the directory is unchanged. groovy: sometimes fail, but not on each rebuild. nasm: fails some new soft tests, but the issue is unreproducible when running the interpreter manually. objpascal: unreproducible with fpc 3.2.2. ocaml: unreproducible with 4.11.1. perl6: unreproducible with rakudo 2021.09. Unrelated changes: Reduce diff betweens steps. Prevent defmacro! from mutating functions: c forth logo miniMAL vb. dart: fix recent errors and warnings ocaml: remove metadata from symbols. Improve the logo implementation. Encapsulate all representation in types.lg and env.lg, unwrap numbers. Replace some manual iterations with logo control structures. Reduce the diff between steps. Use native iteration in env_get and env_map Rewrite the reader with less temporary strings. Reduce the number of temporary lists (for example, reverse iteration with butlast requires O(n^2) allocations). It seems possible to remove a few exceptions: GC settings (Dockerfile), NO_SELF_HOSTING (IMPLS.yml) and step5_EXCLUDES (Makefile.impls) .
2022-01-10 02:15:40 +03:00
(let ((dbgeval (mal-env-get env 'DEBUG-EVAL)))
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(if (not (memq dbgeval (list nil mal-nil mal-false)))
Merge eval-ast and macro expansion into EVAL, add DEBUG-EVAL See issue #587. * Merge eval-ast and eval into a single conditional. * Expand macros during the apply phase, removing lots of duplicate tests, and increasing the overall consistency by allowing the macro to be computed instead of referenced by name (`((defmacro! cond (...)))` is currently illegal for example). * Print "EVAL: $ast" at the top of EVAL if DEBUG-EVAL exists in the MAL environment. * Remove macroexpand and quasiquoteexpand special forms. * Use pattern-matching style in process/step*.txt. Unresolved issues: c.2: unable to reproduce with gcc 11.12.0. elm: the directory is unchanged. groovy: sometimes fail, but not on each rebuild. nasm: fails some new soft tests, but the issue is unreproducible when running the interpreter manually. objpascal: unreproducible with fpc 3.2.2. ocaml: unreproducible with 4.11.1. perl6: unreproducible with rakudo 2021.09. Unrelated changes: Reduce diff betweens steps. Prevent defmacro! from mutating functions: c forth logo miniMAL vb. dart: fix recent errors and warnings ocaml: remove metadata from symbols. Improve the logo implementation. Encapsulate all representation in types.lg and env.lg, unwrap numbers. Replace some manual iterations with logo control structures. Reduce the diff between steps. Use native iteration in env_get and env_map Rewrite the reader with less temporary strings. Reduce the number of temporary lists (for example, reverse iteration with butlast requires O(n^2) allocations). It seems possible to remove a few exceptions: GC settings (Dockerfile), NO_SELF_HOSTING (IMPLS.yml) and step5_EXCLUDES (Makefile.impls) .
2022-01-10 02:15:40 +03:00
(println "EVAL: %s\n" (PRINT ast))))
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(cond
2016-02-29 23:01:13 +03:00
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
((setq a (mal-list-value ast))
(cl-case (mal-symbol-value (car a))
(def!
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(let ((identifier (mal-symbol-value (cadr a)))
(value (EVAL (caddr a) env)))
(setq return (mal-env-set env identifier value))))
(let*
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(let ((env* (mal-env env))
(bindings (mal-seq-value (cadr a)))
(form (caddr a))
key)
(seq-do (lambda (current)
(if key
(let ((value (EVAL current env*)))
(mal-env-set env* key value)
(setq key nil))
(setq key (mal-symbol-value current))))
bindings)
2016-02-29 23:01:13 +03:00
(setq env env*
ast form))) ; TCO
(quote
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(setq return (cadr a)))
(quasiquote
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(setq ast (quasiquote (cadr a)))) ; TCO
(defmacro!
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(let ((identifier (mal-symbol-value (cadr a)))
(value (mal-macro (mal-func-value (EVAL (caddr a) env)))))
(setq return (mal-env-set env identifier value))))
(do
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(setq a (cdr a)) ; skip 'do
(while (cdr a)
(EVAL (pop a) env))
(setq ast (car a))) ; TCO
(if
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(let ((condition (EVAL (cadr a) env)))
(if (memq condition (list mal-nil mal-false))
(if (cdddr a)
(setq ast (cadddr a)) ; TCO
(setq return mal-nil))
(setq ast (caddr a))))) ; TCO
(fn*
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(let ((binds (mapcar 'mal-symbol-value (mal-seq-value (cadr a))))
(body (caddr a)))
(setq return (mal-func
2016-02-29 23:01:13 +03:00
(lambda (&rest args)
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(EVAL body (mal-env env binds args)))
body binds env))))
2016-02-29 23:01:13 +03:00
(t
;; not a special form
Merge eval-ast and macro expansion into EVAL, add DEBUG-EVAL See issue #587. * Merge eval-ast and eval into a single conditional. * Expand macros during the apply phase, removing lots of duplicate tests, and increasing the overall consistency by allowing the macro to be computed instead of referenced by name (`((defmacro! cond (...)))` is currently illegal for example). * Print "EVAL: $ast" at the top of EVAL if DEBUG-EVAL exists in the MAL environment. * Remove macroexpand and quasiquoteexpand special forms. * Use pattern-matching style in process/step*.txt. Unresolved issues: c.2: unable to reproduce with gcc 11.12.0. elm: the directory is unchanged. groovy: sometimes fail, but not on each rebuild. nasm: fails some new soft tests, but the issue is unreproducible when running the interpreter manually. objpascal: unreproducible with fpc 3.2.2. ocaml: unreproducible with 4.11.1. perl6: unreproducible with rakudo 2021.09. Unrelated changes: Reduce diff betweens steps. Prevent defmacro! from mutating functions: c forth logo miniMAL vb. dart: fix recent errors and warnings ocaml: remove metadata from symbols. Improve the logo implementation. Encapsulate all representation in types.lg and env.lg, unwrap numbers. Replace some manual iterations with logo control structures. Reduce the diff between steps. Use native iteration in env_get and env_map Rewrite the reader with less temporary strings. Reduce the number of temporary lists (for example, reverse iteration with butlast requires O(n^2) allocations). It seems possible to remove a few exceptions: GC settings (Dockerfile), NO_SELF_HOSTING (IMPLS.yml) and step5_EXCLUDES (Makefile.impls) .
2022-01-10 02:15:40 +03:00
(let ((fn (EVAL (car a) env))
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(args (cdr a))
fn*)
(cond
((setq fn* (mal-macro-value fn))
(setq ast (apply fn* args))) ; TCO
((mal-func-value fn)
(setq env (mal-env (mal-func-env fn)
2016-02-29 23:01:13 +03:00
(mal-func-params fn)
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(mapcar (lambda (x) (EVAL x env)) args))
ast (mal-func-body fn))) ; TCO
((setq fn* (mal-fn-core-value fn))
2016-02-29 23:01:13 +03:00
;; built-in function
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(setq return (apply fn* (mapcar (lambda (x) (EVAL x env)) args))))
(t (error "cannot apply %s" (PRINT ast))))))))
((setq a (mal-symbol-value ast))
(setq return (or (mal-env-get env a)
(error "'%s' not found" a))))
((setq a (mal-vector-value ast))
(setq return
Merge eval-ast and macro expansion into EVAL, add DEBUG-EVAL See issue #587. * Merge eval-ast and eval into a single conditional. * Expand macros during the apply phase, removing lots of duplicate tests, and increasing the overall consistency by allowing the macro to be computed instead of referenced by name (`((defmacro! cond (...)))` is currently illegal for example). * Print "EVAL: $ast" at the top of EVAL if DEBUG-EVAL exists in the MAL environment. * Remove macroexpand and quasiquoteexpand special forms. * Use pattern-matching style in process/step*.txt. Unresolved issues: c.2: unable to reproduce with gcc 11.12.0. elm: the directory is unchanged. groovy: sometimes fail, but not on each rebuild. nasm: fails some new soft tests, but the issue is unreproducible when running the interpreter manually. objpascal: unreproducible with fpc 3.2.2. ocaml: unreproducible with 4.11.1. perl6: unreproducible with rakudo 2021.09. Unrelated changes: Reduce diff betweens steps. Prevent defmacro! from mutating functions: c forth logo miniMAL vb. dart: fix recent errors and warnings ocaml: remove metadata from symbols. Improve the logo implementation. Encapsulate all representation in types.lg and env.lg, unwrap numbers. Replace some manual iterations with logo control structures. Reduce the diff between steps. Use native iteration in env_get and env_map Rewrite the reader with less temporary strings. Reduce the number of temporary lists (for example, reverse iteration with butlast requires O(n^2) allocations). It seems possible to remove a few exceptions: GC settings (Dockerfile), NO_SELF_HOSTING (IMPLS.yml) and step5_EXCLUDES (Makefile.impls) .
2022-01-10 02:15:40 +03:00
(mal-vector (vconcat (mapcar (lambda (item) (EVAL item env))
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
a)))))
((setq a (mal-map-value ast))
(let ((map (copy-hash-table a)))
(maphash (lambda (key val)
(puthash key (EVAL val env) map))
2016-02-29 23:01:13 +03:00
map)
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(setq return (mal-map map))))
2016-02-29 23:01:13 +03:00
(t
;; return as is
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(setq return ast))))
2016-02-29 23:01:13 +03:00
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
;; End of the TCO loop
return))
2016-02-29 23:01:13 +03:00
(defun PRINT (input)
(pr-str input t))
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(defun rep (input repl-env)
2016-02-29 23:01:13 +03:00
(PRINT (EVAL (READ input) repl-env)))
(defun readln (prompt)
;; C-d throws an error
(ignore-errors (read-from-minibuffer prompt)))
(defun println (format-string &rest args)
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(princ (if args
(apply 'format format-string args)
format-string))
2016-02-29 23:01:13 +03:00
(terpri))
(defmacro with-error-handling (&rest body)
`(condition-case err
(progn ,@body)
(end-of-token-stream
;; empty input, carry on
)
(unterminated-sequence
(princ (format "Expected '%c', got EOF\n"
(cl-case (cadr err)
(string ?\")
(list ?\))
(vector ?\])
(map ?})))))
2016-02-29 23:01:13 +03:00
(error ; catch-all
(println (error-message-string err)))))
(defun main ()
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(defvar repl-env (mal-env))
(dolist (binding core-ns)
(let ((symbol (car binding))
(fn (cdr binding)))
(mal-env-set repl-env symbol (mal-fn-core fn))))
(mal-env-set repl-env 'eval (mal-fn-core (byte-compile (lambda (form) (EVAL form repl-env)))))
(mal-env-set repl-env '*ARGV* (mal-list (mapcar 'mal-string (cdr argv))))
(rep "(def! not (fn* (a) (if a false true)))" repl-env)
(rep "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f)
\"\nnil)\")))))" repl-env)
(rep "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first
xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to
cond\")) (cons 'cond (rest (rest xs)))))))" repl-env)
2016-02-29 23:01:13 +03:00
(if argv
(with-error-handling
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(rep (format "(load-file \"%s\")" (car argv)) repl-env))
(let (input)
(while (setq input (readln "user> "))
2016-02-29 23:01:13 +03:00
(with-error-handling
elisp: fix new tests, byte-compile, various improvements The original motivation is to fix the new (= nil ()) and core_apply_accepts_macros tests. Improve speed and warnings with byte compilation. mal/core.el: Wrap core functions during the loop in main, instead of writing the conversion in each line of core-ns. Use apply built-in concatenation of last argument. Move handling of metadata to types.el. mal/env.el: Represent environments as cons cells instead of vectors. mal/func.el: Merged into types.el, it is not a special case anymore. mal/printer.el: Add macro case. Define a pr-join helper for sequences and core.el. mal/reader.el: Rename the tokens local variable in reader.el (compiler warning). mal/types.el: Use type-specific accessors returning nil for the wrong type (structural pattern matching would be better, but is too slow). Represent native types directly when possible, and inline some trivial accessors. Use dedicated records instead of vectors. Implement metadata only when required. Represent keywords as strings (easyer, no counterpart). run: Run byte-compiled version. steps: Backport good ideas from stepA to step1, reducing the diff between steps for future maintenance. Implement 'do with a simple iteration (without map and butlast). Make the repl-env local to main (compiler warning). Make the code more idiomatic * prefer loop over recursion (search in environments) * declare variable and reassign them when convenient (exit of the TCO loop) * car cdr cadr and so on instead of nth * remove various vector <-> list conversions.
2024-08-26 14:28:46 +03:00
(println (rep input repl-env))))
;; print final newline
(terpri))))
2016-02-29 23:01:13 +03:00
(main)