future-lang 0.4.0 → 0.4.2
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.
- package/ARCHITECTURE.md +47 -13
- package/FUTURE_FOR_LLMS.md +55 -2
- package/MIGRATION.md +209 -1
- package/README.md +103 -11
- package/ROADMAP.md +58 -11
- package/package.json +1 -1
- package/runtime/ai.js +54 -9
- package/runtime/assert.js +27 -0
- package/runtime/http.js +54 -8
- package/runtime/index.js +19 -4
- package/runtime/providers/anthropic.js +70 -11
- package/runtime/providers/openai-compat.js +65 -19
- package/src/cli.js +137 -17
- package/src/generator.js +8 -1
- package/src/parser.js +1 -1
- package/src/sourcemap.js +69 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -15,22 +15,25 @@ future-lang/
|
|
|
15
15
|
│ ├── index.js # Public API — compile(source, options)
|
|
16
16
|
│ ├── lexer.js # Phase 1: source text → token list
|
|
17
17
|
│ ├── parser.js # Phase 2: token list → AST
|
|
18
|
-
│ ├── ast.js # AST node types and factory functions (
|
|
18
|
+
│ ├── ast.js # AST node types and factory functions (24 types)
|
|
19
19
|
│ ├── generator.js # Phase 3: AST → JavaScript source
|
|
20
20
|
│ ├── errors.js # FutureError with line/column tracking
|
|
21
|
-
│
|
|
21
|
+
│ ├── formatter.js # Line-based auto-formatter (future fmt)
|
|
22
|
+
│ ├── sourcemap.js # VLQ encoder + Source Map v3 builder
|
|
23
|
+
│ └── cli.js # CLI binary: 9 commands including future test
|
|
22
24
|
│
|
|
23
25
|
├── runtime/ # Capability modules (imported by generated JS)
|
|
24
26
|
│ ├── index.js # Aggregator: runtime object + manifest + introspection
|
|
25
27
|
│ │
|
|
26
|
-
│ ├── ai.js # Text generation —
|
|
27
|
-
│ ├── http.js # REST API
|
|
28
|
+
│ ├── ai.js # Text generation — ask/chat/stream accept opts {temperature, max_tokens, model}
|
|
29
|
+
│ ├── http.js # REST API — HttpError class, configure() for global headers/timeout
|
|
28
30
|
│ ├── mqtt.js # Pub/sub messaging (real broker or in-process loopback)
|
|
29
31
|
│ ├── tts.js # Text-to-speech (system engine)
|
|
30
32
|
│ ├── rag.js # RAG — chunk → embed → store → retrieve → answer
|
|
31
33
|
│ ├── vision.js # Vision AI — describe, detect, ocr, classify, compare
|
|
32
34
|
│ ├── home.js # Home automation (composes over MQTT)
|
|
33
35
|
│ │
|
|
36
|
+
│ ├── assert.js # Test assertions — ok/equal/notEqual/deepEqual/fail
|
|
34
37
|
│ ├── memory.js # In-process key-value store (set/get/search/delete/forget)
|
|
35
38
|
│ ├── schedule.js # Recurring / one-shot / cron scheduling
|
|
36
39
|
│ ├── system.js # OS utilities: exec, open, notify, read, write
|
|
@@ -41,7 +44,7 @@ future-lang/
|
|
|
41
44
|
│ │
|
|
42
45
|
│ ├── providers/ # AI provider implementations
|
|
43
46
|
│ │ ├── index.js # Provider factory + env-var resolution
|
|
44
|
-
│ │ ├── anthropic.js # Anthropic Messages API
|
|
47
|
+
│ │ ├── anthropic.js # Anthropic Messages API — AiError class, opts forwarding
|
|
45
48
|
│ │ ├── openai-compat.js # OpenAI-compatible (OpenAI, Ollama, Gemini, OpenRouter, …)
|
|
46
49
|
│ │ └── util.js # SSE parser, keyword vector, cosine similarity
|
|
47
50
|
│ │
|
|
@@ -69,6 +72,7 @@ future-lang/
|
|
|
69
72
|
│
|
|
70
73
|
├── future-browser.js # Browser entry point: window.Future + <script type="future">
|
|
71
74
|
├── future-playground.html # In-browser editor (11 examples, live compile)
|
|
75
|
+
├── FUTURE_FOR_LLMS.md # BNF grammar + all APIs — quick-reference for AI assistants
|
|
72
76
|
├── package.json
|
|
73
77
|
├── ARCHITECTURE.md # This file
|
|
74
78
|
├── ROADMAP.md # Feature roadmap
|
|
@@ -114,7 +118,7 @@ In **browser mode** (`browserMode: true` option), the `import` statement is omit
|
|
|
114
118
|
|
|
115
119
|
## Lexer
|
|
116
120
|
|
|
117
|
-
### Keywords (
|
|
121
|
+
### Keywords (26)
|
|
118
122
|
|
|
119
123
|
| Keyword | Token | Purpose |
|
|
120
124
|
|---------|-------|---------|
|
|
@@ -136,7 +140,8 @@ In **browser mode** (`browserMode: true` option), the `import` statement is omit
|
|
|
136
140
|
| `null` / `none` | NULL | Null literal (two spellings) |
|
|
137
141
|
| `stream` | STREAM | Streaming statement |
|
|
138
142
|
| `agent` | AGENT | Agent declaration |
|
|
139
|
-
| `use` | USE |
|
|
143
|
+
| `use` | USE | Import statement / capability declaration inside `agent` |
|
|
144
|
+
| `as` | AS | Alias in `use "..." as alias` |
|
|
140
145
|
|
|
141
146
|
### String escape
|
|
142
147
|
|
|
@@ -144,12 +149,13 @@ In **browser mode** (`browserMode: true` option), the `import` statement is omit
|
|
|
144
149
|
|
|
145
150
|
---
|
|
146
151
|
|
|
147
|
-
## AST Node Types (
|
|
152
|
+
## AST Node Types (24)
|
|
148
153
|
|
|
149
154
|
| Category | Nodes |
|
|
150
155
|
|----------|-------|
|
|
151
156
|
| Program | `Program` |
|
|
152
157
|
| Statements | `PrintStatement`, `Assignment`, `IfStatement`, `FunctionDeclaration`, `ReturnStatement`, `ExpressionStatement` |
|
|
158
|
+
| Import | `UseStatement` — `use "path"` / `use "path" as alias` |
|
|
153
159
|
| Control flow | `ForStatement`, `WhileStatement`, `TryStatement` |
|
|
154
160
|
| Event statements | `OnStatement`, `EveryStatement` |
|
|
155
161
|
| AI/IoT statements | `AgentDeclaration`, `StreamStatement` |
|
|
@@ -191,12 +197,37 @@ export const NAMESPACES = new Set([
|
|
|
191
197
|
'ai', 'http', 'mqtt', 'tts',
|
|
192
198
|
'rag', 'vision', 'home',
|
|
193
199
|
'memory', 'schedule', 'system', 'device',
|
|
194
|
-
'math',
|
|
200
|
+
'math', 'assert',
|
|
195
201
|
]);
|
|
196
202
|
```
|
|
197
203
|
|
|
198
204
|
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
205
|
|
|
206
|
+
`use ... as alias` imports are tracked in a `useAliases` Set and explicitly excluded from namespace routing — `m.add()` never becomes `__rt.m.add()`.
|
|
207
|
+
|
|
208
|
+
### Source maps (`sourceMaps` option)
|
|
209
|
+
|
|
210
|
+
When `compile(source, { sourceMaps: true })` is used, the generator prefixes each top-level statement line with `/*@FL:N*/` (where N is the original `.future` line number). `src/sourcemap.js` post-processes this output:
|
|
211
|
+
|
|
212
|
+
1. Scans the generated JS line by line.
|
|
213
|
+
2. Strips `/*@FL:N*/` markers.
|
|
214
|
+
3. Builds VLQ-encoded `mappings` in Source Map v3 format.
|
|
215
|
+
4. Returns `{ code: cleanJS, map: { version: 3, sources, sourcesContent, mappings } }`.
|
|
216
|
+
|
|
217
|
+
The CLI appends `//# sourceMappingURL=file.js.map` to the clean JS and writes the map as JSON.
|
|
218
|
+
|
|
219
|
+
### Import system (UseStatement)
|
|
220
|
+
|
|
221
|
+
`use "./file.future"` statements are emitted before all other code. At compile time, when `resolveSource` is provided, the compiler reads the imported file, parses it, and extracts top-level `FunctionDeclaration` names. This enables named imports:
|
|
222
|
+
|
|
223
|
+
```js
|
|
224
|
+
import { formatName, greet } from "./utils.js"; // named import (default)
|
|
225
|
+
import * as m from "./math.js"; // namespace import (alias)
|
|
226
|
+
import * as df from "date-fns"; // npm package (alias)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The `pathMap` option (a `Map<futurePath, fileURL>`) allows `future run` to redirect imports to temp `.mjs` files compiled in `tmpdir`.
|
|
230
|
+
|
|
200
231
|
### String interpolation
|
|
201
232
|
|
|
202
233
|
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:
|
|
@@ -227,7 +258,7 @@ In ASYNC mode, ALL call expressions where the callee is a `MemberExpression` are
|
|
|
227
258
|
```
|
|
228
259
|
runtime/index.js
|
|
229
260
|
│
|
|
230
|
-
├── Imports
|
|
261
|
+
├── Imports 13 capability modules (+ readline for input())
|
|
231
262
|
├── Exports `runtime` object → used as `__rt` in generated JS
|
|
232
263
|
├── Exports `manifest` → structured metadata for every function
|
|
233
264
|
└── Attaches introspection:
|
|
@@ -237,6 +268,8 @@ runtime/index.js
|
|
|
237
268
|
runtime.input(prompt) → Promise<string> (stdin)
|
|
238
269
|
```
|
|
239
270
|
|
|
271
|
+
When `FUTURE_DEBUG=1` (`future run --debug`), the runtime is wrapped by `wrapDebug()` which proxies every namespace method to log timing and arguments to stderr with ANSI colours.
|
|
272
|
+
|
|
240
273
|
### Manifest shape (per function)
|
|
241
274
|
|
|
242
275
|
```js
|
|
@@ -402,14 +435,15 @@ await __rt.ai.stream("Tell me a story", async (chunk) => {
|
|
|
402
435
|
|
|
403
436
|
---
|
|
404
437
|
|
|
405
|
-
## Adding a New Capability (
|
|
438
|
+
## Adding a New Capability (5 steps)
|
|
406
439
|
|
|
407
440
|
1. Create `runtime/mymodule.js` with named exports.
|
|
408
441
|
2. Import it in `runtime/index.js`, add to `runtime` object, `MODULE_NAMES`, and `manifest`.
|
|
409
442
|
3. Add the namespace name to `NAMESPACES` in `src/generator.js`.
|
|
410
|
-
4. Add the
|
|
443
|
+
4. Add the namespace name to `RESERVED_NAMESPACES` in `src/parser.js`.
|
|
444
|
+
5. Add the module to `browserRuntime` in `runtime/browser.js` if browser support is wanted.
|
|
411
445
|
|
|
412
|
-
No grammar, lexer,
|
|
446
|
+
No grammar, lexer, or AST changes needed.
|
|
413
447
|
|
|
414
448
|
---
|
|
415
449
|
|
package/FUTURE_FOR_LLMS.md
CHANGED
|
@@ -4,6 +4,19 @@ Future is a small language that compiles to JavaScript. It does NOT exist in you
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## Capability layers
|
|
8
|
+
|
|
9
|
+
| Layer | Namespaces | Notes |
|
|
10
|
+
|-------|-----------|-------|
|
|
11
|
+
| **Core language** | *(none)* | variables, if/end, for/end, while/end, try/catch/end, functions, lists, objects, strings |
|
|
12
|
+
| **Standard** | `math` `http` `memory` `system` `schedule` | General-purpose I/O; triggers async mode |
|
|
13
|
+
| **Extended** | `ai` `rag` `vision` `mqtt` `tts` `home` `device` `agent` | AI, IoT, automation; triggers async mode |
|
|
14
|
+
| **Testing** | `assert` | Use only in `*.test.future` files |
|
|
15
|
+
|
|
16
|
+
Any call from Standard or Extended triggers ASYNC mode automatically.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
7
20
|
## Reserved words
|
|
8
21
|
|
|
9
22
|
```
|
|
@@ -14,7 +27,7 @@ agent use as
|
|
|
14
27
|
|
|
15
28
|
Reserved namespaces (cannot be reassigned or used as function names):
|
|
16
29
|
```
|
|
17
|
-
ai http mqtt tts rag vision home memory schedule system device math
|
|
30
|
+
ai http mqtt tts rag vision home memory schedule system device math assert
|
|
18
31
|
```
|
|
19
32
|
|
|
20
33
|
---
|
|
@@ -176,6 +189,17 @@ embed = ai.embed("text to embed")
|
|
|
176
189
|
ai.configure("openai", "sk-...")
|
|
177
190
|
ai.configure("ollama")
|
|
178
191
|
|
|
192
|
+
# With inference options
|
|
193
|
+
answer = ai.ask("Explain quantum physics", { temperature: 0.2 max_tokens: 200 })
|
|
194
|
+
reply = ai.chat(messages, { model: "gpt-4o" temperature: 0.7 })
|
|
195
|
+
|
|
196
|
+
# Structured response: text + token counts + model + provider
|
|
197
|
+
result = ai.complete("Summarise this in one line.")
|
|
198
|
+
print result.text
|
|
199
|
+
print result.tokens.total # total tokens used
|
|
200
|
+
print result.model # e.g. "claude-sonnet-4-6"
|
|
201
|
+
print result.provider # e.g. "anthropic"
|
|
202
|
+
|
|
179
203
|
stream ai.ask("Tell me a story")
|
|
180
204
|
print chunk
|
|
181
205
|
end
|
|
@@ -224,7 +248,36 @@ end
|
|
|
224
248
|
# schedule.once and schedule.cron also available
|
|
225
249
|
```
|
|
226
250
|
|
|
227
|
-
### `http
|
|
251
|
+
### `http`
|
|
252
|
+
```
|
|
253
|
+
data = http.get("https://api.example.com/todos/1")
|
|
254
|
+
print data.title
|
|
255
|
+
|
|
256
|
+
res = http.post("https://api.example.com/items", { name: "Widget" price: 9.99 })
|
|
257
|
+
print res.id
|
|
258
|
+
|
|
259
|
+
# Global config (call once at the top of your program)
|
|
260
|
+
http.configure({ headers: { Authorization: "Bearer {token}" } timeout: 5000 })
|
|
261
|
+
|
|
262
|
+
# Errors have .status, .code, .url, .body properties
|
|
263
|
+
try
|
|
264
|
+
data = http.get("https://api.example.com/private")
|
|
265
|
+
catch err
|
|
266
|
+
print "Status: {err.status}"
|
|
267
|
+
print "Code: {err.code}"
|
|
268
|
+
end
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### `assert` (use in *.test.future files)
|
|
272
|
+
```
|
|
273
|
+
assert.ok(value)
|
|
274
|
+
assert.equal(actual, expected)
|
|
275
|
+
assert.notEqual(a, b)
|
|
276
|
+
assert.deepEqual(obj1, obj2)
|
|
277
|
+
assert.fail("custom message")
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### `system`, `rag`, `vision`, `home`, `device`
|
|
228
281
|
See [README.md](README.md) for full API tables.
|
|
229
282
|
|
|
230
283
|
### `math`
|
package/MIGRATION.md
CHANGED
|
@@ -4,7 +4,215 @@ All releases are **additive only**. No existing Future program has ever required
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## v0.
|
|
7
|
+
## v0.4.0 → v0.4.1 (current — Gemini improvements)
|
|
8
|
+
|
|
9
|
+
**No breaking changes.**
|
|
10
|
+
|
|
11
|
+
### AI inference options
|
|
12
|
+
|
|
13
|
+
`ai.ask`, `ai.chat`, and `ai.stream` now accept an optional second argument with inference parameters:
|
|
14
|
+
|
|
15
|
+
```future
|
|
16
|
+
# temperature controls creativity (0.0 = deterministic, 1.0 = creative)
|
|
17
|
+
precise = ai.ask("List the planets.", { temperature: 0.1 max_tokens: 100 })
|
|
18
|
+
creative = ai.chat(messages, { temperature: 0.9 model: "gpt-4o" })
|
|
19
|
+
ai.stream(prompt, { temperature: 0.7 })
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Supported fields: `temperature`, `max_tokens`, `model`, `system` (Anthropic only).
|
|
23
|
+
Both providers (Anthropic native, OpenAI-compat) forward all opts to the API.
|
|
24
|
+
|
|
25
|
+
### Structured errors
|
|
26
|
+
|
|
27
|
+
`HttpError` and `AiError` replace generic `Error` objects. Catchable with `try/catch err`:
|
|
28
|
+
|
|
29
|
+
```future
|
|
30
|
+
try
|
|
31
|
+
data = http.get("https://api.example.com/private")
|
|
32
|
+
catch err
|
|
33
|
+
print "{err.status}" # 401
|
|
34
|
+
print "{err.code}" # HTTP_401
|
|
35
|
+
print "{err.url}" # https://api.example.com/private
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
try
|
|
39
|
+
reply = ai.ask("hello")
|
|
40
|
+
catch err
|
|
41
|
+
print "{err.provider}" # anthropic
|
|
42
|
+
print "{err.status}" # 429
|
|
43
|
+
print "{err.code}" # AI_HTTP_429
|
|
44
|
+
end
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Error classes are exported from `runtime/providers/anthropic.js` (`AiError`) and `runtime/http.js` (`HttpError`) for use in JS integrations.
|
|
48
|
+
|
|
49
|
+
### `http.configure()` — global request defaults
|
|
50
|
+
|
|
51
|
+
```future
|
|
52
|
+
# Call once at the top of your program
|
|
53
|
+
http.configure({ headers: { Authorization: "Bearer {token}" } timeout: 5000 })
|
|
54
|
+
|
|
55
|
+
# All subsequent http.get / http.post calls include the header and timeout automatically
|
|
56
|
+
data = http.get("https://api.example.com/me")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Supported fields: `headers` (merged with per-call headers), `timeout` (ms, uses `AbortSignal.timeout`).
|
|
60
|
+
|
|
61
|
+
### Source maps (`future compile --sourcemap`)
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
future compile --sourcemap program.future
|
|
65
|
+
# Produces: program.js + program.js.map
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The `.js.map` is a standard Source Map v3 file. Stack traces in Node.js, VS Code, and browser DevTools automatically map back to the original `.future` line numbers.
|
|
69
|
+
|
|
70
|
+
The generator embeds `/*@FL:N*/` markers at each statement and `src/sourcemap.js` post-processes them into VLQ-encoded mappings.
|
|
71
|
+
|
|
72
|
+
### `future test` command + `assert` namespace
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
future test # finds and runs all *.test.future / test/**/*.future files
|
|
76
|
+
future test myfeature # filter by filename substring
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Test files use the reserved `assert` namespace:
|
|
80
|
+
|
|
81
|
+
```future
|
|
82
|
+
# calculator.test.future
|
|
83
|
+
assert.equal(1 + 1, 2)
|
|
84
|
+
assert.ok(math.sqrt(16) == 4)
|
|
85
|
+
assert.notEqual("hello", "world")
|
|
86
|
+
assert.deepEqual([1, 2, 3], [1, 2, 3])
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Exit code 0 when all pass, 1 when any fail. `assert.*` calls throw `AssertionError` on failure — the test runner catches them and reports per-file results.
|
|
90
|
+
|
|
91
|
+
`assert` is a reserved namespace — it cannot be redefined by user code.
|
|
92
|
+
|
|
93
|
+
### Internal changes
|
|
94
|
+
|
|
95
|
+
- `runtime/assert.js` — new module, wraps `node:assert/strict`
|
|
96
|
+
- `src/sourcemap.js` — new module, VLQ encoder + Source Map v3 builder
|
|
97
|
+
- `runtime/providers/anthropic.js` — exports `AiError` class; `chat`/`stream` accept `opts`
|
|
98
|
+
- `runtime/providers/openai-compat.js` — imports `AiError`; `chat`/`stream` accept `opts`
|
|
99
|
+
- `runtime/http.js` — exports `HttpError` class; `get`/`post` throw it; adds `configure()`; uses `AbortSignal.timeout`
|
|
100
|
+
- `runtime/index.js` — `assert` added to module list, `_base`, and `manifest`
|
|
101
|
+
- `src/generator.js` — `assert` added to `NAMESPACES`; `sourceMaps` option emits `/*@FL:N*/` markers
|
|
102
|
+
- `src/parser.js` — `assert` added to `RESERVED_NAMESPACES`
|
|
103
|
+
- `src/cli.js` — `future test` command; `--sourcemap` flag in `future compile`; calls `buildSourceMap()` to strip markers and write `.js.map`
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## v0.3.2 → v0.4.0 (CLI + Import system + Language improvements)
|
|
108
|
+
|
|
109
|
+
**No breaking changes.**
|
|
110
|
+
|
|
111
|
+
### CLI commands
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
future run <file.future> # compile + run
|
|
115
|
+
future compile <file.future> # compile to .js next to source
|
|
116
|
+
future new <name> # scaffold a new project directory
|
|
117
|
+
future check <file.future> # syntax-check only, no output
|
|
118
|
+
future fmt <file.future> # auto-format source in-place
|
|
119
|
+
future playground # launch the interactive playground
|
|
120
|
+
future doctor # check Node.js version, runtime, AI env, MQTT, etc.
|
|
121
|
+
future --version # show version
|
|
122
|
+
future run --debug <file> # print per-call timing to stderr (FUTURE_DEBUG=1)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Import system (`use`)
|
|
126
|
+
|
|
127
|
+
```future
|
|
128
|
+
# Import all top-level functions by name
|
|
129
|
+
use "./utils.future"
|
|
130
|
+
print formatName("Alice")
|
|
131
|
+
|
|
132
|
+
# Import as a namespace
|
|
133
|
+
use "./math.future" as m
|
|
134
|
+
result = m.add(10, 20)
|
|
135
|
+
|
|
136
|
+
# Import an npm package as a namespace
|
|
137
|
+
use "date-fns" as df
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Compiles to standard ES module imports:
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
import { formatName } from "./utils.js";
|
|
144
|
+
import * as m from "./math.js";
|
|
145
|
+
import * as df from "date-fns";
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The compiler reads imported `.future` files at compile time, parses them, and extracts top-level function names to generate named imports instead of wildcard imports. Dependencies are compiled recursively.
|
|
149
|
+
|
|
150
|
+
`use ... as alias` aliases are excluded from `__rt` routing — `m.add()` does not become `__rt.m.add()`.
|
|
151
|
+
|
|
152
|
+
### `else if` chains
|
|
153
|
+
|
|
154
|
+
```future
|
|
155
|
+
if score >= 90
|
|
156
|
+
print "A"
|
|
157
|
+
else if score >= 80
|
|
158
|
+
print "B"
|
|
159
|
+
else if score >= 70
|
|
160
|
+
print "C"
|
|
161
|
+
else
|
|
162
|
+
print "F"
|
|
163
|
+
end
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
One `end` closes the entire chain. Previously required nesting.
|
|
167
|
+
|
|
168
|
+
### Reserved namespace protection
|
|
169
|
+
|
|
170
|
+
Trying to reassign a namespace name now raises a compile-time error:
|
|
171
|
+
|
|
172
|
+
```future
|
|
173
|
+
math = 42 # error[parse]: 'math' is a reserved namespace
|
|
174
|
+
http = {} # error[parse]: 'http' is a reserved namespace
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Async handler error safety (`__safe`)
|
|
178
|
+
|
|
179
|
+
Programs that use `on`, `every`, or `stream` now wrap their handlers in `__safe`. Errors inside handlers are logged to `stderr` with `[future:ns]` prefix instead of crashing the process silently:
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
const __safe = (ns, fn) => async (...a) => {
|
|
183
|
+
try { return await fn(...a); }
|
|
184
|
+
catch (e) { console.error(`[future:${ns}]`, e.message); }
|
|
185
|
+
};
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Better error messages
|
|
189
|
+
|
|
190
|
+
Parse errors now show the source line and a `^` pointer:
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
error[parse]: Expected 'end' to close 'if' — did you forget 'end'?
|
|
194
|
+
--> hello.future:5:1
|
|
195
|
+
5 | x = 1
|
|
196
|
+
^
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### `FUTURE_FOR_LLMS.md`
|
|
200
|
+
|
|
201
|
+
A complete quick-reference for AI assistants generating Future code: BNF grammar, all keywords, all namespace APIs, every construct with an example, common mistakes, and what-compiles-to-what pairs.
|
|
202
|
+
|
|
203
|
+
### Internal changes
|
|
204
|
+
|
|
205
|
+
- `src/lexer.js` — `as` keyword added (`AS` token)
|
|
206
|
+
- `src/ast.js` — `UseStatement` node type and factory added
|
|
207
|
+
- `src/parser.js` — `parseUse()`, `parseIf(isChained)` updated; `RESERVED_NAMESPACES` set added
|
|
208
|
+
- `src/generator.js` — `genUseStatement()`, `useAliases` Set, `isModule` and `pathMap` options, `__safe` emission, `else if` chain detection
|
|
209
|
+
- `src/index.js` — `compile()` accepts `resolveSource`, `isModule`, `pathMap`, `importedNames` options
|
|
210
|
+
- `src/formatter.js` — new module: line-based indentation formatter
|
|
211
|
+
- `src/cli.js` — full rewrite; `compileDepsToTemp()` for `future run`; all CLI commands implemented
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## v0.3.1 → v0.3.2 (Phase 7: General-Purpose Programming)
|
|
8
216
|
|
|
9
217
|
**No breaking changes.**
|
|
10
218
|
|
package/README.md
CHANGED
|
@@ -164,6 +164,18 @@ In the browser this uses `window.prompt()`. In a Node.js CLI program it reads fr
|
|
|
164
164
|
|
|
165
165
|
Future programs talk to the outside world through **namespace calls**. The compiler detects them and automatically switches the program to async mode — you never write `async` or `await`.
|
|
166
166
|
|
|
167
|
+
### Capability layers
|
|
168
|
+
|
|
169
|
+
Future organises its built-ins into three layers. You only need to know the layer you're using.
|
|
170
|
+
|
|
171
|
+
| Layer | What it includes | Typical use |
|
|
172
|
+
|-------|-----------------|-------------|
|
|
173
|
+
| **Core language** | variables, functions, `if/else/end`, `for`, `while`, `try/catch`, lists, objects, string interpolation | Any program — no external calls |
|
|
174
|
+
| **Standard capabilities** | `math`, `http`, `memory`, `system`, `schedule` | General-purpose programs with I/O |
|
|
175
|
+
| **Extended modules** | `ai`, `rag`, `vision`, `mqtt`, `tts`, `home`, `device`, `agent`, `assert` | AI, IoT, and automation programs |
|
|
176
|
+
|
|
177
|
+
Any call from Standard or Extended triggers async mode — the compiler handles it automatically.
|
|
178
|
+
|
|
167
179
|
```future
|
|
168
180
|
# HTTP
|
|
169
181
|
todo = http.get("https://jsonplaceholder.typicode.com/todos/1")
|
|
@@ -182,8 +194,8 @@ mqtt.publish("home/livingroom/light", "on")
|
|
|
182
194
|
|
|
183
195
|
| Namespace | Functions | Notes |
|
|
184
196
|
|------------|-----------|-------|
|
|
185
|
-
| `http` | `get(url)`, `post(url, body)` | Parses JSON automatically |
|
|
186
|
-
| `ai` | `ask(prompt)`, `chat(messages)`, `embed(text)`, `stream(prompt, cb)`, `configure(provider, key)` |
|
|
197
|
+
| `http` | `get(url)`, `post(url, body)`, `configure(opts)` | Parses JSON automatically; throws `HttpError` with `.status`, `.code`, `.body` |
|
|
198
|
+
| `ai` | `ask(prompt, opts?)`, `chat(messages, opts?)`, `embed(text)`, `stream(prompt, cb, opts?)`, `configure(provider, key)` | opts: `{ temperature, max_tokens, model }`; throws `AiError` |
|
|
187
199
|
| `tts` | `speak(text)` | System engine (`say` / SAPI / `espeak-ng`) |
|
|
188
200
|
| `mqtt` | `publish(topic, msg)`, `subscribe(topic, handler)` | Real broker or in-process loopback |
|
|
189
201
|
| `memory` | `set(key, v)`, `get(key)`, `delete(key)`, `search(q)`, `forget(pattern?)` | In-process key-value store |
|
|
@@ -194,6 +206,7 @@ mqtt.publish("home/livingroom/light", "on")
|
|
|
194
206
|
| `home` | `turnOn(device)`, `turnOff(device)`, `set(device, value)` | Home automation via MQTT |
|
|
195
207
|
| `math` | `round`, `floor`, `ceil`, `abs`, `sqrt`, `pow`, `log`, `random`, `min`, `max`, `pi`, `e` | Full Math wrapper |
|
|
196
208
|
| `device` | `register(config)`, `get(name)`, `list()` | IoT device registry |
|
|
209
|
+
| `assert` | `ok(val)`, `equal(a, b)`, `notEqual(a, b)`, `deepEqual(a, b)`, `fail(msg?)` | Use in `*.test.future` files |
|
|
197
210
|
|
|
198
211
|
### Configuration (environment variables)
|
|
199
212
|
|
|
@@ -211,12 +224,56 @@ FUTURE_VECTOR_DB=memory # memory | file | qdrant
|
|
|
211
224
|
## AI configuration
|
|
212
225
|
|
|
213
226
|
```future
|
|
214
|
-
#
|
|
227
|
+
# Provider selection
|
|
215
228
|
ai.configure("openai", "sk-...")
|
|
216
229
|
ai.configure("ollama") # local, no key needed
|
|
217
230
|
|
|
231
|
+
# Basic usage
|
|
218
232
|
answer = ai.ask("What is 2 + 2?")
|
|
219
233
|
print answer
|
|
234
|
+
|
|
235
|
+
# With inference options
|
|
236
|
+
precise = ai.ask("List the planets.", { temperature: 0.1 max_tokens: 150 })
|
|
237
|
+
creative = ai.chat(messages, { temperature: 0.9 model: "gpt-4o" })
|
|
238
|
+
|
|
239
|
+
# Structured response — text + token counts + model + provider
|
|
240
|
+
result = ai.complete("Explain recursion in one sentence.")
|
|
241
|
+
print result.text
|
|
242
|
+
print "Tokens used: {result.tokens.total}"
|
|
243
|
+
print "Model: {result.model}"
|
|
244
|
+
print "Provider: {result.provider}"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
`ai.ask()` returns a plain string. `ai.complete()` returns `{ text, model, provider, tokens: { input, output, total } }` — useful when you need to track costs or log which model answered.
|
|
248
|
+
|
|
249
|
+
## HTTP configuration
|
|
250
|
+
|
|
251
|
+
```future
|
|
252
|
+
# Set global headers and timeout once at the top of your program
|
|
253
|
+
http.configure({ headers: { Authorization: "Bearer {token}" } timeout: 5000 })
|
|
254
|
+
|
|
255
|
+
data = http.get("https://api.example.com/me") # Authorization header included automatically
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Structured errors
|
|
259
|
+
|
|
260
|
+
HTTP and AI errors now carry structured data you can inspect:
|
|
261
|
+
|
|
262
|
+
```future
|
|
263
|
+
try
|
|
264
|
+
data = http.get("https://api.example.com/private")
|
|
265
|
+
catch err
|
|
266
|
+
print "Status: {err.status}" # e.g. 401
|
|
267
|
+
print "Code: {err.code}" # e.g. HTTP_401
|
|
268
|
+
print "URL: {err.url}"
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
try
|
|
272
|
+
reply = ai.ask("hello")
|
|
273
|
+
catch err
|
|
274
|
+
print "Provider: {err.provider}" # e.g. anthropic
|
|
275
|
+
print "Status: {err.status}" # e.g. 429
|
|
276
|
+
end
|
|
220
277
|
```
|
|
221
278
|
|
|
222
279
|
---
|
|
@@ -333,14 +390,49 @@ Open `future-playground.html` in any browser for a live editor with 11 built-in
|
|
|
333
390
|
```bash
|
|
334
391
|
npm install -g future-lang
|
|
335
392
|
|
|
336
|
-
future --version
|
|
337
|
-
future new myapp
|
|
338
|
-
future run program.future
|
|
339
|
-
future
|
|
340
|
-
future
|
|
341
|
-
future
|
|
342
|
-
future
|
|
343
|
-
future
|
|
393
|
+
future --version # show version
|
|
394
|
+
future new myapp # create a new project
|
|
395
|
+
future run program.future # compile + run
|
|
396
|
+
future run --debug program.future # run with per-call timing logs
|
|
397
|
+
future compile program.future # compile to JavaScript
|
|
398
|
+
future compile --sourcemap program.future # compile + emit .js.map
|
|
399
|
+
future test # run all *.test.future files
|
|
400
|
+
future test myfeature # run matching test files
|
|
401
|
+
future ast program.future # print the AST as JSON
|
|
402
|
+
future ast --pretty program.future # indented JSON
|
|
403
|
+
future check program.future # syntax check only
|
|
404
|
+
future fmt program.future # format source in-place
|
|
405
|
+
future playground # launch the interactive playground
|
|
406
|
+
future doctor # check your environment
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## Testing
|
|
412
|
+
|
|
413
|
+
Name your test files `*.test.future` (or put them in a `test/` folder) and use the `assert` namespace:
|
|
414
|
+
|
|
415
|
+
```future
|
|
416
|
+
# math.test.future
|
|
417
|
+
|
|
418
|
+
assert.equal(math.round(3.7), 4)
|
|
419
|
+
assert.equal(math.sqrt(16), 4)
|
|
420
|
+
assert.ok(math.pi > 3.14)
|
|
421
|
+
assert.notEqual(math.random(), math.random())
|
|
422
|
+
print "math tests passed"
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
future test # runs all *.test.future files
|
|
427
|
+
future test math # runs files matching "math"
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Output:
|
|
431
|
+
```
|
|
432
|
+
math tests passed
|
|
433
|
+
✓ math.test.future
|
|
434
|
+
|
|
435
|
+
1/1 tests passed
|
|
344
436
|
```
|
|
345
437
|
|
|
346
438
|
---
|