lispython 0.4.5__tar.gz → 0.4.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. {lispython-0.4.5 → lispython-0.4.7}/.gitignore +3 -1
  2. {lispython-0.4.5 → lispython-0.4.7}/PKG-INFO +22 -11
  3. {lispython-0.4.5 → lispython-0.4.7}/README.md +21 -10
  4. {lispython-0.4.5 → lispython-0.4.7}/docs/syntax/expressions.md +2 -2
  5. lispython-0.4.7/docs/usage/cli.md +41 -0
  6. {lispython-0.4.5 → lispython-0.4.7}/mkdocs.yml +1 -1
  7. {lispython-0.4.5 → lispython-0.4.7}/pyproject.toml +1 -1
  8. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/compiler/expr.py +2 -1
  9. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/macro.py +13 -8
  10. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/nodes.py +1 -1
  11. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/lsp/server.lpy +79 -0
  12. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/macros/sugar.lpy +2 -2
  13. lispython-0.4.7/src/lispy/tools.lpy +726 -0
  14. {lispython-0.4.5 → lispython-0.4.7}/uv.lock +1 -1
  15. lispython-0.4.5/.claude/settings.local.json +0 -11
  16. lispython-0.4.5/docs/usage/cli.md +0 -22
  17. lispython-0.4.5/src/lispy/tools.lpy +0 -289
  18. {lispython-0.4.5 → lispython-0.4.7}/.pre-commit-config.yaml +0 -0
  19. {lispython-0.4.5 → lispython-0.4.7}/.vscode/settings.json +0 -0
  20. {lispython-0.4.5 → lispython-0.4.7}/LICENSE.md +0 -0
  21. {lispython-0.4.5 → lispython-0.4.7}/docs/index.md +0 -0
  22. {lispython-0.4.5 → lispython-0.4.7}/docs/macros.md +0 -0
  23. {lispython-0.4.5 → lispython-0.4.7}/docs/syntax/overview.md +0 -0
  24. {lispython-0.4.5 → lispython-0.4.7}/docs/syntax/statements.md +0 -0
  25. {lispython-0.4.5 → lispython-0.4.7}/docs/usage/getting-started.md +0 -0
  26. {lispython-0.4.5 → lispython-0.4.7}/docs/version_macro.py +0 -0
  27. {lispython-0.4.5 → lispython-0.4.7}/docs/why-lispy.md +0 -0
  28. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/__init__.py +0 -0
  29. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/builtins.py +0 -0
  30. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/compiler/__init__.py +0 -0
  31. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/compiler/literal.py +0 -0
  32. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/compiler/stmt.py +0 -0
  33. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/compiler/utils.py +0 -0
  34. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/importer.py +0 -0
  35. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/meta_functions.py +0 -0
  36. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/parser.py +0 -0
  37. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core/utils.py +0 -0
  38. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/core_meta_functions.lpy +0 -0
  39. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/lsp/__init__.py +0 -0
  40. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/lsp/__main__.py +0 -0
  41. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/macros/__init__.py +0 -0
  42. {lispython-0.4.5 → lispython-0.4.7}/src/lispy/macros/init.lpy +0 -0
  43. {lispython-0.4.5 → lispython-0.4.7}/tests/__init__.py +0 -0
  44. {lispython-0.4.5 → lispython-0.4.7}/tests/test_as_thread.py +0 -0
  45. {lispython-0.4.5 → lispython-0.4.7}/tests/test_expr.py +0 -0
  46. {lispython-0.4.5 → lispython-0.4.7}/tests/test_gensym.py +0 -0
  47. {lispython-0.4.5 → lispython-0.4.7}/tests/test_include_meta.py +0 -0
  48. {lispython-0.4.5 → lispython-0.4.7}/tests/test_literal.py +0 -0
  49. {lispython-0.4.5 → lispython-0.4.7}/tests/test_literal_unwrap.py +0 -0
  50. {lispython-0.4.5 → lispython-0.4.7}/tests/test_meta_functions.py +0 -0
  51. {lispython-0.4.5 → lispython-0.4.7}/tests/test_parser.py +0 -0
  52. {lispython-0.4.5 → lispython-0.4.7}/tests/test_stmt.py +0 -0
  53. {lispython-0.4.5 → lispython-0.4.7}/tests/utils.py +0 -0
@@ -332,4 +332,6 @@ GEMINI.md
332
332
  .worktrees/
333
333
 
334
334
  # Agent-generated docs (not mkdocs content)
335
- docs/superpowers/
335
+ docs/superpowers/.stacks
336
+ .agents
337
+ .claude
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lispython
3
- Version: 0.4.5
3
+ Version: 0.4.7
4
4
  Summary: Lisp-like Syntax for Python with Lisp-like Macros
