source: EcnlProtoTool/trunk/webapp/webmrbc/Generator.cs@ 270

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

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csharp
File size: 8.5 KB
Line 
1/**
2 * @license
3 * Visual Blocks Editor
4 *
5 * Copyright 2012 Google Inc.
6 * https://developers.google.com/blockly/
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21/**
22 * @fileoverview Utility functions for generating executable code from
23 * Blockly code.
24 * @author fraser@google.com (Neil Fraser)
25 */
26using System;
27using System.Linq;
28using System.Collections.Generic;
29using System.Reflection;
30using System.Runtime.InteropServices;
31using Bridge;
32using Bridge.Text.RegularExpressions;
33
34namespace WebMrbc
35{
36 [ComVisible(true)]
37 public abstract class Generator
38 {
39 public string name_;
40
41 /// <summary>
42 /// Class for a code generator that translates the blocks into a language.
43 /// </summary>
44 /// <param name="name">Language name of this generator.</param>
45 public Generator(string name)
46 {
47 this.name_ = name;
48 this.FUNCTION_NAME_PLACEHOLDER_REGEXP_ =
49 new Regex(this.FUNCTION_NAME_PLACEHOLDER_, "g");
50 }
51
52 /// <summary>
53 // Category to separate generated function names from variables and procedures.
54 /// </summary>
55 public static string NAME_TYPE = "generated_function";
56
57 /// <summary>
58 /// Arbitrary code to inject into locations that risk causing infinite loops.
59 /// Any instances of '%1' will be replaced by the block ID that failed.
60 /// E.g. ' checkTimeout(%1);\n'
61 /// </summary>
62 public string INFINITE_LOOP_TRAP = null;
63
64 /// <summary>
65 /// Arbitrary code to inject before every statement.
66 /// Any instances of '%1' will be replaced by the block ID of the statement.
67 /// E.g. 'highlight(%1);\n'
68 /// </summary>
69 public string STATEMENT_PREFIX = null;
70
71 /// <summary>
72 /// The method of indenting. Defaults to two spaces, but language generators
73 /// may override this to increase indent or change to tabs.
74 /// </summary>
75 public string INDENT = " ";
76
77 /// <summary>
78 /// Maximum length for a comment before wrapping. Does not account for
79 /// indenting level.
80 /// </summary>
81 public int COMMENT_WRAP = 60;
82
83 /// <summary>
84 /// List of outer-inner pairings that do NOT require parentheses.
85 /// </summary>
86 public int[][] ORDER_OVERRIDES = new int[0][];
87
88 public abstract void init(Workspace workspace);
89 public abstract string finish(node[] code);
90 public abstract node[] scrubNakedValue(node[] line);
91 public abstract node[] scrub_(Block block, node[] code);
92
93 /// <summary>
94 /// Generate code for all blocks in the workspace to the specified language.
95 /// </summary>
96 /// <param name="workspace">workspace Workspace to generate code from.</param>
97 /// <returns>Generated code.</returns>
98 public string workspaceToCode(Workspace workspace)
99 {
100 if (workspace == null) {
101 // Backwards compatibility from before there could be multiple workspaces.
102 App.WriteLine("No workspace specified in workspaceToCode call. Guessing.");
103 workspace = Blockly.getMainWorkspace();
104 }
105 this.init(workspace);
106 var codes = workspaceToNodes(workspace);
107 return this.finish(codes);
108 }
109
110 public node[] workspaceToNodes(Workspace workspace)
111 {
112 var nodes = new node[0];
113 var blocks = workspace.getTopBlocks(true);
114 foreach (var block in blocks) {
115 var line = this.blockToCode(block);
116 if (line != null) {
117 if (block.outputConnection != null/*&& this.scrubNakedValue*/) {
118 // This block is a naked value. Ask the language's code generator if
119 // it wants to append a semicolon, or something.
120 line = this.scrubNakedValue(line);
121 }
122 nodes = (node[])nodes.Concat(line);
123 }
124 }
125 return nodes;
126 }
127
128 // The following are some helpful functions which can be used by multiple
129 // languages.
130
131 /// <summary>
132 /// Prepend a common prefix onto each line of code.
133 /// </summary>
134 /// <param name="text">The lines of code.</param>
135 /// <param name="prefix">The common prefix.</param>
136 /// <returns>The prefixed lines of code.</returns>
137 public string prefixLines(string text, string prefix)
138 {
139 return prefix + text.Replace(new Regex("(?!\n$)\n"), "\n" + prefix);
140 }
141
142 /// <summary>
143 /// Recursively spider a tree of blocks, returning all their comments.
144 /// </summary>
145 /// <param name="block">The block from which to start spidering.</param>
146 /// <returns>Concatenated list of comments.</returns>
147 public string allNestedComments(Block block)
148 {
149 var comments = new string[0];
150 var blocks = block.getDescendants();
151 for (var i = 0; i < blocks.Length; i++) {
152 var comment = blocks[i].getCommentText();
153 if (comment != null) {
154 comments.Push(comment);
155 }
156 }
157 // Append an empty string to create a trailing line break when joined.
158 if (comments.Length != 0) {
159 comments.Push("");
160 }
161 return String.Join("\n", comments);
162 }
163
164 /// <summary>
165 /// Generate code for the specified block (and attached blocks).
166 /// </summary>
167 /// <param name="block">The block to generate code for.</param>
168 /// <returns>For statement blocks, the generated code.
169 /// For value blocks, an array containing the generated code and an
170 /// operator order value. Returns '' if block is null.
171 /// </returns>
172 public node[] blockToCode(Block block)
173 {
174 if (block == null) {
175 return null;
176 }
177 if (block.disabled) {
178 // Skip past this block if it is disabled.
179 return this.blockToCode(block.getNextBlock());
180 }
181
182 var func = (dynamic)this[block.type];
183 if (func == null)
184 return null;
185
186 var code = (node)func.call(this, block);
187 if (code == null) {
188 // Block has handled code generation itself.
189 return null;
190 }
191 var result = new node[0];
192 if (code.GetType() == typeof(node)) {
193 do {
194 var c = (node)code.car;
195 c.block_id = block.id;
196 result.Push(c);
197 } while ((code = code.cdr as node) != null);
198 }
199 else {
200 code.block_id = block.id;
201 result.Push(code);
202 }
203 return this.scrub_(block, result);
204 }
205
206 /// <summary>
207 /// Generate code representing the specified value input.
208 /// </summary>
209 /// <param name="block">The block containing the input.</param>
210 /// <param name="name">The name of the input.</param>
211 ///
212 /// <returns>Generated code or '' if no blocks are connected or the
213 /// specified input does not exist.</returns>
214 public node valueToCode(Block block, string name)
215 {
216 var targetBlock = block.getInputTargetBlock(name);
217 if (targetBlock == null) {
218 return null;
219 }
220 var code = this.blockToCode(targetBlock);
221 if(code == null) {
222 return null;
223 }
224 else if (code.Length == 1) {
225 return code[0];
226 }
227 else {
228 throw new Exception();
229 }
230 }
231
232 /// <summary>
233 /// Generate code representing the statement. Indent the code.
234 /// </summary>
235 /// <param name="block">The block containing the input.</param>
236 /// <param name="name">The name of the input.</param>
237 /// <returns>Generated code or '' if no blocks are connected.</returns>
238 public begin_node statementToCode(Block block, string name)
239 {
240 var targetBlock = block.getInputTargetBlock(name);
241 var code = this.blockToCode(targetBlock);
242 // Value blocks must return code and order of operations info.
243 // Statement blocks must only return code.
244 //goog.asserts.assertString(code, "Expecting code from statement block \"%s\".",
245 // targetBlock != null ? targetBlock.type : "");
246 if (code == null)
247 code = new node[0];
248 return new begin_node((IMrbParser)this, code);
249 }
250
251 /// <summary>
252 /// Comma-separated list of reserved words.
253 /// </summary>
254 public static string RESERVED_WORDS_ = "";
255
256 /// <summary>
257 /// Add one or more words to the list of reserved words for this language.
258 /// </summary>
259 /// <param name="words">Comma-separated list of words to add to the list.
260 /// No spaces. Duplicates are ok.</param>
261 public static void addReservedWords(string words)
262 {
263 RESERVED_WORDS_ += words + ",";
264 }
265
266 /// <summary>
267 /// This is used as a placeholder in functions defined using
268 /// Blockly.Generator.provideFunction_. It must not be legal code that could
269 /// legitimately appear in a function definition (or comment), and it must
270 /// not confuse the regular expression parser.
271 /// </summary>
272 public string FUNCTION_NAME_PLACEHOLDER_ = "{leCUI8hutHZI4480Dc}";
273 public Regex FUNCTION_NAME_PLACEHOLDER_REGEXP_;
274 }
275}
Note: See TracBrowser for help on using the repository browser.