future-lang 0.3.0

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 (47) hide show
  1. package/ARCHITECTURE.md +424 -0
  2. package/MIGRATION.md +365 -0
  3. package/README.md +370 -0
  4. package/ROADMAP.md +263 -0
  5. package/examples/adult.future +8 -0
  6. package/examples/api.future +11 -0
  7. package/examples/assistant.future +8 -0
  8. package/examples/browser-demo.html +164 -0
  9. package/examples/greet.future +7 -0
  10. package/examples/hello.future +1 -0
  11. package/examples/math.future +8 -0
  12. package/examples/mini-app.html +301 -0
  13. package/examples/smarthome.future +10 -0
  14. package/future-browser.js +102 -0
  15. package/future-playground.html +650 -0
  16. package/package.json +27 -0
  17. package/runtime/ai.js +92 -0
  18. package/runtime/browser.js +458 -0
  19. package/runtime/device.js +36 -0
  20. package/runtime/home.js +19 -0
  21. package/runtime/http.js +32 -0
  22. package/runtime/index.js +403 -0
  23. package/runtime/lsp-metadata.js +104 -0
  24. package/runtime/math.js +16 -0
  25. package/runtime/memory.js +61 -0
  26. package/runtime/mqtt.js +49 -0
  27. package/runtime/providers/anthropic.js +59 -0
  28. package/runtime/providers/index.js +93 -0
  29. package/runtime/providers/openai-compat.js +85 -0
  30. package/runtime/providers/util.js +70 -0
  31. package/runtime/rag/chunker.js +65 -0
  32. package/runtime/rag/pipeline.js +86 -0
  33. package/runtime/rag/vector-store.js +119 -0
  34. package/runtime/rag.js +94 -0
  35. package/runtime/schedule.js +77 -0
  36. package/runtime/system.js +101 -0
  37. package/runtime/tts.js +38 -0
  38. package/runtime/vision.js +85 -0
  39. package/server.js +42 -0
  40. package/src/ast.js +202 -0
  41. package/src/cli.js +391 -0
  42. package/src/errors.js +21 -0
  43. package/src/formatter.js +48 -0
  44. package/src/generator.js +457 -0
  45. package/src/index.js +48 -0
  46. package/src/lexer.js +248 -0
  47. package/src/parser.js +469 -0
