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
package/MIGRATION.md ADDED
@@ -0,0 +1,365 @@
1
+ # Future — Migration & Changelog
2
+
3
+ All releases are **additive only**. No existing Future program has ever required changes to compile and run.
4
+
5
+ ---
6
+
7
+ ## v0.3.1 → v0.3.2 (current — Phase 7: General-Purpose Programming)
8
+
9
+ **No breaking changes.**
10
+
11
+ ### New built-in: `len(x)`
12
+
13
+ ```future
14
+ items = [1, 2, 3, 4, 5]
15
+ print len(items) # 5
16
+ print len("hello") # 5
17
+ obj = { a: 1 b: 2 }
18
+ print len(obj) # 2
19
+ ```
20
+
21
+ `len()` is a sync built-in — it never triggers ASYNC mode on its own. Programs that only use `len()` still compile to plain synchronous JavaScript. Works on arrays, strings, and objects (falls back to `Object.keys().length` for objects).
22
+
23
+ ### New module: `math`
24
+
25
+ ```future
26
+ print math.round(3.7) # 4
27
+ print math.floor(3.9) # 3
28
+ print math.ceil(3.1) # 4
29
+ print math.abs(-5) # 5
30
+ print math.sqrt(16) # 4
31
+ print math.pow(2, 8) # 256
32
+ print math.min(1, 5, 3) # 1
33
+ print math.max(1, 5, 3) # 5
34
+ print math.random() # 0.0–1.0
35
+ print math.log(math.e) # 1
36
+ print math.pi # 3.14159...
37
+ print math.e # 2.71828...
38
+ ```
39
+
40
+ `math.*` calls are capability calls — they trigger ASYNC mode and are routed through `__rt.math.*`. `math.pi` and `math.e` are constants (property access, not function calls).
41
+
42
+ ### New built-in: `input(prompt)`
43
+
44
+ ```future
45
+ name = input("What is your name? ")
46
+ print "Hello, {name}!"
47
+ ```
48
+
49
+ `input()` is an async built-in — it always triggers ASYNC mode. In Node.js it reads a line from stdin via `readline`. In the browser it calls `window.prompt()`.
50
+
51
+ ### Namespace references inside strings
52
+
53
+ String interpolation now correctly handles namespace property access:
54
+
55
+ ```future
56
+ print "Pi is {math.pi}"
57
+ print "Euler: {math.e}"
58
+ ```
59
+
60
+ Previously, `{math.pi}` inside a string literal would emit `${math.pi}` — a ReferenceError at runtime because `math` is not a JS variable. Now it emits `${__rt.math.pi}` in ASYNC mode.
61
+
62
+ The fix also triggers ASYNC mode detection for programs where the only namespace usage is inside a string.
63
+
64
+ ### Browser runtime (`future-browser.js`)
65
+
66
+ The browser runtime bundles the full compiler and a browser-compatible capability set. It can be loaded with a single `<script>` tag.
67
+
68
+ ```html
69
+ <script type="module" src="future-browser.js"></script>
70
+
71
+ <script type="module">
72
+ import Future from './future-browser.js'
73
+ Future.configure({ proxy: '/api/ai' })
74
+ Future.runtime.print = (...args) =>
75
+ document.getElementById('output').textContent += args.join(' ') + '\n'
76
+ </script>
77
+
78
+ <script type="future">
79
+ scores = [85, 92, 78]
80
+ n = len(scores)
81
+ avg = math.round((85 + 92 + 78) / n)
82
+ print "Average: {avg}"
83
+ </script>
84
+ ```
85
+
86
+ API key security options:
87
+ - **Proxy mode** (`Future.configure({ proxy: '/api/ai' })`) — key stays on your server.
88
+ - **Demo mode** (`Future.configure({ provider: 'openai', apiKey: 'sk-...' })`) — key visible in source, dev/demos only.
89
+
90
+ ### Internal compiler changes
91
+
92
+ - `NAMESPACES` in `src/generator.js` — `'math'` added.
93
+ - `usesRuntime()` — now detects `input()` calls, namespace `MemberExpression` nodes, and `{namespace.prop}` patterns inside `StringLiteral` values.
94
+ - `usesBuiltin(node, name)` — new helper to detect specific built-in call sites (used for `len`).
95
+ - `Generator.genStringLiteral()` — promoted from a standalone function to an instance method, gains access to `this.asyncMode` and `NAMESPACES` to correctly prefix namespace refs with `__rt.`.
96
+ - `genCall()` — special-cases `len` → `__len(args)` and `input` → `await __rt.input(args)`.
97
+ - `runtime/math.js` — new module, 12 exports (10 functions + 2 constants).
98
+ - `runtime/index.js` — `math` added to module list + manifest; `runtime.input` added (readline-based).
99
+ - `runtime/browser.js` — `math` module and `input` function added; `browserRuntime` object updated.
100
+
101
+ ### Reserved keywords added
102
+
103
+ - `math` — now a reserved namespace identifier (cannot be used as a variable name).
104
+ - `input` — built-in identifier (shadowing it with a user variable is not recommended).
105
+
106
+ ---
107
+
108
+ ## v0.3.0 → v0.3.1 (Phase 6: Core Language)
109
+
110
+ **No breaking changes.**
111
+
112
+ ### New language features
113
+
114
+ #### List literals
115
+
116
+ ```future
117
+ items = [1, 2, 3]
118
+ names = ["Alice", "Bob"]
119
+ empty = []
120
+ ```
121
+
122
+ Emits a standard JS array literal. Elements can be any expression.
123
+
124
+ #### `for item in list ... end`
125
+
126
+ ```future
127
+ for name in names
128
+ print "Hello {name}"
129
+ end
130
+ ```
131
+
132
+ Compiles to `for (const item of list) { … }`. The loop variable is block-scoped (`const`), not hoisted.
133
+
134
+ #### `try ... catch err ... end`
135
+
136
+ ```future
137
+ try
138
+ result = ai.ask("question")
139
+ catch err
140
+ print "Error: {err}"
141
+ end
142
+ ```
143
+
144
+ Compiles to a standard JS `try/catch`. The catch variable is block-scoped — not hoisted to the outer `let` block. Before this, any runtime error would crash the program with an unhandled rejection.
145
+
146
+ #### Object literals
147
+
148
+ ```future
149
+ user = {
150
+ name: "João"
151
+ age: 30
152
+ }
153
+ ```
154
+
155
+ No commas between properties — whitespace and newlines act as separators. Optional commas are also accepted for users who prefer them. Emits a standard JS object literal with quoted keys.
156
+
157
+ #### String interpolation
158
+
159
+ ```future
160
+ name = "João"
161
+ print "Olá {name}, você tem {user.age} anos"
162
+ ```
163
+
164
+ Any string containing `{identifier}` or `{identifier.prop}` is automatically emitted as a JS template literal. No syntax changes required. To emit a literal `{` without interpolation, escape it: `\{`.
165
+
166
+ ### New runtime functions
167
+
168
+ #### `system.read(path)` and `system.write(path, content)`
169
+
170
+ ```future
171
+ content = system.read("config.json")
172
+ system.write("output.txt", result)
173
+ ```
174
+
175
+ `read` returns the file content as a string (UTF-8). `write` creates or overwrites the file, and returns the path that was written.
176
+
177
+ #### `rag.indexFile(path)` and `rag.indexUrl(url)`
178
+
179
+ ```future
180
+ rag.indexFile("manual.txt")
181
+ rag.indexUrl("https://docs.example.com/api")
182
+ answer = rag.query("How do I reset the device?")
183
+ ```
184
+
185
+ `indexFile` reads a local file and indexes its content into the default knowledge base. `indexUrl` fetches a URL, strips HTML tags, and indexes the resulting text. Both support any text-based format (TXT, MD, JSON, CSV, HTML). For PDFs, convert first: `system.exec("pdftotext manual.pdf manual.txt")`.
186
+
187
+ ### Reserved keywords added
188
+
189
+ The following words are now reserved and cannot be used as variable names:
190
+
191
+ - `for`, `in` — iteration
192
+ - `try`, `catch` — error handling
193
+ - `while` — condition-based loop
194
+ - `null`, `none` — null literal
195
+ - `stream` — streaming statement
196
+ - `agent`, `use` — agent declaration
197
+
198
+ No real-world program is expected to be affected — these are common programming keywords.
199
+
200
+ ### New language constructs
201
+
202
+ #### `while condition ... end`
203
+
204
+ ```future
205
+ count = 0
206
+ while count < 10
207
+ count = count + 1
208
+ end
209
+ ```
210
+
211
+ Compiles to `while (cond) { ... }`. Variables assigned inside the body are hoisted to the outer scope.
212
+
213
+ #### `null` and `none` literals
214
+
215
+ ```future
216
+ x = null
217
+ if x == none
218
+ print "sem valor"
219
+ end
220
+ ```
221
+
222
+ Both `null` and `none` are synonyms — both compile to JS `null`.
223
+
224
+ #### `stream <call> ... end`
225
+
226
+ ```future
227
+ stream ai.ask("Conta uma história")
228
+ print chunk
229
+ end
230
+ ```
231
+
232
+ Compiles to `await __rt.<namespace>.stream(args, async (chunk) => { ... })`. The body receives an implicit `chunk` variable with each streamed piece of text. Activates ASYNC mode automatically. The call must be a capability call (e.g. `ai.ask`, `ai.chat`).
233
+
234
+ #### `agent <name> ... end`
235
+
236
+ ```future
237
+ agent support
238
+ use rag
239
+ use memory
240
+
241
+ docs = rag.query(goal)
242
+ memory.set("last", goal)
243
+ return docs
244
+ end
245
+
246
+ answer = support("Como faço reset?")
247
+ ```
248
+
249
+ Compiles to `async function name(goal) { ... }`. The body receives an implicit `goal` parameter — no need to declare it. `use <capability>` lines are documentation only (no generated code). An `agent` declaration always activates ASYNC mode so the call site correctly `await`s the result.
250
+
251
+ ### Internal compiler changes
252
+
253
+ - Lexer: tokens LBRACKET (`[`), RBRACKET (`]`), LBRACE (`{`), RBRACE (`}`), COLON (`:`) added.
254
+ - Lexer: `\{` in string literals is stored as `\x01` (placeholder) to prevent generator from treating it as an interpolation start.
255
+ - Parser: `parseFor()`, `parseTry()`, `parseArrayLiteral()`, `parseObjectLiteral()` added.
256
+ - Parser: `EXPR_TERMINATORS` now includes `CATCH` — prevents `return` inside a `try` block from trying to parse `catch` as a value.
257
+ - Generator: `collectAssignedNames` now recurses into `ForStatement.body` and `TryStatement.body/catchBody`. Loop and catch variables are intentionally excluded from hoisting.
258
+ - Generator: `genStringLiteral()` function replaces direct `JSON.stringify` for all string values — handles interpolation detection and `\x01` restoration.
259
+
260
+ ---
261
+
262
+ ## v0.2.0 → v0.3.0 (Phase 5: AI Stack)
263
+
264
+ **No breaking changes.**
265
+
266
+ ### Added — PROMPT_1 (Runtime Foundation)
267
+
268
+ #### New language keywords
269
+ - `on` — event subscription: `on mqtt "topic" ... end`
270
+ - `every` — recurring task: `every "30m" ... end`
271
+
272
+ > These are reserved words. Rename variables named `on` or `every` if any exist.
273
+
274
+ #### New runtime modules
275
+ | Module | Functions |
276
+ |--------|-----------|
277
+ | `memory` | `set`, `get`, `delete`, `search`, `forget` |
278
+ | `schedule` | `every`, `once`, `cron` |
279
+ | `system` | `exec`, `open`, `notify` |
280
+ | `device` | `register`, `get`, `list` |
281
+
282
+ #### Runtime introspection
283
+ - `runtime.listModules()` → all module names
284
+ - `runtime.listFunctions(mod)` → all function names in a module
285
+ - `runtime.describe()` → full manifest + version
286
+
287
+ #### Manifest upgrade
288
+ - Function signatures changed from `'async (prompt)'` strings to structured objects with `description`, `params`, `returns`, `async`.
289
+ - The manifest is consumed by tooling only — not by generated JS. No program is affected.
290
+
291
+ #### New exports
292
+ - `future-lang/runtime/lsp-metadata` — VSCode / LSP metadata module
293
+
294
+ ---
295
+
296
+ ### Added — PROMPT_2 (AI Stack)
297
+
298
+ #### AI provider abstraction
299
+ - `ai.configure(provider, key, model)` — configure from code
300
+ - `FUTURE_AI_PROVIDER` env var — switch providers without code change
301
+ - Supported: `anthropic`, `openai`, `gemini`, `ollama`, `openrouter`, `venice`, `groq`, `together`
302
+ - Gemini uses Google's OpenAI-compat endpoint — no extra SDK
303
+
304
+ #### New AI functions
305
+ - `ai.embed(text)` → `number[]` — vector embeddings (real or keyword fallback)
306
+ - `ai.stream(prompt, onChunk)` — streaming SSE response
307
+
308
+ #### Real RAG pipeline
309
+ - `rag.index(docs)` now runs a full pipeline: **chunk → embed → vector store → cosine index**
310
+ - `rag.query(question)` now runs: **embed query → similarity search → LLM answer**
311
+ - `rag.create(name)` → named Knowledge Base with isolated vector store
312
+ - `rag.stats()` → chunk and vector count
313
+ - Vector stores: `memory` (default), `file` (JSON persistence), cloud stubs (Qdrant/Pinecone/Weaviate)
314
+ - Offline mode: keyword-based vectors if no embedding API is configured
315
+
316
+ #### Vision upgrade
317
+ - `vision.describe` / `vision.detect` — now use real AI provider (were stubs)
318
+ - `vision.ocr(image)` — new: extract text from image
319
+ - `vision.classify(image)` — new: categorise image
320
+ - `vision.compare(imageA, imageB)` — new: describe differences
321
+
322
+ #### Memory upgrade
323
+ - `memory.forget(pattern?)` — delete by substring pattern or clear all
324
+
325
+ #### Generator fix
326
+ - In async mode, ALL method calls on dynamic objects are now `await`ed.
327
+ - `await` on a synchronous return value is harmless (`await "str"` returns `"str"`).
328
+ - This is required for `kb.query()` and any future runtime-returned objects.
329
+ - Existing programs: no change in behaviour.
330
+
331
+ #### AST additions (architecture only — no parser yet)
332
+ - `AgentDeclaration` — for `agent <name> ... end`
333
+ - `StreamStatement` — for `stream <call> ... end`
334
+
335
+ #### Internal refactoring (no public API change)
336
+ - `runtime/providers/` — provider factory, Anthropic, OpenAI-compat, SSE util
337
+ - `runtime/rag/` — chunker, vector store adapters, pipeline
338
+
339
+ ---
340
+
341
+ ## Verification
342
+
343
+ After any upgrade, run:
344
+
345
+ ```bash
346
+ node --test
347
+ ```
348
+
349
+ Expected: **33 tests, 0 failures.**
350
+
351
+ All existing example programs in `examples/` compile and run without modifications.
352
+
353
+ ---
354
+
355
+ ## Environment variable reference
356
+
357
+ | Variable | Default | Purpose |
358
+ |----------|---------|---------|
359
+ | `FUTURE_AI_PROVIDER` | *(auto)* | `anthropic` \| `openai` \| `gemini` \| `ollama` \| `openrouter` \| `venice` \| `groq` \| `together` |
360
+ | `FUTURE_AI_API_KEY` | — | API key for the selected provider |
361
+ | `FUTURE_AI_BASE_URL` | *(from preset)* | Override base URL for any OpenAI-compat provider |
362
+ | `FUTURE_AI_MODEL` | provider default | Model ID |
363
+ | `ANTHROPIC_API_KEY` | — | Legacy — activates Anthropic without `FUTURE_AI_PROVIDER` |
364
+ | `FUTURE_VECTOR_DB` | `memory` | `memory` \| `file` \| `qdrant` \| `pinecone` \| `weaviate` |
365
+ | `MQTT_URL` | *(loopback)* | MQTT broker URL, e.g. `mqtt://localhost:1883` |