source: EcnlProtoTool/trunk/webapp/webmrbc/Ruby.cs@ 321

Last change on this file since 321 was 321, checked in by coas-nagasima, 7 years ago

文字コードを設定

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csharp;charset=UTF-8
File size: 7.9 KB
Line 
1// Porting from
2// https://github.com/jeanlazarou/blockly2ruby
3// Copyright (c) 2014 Jean Lazarou
4// MIT Lisence
5using System;
6using System.Linq;
7using Bridge;
8using Bridge.Text.RegularExpressions;
9using System.Collections.Generic;
10using System.Runtime.InteropServices;
11
12namespace WebMrbc
13{
14 [ComVisible(true)]
15 public partial class Ruby : Generator, IMrbParser
16 {
17 static Ruby()
18 {
19 /**
20 * List of illegal variable names.
21 * This is not intended to be a security feature. Blockly is 100% client-side,
22 * so bypassing this list is trivial. This is intended to prevent users from
23 * accidentally clobbering a built-in object or function.
24 * @private
25 */
26 addReservedWords(
27 "Class,Object,BEGIN,END,__ENCODING__,__END__,__FILE__,__LINE__" +
28 "alias,and,begin,break,case,class,def,defined?,do,else,elsif,end,ensure,false,for,if,in,module,next" +
29 "nil,not,or,redo,rescue,retry,return,self,super,then,true,undef,unless,until,when,while,yield");
30 }
31
32 node tree;
33 node[] allNodes;
34 locals_node locals;
35 bool global = true;
36
37 public Ruby(string filename)
38 : base("Ruby")
39 {
40 this.filename = filename;
41 }
42
43 /**
44 * Initialise the database of variable names.
45 */
46 public override void init(Workspace workspace)
47 {
48 locals = new locals_node(null);
49 }
50
51 /**
52 * Prepend the generated code with the variable definitions.
53 * @param {string} code Generated code.
54 * @return {string} Completed code.
55 */
56 public override string finish(node[] codes)
57 {
58 tree = new scope_node(this, new begin_node(this, codes));
59 var cond = new ruby_code_cond(filename, INDENT);
60 tree.to_ruby(cond);
61 allNodes = cond.nodes;
62 return cond.ToString();
63 }
64
65 /**
66 * Naked values are top-level blocks with outputs that aren't plugged into
67 * anything.
68 * @param {string} line Line of generated code.
69 * @return {string} Legal line of code.
70 */
71 public override node[] scrubNakedValue(node[] line)
72 {
73 return line;
74 }
75
76 /**
77 * Common tasks for generating Ruby from blocks.
78 * Handles comments for the specified block and any connected value blocks.
79 * Calls any statements following this block.
80 * @param {!Blockly.Block} block The current block.
81 * @param {string} code The Ruby code created for this block.
82 * @return {string} Ruby code with comments and subsequent blocks added.
83 * @this {Blockly.CodeGenerator}
84 * @private
85 */
86 public override node[] scrub_(Block block, node[] code)
87 {
88 var commentCode = "";
89 // Only collect comments for blocks that aren't inline.
90 if (block.outputConnection == null || block.outputConnection.targetConnection == null) {
91 // Collect comment for this block.
92 var comment = block.getCommentText();
93 if (!String.IsNullOrEmpty(comment)) {
94 commentCode += this.prefixLines(comment, "# ") + "\n";
95 }
96 // Collect comments for all value arguments.
97 // Don't collect comments for nested statements.
98 var inputList = block.inputList;
99 for (var x = 0; x < inputList.Length; x++) {
100 if (inputList[x].type == Blockly.INPUT_VALUE) {
101 var childBlock = inputList[x].connection.targetBlock();
102 if (childBlock != null) {
103 comment = allNestedComments(childBlock);
104 if (!String.IsNullOrEmpty(comment)) {
105 commentCode += this.prefixLines(comment, "# ");
106 }
107 }
108 }
109 }
110 }
111 Block nextBlock = null;
112 if (block.nextConnection != null)
113 nextBlock = block.nextConnection.targetBlock();
114 var nextCode = blockToCode(nextBlock);
115 if (nextCode == null)
116 return code;
117 return (node[])code.Concat(nextCode);
118 }
119
120 public int lineno { get; set; }
121 public int column { get; set; }
122 public string filename { get; }
123
124 string[] syms = new string[0];
125
126 private mrb_sym get_sym(string str)
127 {
128 int i = syms.IndexOf(str);
129 if (i < 0) {
130 i = syms.Length;
131 syms.Push(str);
132 }
133 return (mrb_sym)(i + 1);
134 }
135
136 public string sym2name(mrb_sym sym)
137 {
138 int i = (int)sym - 1;
139 if ((i < 0) || (i >= syms.Length))
140 return ((int)sym).ToString();
141 return syms[i];
142 }
143
144 mrb_sym intern(string str)
145 {
146 return get_sym(str);
147 }
148
149 mrb_sym get_var_name(string str)
150 {
151 int i = syms.IndexOf(str);
152
153 // ローカル変数なら登録されているはずなので、
154 if (i < 0)
155 // グローバル変数とする
156 return get_sym((global ? "$" : "@") + str);
157
158 var sym = (mrb_sym)(i + 1);
159
160 // ローカル変数でなければ、
161 if (!local_var_p(sym))
162 // グローバル変数とする
163 return get_sym((global ? "$" : "@") + str);
164
165 return sym;
166 }
167
168 node new_var_node(mrb_sym sym)
169 {
170 var name = sym2name(sym);
171 if (name.StartsWith("$")) {
172 return new gvar_node(this, sym);
173 }
174 else if (name.StartsWith("@@")) {
175 return new cvar_node(this, sym);
176 }
177 else if (name.StartsWith("@")) {
178 return new ivar_node(this, sym);
179 }
180 else {
181 return new lvar_node(this, sym);
182 }
183 }
184
185 node new_num_node(string num)
186 {
187 var result = MrbParser.parse(num);
188 var begin = result as begin_node;
189 if ((begin != null) && (begin.progs.Length == 1))
190 return begin.progs[0];
191 return result;
192 }
193
194 node new_str_node(string text)
195 {
196 var result = MrbParser.parse("\"" + text + "\"");
197 var begin = result as begin_node;
198 if ((begin != null) && (begin.progs.Length == 1))
199 return begin.progs[0];
200 return result;
201 }
202
203 locals_node local_switch()
204 {
205 var prev = this.locals;
206 this.locals = new locals_node(null);
207 return prev;
208 }
209
210 void local_resume(locals_node prev)
211 {
212 this.locals = prev;
213 }
214
215 void local_nest()
216 {
217 this.locals = new locals_node(this.locals);
218 }
219
220 void local_unnest()
221 {
222 if (this.locals != null) {
223 this.locals = this.locals.cdr;
224 }
225 }
226
227 bool local_var_p(mrb_sym sym)
228 {
229 locals_node l = this.locals;
230
231 while (l != null) {
232 if (l.symList.Contains(sym))
233 return true;
234 l = l.cdr;
235 }
236 return false;
237 }
238
239 void local_add_f(mrb_sym sym)
240 {
241 if (this.locals != null) {
242 this.locals.push(sym);
243 }
244 }
245
246 mrb_sym local_add_f(string name)
247 {
248 var sym = intern(name);
249 local_add_f(sym);
250 return sym;
251 }
252
253 void local_add(mrb_sym sym)
254 {
255 if (!local_var_p(sym)) {
256 local_add_f(sym);
257 }
258 }
259
260 public mrb_sym[] locals_node()
261 {
262 return this.locals != null ? this.locals.symList : null;
263 }
264
265 void assignable(node lhs)
266 {
267 var lvar = lhs as lvar_node;
268 if (lvar != null) {
269 local_add(lvar.name);
270 }
271 }
272
273 node var_reference(node lhs)
274 {
275 node n;
276
277 var lvar = lhs as lvar_node;
278 if (lvar != null) {
279 if (!local_var_p(lvar.name)) {
280 n = new fcall_node(this, lvar.name, null);
281 return n;
282 }
283 }
284
285 return lhs;
286 }
287
288 public string[] GetBlockId(string filename, int lineno)
289 {
290 var nodes = allNodes;
291 var result = new string[0];
292 foreach (var node in nodes) {
293 if (node.filename != filename)
294 continue;
295 if (lineno < node.start_lineno)
296 continue;
297 if (node.column == 0) {
298 if (lineno >= node.lineno)
299 continue;
300 }
301 else {
302 if (lineno > node.lineno)
303 continue;
304 }
305 if (String.IsNullOrEmpty(node.block_id))
306 continue;
307
308 result.Push(node.block_id);
309 }
310 return result;
311 }
312
313 public string[] GetBlockId(string filename, int lineno, int column)
314 {
315 var nodes = allNodes;
316 var result = new string[0];
317 foreach (var node in nodes) {
318 if (node.filename != filename)
319 continue;
320 if ((lineno < node.start_lineno))
321 continue;
322 if ((lineno == node.start_lineno) && (column < node.column))
323 continue;
324 if (node.column == 0) {
325 if (lineno >= node.lineno)
326 continue;
327 }
328 else {
329 if ((lineno == node.lineno) && (column > node.column))
330 continue;
331 if (lineno > node.lineno)
332 continue;
333 }
334 if (String.IsNullOrEmpty(node.block_id))
335 continue;
336
337 result.Push(node.block_id);
338 }
339 return result;
340 }
341
342 public void yyError(string message, params object[] expected)
343 {
344 App.WriteLine($"{filename}({lineno},{column}): error {String.Format(message, expected)}");
345 }
346 }
347}
Note: See TracBrowser for help on using the repository browser.