@@ -0,0 +1,424 @@
1
+ # Future — Architecture & Folder Structure
2
+
3
+ ## Overview
4
+
5
+ Future is an AI-first, IoT-first programming language that transpiles to JavaScript and runs on Node.js (and in the browser). The compiler is a classic three-phase pipeline: **Lex → Parse → Generate**. Capabilities (AI, HTTP, MQTT, math, …) are runtime modules — adding a new capability never requires a grammar change.
6
+
7
+ ---
8
+
9
+ ## Folder Structure
10
+
11
+ ```
12
+ future-lang/
13
+
14
+ ├── src/ # Compiler frontend
15
+ │ ├── index.js # Public API — compile(source, options)
16
+ │ ├── lexer.js # Phase 1: source text → token list
17
+ │ ├── parser.js # Phase 2: token list → AST
18
+ │ ├── ast.js # AST node types and factory functions (23 types)
19
+ │ ├── generator.js # Phase 3: AST → JavaScript source
20
+ │ ├── errors.js # FutureError with line/column tracking
21
+ │ └── cli.js # CLI binary: future run / future compile
22
+
23
+ ├── runtime/ # Capability modules (imported by generated JS)
24
+ │ ├── index.js # Aggregator: runtime object + manifest + introspection
25
+ │ │
26
+ │ ├── ai.js # Text generation — pluggable provider architecture
27
+ │ ├── http.js # REST API consumption (fetch-based)
28
+ │ ├── mqtt.js # Pub/sub messaging (real broker or in-process loopback)
29
+ │ ├── tts.js # Text-to-speech (system engine)
30
+ │ ├── rag.js # RAG — chunk → embed → store → retrieve → answer
31
+ │ ├── vision.js # Vision AI — describe, detect, ocr, classify, compare
32
+ │ ├── home.js # Home automation (composes over MQTT)
33
+ │ │
34
+ │ ├── memory.js # In-process key-value store (set/get/search/delete/forget)
35
+ │ ├── schedule.js # Recurring / one-shot / cron scheduling
36
+ │ ├── system.js # OS utilities: exec, open, notify, read, write
37
+ │ ├── device.js # IoT device registry
38
+ │ ├── math.js # Math module: round/floor/ceil/abs/sqrt/pow/log/random/min/max/pi/e
39
+ │ ├── browser.js # Browser-compatible runtime (no Node.js deps)
40
+ │ ├── lsp-metadata.js # VSCode / LSP metadata generated from the manifest
41
+ │ │
42
+ │ ├── providers/ # AI provider implementations
43
+ │ │ ├── index.js # Provider factory + env-var resolution
44
+ │ │ ├── anthropic.js # Anthropic Messages API (native format)
45
+ │ │ ├── openai-compat.js # OpenAI-compatible (OpenAI, Ollama, Gemini, OpenRouter, …)
46
+ │ │ └── util.js # SSE parser, keyword vector, cosine similarity
47
+ │ │
48
+ │ └── rag/ # RAG pipeline internals
49
+ │ ├── chunker.js # Document → overlapping text chunks
50
+ │ ├── vector-store.js # Vector store adapters (memory, file, cloud stubs)
51
+ │ └── pipeline.js # Full pipeline: index() and query()
52
+
53
+ ├── test/ # Node built-in test runner suites
54
+ │ ├── lexer.test.js
55
+ │ ├── parser.test.js
56
+ │ ├── generator.test.js
57
+ │ ├── runtime.test.js
58
+ │ ├── capabilities.test.js
59
+ │ └── e2e.test.js
60
+
61
+ ├── examples/ # Demo Future programs
62
+ │ ├── hello.future
63
+ │ ├── greet.future
64
+ │ ├── adult.future
65
+ │ ├── math.future
66
+ │ ├── api.future
67
+ │ ├── assistant.future
68
+ │ └── smarthome.future
69
+
70
+ ├── future-browser.js # Browser entry point: window.Future + <script type="future">
71
+ ├── future-playground.html # In-browser editor (11 examples, live compile)
72
+ ├── package.json
73
+ ├── ARCHITECTURE.md # This file
74
+ ├── ROADMAP.md # Feature roadmap
75
+ └── MIGRATION.md # Changelog and migration notes
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Compiler Pipeline
81
+
82
+ ```
83
+ Source text (.future)
84
+
85
+
86
+ [ Lexer ] src/lexer.js
87
+ Token list 24 keywords, operators, strings, numbers
88
+
89
+
90
+ [ Parser ] src/parser.js
91
+ AST (Program node) Recursive-descent, 23 node types
92
+
93
+
94
+ [ Generator ] src/generator.js
95
+ JavaScript source SIMPLE or ASYNC mode
96
+
97
+
98
+ Node.js / Browser runtime
99
+ (imports future-lang/runtime as __rt)
100
+ ```
101
+
102
+ ### Two output modes
103
+
104
+ | Mode | Trigger | Output |
105
+ |------|---------|--------|
106
+ | **SIMPLE** | No capability calls, no `on`/`every`, no `input()`, no `math.*` | Plain synchronous JS, no imports |
107
+ | **ASYNC** | Any capability call, `on`, `every`, `input()`, `math.*`, `agent`, `stream` | ES module with `import { runtime as __rt }`, all functions `async`, all method calls `await`ed |
108
+
109
+ The user never writes `async` or `await` — the compiler injects them automatically.
110
+
111
+ In **browser mode** (`browserMode: true` option), the `import` statement is omitted and `print` is routed through `__rt.print` so it can be redirected to the DOM.
112
+
113
+ ---
114
+
115
+ ## Lexer
116
+
117
+ ### Keywords (24)
118
+
119
+ | Keyword | Token | Purpose |
120
+ |---------|-------|---------|
121
+ | `print` | PRINT | Output statement |
122
+ | `if` | IF | Conditional |
123
+ | `else` | ELSE | Else branch |
124
+ | `end` | END | Block terminator |
125
+ | `function` | FUNCTION | Function declaration |
126
+ | `return` | RETURN | Return statement |
127
+ | `true` / `false` | TRUE / FALSE | Boolean literals |
128
+ | `and` / `or` / `not` | AND / OR / NOT | Logical operators |
129
+ | `on` | ON | Event subscription |
130
+ | `every` | EVERY | Recurring task |
131
+ | `for` | FOR | List iteration |
132
+ | `in` | IN | Used with `for` |
133
+ | `try` | TRY | Error handling |
134
+ | `catch` | CATCH | Error handler branch |
135
+ | `while` | WHILE | Condition-based loop |
136
+ | `null` / `none` | NULL | Null literal (two spellings) |
137
+ | `stream` | STREAM | Streaming statement |
138
+ | `agent` | AGENT | Agent declaration |
139
+ | `use` | USE | Capability declaration inside `agent` |
140
+
141
+ ### String escape
142
+
143
+ `\{` in source text is stored as the placeholder `\x01` during lexing. The generator converts it back to a literal `{` when building template literals, preventing accidental interpolation.
144
+
145
+ ---
146
+
147
+ ## AST Node Types (23)
148
+
149
+ | Category | Nodes |
150
+ |----------|-------|
151
+ | Program | `Program` |
152
+ | Statements | `PrintStatement`, `Assignment`, `IfStatement`, `FunctionDeclaration`, `ReturnStatement`, `ExpressionStatement` |
153
+ | Control flow | `ForStatement`, `WhileStatement`, `TryStatement` |
154
+ | Event statements | `OnStatement`, `EveryStatement` |
155
+ | AI/IoT statements | `AgentDeclaration`, `StreamStatement` |
156
+ | Expressions | `BinaryExpression`, `UnaryExpression`, `CallExpression`, `MemberExpression` |
157
+ | Literals | `Identifier`, `NumberLiteral`, `StringLiteral`, `BooleanLiteral`, `NullLiteral`, `ArrayLiteral`, `ObjectLiteral` |
158
+
159
+ ---
160
+
161
+ ## Generator
162
+
163
+ ### SIMPLE vs ASYNC detection (`usesRuntime`)
164
+
165
+ The generator walks the full AST before emitting any code. ASYNC mode is triggered by any of:
166
+
167
+ - A `CallExpression` whose callee is `<namespace>.<method>` (namespace call)
168
+ - A `CallExpression` to the built-in `input()` function
169
+ - A `MemberExpression` where the object is a known namespace (e.g. `math.pi`)
170
+ - A `StringLiteral` whose value contains `{namespace.prop}` interpolation
171
+ - An `OnStatement`, `EveryStatement`, `StreamStatement`, or `AgentDeclaration`
172
+
173
+ ### Built-in functions
174
+
175
+ Two built-in identifiers are special-cased in the generator — they do not go through the namespace routing:
176
+
177
+ | Built-in | Trigger ASYNC? | Emitted JS |
178
+ |----------|---------------|------------|
179
+ | `len(x)` | No | `__len(x)` — helper emitted once at top of program |
180
+ | `input(prompt)` | Yes | `await __rt.input(prompt)` |
181
+
182
+ The `__len` helper is only emitted when `len` is actually used:
183
+ ```js
184
+ function __len(x) { return x == null ? 0 : (x.length ?? Object.keys(x).length); }
185
+ ```
186
+
187
+ ### Namespace set
188
+
189
+ ```js
190
+ export const NAMESPACES = new Set([
191
+ 'ai', 'http', 'mqtt', 'tts',
192
+ 'rag', 'vision', 'home',
193
+ 'memory', 'schedule', 'system', 'device',
194
+ 'math',
195
+ ]);
196
+ ```
197
+
198
+ Any identifier in this set, when used as the object of a `MemberExpression` or `CallExpression`, is routed through `__rt` in ASYNC mode. Adding a new capability is just a name in this set plus a matching runtime module — no grammar change.
199
+
200
+ ### String interpolation
201
+
202
+ String literals containing `{identifier}` or `{identifier.prop}` are emitted as JS template literals. Namespace references inside strings are correctly prefixed with `__rt.` in ASYNC mode:
203
+
204
+ ```future
205
+ print "π ≈ {math.pi}"
206
+ ```
207
+
208
+ Emits (async/browser mode):
209
+ ```js
210
+ __rt.print(`π ≈ ${__rt.math.pi}`);
211
+ ```
212
+
213
+ The interpolation logic lives in `Generator.genStringLiteral()` — an instance method so it has access to `this.asyncMode` and `NAMESPACES`.
214
+
215
+ ### Variable hoisting
216
+
217
+ All variables assigned at a scope level are collected by `collectAssignedNames` and declared as `let` at the top of that scope. The collector recurses into `if`, `for`, `while`, and `try/catch` bodies. Loop variables (`const item of …`) and catch variables (`catch (err)`) are **not** hoisted — they are block-scoped by JS design.
218
+
219
+ ### Method call awaiting
220
+
221
+ In ASYNC mode, ALL call expressions where the callee is a `MemberExpression` are `await`ed — including calls on runtime-returned objects like `kb.query()`. `await` on a synchronous return value is harmless in JS, and this rule is required for the Knowledge Base API to work correctly.
222
+
223
+ ---
224
+
225
+ ## Runtime Architecture
226
+
227
+ ```
228
+ runtime/index.js
229
+
230
+ ├── Imports 12 capability modules (+ readline for input())
231
+ ├── Exports `runtime` object → used as `__rt` in generated JS
232
+ ├── Exports `manifest` → structured metadata for every function
233
+ └── Attaches introspection:
234
+ runtime.listModules() → string[]
235
+ runtime.listFunctions(mod) → string[]
236
+ runtime.describe() → { version, modules, manifest }
237
+ runtime.input(prompt) → Promise<string> (stdin)
238
+ ```
239
+
240
+ ### Manifest shape (per function)
241
+
242
+ ```js
243
+ {
244
+ description: string,
245
+ params: [{ name: string, type: string, optional?: boolean }],
246
+ returns: string,
247
+ async: boolean,
248
+ }
249
+ ```
250
+
251
+ ---
252
+
253
+ ## Browser Runtime
254
+
255
+ `runtime/browser.js` is a self-contained browser-compatible runtime with no Node.js dependencies. It is bundled into `future-browser.js` along with the compiler.
256
+
257
+ ```
258
+ future-browser.js
259
+
260
+ ├── Imports compiler (lexer + parser + generator)
261
+ ├── Imports browserRuntime from runtime/browser.js
262
+ └── Exposes window.Future:
263
+ Future.configure({ proxy, provider, apiKey, model })
264
+ Future.run(source) → Promise (compile + execute)
265
+ Future.compile(source) → string (JS output only)
266
+ Future.runtime → browserRuntime object
267
+ ```
268
+
269
+ ### `<script type="future">` interceptor
270
+
271
+ `future-browser.js` intercepts all `<script type="future">` tags on the page and executes them via `Future.run()`. Execution is deferred with `setTimeout(runScripts, 0)` so all `<script type="module">` configuration blocks (which set proxy, API key, or `print` override) finish initialising before any Future script runs.
272
+
273
+ ### API key security (browser)
274
+
275
+ | Mode | Setup | Security |
276
+ |------|-------|----------|
277
+ | **Proxy** | `Future.configure({ proxy: '/api/ai' })` | Key stays on your server — recommended for production |
278
+ | **Demo** | `Future.configure({ provider: 'openai', apiKey: 'sk-...' })` | Key visible in source — dev/demos only |
279
+
280
+ Proxy contract:
281
+ ```
282
+ POST {proxy}/ask { prompt } → { text }
283
+ POST {proxy}/chat { messages } → { text }
284
+ POST {proxy}/stream { prompt } → SSE stream
285
+ POST {proxy}/embed { text } → { embedding: number[] }
286
+ ```
287
+
288
+ ---
289
+
290
+ ## AI Provider Architecture
291
+
292
+ ```
293
+ runtime/providers/index.js ← resolveProvider()
294
+
295
+ ├── runtime/providers/anthropic.js ask / chat / stream / embed (keyword fallback)
296
+ └── runtime/providers/openai-compat.js ask / chat / stream / embed (real embeddings)
297
+
298
+ └── Preset base URLs for:
299
+ openai | ollama | openrouter | gemini | venice | groq | together
300
+ ```
301
+
302
+ ### Provider resolution order
303
+
304
+ ```
305
+ 1. ai.configure(provider, key, model) ← called from Future code (highest priority)
306
+ 2. FUTURE_AI_PROVIDER + FUTURE_AI_API_KEY ← named preset (anthropic/openai/gemini/…)
307
+ 3. FUTURE_AI_BASE_URL + FUTURE_AI_API_KEY ← custom OpenAI-compat endpoint
308
+ 4. ANTHROPIC_API_KEY ← legacy default
309
+ 5. (nothing) ← offline stub — program keeps running
310
+ ```
311
+
312
+ ---
313
+
314
+ ## RAG Pipeline Architecture
315
+
316
+ ```
317
+ Documents (strings, objects, or local files)
318
+
319
+
320
+ [ Chunker ] runtime/rag/chunker.js
321
+ Overlapping chunks sentence-aware splitting (512 chars, 64 overlap)
322
+
323
+
324
+ [ Embedder ] runtime/ai.js → provider.embed()
325
+ Float vectors real (OpenAI/Ollama) or keyword-based fallback
326
+
327
+
328
+ [ Vector Store ] runtime/rag/vector-store.js
329
+ Indexed chunks memory | file | qdrant* | pinecone* | weaviate*
330
+ │ (* stubs — implement adapter to activate)
331
+
332
+ [ Retriever ] cosine similarity search (top-k)
333
+
334
+
335
+ [ Context Builder ] runtime/rag/pipeline.js
336
+ Ranked passages
337
+
338
+
339
+ [ LLM Answer ] ai.ask() with injected context
340
+ ```
341
+
342
+ ---
343
+
344
+ ## Event-Oriented Statements
345
+
346
+ ```future
347
+ on mqtt "house/temp" → await __rt.mqtt.subscribe(ch, async (message) => { … })
348
+ print message
349
+ end
350
+
351
+ every "30m" → await __rt.schedule.every(interval, async () => { … })
352
+ print "tick"
353
+ end
354
+ ```
355
+
356
+ ---
357
+
358
+ ## Agent Architecture
359
+
360
+ ```future
361
+ agent support
362
+ use rag
363
+ use memory
364
+ docs = rag.query(goal)
365
+ return docs
366
+ end
367
+ ```
368
+
369
+ Compiles to:
370
+
371
+ ```js
372
+ async function support(goal) {
373
+ let docs;
374
+ docs = await __rt.rag.query(goal);
375
+ return docs;
376
+ }
377
+ ```
378
+
379
+ - `goal` is the implicit parameter — automatically available inside the body.
380
+ - `use <capability>` lines are documentation only — no generated code.
381
+ - An `agent` declaration always forces ASYNC mode — callers `await` the result.
382
+
383
+ ---
384
+
385
+ ## Streaming Architecture
386
+
387
+ ```future
388
+ stream ai.ask("Tell me a story")
389
+ print chunk
390
+ end
391
+ ```
392
+
393
+ Compiles to:
394
+
395
+ ```js
396
+ await __rt.ai.stream("Tell me a story", async (chunk) => {
397
+ __rt.print(chunk);
398
+ });
399
+ ```
400
+
401
+ `chunk` is an implicit variable provided by the streaming callback. The call must be a namespace capability call.
402
+
403
+ ---
404
+
405
+ ## Adding a New Capability (4 steps)
406
+
407
+ 1. Create `runtime/mymodule.js` with named exports.
408
+ 2. Import it in `runtime/index.js`, add to `runtime` object, `MODULE_NAMES`, and `manifest`.
409
+ 3. Add the namespace name to `NAMESPACES` in `src/generator.js`.
410
+ 4. Add the module to `browserRuntime` in `runtime/browser.js` if browser support is wanted.
411
+
412
+ No grammar, lexer, parser, or AST changes needed.
413
+
414
+ ---
415
+
416
+ ## Package Exports
417
+
418
+ ```json
419
+ {
420
+ ".": "./src/index.js",
421
+ "./runtime": "./runtime/index.js",
422
+ "./runtime/lsp-metadata": "./runtime/lsp-metadata.js"
423
+ }
424
+ ```