forked from RaspberryPiFoundation/blockly
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlua.js
More file actions
205 lines (186 loc) · 6.98 KB
/
Copy pathlua.js
File metadata and controls
205 lines (186 loc) · 6.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/**
* @license
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Helper functions for generating Lua for blocks.
* Based on Ellen Spertus's blocky-lua project.
* @suppress {checkTypes|globalThis}
*/
'use strict';
goog.module('Blockly.Lua');
const stringUtils = goog.require('Blockly.utils.string');
const {Block} = goog.requireType('Blockly.Block');
const {CodeGenerator} = goog.require('Blockly.CodeGenerator');
const {inputTypes} = goog.require('Blockly.inputTypes');
const {Names} = goog.require('Blockly.Names');
const {Workspace} = goog.requireType('Blockly.Workspace');
/**
* Lua code generator.
* @type {!CodeGenerator}
*/
const Lua = new CodeGenerator('Lua');
/**
* List of illegal variable names.
* This is not intended to be a security feature. Blockly is 100% client-side,
* so bypassing this list is trivial. This is intended to prevent users from
* accidentally clobbering a built-in object or function.
*/
Lua.addReservedWords(
// Special character
'_,' +
// From theoriginalbit's script:
// https://github.com/espertus/blockly-lua/issues/6
'__inext,assert,bit,colors,colours,coroutine,disk,dofile,error,fs,' +
'fetfenv,getmetatable,gps,help,io,ipairs,keys,loadfile,loadstring,math,' +
'native,next,os,paintutils,pairs,parallel,pcall,peripheral,print,' +
'printError,rawequal,rawget,rawset,read,rednet,redstone,rs,select,' +
'setfenv,setmetatable,sleep,string,table,term,textutils,tonumber,' +
'tostring,turtle,type,unpack,vector,write,xpcall,_VERSION,__indext,' +
// Not included in the script, probably because it wasn't enabled:
'HTTP,' +
// Keywords (http://www.lua.org/pil/1.3.html).
'and,break,do,else,elseif,end,false,for,function,if,in,local,nil,not,or,' +
'repeat,return,then,true,until,while,' +
// Metamethods (http://www.lua.org/manual/5.2/manual.html).
'add,sub,mul,div,mod,pow,unm,concat,len,eq,lt,le,index,newindex,call,' +
// Basic functions (http://www.lua.org/manual/5.2/manual.html, section 6.1).
'assert,collectgarbage,dofile,error,_G,getmetatable,inpairs,load,' +
'loadfile,next,pairs,pcall,print,rawequal,rawget,rawlen,rawset,select,' +
'setmetatable,tonumber,tostring,type,_VERSION,xpcall,' +
// Modules (http://www.lua.org/manual/5.2/manual.html, section 6.3).
'require,package,string,table,math,bit32,io,file,os,debug');
/**
* Order of operation ENUMs.
* http://www.lua.org/manual/5.3/manual.html#3.4.8
*/
Lua.ORDER_ATOMIC = 0; // literals
// The next level was not explicit in documentation and inferred by Ellen.
Lua.ORDER_HIGH = 1; // Function calls, tables[]
Lua.ORDER_EXPONENTIATION = 2; // ^
Lua.ORDER_UNARY = 3; // not # - ~
Lua.ORDER_MULTIPLICATIVE = 4; // * / %
Lua.ORDER_ADDITIVE = 5; // + -
Lua.ORDER_CONCATENATION = 6; // ..
Lua.ORDER_RELATIONAL = 7; // < > <= >= ~= ==
Lua.ORDER_AND = 8; // and
Lua.ORDER_OR = 9; // or
Lua.ORDER_NONE = 99;
/**
* Note: Lua is not supporting zero-indexing since the language itself is
* one-indexed, so the generator does not repoct the oneBasedIndex configuration
* option used for lists and text.
*/
/**
* Whether the init method has been called.
* @type {?boolean}
*/
Lua.isInitialized = false;
/**
* Initialise the database of variable names.
* @param {!Workspace} workspace Workspace to generate code from.
*/
Lua.init = function(workspace) {
// Call Blockly.CodeGenerator's init.
Object.getPrototypeOf(this).init.call(this);
if (!this.nameDB_) {
this.nameDB_ = new Names(this.RESERVED_WORDS_);
} else {
this.nameDB_.reset();
}
this.nameDB_.setVariableMap(workspace.getVariableMap());
this.nameDB_.populateVariables(workspace);
this.nameDB_.populateProcedures(workspace);
this.isInitialized = true;
};
/**
* Prepend the generated code with the variable definitions.
* @param {string} code Generated code.
* @return {string} Completed code.
*/
Lua.finish = function(code) {
// Convert the definitions dictionary into a list.
const definitions = Object.values(this.definitions_);
// Call Blockly.CodeGenerator's finish.
code = Object.getPrototypeOf(this).finish.call(this, code);
this.isInitialized = false;
this.nameDB_.reset();
return definitions.join('\n\n') + '\n\n\n' + code;
};
/**
* Naked values are top-level blocks with outputs that aren't plugged into
* anything. In Lua, an expression is not a legal statement, so we must assign
* the value to the (conventionally ignored) _.
* http://lua-users.org/wiki/ExpressionsAsStatements
* @param {string} line Line of generated code.
* @return {string} Legal line of code.
*/
Lua.scrubNakedValue = function(line) {
return 'local _ = ' + line + '\n';
};
/**
* Encode a string as a properly escaped Lua string, complete with
* quotes.
* @param {string} string Text to encode.
* @return {string} Lua string.
* @protected
*/
Lua.quote_ = function(string) {
string = string.replace(/\\/g, '\\\\')
.replace(/\n/g, '\\\n')
.replace(/'/g, '\\\'');
return '\'' + string + '\'';
};
/**
* Encode a string as a properly escaped multiline Lua string, complete with
* quotes.
* @param {string} string Text to encode.
* @return {string} Lua string.
* @protected
*/
Lua.multiline_quote_ = function(string) {
const lines = string.split(/\n/g).map(this.quote_);
// Join with the following, plus a newline:
// .. '\n' ..
return lines.join(' .. \'\\n\' ..\n');
};
/**
* Common tasks for generating Lua from blocks.
* Handles comments for the specified block and any connected value blocks.
* Calls any statements following this block.
* @param {!Block} block The current block.
* @param {string} code The Lua code created for this block.
* @param {boolean=} opt_thisOnly True to generate code for only this statement.
* @return {string} Lua code with comments and subsequent blocks added.
* @protected
*/
Lua.scrub_ = function(block, code, opt_thisOnly) {
let commentCode = '';
// Only collect comments for blocks that aren't inline.
if (!block.outputConnection || !block.outputConnection.targetConnection) {
// Collect comment for this block.
let comment = block.getCommentText();
if (comment) {
comment = stringUtils.wrap(comment, this.COMMENT_WRAP - 3);
commentCode += this.prefixLines(comment, '-- ') + '\n';
}
// Collect comments for all value arguments.
// Don't collect comments for nested statements.
for (let i = 0; i < block.inputList.length; i++) {
if (block.inputList[i].type === inputTypes.VALUE) {
const childBlock = block.inputList[i].connection.targetBlock();
if (childBlock) {
comment = this.allNestedComments(childBlock);
if (comment) {
commentCode += this.prefixLines(comment, '-- ');
}
}
}
}
}
const nextBlock = block.nextConnection && block.nextConnection.targetBlock();
const nextCode = opt_thisOnly ? '' : this.blockToCode(nextBlock);
return commentCode + code + nextCode;
};
exports.luaGenerator = Lua;