naidejs 1.0.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.
- package/LICENSE +21 -0
- package/README.md +171 -0
- package/SPEC-X.nx +144 -0
- package/SPEC.naide +182 -0
- package/bin/naide.js +124 -0
- package/examples/async.naide +50 -0
- package/examples/async.nx +40 -0
- package/examples/crud.naide +79 -0
- package/examples/crud.nx +64 -0
- package/examples/hello.naide +33 -0
- package/examples/hello.nx +29 -0
- package/examples/model.naide +44 -0
- package/examples/server.naide +28 -0
- package/examples/server.nx +27 -0
- package/package.json +46 -0
- package/src/generator.js +573 -0
- package/src/index.js +23 -0
- package/src/lexer.js +389 -0
- package/src/parser.js +1079 -0
- package/src/preprocess.js +286 -0
- package/src/tokens.js +162 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 pirikari
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# NAIDE
|
|
2
|
+
|
|
3
|
+
**Node AI Development Environment** — A language designed for AI-speed code generation that transpiles to Node.js.
|
|
4
|
+
|
|
5
|
+
Two modes:
|
|
6
|
+
- **NAIDE** (`.naide`) — ~40% fewer tokens than JavaScript
|
|
7
|
+
- **NAIDE-X** (`.nx`) — ~80% fewer tokens than JavaScript, AI-only readability
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g naide
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Run a file
|
|
19
|
+
naide app.naide
|
|
20
|
+
naide app.nx
|
|
21
|
+
|
|
22
|
+
# Output generated JavaScript
|
|
23
|
+
naide --emit app.nx
|
|
24
|
+
|
|
25
|
+
# Write JS to file
|
|
26
|
+
naide -o app.js app.nx
|
|
27
|
+
|
|
28
|
+
# Show intermediate NAIDE v1 (X mode debug)
|
|
29
|
+
naide --mid app.nx
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## NAIDE syntax (.naide)
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
# Variables with types
|
|
36
|
+
str name = "World"
|
|
37
|
+
int count = 3
|
|
38
|
+
mut int counter = 0
|
|
39
|
+
|
|
40
|
+
# Functions — one way only
|
|
41
|
+
fn greet(str who) -> str:
|
|
42
|
+
ret "Hello, {who}!"
|
|
43
|
+
|
|
44
|
+
# Async
|
|
45
|
+
fn.async fetchData(str url) -> any:
|
|
46
|
+
ret await fetch(url)
|
|
47
|
+
|
|
48
|
+
# Control flow
|
|
49
|
+
if count > 5:
|
|
50
|
+
log "many"
|
|
51
|
+
elif count > 2:
|
|
52
|
+
log "some"
|
|
53
|
+
else:
|
|
54
|
+
log "few"
|
|
55
|
+
|
|
56
|
+
# Loops
|
|
57
|
+
each item in items:
|
|
58
|
+
log item
|
|
59
|
+
|
|
60
|
+
for i in 0..10:
|
|
61
|
+
log i
|
|
62
|
+
|
|
63
|
+
# Server (Express built-in)
|
|
64
|
+
server app port 3000:
|
|
65
|
+
get "/users":
|
|
66
|
+
ret users
|
|
67
|
+
post "/users" (req, res):
|
|
68
|
+
ret req.body
|
|
69
|
+
|
|
70
|
+
# Error handling
|
|
71
|
+
try:
|
|
72
|
+
data = await fetchData(url)
|
|
73
|
+
fail e:
|
|
74
|
+
log.error e.message
|
|
75
|
+
|
|
76
|
+
# Classes
|
|
77
|
+
model User:
|
|
78
|
+
str name
|
|
79
|
+
int age = 0
|
|
80
|
+
fn greet() -> str:
|
|
81
|
+
ret "Hi {self.name}"
|
|
82
|
+
|
|
83
|
+
# Pipe operator
|
|
84
|
+
list result = data
|
|
85
|
+
|> filter((x) => x.active)
|
|
86
|
+
|> map((x) => x.name)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## NAIDE-X syntax (.nx)
|
|
90
|
+
|
|
91
|
+
Every keyword is a single character. Line-start symbol = intent.
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
-- Variables
|
|
95
|
+
s:name="World"
|
|
96
|
+
i:count=3
|
|
97
|
+
~i:counter=0
|
|
98
|
+
|
|
99
|
+
-- Function
|
|
100
|
+
f greet(s:who)s
|
|
101
|
+
>"Hello, {who}!"
|
|
102
|
+
|
|
103
|
+
-- Async
|
|
104
|
+
~f fetchData(s:url)a
|
|
105
|
+
>~fetch(url)
|
|
106
|
+
|
|
107
|
+
-- Control flow
|
|
108
|
+
?count>5
|
|
109
|
+
log"many"
|
|
110
|
+
|count>2
|
|
111
|
+
log"some"
|
|
112
|
+
:
|
|
113
|
+
log"few"
|
|
114
|
+
|
|
115
|
+
-- Loops
|
|
116
|
+
@item<items
|
|
117
|
+
log item
|
|
118
|
+
@i<0..10
|
|
119
|
+
log i
|
|
120
|
+
|
|
121
|
+
-- Server
|
|
122
|
+
$app:3000
|
|
123
|
+
G"/users"
|
|
124
|
+
>users
|
|
125
|
+
P"/users"(req,res)
|
|
126
|
+
>req.body
|
|
127
|
+
|
|
128
|
+
-- Error handling
|
|
129
|
+
!
|
|
130
|
+
data=~fetchData(url)
|
|
131
|
+
!!e
|
|
132
|
+
log.e e.message
|
|
133
|
+
|
|
134
|
+
-- Model
|
|
135
|
+
^User
|
|
136
|
+
s:name
|
|
137
|
+
i:age=0
|
|
138
|
+
f greet()s
|
|
139
|
+
>"Hi {self.name}"
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### NAIDE-X cheat sheet
|
|
143
|
+
|
|
144
|
+
| Symbol | Meaning | Symbol | Meaning |
|
|
145
|
+
|--------|---------|--------|---------|
|
|
146
|
+
| `>` | return | `?` | if |
|
|
147
|
+
| `\|` | elif | `:` | else |
|
|
148
|
+
| `@` | loop | `*` | while |
|
|
149
|
+
| `!` | try | `!!` | catch |
|
|
150
|
+
| `$` | server | `^` | model |
|
|
151
|
+
| `<` | import | `%` | match |
|
|
152
|
+
| `f` | function | `~f` | async function |
|
|
153
|
+
| `+` | export | `~` | await |
|
|
154
|
+
| `G` | GET | `P` | POST |
|
|
155
|
+
| `U` | PUT | `D` | DELETE |
|
|
156
|
+
|
|
157
|
+
Types: `s`=str `i`=int `n`=num `b`=bool `l`=list `m`=map `a`=any
|
|
158
|
+
|
|
159
|
+
## Why?
|
|
160
|
+
|
|
161
|
+
AI code generation speed depends on:
|
|
162
|
+
|
|
163
|
+
1. **Token count** — fewer output tokens = faster generation
|
|
164
|
+
2. **Predictability** — one way to write everything = better next-token prediction
|
|
165
|
+
3. **Context window** — shorter code = more room for complex projects
|
|
166
|
+
|
|
167
|
+
NAIDE-X is designed as an **AI-internal representation** — the AI thinks in NAIDE-X, users receive standard JavaScript.
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT
|
package/SPEC-X.nx
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
-- ============================================
|
|
2
|
+
-- NAIDE-X Language Specification
|
|
3
|
+
-- ~80% fewer tokens than JavaScript
|
|
4
|
+
-- AI-only readability. Maximum generation speed.
|
|
5
|
+
-- ============================================
|
|
6
|
+
-- Rule: first char of line = intent
|
|
7
|
+
-- > return ? if | elif : else
|
|
8
|
+
-- @ loop * while ! try !! catch
|
|
9
|
+
-- $ server ^ model < import % match
|
|
10
|
+
-- f func ~f async + export
|
|
11
|
+
-- s:i:n:b:l:m:a: typed vars
|
|
12
|
+
-- ~ await ~~ await.all
|
|
13
|
+
-- ============================================
|
|
14
|
+
|
|
15
|
+
-- Types: s=str i=int n=num b=bool l=list m=map a=any
|
|
16
|
+
s:name="hello"
|
|
17
|
+
i:count=42
|
|
18
|
+
n:price=9.99
|
|
19
|
+
b:active=true
|
|
20
|
+
l:items=[1,2,3]
|
|
21
|
+
m:cfg={host:"localhost",port:3000}
|
|
22
|
+
a:data=null
|
|
23
|
+
|
|
24
|
+
-- Mutable: ~ prefix
|
|
25
|
+
~i:counter=0
|
|
26
|
+
~s:label="init"
|
|
27
|
+
|
|
28
|
+
-- String interpolation: "{expr}" (double quotes)
|
|
29
|
+
s:greet="Hello {name}, count is {count}"
|
|
30
|
+
|
|
31
|
+
-- Functions: f name(TYPE:param,...)RETTYPE
|
|
32
|
+
f add(i:a,i:b)i
|
|
33
|
+
>a+b
|
|
34
|
+
|
|
35
|
+
f sayHi(s:who)
|
|
36
|
+
log"Hi {who}"
|
|
37
|
+
|
|
38
|
+
f greet2(s:name,s:prefix="Hello")
|
|
39
|
+
log"{prefix}, {name}!"
|
|
40
|
+
|
|
41
|
+
-- Async: ~f
|
|
42
|
+
~f fetchUser(s:id)m
|
|
43
|
+
a:res=~fetch("/api/users/{id}")
|
|
44
|
+
a:data=~res.json()
|
|
45
|
+
>data
|
|
46
|
+
|
|
47
|
+
-- Return: >
|
|
48
|
+
-- Return with status: >.s CODE BODY
|
|
49
|
+
|
|
50
|
+
-- If/elif/else: ? | :
|
|
51
|
+
?count>10
|
|
52
|
+
log"many"
|
|
53
|
+
|count>5
|
|
54
|
+
log"some"
|
|
55
|
+
:
|
|
56
|
+
log"few"
|
|
57
|
+
|
|
58
|
+
-- Inline ternary (same as NAIDE v1)
|
|
59
|
+
-- s:size=if count>10 then "big" else "small"
|
|
60
|
+
|
|
61
|
+
-- Each: @var<collection
|
|
62
|
+
@item<items
|
|
63
|
+
log item
|
|
64
|
+
|
|
65
|
+
-- Each with key: @key,val<collection
|
|
66
|
+
@k,v<cfg
|
|
67
|
+
log"{k}: {v}"
|
|
68
|
+
|
|
69
|
+
-- For range: @var<start..end
|
|
70
|
+
@i<0..10
|
|
71
|
+
log i
|
|
72
|
+
|
|
73
|
+
-- While: *condition
|
|
74
|
+
*active
|
|
75
|
+
log"running"
|
|
76
|
+
active=false
|
|
77
|
+
|
|
78
|
+
-- Match: %value
|
|
79
|
+
s:status="ok"
|
|
80
|
+
%status
|
|
81
|
+
"ok": log "success"
|
|
82
|
+
"error": log "failed"
|
|
83
|
+
_: log "unknown"
|
|
84
|
+
|
|
85
|
+
-- Try/catch: ! / !!var
|
|
86
|
+
~f safe(s:url)m
|
|
87
|
+
!
|
|
88
|
+
a:data=~fetch(url)
|
|
89
|
+
>{ok:true,data:data}
|
|
90
|
+
!!e
|
|
91
|
+
log.e"fail: {e.message}"
|
|
92
|
+
>{ok:false,error:e.message}
|
|
93
|
+
|
|
94
|
+
-- Pipe: |> (same)
|
|
95
|
+
l:result=[1,2,3,4,5]
|
|
96
|
+
|>filter((x)=>x>2)
|
|
97
|
+
|>map((x)=>x*10)
|
|
98
|
+
|
|
99
|
+
-- Model: ^Name
|
|
100
|
+
^User
|
|
101
|
+
s:name
|
|
102
|
+
s:email
|
|
103
|
+
i:age=0
|
|
104
|
+
f greet()s
|
|
105
|
+
>"Hi, I'm {self.name}"
|
|
106
|
+
~f save()
|
|
107
|
+
log"Saving {self.name}..."
|
|
108
|
+
|
|
109
|
+
-- Inheritance: ^Child<Parent
|
|
110
|
+
^Admin<User
|
|
111
|
+
s:role="admin"
|
|
112
|
+
f perms()l
|
|
113
|
+
>["read","write","delete"]
|
|
114
|
+
|
|
115
|
+
-- Server: $name:port
|
|
116
|
+
-- Routes: G P U D + "path"
|
|
117
|
+
-- $app:3000
|
|
118
|
+
-- G"/users"
|
|
119
|
+
-- >users
|
|
120
|
+
-- P"/users"(req,res)
|
|
121
|
+
-- >req.body
|
|
122
|
+
|
|
123
|
+
-- Import: <module or <{names}"module"
|
|
124
|
+
-- <express
|
|
125
|
+
-- <{readFile,writeFile}"fs/promises"
|
|
126
|
+
|
|
127
|
+
-- Export: + prefix
|
|
128
|
+
+f helper()s
|
|
129
|
+
>"exported"
|
|
130
|
+
+s:VER="1.0.0"
|
|
131
|
+
|
|
132
|
+
-- Log: log, log.e, log.w
|
|
133
|
+
log"info"
|
|
134
|
+
log.e"error"
|
|
135
|
+
log.w"warning"
|
|
136
|
+
|
|
137
|
+
-- Null safe: ?. and ?? (same)
|
|
138
|
+
a:val=data?.nested?.value??"default"
|
|
139
|
+
|
|
140
|
+
-- Await all: ~~[expr1,expr2]
|
|
141
|
+
|
|
142
|
+
-- Spread: ...
|
|
143
|
+
l:combined=[...items,4,5,6]
|
|
144
|
+
m:merged={...cfg,debug:true}
|
package/SPEC.naide
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# ============================================
|
|
2
|
+
# NAIDE Language Specification
|
|
3
|
+
# Node AI Development Environment
|
|
4
|
+
# ============================================
|
|
5
|
+
# AIが最速でコード生成できるように設計された言語
|
|
6
|
+
#
|
|
7
|
+
# 設計原則:
|
|
8
|
+
# 1. 1つの書き方しかない (曖昧さゼロ)
|
|
9
|
+
# 2. キーワード駆動 (行頭で意図が確定)
|
|
10
|
+
# 3. 最小トークン数 (生成量削減 = 高速)
|
|
11
|
+
# 4. よく使うパターンが組み込み
|
|
12
|
+
# 5. インデントベース (波括弧不要)
|
|
13
|
+
# ============================================
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ---- 変数宣言 ----
|
|
17
|
+
# 型名 変数名 = 値 (不変 const)
|
|
18
|
+
str name = "hello"
|
|
19
|
+
int count = 42
|
|
20
|
+
num price = 9.99
|
|
21
|
+
bool active = true
|
|
22
|
+
list items = [1, 2, 3]
|
|
23
|
+
map config = {host: "localhost", port: 3000}
|
|
24
|
+
any data = null
|
|
25
|
+
|
|
26
|
+
# 可変変数 (let)
|
|
27
|
+
mut int counter = 0
|
|
28
|
+
mut str label = "initial"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ---- 文字列補間 ----
|
|
32
|
+
# ダブルクォートで {式} が自動展開
|
|
33
|
+
str greeting = "Hello {name}, count is {count}"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ---- 関数 ----
|
|
37
|
+
# fn 名前(型 引数) -> 戻り型:
|
|
38
|
+
fn add(int a, int b) -> int:
|
|
39
|
+
ret a + b
|
|
40
|
+
|
|
41
|
+
# 戻り値なし
|
|
42
|
+
fn sayHi(str who):
|
|
43
|
+
log "Hi {who}"
|
|
44
|
+
|
|
45
|
+
# デフォルト引数
|
|
46
|
+
fn greet(str name, str prefix = "Hello"):
|
|
47
|
+
log "{prefix}, {name}!"
|
|
48
|
+
|
|
49
|
+
# 可変長引数
|
|
50
|
+
fn sum(...int nums) -> int:
|
|
51
|
+
mut int total = 0
|
|
52
|
+
each n in nums:
|
|
53
|
+
total += n
|
|
54
|
+
ret total
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# ---- 非同期関数 ----
|
|
58
|
+
fn.async fetchUser(str id) -> map:
|
|
59
|
+
any res = await fetch("/api/users/{id}")
|
|
60
|
+
any data = await res.json()
|
|
61
|
+
ret data
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# ---- 条件分岐 ----
|
|
65
|
+
if count > 10:
|
|
66
|
+
log "many"
|
|
67
|
+
elif count > 5:
|
|
68
|
+
log "some"
|
|
69
|
+
else:
|
|
70
|
+
log "few"
|
|
71
|
+
|
|
72
|
+
# インライン三項
|
|
73
|
+
str size = if count > 10 then "big" else "small"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# ---- ループ ----
|
|
77
|
+
# each: コレクション反復
|
|
78
|
+
each item in items:
|
|
79
|
+
log item
|
|
80
|
+
|
|
81
|
+
# each with key (Object.entries)
|
|
82
|
+
each key, val in config:
|
|
83
|
+
log "{key}: {val}"
|
|
84
|
+
|
|
85
|
+
# for: 範囲ループ
|
|
86
|
+
for i in 0..10:
|
|
87
|
+
log i
|
|
88
|
+
|
|
89
|
+
# while
|
|
90
|
+
while active:
|
|
91
|
+
log "running"
|
|
92
|
+
active = false
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# ---- パターンマッチ ----
|
|
96
|
+
str status = "ok"
|
|
97
|
+
match status:
|
|
98
|
+
"ok": log "success"
|
|
99
|
+
"error": log "failed"
|
|
100
|
+
_: log "unknown"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# ---- エラーハンドリング ----
|
|
104
|
+
fn.async safeFetch(str url) -> map:
|
|
105
|
+
try:
|
|
106
|
+
any data = await fetch(url)
|
|
107
|
+
ret {ok: true, data: data}
|
|
108
|
+
fail e:
|
|
109
|
+
log.error e.message
|
|
110
|
+
ret {ok: false, error: e.message}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# ---- パイプ演算子 ----
|
|
114
|
+
# データ変換チェーンが読みやすい
|
|
115
|
+
list result = [1, 2, 3, 4, 5]
|
|
116
|
+
|> filter((x) => x > 2)
|
|
117
|
+
|> map((x) => x * 10)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# ---- クラス (model) ----
|
|
121
|
+
model User:
|
|
122
|
+
str name
|
|
123
|
+
str email
|
|
124
|
+
int age = 0
|
|
125
|
+
|
|
126
|
+
fn greet() -> str:
|
|
127
|
+
ret "Hi, I'm {self.name}"
|
|
128
|
+
|
|
129
|
+
fn.async save():
|
|
130
|
+
log "Saving {self.name}..."
|
|
131
|
+
|
|
132
|
+
# 継承
|
|
133
|
+
model Admin extends User:
|
|
134
|
+
str role = "admin"
|
|
135
|
+
|
|
136
|
+
fn permissions() -> list:
|
|
137
|
+
ret ["read", "write", "delete"]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# ---- サーバー定義 ----
|
|
141
|
+
# Express.jsのボイラープレートが不要
|
|
142
|
+
# server 名前 port ポート:
|
|
143
|
+
# get "/path" (req, res):
|
|
144
|
+
# ret {data: "response"}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# ---- インポート ----
|
|
148
|
+
# use モジュール名
|
|
149
|
+
# use {名前1, 名前2} from "モジュール"
|
|
150
|
+
# use モジュール from "パッケージ"
|
|
151
|
+
# use モジュール as 別名
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# ---- イベント ----
|
|
155
|
+
# on オブジェクト.イベント:
|
|
156
|
+
# ハンドラ
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# ---- ログ ----
|
|
160
|
+
log "info message"
|
|
161
|
+
log.error "error message"
|
|
162
|
+
log.warn "warning"
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
# ---- 公開 (export) ----
|
|
166
|
+
pub fn helper() -> str:
|
|
167
|
+
ret "exported"
|
|
168
|
+
|
|
169
|
+
pub str VERSION = "1.0.0"
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# ---- null安全 ----
|
|
173
|
+
any val = data?.nested?.value ?? "default"
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# ---- await.all (Promise.all) ----
|
|
177
|
+
# list results = await.all [expr1, expr2, expr3]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# ---- スプレッド ----
|
|
181
|
+
list combined = [...items, 4, 5, 6]
|
|
182
|
+
map merged = {...config, debug: true}
|
package/bin/naide.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
4
|
+
import { resolve, basename, extname } from 'path';
|
|
5
|
+
import { compile } from '../src/index.js';
|
|
6
|
+
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
|
|
9
|
+
const flags = {
|
|
10
|
+
run: true,
|
|
11
|
+
emit: false,
|
|
12
|
+
ast: false,
|
|
13
|
+
tokens: false,
|
|
14
|
+
output: null,
|
|
15
|
+
help: false,
|
|
16
|
+
mode: null,
|
|
17
|
+
mid: false,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const files = [];
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < args.length; i++) {
|
|
23
|
+
const arg = args[i];
|
|
24
|
+
switch (arg) {
|
|
25
|
+
case '--emit': case '-e': flags.emit = true; flags.run = false; break;
|
|
26
|
+
case '--ast': flags.ast = true; flags.run = false; break;
|
|
27
|
+
case '--tokens': flags.tokens = true; flags.run = false; break;
|
|
28
|
+
case '--output': case '-o': flags.output = args[++i]; break;
|
|
29
|
+
case '--help': case '-h': flags.help = true; break;
|
|
30
|
+
case '--x': case '-x': flags.mode = 'x'; break;
|
|
31
|
+
case '--mid': flags.mid = true; flags.run = false; break;
|
|
32
|
+
default: files.push(arg);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (flags.help || files.length === 0) {
|
|
37
|
+
console.log(`
|
|
38
|
+
NAIDE - Node AI Development Environment
|
|
39
|
+
A language designed for AI-speed code generation
|
|
40
|
+
|
|
41
|
+
Usage:
|
|
42
|
+
naide <file.naide> Run a NAIDE file
|
|
43
|
+
naide <file.nx> Run a NAIDE-X file (auto-detected)
|
|
44
|
+
naide --emit <file.nx> Output generated JavaScript
|
|
45
|
+
naide --mid <file.nx> Output intermediate NAIDE v1 (debug)
|
|
46
|
+
naide -x <file.naide> Force NAIDE-X mode
|
|
47
|
+
|
|
48
|
+
Modes:
|
|
49
|
+
.naide Standard NAIDE (~40% fewer tokens than JS)
|
|
50
|
+
.nx NAIDE-X extreme (~80% fewer tokens than JS)
|
|
51
|
+
|
|
52
|
+
Options:
|
|
53
|
+
-e, --emit Print generated JavaScript
|
|
54
|
+
-o, --output Write generated JavaScript to file
|
|
55
|
+
-x Force NAIDE-X mode
|
|
56
|
+
--mid Show intermediate NAIDE v1 (X mode only)
|
|
57
|
+
--ast Print AST
|
|
58
|
+
--tokens Print tokens
|
|
59
|
+
-h, --help Show this help
|
|
60
|
+
`);
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for (const file of files) {
|
|
65
|
+
const filePath = resolve(file);
|
|
66
|
+
let source;
|
|
67
|
+
try {
|
|
68
|
+
source = readFileSync(filePath, 'utf-8');
|
|
69
|
+
} catch (err) {
|
|
70
|
+
console.error(`Error: Cannot read file '${file}'`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const ext = extname(file);
|
|
75
|
+
const mode = flags.mode || (ext === '.nx' ? 'x' : 'naide');
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
if (flags.mid && mode === 'x') {
|
|
79
|
+
const { preprocess } = await import('../src/preprocess.js');
|
|
80
|
+
console.log(preprocess(source));
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const result = compile(source, { mode });
|
|
85
|
+
|
|
86
|
+
if (flags.tokens) {
|
|
87
|
+
console.log(JSON.stringify(result.tokens, null, 2));
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (flags.ast) {
|
|
92
|
+
console.log(JSON.stringify(result.ast, null, 2));
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (flags.output) {
|
|
97
|
+
writeFileSync(flags.output, result.js, 'utf-8');
|
|
98
|
+
console.log(`Written to ${flags.output}`);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (flags.emit) {
|
|
103
|
+
console.log(result.js);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Run mode
|
|
108
|
+
const tempFile = resolve(`.naide_tmp_${basename(file, ext)}.mjs`);
|
|
109
|
+
writeFileSync(tempFile, result.js, 'utf-8');
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
await import('file:///' + tempFile.replace(/\\/g, '/'));
|
|
113
|
+
} finally {
|
|
114
|
+
try {
|
|
115
|
+
const { unlinkSync } = await import('fs');
|
|
116
|
+
unlinkSync(tempFile);
|
|
117
|
+
} catch {}
|
|
118
|
+
}
|
|
119
|
+
} catch (err) {
|
|
120
|
+
console.error(`\n${err.message}`);
|
|
121
|
+
if (process.env.NAIDE_DEBUG) console.error(err.stack);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# NAIDE - Async/Await & エラーハンドリング
|
|
2
|
+
# 非同期処理がシンプル
|
|
3
|
+
|
|
4
|
+
# 非同期関数
|
|
5
|
+
fn.async fetchData(str url) -> any:
|
|
6
|
+
any response = await fetch(url)
|
|
7
|
+
any data = await response.json()
|
|
8
|
+
ret data
|
|
9
|
+
|
|
10
|
+
# パイプで変換チェーン
|
|
11
|
+
fn.async getTopUsers() -> list:
|
|
12
|
+
any data = await fetchData("https://jsonplaceholder.typicode.com/users")
|
|
13
|
+
list result = data
|
|
14
|
+
|> filter((u) => u.name.length > 5)
|
|
15
|
+
|> map((u) => {name: u.name, email: u.email})
|
|
16
|
+
ret result
|
|
17
|
+
|
|
18
|
+
# エラーハンドリング
|
|
19
|
+
fn.async safeFetch(str url) -> map:
|
|
20
|
+
try:
|
|
21
|
+
any data = await fetchData(url)
|
|
22
|
+
ret {ok: true, data: data}
|
|
23
|
+
fail e:
|
|
24
|
+
log.error "Fetch failed: {e.message}"
|
|
25
|
+
ret {ok: false, error: e.message}
|
|
26
|
+
|
|
27
|
+
# await.all で並列実行
|
|
28
|
+
fn.async loadDashboard() -> map:
|
|
29
|
+
list urls = [
|
|
30
|
+
"https://jsonplaceholder.typicode.com/users",
|
|
31
|
+
"https://jsonplaceholder.typicode.com/posts",
|
|
32
|
+
"https://jsonplaceholder.typicode.com/todos"
|
|
33
|
+
]
|
|
34
|
+
list results = await.all urls.map((url) => fetchData(url))
|
|
35
|
+
ret {
|
|
36
|
+
users: results[0],
|
|
37
|
+
posts: results[1],
|
|
38
|
+
todos: results[2]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# 実行
|
|
42
|
+
fn.async main():
|
|
43
|
+
log "Fetching data..."
|
|
44
|
+
map dashboard = await safeFetch("https://jsonplaceholder.typicode.com/users")
|
|
45
|
+
if dashboard.ok:
|
|
46
|
+
log "Got {dashboard.data.length} items"
|
|
47
|
+
else:
|
|
48
|
+
log.error dashboard.error
|
|
49
|
+
|
|
50
|
+
main()
|