5
5
  Project-URL: Homepage, https://jetack.github.io/lispython
6
6
  Project-URL: Repository, https://github.com/jetack/lispython
@@ -85,25 +85,36 @@ lpy -m pytest
85
85
  LisPython ships with a language server (`lpy-lsp`) that speaks LSP over stdio. It provides:
86
86
 
87
87
  - Diagnostics (parse / compile errors)
88
- - Hover documentation for special forms
88
+ - Completions (special forms, builtins, file/workspace symbols)
89
+ - Hover documentation for special forms and builtins
89
90
  - Document symbols
90
91
  - Go-to-definition, including across `.lpy` files in the workspace
91
92
 
93
+ ## nREPL Server
94
+ LisPython includes an nREPL server for REPL-driven development:
95
+
96
+ ```bash
97
+ lpy --nrepl # start on a random port
98
+ lpy --nrepl 7888 # start on a specific port
99
+ ```
100
+
101
+ The server accepts newline-delimited JSON over TCP and supports:
102
+ - `eval` — evaluate LisPython code, return value/stdout/error
103
+ - `load-file` — load a `.lpy` file into the session
104
+ - `macroexpand` — expand macros and return the result
105
+ - `complete` — prefix and dot-completion from the live scope
106
+ - `docs` — signature and docstring for a symbol
107
+ - `annotate` — type tag (function/class/module/macro)
108
+
92
109
  ### Editor setup
93
- Point your editor's LSP client at the `lpy-lsp` command for files with the `.lpy` extension. The server speaks LSP over stdio.
94
110
 
