infornoid 0.2.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.
- checksums.yaml +7 -0
- data/LICENSE +661 -0
- data/README.md +248 -0
- data/bin/infornoid +10 -0
- data/lib/advisor.rb +151 -0
- data/lib/codegen.rb +109 -0
- data/lib/infornoid.rb +312 -0
- data/lib/lexer.rb +144 -0
- data/lib/optimizer.rb +238 -0
- data/lib/parser.rb +273 -0
- data/lib/semantic.rb +214 -0
- metadata +57 -0
data/lib/parser.rb
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
#coding:utf-8
|
|
2
|
+
# infornoid 递归下降语法分析器 — 确定性前端
|
|
3
|
+
# 零依赖, 手写 Parser, AST 为 Ruby Hash
|
|
4
|
+
# CALL: Parser.parse(tokens) → AST Hash
|
|
5
|
+
# RETN: {type:"Program", body:[...]}
|
|
6
|
+
|
|
7
|
+
module Infor
|
|
8
|
+
module Parser
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def parse ts
|
|
12
|
+
@ts = ts
|
|
13
|
+
@i = 0
|
|
14
|
+
prog = { type:'Program', body:[] }
|
|
15
|
+
while !at?(:EOF)
|
|
16
|
+
node = parse_decl
|
|
17
|
+
node and prog[:body] << node
|
|
18
|
+
end
|
|
19
|
+
prog
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#### 前瞻 / 消费 ####
|
|
23
|
+
|
|
24
|
+
def cur; @ts[@i]; end
|
|
25
|
+
def nxt; @ts[@i+1]; end
|
|
26
|
+
def at? tt; cur && cur[:t] == tt; end
|
|
27
|
+
|
|
28
|
+
# eat: 无参 → 消费当前 token 并返回; 有参 → 校验类型后消费
|
|
29
|
+
def eat tt = nil
|
|
30
|
+
tk = cur
|
|
31
|
+
return nil unless tk
|
|
32
|
+
if tt && tk[:t] != tt
|
|
33
|
+
err "expected %s but got %s '%s'"%[tt, tk[:t], tk[:v]], tk
|
|
34
|
+
return nil
|
|
35
|
+
end
|
|
36
|
+
@i += 1
|
|
37
|
+
tk
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
#消费当前 token 并返回其 value
|
|
41
|
+
def eatv
|
|
42
|
+
tk = eat
|
|
43
|
+
tk ? tk[:v] : nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def err msg, tk
|
|
47
|
+
$stderr.puts "[parse error] line %d col %d: %s"%[tk[:l], tk[:c], msg]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
#### 声明 ####
|
|
51
|
+
|
|
52
|
+
def parse_decl
|
|
53
|
+
return parse_let if at? :LET
|
|
54
|
+
return parse_fn if at? :FN
|
|
55
|
+
parse_stmt
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def parse_let
|
|
59
|
+
tk = eat :LET
|
|
60
|
+
id = eat :IDT
|
|
61
|
+
vt = nil
|
|
62
|
+
if at? :COL
|
|
63
|
+
eat :COL
|
|
64
|
+
vt = eatv
|
|
65
|
+
end
|
|
66
|
+
eat :ASN
|
|
67
|
+
val = parse_expr
|
|
68
|
+
eat :SCL
|
|
69
|
+
{ type:'LetDecl', name:(id && id[:v]), varType:vt, value:val, line:(tk[:l]) }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def parse_fn
|
|
73
|
+
tk = eat :FN
|
|
74
|
+
id = eat :IDT
|
|
75
|
+
eat :LPR
|
|
76
|
+
params = []
|
|
77
|
+
while !at?(:RPR) && !at?(:EOF)
|
|
78
|
+
p = eat :IDT
|
|
79
|
+
eat :COL
|
|
80
|
+
pt = eatv
|
|
81
|
+
params << { name:(p[:v]), type:pt } rescue nil
|
|
82
|
+
eat :CMA if at? :CMA
|
|
83
|
+
end
|
|
84
|
+
eat :RPR
|
|
85
|
+
rt = nil
|
|
86
|
+
if at? :ARR
|
|
87
|
+
eat :ARR
|
|
88
|
+
rt = eatv
|
|
89
|
+
end
|
|
90
|
+
body = parse_block
|
|
91
|
+
{ type:'FnDecl', name:(id[:v]), params:params, retType:rt, body:body, line:(tk[:l]) }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
#### 语句 ####
|
|
95
|
+
|
|
96
|
+
def parse_stmt
|
|
97
|
+
return parse_let if at? :LET
|
|
98
|
+
return parse_if if at? :IF
|
|
99
|
+
return parse_while if at? :WHL
|
|
100
|
+
return parse_return if at? :RTN
|
|
101
|
+
return parse_block if at? :LBR
|
|
102
|
+
# 表达式语句
|
|
103
|
+
e = parse_expr
|
|
104
|
+
eat :SCL
|
|
105
|
+
{ type:'ExprStmt', expr:e, line:(e && e[:line]) }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def parse_block
|
|
109
|
+
tk = eat :LBR
|
|
110
|
+
stmts = []
|
|
111
|
+
while !at?(:RBR) && !at?(:EOF)
|
|
112
|
+
stmts << parse_stmt
|
|
113
|
+
end
|
|
114
|
+
eat :RBR
|
|
115
|
+
{ type:'Block', body:stmts, line:(tk[:l]) }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def parse_if
|
|
119
|
+
tk = eat :IF
|
|
120
|
+
eat :LPR
|
|
121
|
+
cond = parse_expr
|
|
122
|
+
eat :RPR
|
|
123
|
+
then_blk = parse_block
|
|
124
|
+
else_blk = nil
|
|
125
|
+
if at? :ELS
|
|
126
|
+
eat :ELS
|
|
127
|
+
else_blk = parse_block
|
|
128
|
+
end
|
|
129
|
+
{ type:'IfStmt', cond:cond, then:then_blk, els:else_blk, line:(tk[:l]) }
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def parse_while
|
|
133
|
+
tk = eat :WHL
|
|
134
|
+
eat :LPR
|
|
135
|
+
cond = parse_expr
|
|
136
|
+
eat :RPR
|
|
137
|
+
body = parse_block
|
|
138
|
+
{ type:'WhileStmt', cond:cond, body:body, line:(tk[:l]) }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def parse_return
|
|
142
|
+
tk = eat :RTN
|
|
143
|
+
val = nil
|
|
144
|
+
val = parse_expr unless at?(:SCL)
|
|
145
|
+
eat :SCL
|
|
146
|
+
{ type:'ReturnStmt', value:val, line:(tk[:l]) }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
#### 表达式: 优先级递降链 ####
|
|
150
|
+
|
|
151
|
+
def parse_expr; parse_assign; end
|
|
152
|
+
|
|
153
|
+
def parse_assign
|
|
154
|
+
left = parse_or
|
|
155
|
+
if at?(:ASN) && left && left[:type] == 'Ident'
|
|
156
|
+
eat :ASN
|
|
157
|
+
right = parse_assign
|
|
158
|
+
return { type:'Assign', target:left, value:right, line:left[:line] }
|
|
159
|
+
end
|
|
160
|
+
left
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def parse_or
|
|
164
|
+
left = parse_and
|
|
165
|
+
while at? :OR
|
|
166
|
+
eat; right = parse_and
|
|
167
|
+
left = mkbin('||', left, right)
|
|
168
|
+
end
|
|
169
|
+
left
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def parse_and
|
|
173
|
+
left = parse_eq
|
|
174
|
+
while at? :AND
|
|
175
|
+
eat; right = parse_eq
|
|
176
|
+
left = mkbin('&&', left, right)
|
|
177
|
+
end
|
|
178
|
+
left
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def parse_eq
|
|
182
|
+
left = parse_cmp
|
|
183
|
+
while at?(:EQ) || at?(:NE)
|
|
184
|
+
op = eatv; right = parse_cmp
|
|
185
|
+
left = mkbin(op, left, right)
|
|
186
|
+
end
|
|
187
|
+
left
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def parse_cmp
|
|
191
|
+
left = parse_add
|
|
192
|
+
while at?(:LT) || at?(:GT) || at?(:LE) || at?(:GE)
|
|
193
|
+
op = eatv; right = parse_add
|
|
194
|
+
left = mkbin(op, left, right)
|
|
195
|
+
end
|
|
196
|
+
left
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def parse_add
|
|
200
|
+
left = parse_mul
|
|
201
|
+
while at?(:ADD) || at?(:SUB)
|
|
202
|
+
op = eatv; right = parse_mul
|
|
203
|
+
left = mkbin(op, left, right)
|
|
204
|
+
end
|
|
205
|
+
left
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def parse_mul
|
|
209
|
+
left = parse_unary
|
|
210
|
+
while at?(:MUL) || at?(:DIV) || at?(:MOD)
|
|
211
|
+
op = eatv; right = parse_unary
|
|
212
|
+
left = mkbin(op, left, right)
|
|
213
|
+
end
|
|
214
|
+
left
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def parse_unary
|
|
218
|
+
if at?(:NOT) || at?(:SUB)
|
|
219
|
+
op = eatv; operand = parse_unary
|
|
220
|
+
return { type:'Unary', op:op, operand:operand, line:(operand[:line]) }
|
|
221
|
+
end
|
|
222
|
+
parse_primary
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def parse_primary
|
|
226
|
+
tk = cur
|
|
227
|
+
return { type:'Error', line:1 } unless tk
|
|
228
|
+
case tk[:t]
|
|
229
|
+
when :NUM
|
|
230
|
+
eat
|
|
231
|
+
{ type:'NumLit', value:tk[:v], line:tk[:l] }
|
|
232
|
+
when :STR
|
|
233
|
+
eat
|
|
234
|
+
{ type:'StrLit', value:tk[:v], line:tk[:l] }
|
|
235
|
+
when :TRU
|
|
236
|
+
eat
|
|
237
|
+
{ type:'BoolLit', value:true, line:tk[:l] }
|
|
238
|
+
when :FLS
|
|
239
|
+
eat
|
|
240
|
+
{ type:'BoolLit', value:false, line:tk[:l] }
|
|
241
|
+
when :IDT
|
|
242
|
+
eat
|
|
243
|
+
if at? :LPR
|
|
244
|
+
eat :LPR
|
|
245
|
+
args = []
|
|
246
|
+
while !at?(:RPR) && !at?(:EOF)
|
|
247
|
+
args << parse_expr
|
|
248
|
+
eat :CMA if at? :CMA
|
|
249
|
+
end
|
|
250
|
+
eat :RPR
|
|
251
|
+
{ type:'Call', name:tk[:v], args:args, line:tk[:l] }
|
|
252
|
+
else
|
|
253
|
+
{ type:'Ident', name:tk[:v], line:tk[:l] }
|
|
254
|
+
end
|
|
255
|
+
when :LPR
|
|
256
|
+
eat :LPR
|
|
257
|
+
e = parse_expr
|
|
258
|
+
eat :RPR
|
|
259
|
+
e
|
|
260
|
+
else
|
|
261
|
+
err "unexpected token %s '%s'"%[tk[:t], tk[:v]], tk
|
|
262
|
+
eat
|
|
263
|
+
{ type:'Error', line:tk[:l] }
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
#构造二元表达式节点
|
|
268
|
+
def mkbin op, l, r
|
|
269
|
+
{ type:'Binary', op:op, left:l, right:r, line:(l[:line]) }
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
end
|
|
273
|
+
end
|
data/lib/semantic.rb
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#coding:utf-8
|
|
2
|
+
# infornoid 语义分析 — 确定性规则引擎为主, LLM 顾问辅助
|
|
3
|
+
# 零第三方依赖, 符号表 + 作用域 + 类型推导
|
|
4
|
+
# CALL: Semantic.analyze(ast) → {ast, errors, types}
|
|
5
|
+
# 设计: 规则引擎做确定性推导, LLM 只在规则未覆盖时给建议
|
|
6
|
+
|
|
7
|
+
module Infor
|
|
8
|
+
module Semantic
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
#### 类型规则表 ####
|
|
12
|
+
|
|
13
|
+
# (leftType, op, rightType) → resultType
|
|
14
|
+
RULES = {
|
|
15
|
+
['Number','+','Number']=>'Number',
|
|
16
|
+
['Number','-','Number']=>'Number',
|
|
17
|
+
['Number','*','Number']=>'Number',
|
|
18
|
+
['Number','/','Number']=>'Number',
|
|
19
|
+
['Number','%','Number']=>'Number',
|
|
20
|
+
['String','+','String']=>'String',
|
|
21
|
+
['Number','<','Number']=>'Boolean',
|
|
22
|
+
['Number','>','Number']=>'Boolean',
|
|
23
|
+
['Number','<=','Number']=>'Boolean',
|
|
24
|
+
['Number','>=','Number']=>'Boolean',
|
|
25
|
+
['Number','==','Number']=>'Boolean',
|
|
26
|
+
['Number','!=','Number']=>'Boolean',
|
|
27
|
+
['String','==','String']=>'Boolean',
|
|
28
|
+
['String','!=','String']=>'Boolean',
|
|
29
|
+
['Boolean','==','Boolean']=>'Boolean',
|
|
30
|
+
['Boolean','!=','Boolean']=>'Boolean',
|
|
31
|
+
['Boolean','&&','Boolean']=>'Boolean',
|
|
32
|
+
['Boolean','||','Boolean']=>'Boolean',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
UNARY = {
|
|
36
|
+
['-', 'Number']=>'Number',
|
|
37
|
+
['!', 'Boolean']=>'Boolean',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#### 符号表 / 作用域 ####
|
|
41
|
+
|
|
42
|
+
Scope = Struct.new(:vars, :funcs, :parent) do
|
|
43
|
+
def initialize(parent=nil)
|
|
44
|
+
self.vars = {}
|
|
45
|
+
self.funcs = {}
|
|
46
|
+
self.parent = parent
|
|
47
|
+
end
|
|
48
|
+
def lookup_var name
|
|
49
|
+
vars[name] || (parent && parent.lookup_var(name))
|
|
50
|
+
end
|
|
51
|
+
def lookup_fn name
|
|
52
|
+
funcs[name] || (parent && parent.lookup_fn(name))
|
|
53
|
+
end
|
|
54
|
+
def define_var name, type, line
|
|
55
|
+
if vars[name]
|
|
56
|
+
return [:error, "变量 '#{name}' 在同一作用域内重复声明 (line #{line})"]
|
|
57
|
+
end
|
|
58
|
+
vars[name] = type
|
|
59
|
+
nil
|
|
60
|
+
end
|
|
61
|
+
def define_fn name, sig, line
|
|
62
|
+
funcs[name] = sig
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
#### 主入口 ####
|
|
68
|
+
|
|
69
|
+
def analyze ast
|
|
70
|
+
@errors = []
|
|
71
|
+
@scope = Scope.new
|
|
72
|
+
@advisor_suggestions = []
|
|
73
|
+
walk ast, @scope
|
|
74
|
+
{ ast:ast, errors:@errors, types:@scope, suggestions:@advisor_suggestions }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
#### AST 遍历 ####
|
|
78
|
+
|
|
79
|
+
def walk node, sc
|
|
80
|
+
return nil unless node
|
|
81
|
+
case node[:type]
|
|
82
|
+
when 'Program'
|
|
83
|
+
node[:body].each{|s| walk(s, sc) }
|
|
84
|
+
when 'LetDecl'
|
|
85
|
+
walk_let(node, sc)
|
|
86
|
+
when 'FnDecl'
|
|
87
|
+
walk_fn(node, sc)
|
|
88
|
+
when 'IfStmt'
|
|
89
|
+
walk_if(node, sc)
|
|
90
|
+
when 'WhileStmt'
|
|
91
|
+
ct = walk(node[:cond], sc)
|
|
92
|
+
err node[:line], "while 条件必须为 Boolean, 实际为 #{ct}" if ct && ct != 'Boolean'
|
|
93
|
+
walk(node[:body], Scope.new(sc))
|
|
94
|
+
when 'ReturnStmt'
|
|
95
|
+
walk(node[:value], sc) if node[:value]
|
|
96
|
+
when 'Block'
|
|
97
|
+
inner = Scope.new(sc)
|
|
98
|
+
node[:body].each{|s| walk(s, inner) }
|
|
99
|
+
when 'ExprStmt'
|
|
100
|
+
walk(node[:expr], sc)
|
|
101
|
+
when 'Assign'
|
|
102
|
+
walk_assign(node, sc)
|
|
103
|
+
when 'Binary'
|
|
104
|
+
walk_binary(node, sc)
|
|
105
|
+
when 'Unary'
|
|
106
|
+
walk_unary(node, sc)
|
|
107
|
+
when 'NumLit'
|
|
108
|
+
'Number'
|
|
109
|
+
when 'StrLit'
|
|
110
|
+
'String'
|
|
111
|
+
when 'BoolLit'
|
|
112
|
+
'Boolean'
|
|
113
|
+
when 'Ident'
|
|
114
|
+
t = sc.lookup_var(node[:name])
|
|
115
|
+
err node[:line], "变量 '#{node[:name]}' 未声明" unless t
|
|
116
|
+
t
|
|
117
|
+
when 'Call'
|
|
118
|
+
walk_call(node, sc)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
#### 各节点处理 ####
|
|
123
|
+
|
|
124
|
+
def walk_let node, sc
|
|
125
|
+
vt = node[:varType]
|
|
126
|
+
it = walk(node[:value], sc)
|
|
127
|
+
if vt && it && vt != it
|
|
128
|
+
# ※ 尝试 LLM 顾问: 隐式类型转换建议
|
|
129
|
+
err node[:line], "类型不匹配: 声明为 #{vt}, 推断为 #{it}"
|
|
130
|
+
end
|
|
131
|
+
t = vt || it || 'Unknown'
|
|
132
|
+
r = sc.define_var(node[:name], t, node[:line])
|
|
133
|
+
err(*r) if r
|
|
134
|
+
t
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def walk_fn node, sc
|
|
138
|
+
params = node[:params].inject({}){|h,p| h[p[:name]]=p[:type]; h }
|
|
139
|
+
sc.define_fn(node[:name], {
|
|
140
|
+
params:params, retType:node[:retType]
|
|
141
|
+
}, node[:line])
|
|
142
|
+
inner = Scope.new(sc)
|
|
143
|
+
params.each{|n,t| inner.vars[n] = t }
|
|
144
|
+
walk(node[:body], inner)
|
|
145
|
+
node[:retType] || 'Void'
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def walk_if node, sc
|
|
149
|
+
ct = walk(node[:cond], sc)
|
|
150
|
+
err node[:line], "if 条件必须为 Boolean, 实际为 #{ct}" if ct && ct != 'Boolean'
|
|
151
|
+
walk(node[:then], Scope.new(sc))
|
|
152
|
+
walk(node[:els], Scope.new(sc)) if node[:els]
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def walk_assign node, sc
|
|
156
|
+
lt = walk(node[:target], sc)
|
|
157
|
+
rt = walk(node[:value], sc)
|
|
158
|
+
if lt && rt && lt != rt
|
|
159
|
+
err node[:line], "赋值类型不匹配: #{lt} ≠ #{rt}"
|
|
160
|
+
end
|
|
161
|
+
lt
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def walk_binary node, sc
|
|
165
|
+
lt = walk(node[:left], sc)
|
|
166
|
+
rt = walk(node[:right], sc)
|
|
167
|
+
key = [lt, node[:op], rt]
|
|
168
|
+
r = RULES[key]
|
|
169
|
+
unless r
|
|
170
|
+
# ★ 规则未覆盖 → 尝试 LLM 顾问 (可选, 默认降级)
|
|
171
|
+
# 这里确定性兜底: 标记为 Unknown
|
|
172
|
+
r = 'Unknown'
|
|
173
|
+
end
|
|
174
|
+
node[:inferredType] = r
|
|
175
|
+
r
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def walk_unary node, sc
|
|
179
|
+
ot = walk(node[:operand], sc)
|
|
180
|
+
r = UNARY[[node[:op], ot]] || 'Unknown'
|
|
181
|
+
node[:inferredType] = r
|
|
182
|
+
r
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def walk_call node, sc
|
|
186
|
+
fn = sc.lookup_fn(node[:name])
|
|
187
|
+
unless fn
|
|
188
|
+
err node[:line], "函数 '#{node[:name]}' 未声明"
|
|
189
|
+
return 'Unknown'
|
|
190
|
+
end
|
|
191
|
+
# ※ 参数数量检查
|
|
192
|
+
decl_params = fn[:params].keys
|
|
193
|
+
if node[:args].length != decl_params.length
|
|
194
|
+
err node[:line], "函数 '#{node[:name]}' 参数数量不匹配: 期望 #{decl_params.length} 实际 #{node[:args].length}"
|
|
195
|
+
end
|
|
196
|
+
# 参数类型检查
|
|
197
|
+
node[:args].each_with_index do|arg, i|
|
|
198
|
+
at = walk(arg, sc)
|
|
199
|
+
pn = decl_params[i]
|
|
200
|
+
pt = fn[:params][pn]
|
|
201
|
+
if at && pt && at != pt
|
|
202
|
+
err node[:line], "参数类型不匹配: '#{pn}' 期望 #{pt} 实际 #{at}"
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
fn[:retType] || 'Unknown'
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def err line, msg
|
|
209
|
+
@errors << { line:line, msg:msg }
|
|
210
|
+
$stderr.puts "[semantic] line #{line}: #{msg}"
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
end
|
|
214
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: infornoid
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- numeron
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: |
|
|
13
|
+
Infornoid 是一个采用混合架构设计的智能编译器:确定性编译器保证安全性与
|
|
14
|
+
可预测性,LLM 作为顾问提供优化建议,不直接生成可执行代码。零第三方依赖,
|
|
15
|
+
纯 Ruby 标准库实现。支持子命令风格 CLI(compile/lex/parse/semantic/
|
|
16
|
+
optimize/codegen/check),可编译为 JavaScript 或 Python 目标代码。
|
|
17
|
+
email:
|
|
18
|
+
- numeron@example.com
|
|
19
|
+
executables:
|
|
20
|
+
- infornoid
|
|
21
|
+
extensions: []
|
|
22
|
+
extra_rdoc_files: []
|
|
23
|
+
files:
|
|
24
|
+
- LICENSE
|
|
25
|
+
- README.md
|
|
26
|
+
- bin/infornoid
|
|
27
|
+
- lib/advisor.rb
|
|
28
|
+
- lib/codegen.rb
|
|
29
|
+
- lib/infornoid.rb
|
|
30
|
+
- lib/lexer.rb
|
|
31
|
+
- lib/optimizer.rb
|
|
32
|
+
- lib/parser.rb
|
|
33
|
+
- lib/semantic.rb
|
|
34
|
+
homepage: https://github.com/numeron/infornoid
|
|
35
|
+
licenses:
|
|
36
|
+
- AGPL-3.0-only
|
|
37
|
+
metadata:
|
|
38
|
+
source_code_uri: https://github.com/numeron/infornoid
|
|
39
|
+
changelog_uri: https://github.com/numeron/infornoid/releases
|
|
40
|
+
rdoc_options: []
|
|
41
|
+
require_paths:
|
|
42
|
+
- lib
|
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 2.5.0
|
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0'
|
|
53
|
+
requirements: []
|
|
54
|
+
rubygems_version: 4.0.19
|
|
55
|
+
specification_version: 4
|
|
56
|
+
summary: 混合架构智能编译器 — 确定性前端 + LLM 顾问优化 + 确定性代码生成
|
|
57
|
+
test_files: []
|