namel3ss 0.1.0a0__py3-none-any.whl

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 (157) hide show
  1. namel3ss/__init__.py +4 -0
  2. namel3ss/ast/__init__.py +5 -0
  3. namel3ss/ast/agents.py +13 -0
  4. namel3ss/ast/ai.py +23 -0
  5. namel3ss/ast/base.py +10 -0
  6. namel3ss/ast/expressions.py +55 -0
  7. namel3ss/ast/nodes.py +86 -0
  8. namel3ss/ast/pages.py +43 -0
  9. namel3ss/ast/program.py +22 -0
  10. namel3ss/ast/records.py +27 -0
  11. namel3ss/ast/statements.py +107 -0
  12. namel3ss/ast/tool.py +11 -0
  13. namel3ss/cli/__init__.py +2 -0
  14. namel3ss/cli/actions_mode.py +39 -0
  15. namel3ss/cli/app_loader.py +22 -0
  16. namel3ss/cli/commands/action.py +27 -0
  17. namel3ss/cli/commands/run.py +43 -0
  18. namel3ss/cli/commands/ui.py +26 -0
  19. namel3ss/cli/commands/validate.py +23 -0
  20. namel3ss/cli/format_mode.py +30 -0
  21. namel3ss/cli/io/json_io.py +19 -0
  22. namel3ss/cli/io/read_source.py +16 -0
  23. namel3ss/cli/json_io.py +21 -0
  24. namel3ss/cli/lint_mode.py +29 -0
  25. namel3ss/cli/main.py +135 -0
  26. namel3ss/cli/new_mode.py +146 -0
  27. namel3ss/cli/runner.py +28 -0
  28. namel3ss/cli/studio_mode.py +22 -0
  29. namel3ss/cli/ui_mode.py +14 -0
  30. namel3ss/config/__init__.py +4 -0
  31. namel3ss/config/dotenv.py +33 -0
  32. namel3ss/config/loader.py +83 -0
  33. namel3ss/config/model.py +49 -0
  34. namel3ss/errors/__init__.py +2 -0
  35. namel3ss/errors/base.py +34 -0
  36. namel3ss/errors/render.py +22 -0
  37. namel3ss/format/__init__.py +3 -0
  38. namel3ss/format/formatter.py +18 -0
  39. namel3ss/format/rules.py +97 -0
  40. namel3ss/ir/__init__.py +3 -0
  41. namel3ss/ir/lowering/__init__.py +4 -0
  42. namel3ss/ir/lowering/agents.py +42 -0
  43. namel3ss/ir/lowering/ai.py +45 -0
  44. namel3ss/ir/lowering/expressions.py +49 -0
  45. namel3ss/ir/lowering/flow.py +21 -0
  46. namel3ss/ir/lowering/pages.py +48 -0
  47. namel3ss/ir/lowering/program.py +34 -0
  48. namel3ss/ir/lowering/records.py +25 -0
  49. namel3ss/ir/lowering/statements.py +122 -0
  50. namel3ss/ir/lowering/tools.py +16 -0
  51. namel3ss/ir/model/__init__.py +50 -0
  52. namel3ss/ir/model/agents.py +33 -0
  53. namel3ss/ir/model/ai.py +31 -0
  54. namel3ss/ir/model/base.py +20 -0
  55. namel3ss/ir/model/expressions.py +50 -0
  56. namel3ss/ir/model/pages.py +43 -0
  57. namel3ss/ir/model/program.py +28 -0
  58. namel3ss/ir/model/statements.py +76 -0
  59. namel3ss/ir/model/tools.py +11 -0
  60. namel3ss/ir/nodes.py +88 -0
  61. namel3ss/lexer/__init__.py +2 -0
  62. namel3ss/lexer/lexer.py +152 -0
  63. namel3ss/lexer/tokens.py +98 -0
  64. namel3ss/lint/__init__.py +4 -0
  65. namel3ss/lint/engine.py +125 -0
  66. namel3ss/lint/semantic.py +45 -0
  67. namel3ss/lint/text_scan.py +70 -0
  68. namel3ss/lint/types.py +22 -0
  69. namel3ss/parser/__init__.py +3 -0
  70. namel3ss/parser/agent.py +78 -0
  71. namel3ss/parser/ai.py +113 -0
  72. namel3ss/parser/constraints.py +37 -0
  73. namel3ss/parser/core.py +166 -0
  74. namel3ss/parser/expressions.py +105 -0
  75. namel3ss/parser/flow.py +37 -0
  76. namel3ss/parser/pages.py +76 -0
  77. namel3ss/parser/program.py +45 -0
  78. namel3ss/parser/records.py +66 -0
  79. namel3ss/parser/statements/__init__.py +27 -0
  80. namel3ss/parser/statements/control_flow.py +116 -0
  81. namel3ss/parser/statements/core.py +66 -0
  82. namel3ss/parser/statements/data.py +17 -0
  83. namel3ss/parser/statements/letset.py +22 -0
  84. namel3ss/parser/statements.py +1 -0
  85. namel3ss/parser/tokens.py +35 -0
  86. namel3ss/parser/tool.py +29 -0
  87. namel3ss/runtime/__init__.py +3 -0
  88. namel3ss/runtime/ai/http/client.py +24 -0
  89. namel3ss/runtime/ai/mock_provider.py +5 -0
  90. namel3ss/runtime/ai/provider.py +29 -0
  91. namel3ss/runtime/ai/providers/__init__.py +18 -0
  92. namel3ss/runtime/ai/providers/_shared/errors.py +20 -0
  93. namel3ss/runtime/ai/providers/_shared/parse.py +18 -0
  94. namel3ss/runtime/ai/providers/anthropic.py +55 -0
  95. namel3ss/runtime/ai/providers/gemini.py +50 -0
  96. namel3ss/runtime/ai/providers/mistral.py +51 -0
  97. namel3ss/runtime/ai/providers/mock.py +23 -0
  98. namel3ss/runtime/ai/providers/ollama.py +39 -0
  99. namel3ss/runtime/ai/providers/openai.py +55 -0
  100. namel3ss/runtime/ai/providers/registry.py +38 -0
  101. namel3ss/runtime/ai/trace.py +18 -0
  102. namel3ss/runtime/executor/__init__.py +3 -0
  103. namel3ss/runtime/executor/agents.py +91 -0
  104. namel3ss/runtime/executor/ai_runner.py +90 -0
  105. namel3ss/runtime/executor/api.py +54 -0
  106. namel3ss/runtime/executor/assign.py +40 -0
  107. namel3ss/runtime/executor/context.py +31 -0
  108. namel3ss/runtime/executor/executor.py +77 -0
  109. namel3ss/runtime/executor/expr_eval.py +110 -0
  110. namel3ss/runtime/executor/records_ops.py +64 -0
  111. namel3ss/runtime/executor/result.py +13 -0
  112. namel3ss/runtime/executor/signals.py +6 -0
  113. namel3ss/runtime/executor/statements.py +99 -0
  114. namel3ss/runtime/memory/manager.py +52 -0
  115. namel3ss/runtime/memory/profile.py +17 -0
  116. namel3ss/runtime/memory/semantic.py +20 -0
  117. namel3ss/runtime/memory/short_term.py +18 -0
  118. namel3ss/runtime/records/service.py +105 -0
  119. namel3ss/runtime/store/__init__.py +2 -0
  120. namel3ss/runtime/store/memory_store.py +62 -0
  121. namel3ss/runtime/tools/registry.py +13 -0
  122. namel3ss/runtime/ui/__init__.py +2 -0
  123. namel3ss/runtime/ui/actions.py +124 -0
  124. namel3ss/runtime/validators/__init__.py +2 -0
  125. namel3ss/runtime/validators/constraints.py +126 -0
  126. namel3ss/schema/__init__.py +2 -0
  127. namel3ss/schema/records.py +52 -0
  128. namel3ss/studio/__init__.py +4 -0
  129. namel3ss/studio/api.py +115 -0
  130. namel3ss/studio/edit/__init__.py +3 -0
  131. namel3ss/studio/edit/ops.py +80 -0
  132. namel3ss/studio/edit/selectors.py +74 -0
  133. namel3ss/studio/edit/transform.py +39 -0
  134. namel3ss/studio/server.py +175 -0
  135. namel3ss/studio/session.py +11 -0
  136. namel3ss/studio/web/app.js +248 -0
  137. namel3ss/studio/web/index.html +44 -0
  138. namel3ss/studio/web/styles.css +42 -0
  139. namel3ss/templates/__init__.py +3 -0
  140. namel3ss/templates/__pycache__/__init__.cpython-312.pyc +0 -0
  141. namel3ss/templates/ai_assistant/.gitignore +1 -0
  142. namel3ss/templates/ai_assistant/README.md +10 -0
  143. namel3ss/templates/ai_assistant/app.ai +30 -0
  144. namel3ss/templates/crud/.gitignore +1 -0
  145. namel3ss/templates/crud/README.md +10 -0
  146. namel3ss/templates/crud/app.ai +26 -0
  147. namel3ss/templates/multi_agent/.gitignore +1 -0
  148. namel3ss/templates/multi_agent/README.md +10 -0
  149. namel3ss/templates/multi_agent/app.ai +43 -0
  150. namel3ss/ui/__init__.py +2 -0
  151. namel3ss/ui/manifest.py +220 -0
  152. namel3ss/utils/__init__.py +2 -0
  153. namel3ss-0.1.0a0.dist-info/METADATA +123 -0
  154. namel3ss-0.1.0a0.dist-info/RECORD +157 -0
  155. namel3ss-0.1.0a0.dist-info/WHEEL +5 -0
  156. namel3ss-0.1.0a0.dist-info/entry_points.txt +2 -0
  157. namel3ss-0.1.0a0.dist-info/top_level.txt +1 -0