95
- #### VSCode
96
- Install the [LisPython](https://marketplace.visualstudio.com/items?itemName=jetack.vscode-lispython) extension from the VSCode Marketplace.
111
+ #### VS Code
112
+ Install the [LisPython](https://marketplace.visualstudio.com/items?itemName=jetack.vscode-lispython) extension. It connects to both LSP and nREPL automatically.
97
113
 
98
114
  #### Emacs
99
- Use [`lpy-mode`](https://github.com/jetack/lpy-mode) for syntax highlighting and LSP integration. For completion, install [`lpy-autocomplete`](https://github.com/jetack/lpy-autocomplete).
115
+ Use [`lpy-mode`](https://github.com/jetack/lpy-mode). It provides nREPL integration (eval, completion, eldoc, macroexpand) and LSP via eglot.
100
116
 
101
117
  ## Todo
102
- ### Environment
103
- - [ ] Test on more python versions
104
- - [ ] REPL should track history and arrow key navigation
105
- - [ ] REPL multi-line input support
106
- - [ ] Better compilation error messages
107
118
  ### Python AST
108
119
  - [ ] `type_comment` never considered. Later, it should be covered
109
120
  - [ ] Any missing AST nodes in the version 3.12+
@@ -62,25 +62,36 @@ lpy -m pytest
62
62
  LisPython ships with a language server (`lpy-lsp`) that speaks LSP over stdio. It provides:
63
63
 
64
64
  - Diagnostics (parse / compile errors)
65
- - Hover documentation for special forms
65
+ - Completions (special forms, builtins, file/workspace symbols)
66
+ - Hover documentation for special forms and builtins
66
67
  - Document symbols
67
68
  - Go-to-definition, including across `.lpy` files in the workspace
68
69
 
70
+ ## nREPL Server
71
+ LisPython includes an nREPL server for REPL-driven development:
72
+
73
+ ```bash
74
+ lpy --nrepl # start on a random port
75
+ lpy --nrepl 7888 # start on a specific port
76
+ ```
77
+
78
+ The server accepts newline-delimited JSON over TCP and supports:
79
+ - `eval` — evaluate LisPython code, return value/stdout/error
80
+ - `load-file` — load a `.lpy` file into the session
81
+ - `macroexpand` — expand macros and return the result
82
+ - `complete` — prefix and dot-completion from the live scope
83
+ - `docs` — signature and docstring for a symbol
84
+ - `annotate` — type tag (function/class/module/macro)
85
+
69
86
  ### Editor setup
70
- Point your editor's LSP client at the `lpy-lsp` command for files with the `.lpy` extension. The server speaks LSP over stdio.
71
87
 
72
- #### VSCode
73
- Install the [LisPython](https://marketplace.visualstudio.com/items?itemName=jetack.vscode-lispython) extension from the VSCode Marketplace.
88
+ #### VS Code
89
+ Install the [LisPython](https://marketplace.visualstudio.com/items?itemName=jetack.vscode-lispython) extension. It connects to both LSP and nREPL automatically.
74
90
 
75
91
  #### Emacs
76
- Use [`lpy-mode`](https://github.com/jetack/lpy-mode) for syntax highlighting and LSP integration. For completion, install [`lpy-autocomplete`](https://github.com/jetack/lpy-autocomplete).
92
+ Use [`lpy-mode`](https://github.com/jetack/lpy-mode). It provides nREPL integration (eval, completion, eldoc, macroexpand) and LSP via eglot.
77
93
 
78
94
  ## Todo
79
- ### Environment
80
- - [ ] Test on more python versions
81
- - [ ] REPL should track history and arrow key navigation
82
- - [ ] REPL multi-line input support
83
- - [ ] Better compilation error messages
84
95
  ### Python AST
85
96
  - [ ] `type_comment` never considered. Later, it should be covered
86
97
  - [ ] Any missing AST nodes in the version 3.12+
@@ -38,11 +38,11 @@ Python version
38
38
  expr1 == expr2 == expr3 == ...
39
39
  ```
40
40
  #### `>`
41
- Python version
41
+ LisPy version
42
42
  ```python
43
43
  (> expr1 expr2 expr3 ...)
44
44
  ```
45
- LisPy version
45
+ Python version
46
46
  ```python
47
47
  expr1 > expr2 > expr3 > ...
48
48
  ```
@@ -0,0 +1,41 @@
1
+ ## REPL
2
+ ```shell
3
+ lpy
4
+ #or
5
+ lpy -t #if you want to print python translation.
6
+ ```
7
+
8
+ The REPL features Emacs-style keybindings (C-a, C-e, C-b, C-f, M-b, M-f, etc.), arrow key navigation, and persistent command history saved to `~/.lpy_history`.
9
+
10
+ ### Auto-closing pairs
11
+
12
+ The REPL automatically inserts closing brackets and quotes when you type an opening one:
13
+
14
+ | You type | REPL inserts | Cursor position |
15
+ |----------|-------------|-----------------|
16
+ | `(` | `()` | between `(` and `)` |
17
+ | `[` | `[]` | between `[` and `]` |
18
+ | `{` | `{}` | between `{` and `}` |
19
+ | `'` | `''` | between the quotes |
20
+ | `"` | `""` | between the quotes |
21
+
22
+ - Typing a closing character (`)`, `]`, `}`) when the cursor is already before one will skip over it instead of inserting a duplicate.
23
+ - Typing a quote (`'`, `"`) when the cursor is before the same quote will skip over it.
24
+ - Pressing backspace between an empty pair deletes both characters.
25
+
26
+ ## Run from source
27
+ ```shell
28
+ lpy {filename}.lpy
29
+ ```
30
+ ## Run translation
31
+ ```shell
32
+ l2py {filename}.lpy
33
+ ```
34
+ It just displays translation. (don't run it)
35
+ ## Run Tests (for development)
36
+ ```shell
37
+ # in project root directory
38
+ pytest
39
+ #or
40
+ lpy -m pytest
41
+ ```
@@ -1,6 +1,6 @@
1
1
  site_name: LisPython
2
2
 
3
- copyright: Copytright © 2023-2025 Jetack
3
+ copyright: Copyright © 2023-2026 Jetack
4
4
 
5
5
  plugins:
6
6
  - macros:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lispython"
3
- version = "0.4.5"
3
+ version = "0.4.7"
4
4
  description = "Lisp-like Syntax for Python with Lisp-like Macros"
5
5
  authors = [{ name = "Jetack", email = "jetack23@gmail.com" }]
6
6
  license = { text = "MIT" }
@@ -107,7 +107,8 @@ def ifexp_p(sexp):
107
107
 
108
108
 
109
109
  def ifexp_compile(sexp):
110
- [_, test, body, orelse] = sexp.list
110
+ [_, test, body, *rest] = sexp.list
111
+ orelse = rest[0] if rest else Constant("None", **sexp.position_info)
111
112
  return ast.IfExp(
112
113
  test=expr_compile(test),
113
114
  body=expr_compile(body),
@@ -40,14 +40,19 @@ def define_macro(sexp, scope, include_meta=True):
40
40
 
41
41
  def require_macro(sexp, scope, include_meta=True):
42
42
  transformed = require_transform(sexp)
43
- eval(
44
- compile(
45
- ast.Interactive(body=macroexpand_then_compile([transformed], include_meta=include_meta)),
46
- "macro-requiring",
47
- "single",
48
- ),
49
- scope,
50
- )
43
+ try:
44
+ eval(
45
+ compile(
46
+ ast.Interactive(body=macroexpand_then_compile([transformed], include_meta=include_meta)),
47
+ "macro-requiring",
48
+ "single",
49
+ ),
50
+ scope,
51
+ )
52
+ except (ModuleNotFoundError, ImportError):
53
+ import sys
54
+ module_name = str(sexp.list[1])
55
+ print(f"l2py: warning: could not load macros from '{module_name}' (module not found)", file=sys.stderr)
51
56
  return transformed if include_meta else None
52
57
 
53
58
 
@@ -369,7 +369,7 @@ class Symbol(Literal):
369
369
 
370
370
  @property
371
371
  def name(self):
372
- return self.value.replace("-", "_")
372
+ return self.value.replace("->", "_to_").replace("-", "_").replace("?", "_p")
373
373
 
374
374
  def __repr__(self):
375
375
  return "Sym(" + self.value + ")"
@@ -751,6 +751,85 @@
751
751
  :range (make-range lineno 0 lineno 0))])))))
752
752
  (return None)))
753
753
 
754
+ ;; ---------------------------------------------------------------------------
755
+ ;; Completion
756
+ ;; ---------------------------------------------------------------------------
757
+
758
+ (= _LPY-KEYWORDS
759
+ ["defn" "cond" "conde" "ife" "when" "unless"
760
+ "do" "deco" "require" "fn" "match" "case"
761
+ "async-def" "async-for" "async-with"
762
+ "yield-from" "except*"
763
+ "->" "->>" "as->"
764
+ "gensym" "pprint"])
765
+
766
+ (deco (server.feature
767
+ lsp.TEXT_DOCUMENT_COMPLETION
768
+ (lsp.CompletionOptions :trigger-characters ["." "-"]))
769
+ (def completion [ls params]
770
+ (= doc (.get-text-document ls.workspace params.text_document.uri))
771
+ (= pos params.position)
772
+ (= items [])
773
+ (= seen (set))
774
+
775
+ ;; 1. Special forms
776
+ (for name in SPECIAL-FORM-DOCS
777
+ (if (not (in name seen))
778
+ (do (seen.add name)
779
+ (items.append
780
+ (lsp.CompletionItem
781
+ :label name
782
+ :kind lsp.CompletionItemKind.Keyword
783
+ :detail "special form")))))
784
+
785
+ ;; 2. LisPython-specific keywords
786
+ (for name in _LPY-KEYWORDS
787
+ (if (not (in name seen))
788
+ (do (seen.add name)
789
+ (items.append
790
+ (lsp.CompletionItem
791
+ :label name
792
+ :kind lsp.CompletionItemKind.Keyword
793
+ :detail "keyword")))))
794
+
795
+ ;; 3. Python builtins
796
+ (for [name info] in (BUILTIN-INFO.items)
797
+ (if (not (in name seen))
798
+ (do (seen.add name)
799
+ (= kind (ife (isinstance (getattr builtins name None) type)
800
+ lsp.CompletionItemKind.Class
801
+ lsp.CompletionItemKind.Function))
802
+ (items.append
803
+ (lsp.CompletionItem
804
+ :label name
805
+ :kind kind
806
+ :detail (or (.get info "signature") ""))))))
807
+
808
+ ;; 4. Symbols from current file
809
+ (try
810
+ (= tree (parse doc.source))
811
+ (= defs (collect-definitions tree doc.uri))
812
+ (for name in defs
813
+ (if (not (in name seen))
814
+ (do (seen.add name)
815
+ (items.append
816
+ (lsp.CompletionItem
817
+ :label name
818
+ :kind lsp.CompletionItemKind.Variable)))))
819
+ (except [Exception] (pass)))
820
+
821
+ ;; 5. Workspace symbols
822
+ (for name in WORKSPACE-INDEX
823
+ (if (not (in name seen))
824
+ (do (seen.add name)
825
+ (items.append
826
+ (lsp.CompletionItem
827
+ :label name
828
+ :kind lsp.CompletionItemKind.Variable
829
+ :detail "workspace")))))
830
+
831
+ (return (lsp.CompletionList :is-incomplete False :items items))))
832
+
754
833
  (deco (server.feature lsp.TEXT_DOCUMENT_REFERENCES)
755
834
  (def references [ls params]
756
835
  (= doc (.get-text-document ls.workspace params.text_document.uri))
@@ -5,8 +5,8 @@
5
5
  (return `(if ~test ~then (cond ~@orelse))))))
6
6
 
7
7
  (defmacro conde [*body]
8
- (if (< (len body) 4)
9
- (return `(ife ~@body))
8
+ (if (<= (len body) 2)
9
+ (return (sub body -1))
10
10
  (do (= [test then *orelse] body)
11
11
  (return `(ife ~test ~then (conde ~@orelse))))))
12
12