namel3ss/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ """
2
+ Namel3ss: an English-first, AI-native full-stack programming language runtime package.
3
+ """
4
+
@@ -0,0 +1,5 @@
1
+ """Abstract syntax tree definitions for Namel3ss."""
2
+
3
+ from namel3ss.ast import nodes # noqa: F401
4
+
5
+ __all__ = ["nodes"]
namel3ss/ast/agents.py ADDED
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Optional
5
+
6
+ from namel3ss.ast.base import Node
7
+
8
+
9
+ @dataclass
10
+ class AgentDecl(Node):
11
+ name: str
12
+ ai_name: str
13
+ system_prompt: Optional[str]
namel3ss/ast/ai.py ADDED
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List, Optional
5
+
6
+ from namel3ss.ast.base import Node
7
+
8
+
9
+ @dataclass
10
+ class AIMemory(Node):
11
+ short_term: int = 0
12
+ semantic: bool = False
13
+ profile: bool = False
14
+
15
+
16
+ @dataclass
17
+ class AIDecl(Node):
18
+ name: str
19
+ model: str
20
+ provider: str | None
21
+ system_prompt: Optional[str]
22
+ exposed_tools: List[str]
23
+ memory: AIMemory
namel3ss/ast/base.py ADDED
@@ -0,0 +1,10 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Optional
5
+
6
+
7
+ @dataclass
8
+ class Node:
9
+ line: Optional[int]
10
+ column: Optional[int]
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List, Optional, Union
5
+
6
+ from namel3ss.ast.base import Node
7
+
8
+
9
+ @dataclass
10
+ class Expression(Node):
11
+ pass
12
+
13
+
14
+ @dataclass
15
+ class Literal(Expression):
16
+ value: Union[str, int, bool]
17
+
18
+
19
+ @dataclass
20
+ class VarReference(Expression):
21
+ name: str
22
+
23
+
24
+ @dataclass
25
+ class AttrAccess(Expression):
26
+ base: str
27
+ attrs: List[str]
28
+
29
+
30
+ @dataclass
31
+ class StatePath(Expression):
32
+ path: List[str]
33
+
34
+
35
+ @dataclass
36
+ class UnaryOp(Expression):
37
+ op: str
38
+ operand: Expression
39
+
40
+
41
+ @dataclass
42
+ class BinaryOp(Expression):
43
+ op: str
44
+ left: Expression
45
+ right: Expression
46
+
47
+
48
+ @dataclass
49
+ class Comparison(Expression):
50
+ kind: str # eq, gt, lt
51
+ left: Expression
52
+ right: Expression
53
+
54
+
55
+ Assignable = Union[VarReference, StatePath]
namel3ss/ast/nodes.py ADDED
@@ -0,0 +1,86 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List, Optional, Union
5
+
6
+ from namel3ss.ast.agents import AgentDecl
7
+ from namel3ss.ast.ai import AIDecl, AIMemory
8
+ from namel3ss.ast.base import Node
9
+ from namel3ss.ast.expressions import (
10
+ Assignable,
11
+ AttrAccess,
12
+ BinaryOp,
13
+ Comparison,
14
+ Expression,
15
+ Literal,
16
+ StatePath,
17
+ UnaryOp,
18
+ VarReference,
19
+ )
20
+ from namel3ss.ast.pages import ButtonItem, FormItem, PageDecl, PageItem, TableItem, TextItem, TitleItem
21
+ from namel3ss.ast.program import Flow, Program
22
+ from namel3ss.ast.statements import (
23
+ AskAIStmt,
24
+ Find,
25
+ ForEach,
26
+ If,
27
+ Let,
28
+ Match,
29
+ MatchCase,
30
+ ParallelAgentEntry,
31
+ Repeat,
32
+ Return,
33
+ RunAgentStmt,
34
+ RunAgentsParallelStmt,
35
+ Save,
36
+ Set,
37
+ Statement,
38
+ TryCatch,
39
+ )
40
+ from namel3ss.ast.tool import ToolDecl
41
+ from namel3ss.ast.records import FieldConstraint, FieldDecl, RecordDecl
42
+
43
+ __all__ = [
44
+ "Node",
45
+ "Flow",
46
+ "Program",
47
+ "Statement",
48
+ "Let",
49
+ "Set",
50
+ "If",
51
+ "Return",
52
+ "AskAIStmt",
53
+ "RunAgentStmt",
54
+ "ParallelAgentEntry",
55
+ "RunAgentsParallelStmt",
56
+ "Repeat",
57
+ "ForEach",
58
+ "MatchCase",
59
+ "Match",
60
+ "TryCatch",
61
+ "Save",
62
+ "Find",
63
+ "Expression",
64
+ "Literal",
65
+ "VarReference",
66
+ "AttrAccess",
67
+ "StatePath",
68
+ "UnaryOp",
69
+ "BinaryOp",
70
+ "Comparison",
71
+ "Assignable",
72
+ "FieldConstraint",
73
+ "FieldDecl",
74
+ "RecordDecl",
75
+ "PageItem",
76
+ "TitleItem",
77
+ "TextItem",
78
+ "FormItem",
79
+ "TableItem",
80
+ "ButtonItem",
81
+ "PageDecl",
82
+ "AIDecl",
83
+ "AIMemory",
84
+ "ToolDecl",
85
+ "AgentDecl",
86
+ ]
namel3ss/ast/pages.py ADDED
@@ -0,0 +1,43 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List
5
+
6
+ from namel3ss.ast.base import Node
7
+
8
+
9
+ @dataclass
10
+ class PageItem(Node):
11
+ pass
12
+
13
+
14
+ @dataclass
15
+ class TitleItem(PageItem):
16
+ value: str
17
+
18
+
19
+ @dataclass
20
+ class TextItem(PageItem):
21
+ value: str
22
+
23
+
24
+ @dataclass
25
+ class FormItem(PageItem):
26
+ record_name: str
27
+
28
+
29
+ @dataclass
30
+ class TableItem(PageItem):
31
+ record_name: str
32
+
33
+
34
+ @dataclass
35
+ class ButtonItem(PageItem):
36
+ label: str
37
+ flow_name: str
38
+
39
+
40
+ @dataclass
41
+ class PageDecl(Node):
42
+ name: str
43
+ items: List[PageItem]
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List
5
+
6
+ from namel3ss.ast.base import Node
7
+
8
+
9
+ @dataclass
10
+ class Flow(Node):
11
+ name: str
12
+ body: List["Statement"]
13
+
14
+
15
+ @dataclass
16
+ class Program(Node):
17
+ records: List["RecordDecl"]
18
+ flows: List[Flow]
19
+ pages: List["PageDecl"]
20
+ ais: List["AIDecl"]
21
+ tools: List["ToolDecl"]
22
+ agents: List["AgentDecl"]
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List, Optional
5
+
6
+ from namel3ss.ast.base import Node
7
+ from namel3ss.ast.expressions import Expression
8
+
9
+
10
+ @dataclass
11
+ class FieldConstraint(Node):
12
+ kind: str # present, unique, gt, lt, pattern, len_min, len_max
13
+ expression: Optional[Expression] = None
14
+ pattern: Optional[str] = None
15
+
16
+
17
+ @dataclass
18
+ class FieldDecl(Node):
19
+ name: str
20
+ type_name: str
21
+ constraint: Optional[FieldConstraint]
22
+
23
+
24
+ @dataclass
25
+ class RecordDecl(Node):
26
+ name: str
27
+ fields: List[FieldDecl]
@@ -0,0 +1,107 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List, Optional
5
+
6
+ from namel3ss.ast.base import Node
7
+ from namel3ss.ast.expressions import Assignable, Expression
8
+
9
+
10
+ @dataclass
11
+ class Statement(Node):
12
+ pass
13
+
14
+
15
+ @dataclass
16
+ class Let(Statement):
17
+ name: str
18
+ expression: Expression
19
+ constant: bool = False
20
+
21
+
22
+ @dataclass
23
+ class Set(Statement):
24
+ target: Assignable
25
+ expression: Expression
26
+
27
+
28
+ @dataclass
29
+ class If(Statement):
30
+ condition: Expression
31
+ then_body: List[Statement]
32
+ else_body: List[Statement]
33
+
34
+
35
+ @dataclass
36
+ class Return(Statement):
37
+ expression: Expression
38
+
39
+
40
+ @dataclass
41
+ class AskAIStmt(Statement):
42
+ ai_name: str
43
+ input_expr: Expression
44
+ target: str
45
+
46
+
47
+ @dataclass
48
+ class RunAgentStmt(Statement):
49
+ agent_name: str
50
+ input_expr: Expression
51
+ target: str
52
+
53
+
54
+ @dataclass
55
+ class ParallelAgentEntry(Node):
56
+ agent_name: str
57
+ input_expr: Expression
58
+
59
+
60
+ @dataclass
61
+ class RunAgentsParallelStmt(Statement):
62
+ entries: List[ParallelAgentEntry]
63
+ target: str
64
+
65
+
66
+ @dataclass
67
+ class Repeat(Statement):
68
+ count: Expression
69
+ body: List[Statement]
70
+
71
+
72
+ @dataclass
73
+ class ForEach(Statement):
74
+ name: str
75
+ iterable: Expression
76
+ body: List[Statement]
77
+
78
+
79
+ @dataclass
80
+ class MatchCase(Node):
81
+ pattern: Expression
82
+ body: List[Statement]
83
+
84
+
85
+ @dataclass
86
+ class Match(Statement):
87
+ expression: Expression
88
+ cases: List[MatchCase]
89
+ otherwise: Optional[List[Statement]]
90
+
91
+
92
+ @dataclass
93
+ class TryCatch(Statement):
94
+ try_body: List[Statement]
95
+ catch_var: str
96
+ catch_body: List[Statement]
97
+
98
+
99
+ @dataclass
100
+ class Save(Statement):
101
+ record_name: str
102
+
103
+
104
+ @dataclass
105
+ class Find(Statement):
106
+ record_name: str
107
+ predicate: Expression
namel3ss/ast/tool.py ADDED
@@ -0,0 +1,11 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from namel3ss.ast.base import Node
6
+
7
+
8
+ @dataclass
9
+ class ToolDecl(Node):
10
+ name: str
11
+ kind: str
@@ -0,0 +1,2 @@
1
+ """Command-line interface for Namel3ss."""
2
+
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+
3
+ from namel3ss.runtime.store.memory_store import MemoryStore
4
+ from namel3ss.ui.manifest import build_manifest
5
+
6
+
7
+ def list_actions(program_ir, json_mode: bool) -> tuple[dict | None, str | None]:
8
+ manifest = build_manifest(program_ir, state={}, store=MemoryStore())
9
+ actions = manifest.get("actions", {})
10
+ sorted_ids = sorted(actions.keys())
11
+ if json_mode:
12
+ data = []
13
+ for action_id in sorted_ids:
14
+ entry = actions[action_id]
15
+ item = {"id": action_id, "type": entry.get("type")}
16
+ if entry.get("type") == "call_flow":
17
+ item["flow"] = entry.get("flow")
18
+ if entry.get("type") == "submit_form":
19
+ item["record"] = entry.get("record")
20
+ data.append(item)
21
+ return (
22
+ {
23
+ "ok": True,
24
+ "count": len(data),
25
+ "actions": data,
26
+ },
27
+ None,
28
+ )
29
+ lines = []
30
+ for action_id in sorted_ids:
31
+ entry = actions[action_id]
32
+ details: list[str] = []
33
+ if entry.get("type") == "call_flow" and entry.get("flow"):
34
+ details.append(f"flow={entry['flow']}")
35
+ if entry.get("type") == "submit_form" and entry.get("record"):
36
+ details.append(f"record={entry['record']}")
37
+ detail_str = f" {' '.join(details)}" if details else ""
38
+ lines.append(f"{action_id} {entry.get('type')} {detail_str}".rstrip())
39
+ return None, "\n".join(lines)
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from namel3ss.errors.base import Namel3ssError
6
+ from namel3ss.ir.nodes import lower_program
7
+ from namel3ss.parser.core import parse
8
+ from namel3ss.config.dotenv import apply_dotenv, load_dotenv_for_path
9
+
10
+
11
+ def load_program(path_str: str) -> tuple[object, str]:
12
+ path = Path(path_str)
13
+ if path.suffix != ".ai":
14
+ raise Namel3ssError("Input file must have .ai extension")
15
+ apply_dotenv(load_dotenv_for_path(str(path)))
16
+ try:
17
+ source = path.read_text(encoding="utf-8")
18
+ except FileNotFoundError as err:
19
+ raise Namel3ssError(f"File not found: {path}") from err
20
+ ast_program = parse(source)
21
+ program_ir = lower_program(ast_program)
22
+ return program_ir, source
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+
5
+ from namel3ss.errors.base import Namel3ssError
6
+ from namel3ss.errors.render import format_error
7
+ from namel3ss.ir.nodes import lower_program
8
+ from namel3ss.parser.core import parse
9
+ from namel3ss.runtime.store.memory_store import MemoryStore
10
+ from namel3ss.runtime.ui.actions import handle_action
11
+ from namel3ss.cli.io.json_io import dumps_pretty, parse_json
12
+ from namel3ss.cli.io.read_source import read_source
13
+
14
+
15
+ def run(args) -> int:
16
+ source = ""
17
+ try:
18
+ source, _ = read_source(args.path)
19
+ ast_program = parse(source)
20
+ program_ir = lower_program(ast_program)
21
+ payload = parse_json(args.payload or "{}")
22
+ response = handle_action(program_ir, action_id=args.id, payload=payload, state={}, store=MemoryStore())
23
+ print(dumps_pretty(response))
24
+ return 0
25
+ except Namel3ssError as err:
26
+ print(format_error(err, source), file=sys.stderr)
27
+ return 1
@@ -0,0 +1,43 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+
5
+ from namel3ss.errors.base import Namel3ssError
6
+ from namel3ss.errors.render import format_error
7
+ from namel3ss.ir.nodes import lower_program
8
+ from namel3ss.parser.core import parse
9
+ from namel3ss.runtime.executor import execute_program_flow
10
+ from namel3ss.runtime.store.memory_store import MemoryStore
11
+ from namel3ss.cli.io.json_io import dumps_pretty
12
+ from namel3ss.cli.io.read_source import read_source
13
+
14
+
15
+ def run(args) -> int:
16
+ source = ""
17
+ try:
18
+ source, path = read_source(args.path)
19
+ ast_program = parse(source)
20
+ program_ir = lower_program(ast_program)
21
+ flow_name = _select_flow(program_ir, args.flow)
22
+ result = execute_program_flow(program_ir, flow_name, state={}, input={}, store=MemoryStore())
23
+ traces = [_trace_to_dict(t) for t in result.traces]
24
+ output = {"ok": True, "state": result.state, "result": result.last_value, "traces": traces}
25
+ print(dumps_pretty(output))
26
+ return 0
27
+ except Namel3ssError as err:
28
+ print(format_error(err, source), file=sys.stderr)
29
+ return 1
30
+
31
+
32
+ def _select_flow(program_ir, flow_flag: str | None) -> str:
33
+ if flow_flag:
34
+ return flow_flag
35
+ if len(program_ir.flows) == 1:
36
+ return program_ir.flows[0].name
37
+ raise Namel3ssError("Multiple flows found; specify --flow")
38
+
39
+
40
+ def _trace_to_dict(trace) -> dict:
41
+ if hasattr(trace, "__dict__"):
42
+ return trace.__dict__
43
+ return trace if isinstance(trace, dict) else {"value": trace}
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+
5
+ from namel3ss.errors.base import Namel3ssError
6
+ from namel3ss.errors.render import format_error
7
+ from namel3ss.ir.nodes import lower_program
8
+ from namel3ss.parser.core import parse
9
+ from namel3ss.runtime.store.memory_store import MemoryStore
10
+ from namel3ss.ui.manifest import build_manifest
11
+ from namel3ss.cli.io.json_io import dumps_pretty
12
+ from namel3ss.cli.io.read_source import read_source
13
+
14
+
15
+ def run(args) -> int:
16
+ source = ""
17
+ try:
18
+ source, _ = read_source(args.path)
19
+ ast_program = parse(source)
20
+ program_ir = lower_program(ast_program)
21
+ manifest = build_manifest(program_ir, state={}, store=MemoryStore())
22
+ print(dumps_pretty(manifest))
23
+ return 0
24
+ except Namel3ssError as err:
25
+ print(format_error(err, source), file=sys.stderr)
26
+ return 1
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+
5
+ from namel3ss.errors.base import Namel3ssError
6
+ from namel3ss.errors.render import format_error
7
+ from namel3ss.ir.nodes import lower_program
8
+ from namel3ss.parser.core import parse
9
+
10
+
11
+ def run(args) -> int:
12
+ source = ""
13
+ try:
14
+ from namel3ss.cli.io.read_source import read_source
15
+
16
+ source, _ = read_source(args.path)
17
+ ast_program = parse(source)
18
+ lower_program(ast_program)
19
+ print("Validation succeeded.")
20
+ return 0
21
+ except Namel3ssError as err:
22
+ print(format_error(err, source), file=sys.stderr)
23
+ return 1
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from namel3ss.errors.base import Namel3ssError
6
+ from namel3ss.errors.render import format_error
7
+ from namel3ss.format.formatter import format_source
8
+
9
+
10
+ def run_format(path_str: str, check_only: bool) -> int:
11
+ path = Path(path_str)
12
+ if path.suffix != ".ai":
13
+ raise Namel3ssError("Input file must have .ai extension")
14
+ try:
15
+ source = path.read_text(encoding="utf-8")
16
+ except FileNotFoundError as err:
17
+ raise Namel3ssError(f"File not found: {path}") from err
18
+ formatted = format_source(source)
19
+ if check_only:
20
+ if formatted == source:
21
+ print("OK")
22
+ return 0
23
+ print("Needs formatting")
24
+ return 1
25
+ if formatted == source:
26
+ print("Already formatted")
27
+ return 0
28
+ path.write_text(formatted, encoding="utf-8")
29
+ print("Formatted")
30
+ return 0
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+
5
+ from namel3ss.errors.base import Namel3ssError
6
+
7
+
8
+ def parse_json(text: str) -> dict:
9
+ try:
10
+ data = json.loads(text) if text else {}
11
+ except json.JSONDecodeError as exc:
12
+ raise Namel3ssError(f"Invalid JSON payload: {exc.msg}") from exc
13
+ if not isinstance(data, dict):
14
+ raise Namel3ssError("Payload JSON must be an object")
15
+ return data
16
+
17
+
18
+ def dumps_pretty(obj: object) -> str:
19
+ return json.dumps(obj, indent=2, ensure_ascii=False)
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from namel3ss.errors.base import Namel3ssError
6
+
7
+
8
+ def read_source(path_str: str) -> tuple[str, str]:
9
+ path = Path(path_str)
10
+ if path.suffix != ".ai":
11
+ raise Namel3ssError("Input file must have .ai extension")
12
+ try:
13
+ text = path.read_text(encoding="utf-8")
14
+ except FileNotFoundError as err:
15
+ raise Namel3ssError(f"File not found: {path}") from err
16
+ return text, str(path)