1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.typeInfos = undefined;
|
7 |
|
8 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
9 |
|
10 | var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
|
11 |
|
12 | exports.default = transformSource;
|
13 |
|
14 | var _string = require("glsl-tokenizer/string");
|
15 |
|
16 | var _string2 = _interopRequireDefault(_string);
|
17 |
|
18 | var _direct = require("glsl-parser/direct");
|
19 |
|
20 | var _direct2 = _interopRequireDefault(_direct);
|
21 |
|
22 | var _acceptedLicenses = require("./acceptedLicenses");
|
23 |
|
24 | var _acceptedLicenses2 = _interopRequireDefault(_acceptedLicenses);
|
25 |
|
26 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
27 |
|
28 | function extraPositionFromToken(token) {
|
29 | var line = token.line,
|
30 | column = token.column;
|
31 |
|
32 | var out = {};
|
33 | if (typeof line === "number") out.line = line;
|
34 | if (typeof column === "number") out.column = column;
|
35 | return out;
|
36 | }
|
37 |
|
38 | var whitelistMeta = ["author", "license"];
|
39 |
|
40 | var blacklistScope = ["main", "getToColor", "getFromColor", "ratio", "uv", "progress", "from", "to"];
|
41 |
|
42 | var reservedTransitionNames = ["new"];
|
43 |
|
44 | var typeInfos = exports.typeInfos = {
|
45 | float: {
|
46 | primitiveType: "float",
|
47 | exampleValue: "0.7",
|
48 | defaultValue: 0,
|
49 | arity: 1
|
50 | },
|
51 | int: {
|
52 | primitiveType: "int",
|
53 | exampleValue: "42",
|
54 | defaultValue: 0,
|
55 | arity: 1
|
56 | },
|
57 | bool: {
|
58 | primitiveType: "bool",
|
59 | exampleValue: "true",
|
60 | defaultValue: false,
|
61 | arity: 1
|
62 | },
|
63 | sampler2D: {
|
64 | primitiveType: "sampler2D",
|
65 | defaultValue: null,
|
66 | arity: 1
|
67 | },
|
68 | vec2: {
|
69 | primitiveType: "float",
|
70 | exampleValue: "vec2(1.1, 2.2)",
|
71 | defaultValue: Array(2).fill(0),
|
72 | arity: 2
|
73 | },
|
74 | vec3: {
|
75 | primitiveType: "float",
|
76 | exampleValue: "vec3(1.0, 0.7, 0.3)",
|
77 | defaultValue: Array(3).fill(0),
|
78 | arity: 3
|
79 | },
|
80 | vec4: {
|
81 | primitiveType: "float",
|
82 | exampleValue: "vec4(1.0, 0.7, 0.3, 0.9)",
|
83 | defaultValue: Array(4).fill(0),
|
84 | arity: 4
|
85 | },
|
86 | ivec2: {
|
87 | primitiveType: "int",
|
88 | exampleValue: "ivec2(1, 2)",
|
89 | defaultValue: Array(2).fill(0),
|
90 | arity: 2
|
91 | },
|
92 | ivec3: {
|
93 | primitiveType: "int",
|
94 | exampleValue: "ivec3(1, 2, 3)",
|
95 | defaultValue: Array(3).fill(0),
|
96 | arity: 3
|
97 | },
|
98 | ivec4: {
|
99 | primitiveType: "int",
|
100 | exampleValue: "ivec4(1, 2, 3, 4)",
|
101 | defaultValue: Array(4).fill(0),
|
102 | arity: 4
|
103 | },
|
104 | bvec2: {
|
105 | primitiveType: "bool",
|
106 | exampleValue: "bvec2(true, false)",
|
107 | defaultValue: Array(2).fill(false),
|
108 | arity: 2
|
109 | },
|
110 | bvec3: {
|
111 | primitiveType: "bool",
|
112 | exampleValue: "bvec3(true, false, true)",
|
113 | defaultValue: Array(3).fill(false),
|
114 | arity: 3
|
115 | },
|
116 | bvec4: {
|
117 | primitiveType: "bool",
|
118 | exampleValue: "bvec4(true, false, true, false)",
|
119 | defaultValue: Array(4).fill(false),
|
120 | arity: 4
|
121 | },
|
122 | mat2: {
|
123 | primitiveType: "float",
|
124 | exampleValue: "mat2(1.0)",
|
125 | defaultValue: Array(4).fill(0),
|
126 | arity: 4
|
127 | },
|
128 | mat3: {
|
129 | primitiveType: "float",
|
130 | exampleValue: "mat3(1.0)",
|
131 | defaultValue: Array(9).fill(0),
|
132 | arity: 9
|
133 | },
|
134 | mat4: {
|
135 | primitiveType: "float",
|
136 | exampleValue: "mat4(1.0)",
|
137 | defaultValue: Array(16).fill(0),
|
138 | arity: 16
|
139 | }
|
140 | };
|
141 |
|
142 | function extractCommentNode(token) {
|
143 | switch (token.type) {
|
144 | case "line-comment":
|
145 | return token.data.slice(2);
|
146 | case "block-comment":
|
147 | return token.data.slice(2, token.data.length - 2);
|
148 | default:
|
149 | return "";
|
150 | }
|
151 | }
|
152 |
|
153 | function typeCheckTransitionFunction(node) {
|
154 | node = node.parent;
|
155 | if (node.type !== "function") {
|
156 | return false;
|
157 | }
|
158 |
|
159 | if (node.parent.token.data !== "vec4") {
|
160 | return false;
|
161 | }
|
162 |
|
163 | node = node.children.find(function (n) {
|
164 | return n.type === "functionargs";
|
165 | });
|
166 | if (!node) {
|
167 | return false;
|
168 | }
|
169 | if (node.children.length !== 1) {
|
170 | return false;
|
171 | }
|
172 | node = node.children[0];
|
173 | if (node.type !== "decl") {
|
174 | return false;
|
175 | }
|
176 | var args = node.children.filter(function (n) {
|
177 | return n.type !== "placeholder";
|
178 | });
|
179 | if (args.length !== 2) {
|
180 | return false;
|
181 | }
|
182 |
|
183 | var _args = _slicedToArray(args, 2),
|
184 | keywordNode = _args[0],
|
185 | decllist = _args[1];
|
186 |
|
187 | if (keywordNode.type !== "keyword" || keywordNode.token.data !== "vec2") {
|
188 | return false;
|
189 | }
|
190 | if (decllist.type !== "decllist" && decllist.children.length !== 1) {
|
191 | return false;
|
192 | }
|
193 |
|
194 | var _decllist$children = _slicedToArray(decllist.children, 1),
|
195 | identNode = _decllist$children[0];
|
196 |
|
197 | if (identNode.type !== "ident") {
|
198 | return false;
|
199 | }
|
200 | return true;
|
201 | }
|
202 |
|
203 | function transformSource(filename, glsl) {
|
204 | var data = {
|
205 | name: "",
|
206 | author: null,
|
207 | license: null,
|
208 | paramsTypes: {},
|
209 | defaultParams: {},
|
210 | glsl: glsl
|
211 | };
|
212 | var errors = [];
|
213 |
|
214 | var tokens = (0, _string2.default)(glsl);
|
215 |
|
216 | var ast = void 0;
|
217 | try {
|
218 | ast = (0, _direct2.default)(tokens);
|
219 | } catch (e) {
|
220 | var _message = e.message;
|
221 |
|
222 | var r = _message.split(" at line ");
|
223 | var _line = 0;
|
224 | if (r.length === 2) {
|
225 | _line = parseInt(r[1], 10);
|
226 | }
|
227 | errors.push({
|
228 | type: "error",
|
229 | code: "GLT_GLSL_error",
|
230 | message: "GLSL code error: " + e.message,
|
231 | line: _line
|
232 | });
|
233 | }
|
234 |
|
235 | if (ast) {
|
236 | var forbiddenScopes = Object.keys(ast.scope).filter(function (key) {
|
237 | return blacklistScope.includes(key);
|
238 | });
|
239 | forbiddenScopes.forEach(function (id) {
|
240 |
|
241 | var token = ast.scope[id].token;
|
242 | errors.push(_extends({
|
243 | type: "error",
|
244 | code: "GLT_reserved_variable_used",
|
245 | message: "You have defined these forbidden variables in the scope: " + id + ". They are reserved for the wrapping code."
|
246 | }, extraPositionFromToken(token)));
|
247 | });
|
248 |
|
249 | if (!ast.scope.transition) {
|
250 | errors.push({
|
251 | type: "error",
|
252 | code: "GLT_transition_no_impl",
|
253 | message: "'vec4 transition(vec2 uv)' function is not implemented"
|
254 | });
|
255 | } else {
|
256 | if (!typeCheckTransitionFunction(ast.scope.transition)) {
|
257 | errors.push(_extends({
|
258 | type: "error",
|
259 | code: "GLT_transition_wrong_type",
|
260 | message: "transition must be a function with following signature: 'vec4 transition(vec2 uv)'"
|
261 | }, extraPositionFromToken(ast.scope.transition.token)));
|
262 | }
|
263 | }
|
264 | }
|
265 |
|
266 | function parseUniformCommentDefault(comment, type, uniformId, uniformToken) {
|
267 | comment = comment.trim();
|
268 | if (comment.indexOf("=") !== 0) {
|
269 | return;
|
270 | }
|
271 | var tokens = (0, _string2.default)(uniformId + " " + comment + ";");
|
272 |
|
273 |
|
274 | var ast = void 0;
|
275 | try {
|
276 | ast = (0, _direct2.default)(tokens);
|
277 | } catch (e) {
|
278 | errors.push(_extends({
|
279 | type: "error",
|
280 | code: "GLT_invalid_default_value",
|
281 | message: "uniform '" + uniformId + "' default value '" + comment + "' does not parse as GLSL code: " + e.message
|
282 | }, extraPositionFromToken(uniformToken)));
|
283 | return;
|
284 | }
|
285 |
|
286 | var node = void 0;
|
287 |
|
288 | (node = ast) && (node = node.type === "stmtlist" && node.children[0]) && (node = node.type === "stmt" && node.children[0]) && (node = node.type === "expr" && node.children[0]) && (node = node.type === "assign" && node.children[1]);
|
289 |
|
290 | var valueNode = node;
|
291 | if (!valueNode) {
|
292 | errors.push(_extends({
|
293 | type: "error",
|
294 | code: "GLT_invalid_default_value",
|
295 | message: "uniform '" + uniformId + "' has invalid format for default value. Got: '" + comment + "'. It should be an assignment in a comment.\nExample: uniform " + type + " " + uniformId + "; // = " + typeInfos[type].exampleValue
|
296 | }, extraPositionFromToken(uniformToken)));
|
297 | return;
|
298 | }
|
299 | var _typeInfos$type = typeInfos[type],
|
300 | arity = _typeInfos$type.arity,
|
301 | primitiveType = _typeInfos$type.primitiveType;
|
302 |
|
303 |
|
304 | function literalToJSValue(literalNode) {
|
305 | switch (primitiveType) {
|
306 | case "float":
|
307 | {
|
308 | var f = parseFloat(literalNode.data, 10);
|
309 | if (isNaN(f)) {
|
310 | errors.push(_extends({
|
311 | type: "error",
|
312 | code: "GLT_invalid_default_value",
|
313 | message: "uniform '" + uniformId + "' has invalid default value type. Expected a float but could not parseFloat it! Got: '" + literalNode.data + "'"
|
314 | }, extraPositionFromToken(uniformToken)));
|
315 | return;
|
316 | }
|
317 | return f;
|
318 | }
|
319 | case "int":
|
320 | {
|
321 | var i = parseInt(literalNode.data, 10);
|
322 | if (isNaN(i)) {
|
323 | errors.push(_extends({
|
324 | type: "error",
|
325 | code: "GLT_invalid_default_value",
|
326 | message: "uniform '" + uniformId + "' has invalid default value type. Expected an int but could not parseInt it! Got: '" + literalNode.data + "'"
|
327 | }, extraPositionFromToken(uniformToken)));
|
328 | return;
|
329 | }
|
330 | return i;
|
331 | }
|
332 | case "bool":
|
333 | {
|
334 | switch (literalNode.data) {
|
335 | case "1":
|
336 | case "true":
|
337 | return true;
|
338 | case "0":
|
339 | case "false":
|
340 | return false;
|
341 | default:
|
342 | errors.push(_extends({
|
343 | type: "error",
|
344 | code: "GLT_invalid_default_value",
|
345 | message: "uniform '" + uniformId + "' has invalid default value type. Expected a bool but could not parse it! Got: '" + literalNode.data + "'"
|
346 | }, extraPositionFromToken(uniformToken)));
|
347 | return;
|
348 | }
|
349 | }
|
350 | default:
|
351 | return;
|
352 | }
|
353 | }
|
354 |
|
355 | if (valueNode.type === "call") {
|
356 | var values = [];
|
357 | for (var c = 0; c < valueNode.children.length; c++) {
|
358 | var _node = valueNode.children[c];
|
359 | switch (_node.type) {
|
360 | case "keyword":
|
361 | if (_node.data !== type) {
|
362 | errors.push(_extends({
|
363 | type: "error",
|
364 | code: "GLT_invalid_default_value",
|
365 | message: "uniform '" + uniformId + "' has invalid format for default value: the value type '" + _node.data + "' does not match the uniform type '" + type + "'. Got: '" + comment + "'.\nExample: uniform " + type + " " + uniformId + "; // = " + typeInfos[type].exampleValue
|
366 | }, extraPositionFromToken(uniformToken)));
|
367 | return;
|
368 | }
|
369 | break;
|
370 | case "literal":
|
371 | var v = literalToJSValue(_node);
|
372 | if (v === undefined) return;
|
373 | values.push(v);
|
374 | break;
|
375 | default:
|
376 | errors.push(_extends({
|
377 | type: "error",
|
378 | code: "GLT_invalid_default_value",
|
379 | message: "uniform '" + uniformId + "' has invalid format for default value: unsupported synthax. Got: '" + comment + "'.\nExample: uniform " + type + " " + uniformId + "; // = " + typeInfos[type].exampleValue
|
380 | }, extraPositionFromToken(uniformToken)));
|
381 | return;
|
382 | }
|
383 | }
|
384 | if (arity === values.length) {
|
385 | return values;
|
386 | }
|
387 | if (values.length === 1) {
|
388 | return Array(arity).fill(values[0]);
|
389 | } else {
|
390 | errors.push(_extends({
|
391 | type: "error",
|
392 | code: "GLT_invalid_default_value",
|
393 | message: "uniform '" + uniformId + "' has invalid format for default value: invalid arity of " + type + ". Got: '" + comment + "'.\nExample: uniform " + type + " " + uniformId + "; // = " + typeInfos[type].exampleValue
|
394 | }, extraPositionFromToken(uniformToken)));
|
395 | return;
|
396 | }
|
397 | } else if (valueNode.type === "literal" || valueNode.type === "keyword") {
|
398 | if (arity !== 1) {
|
399 | errors.push(_extends({
|
400 | type: "error",
|
401 | code: "GLT_invalid_default_value",
|
402 | message: "uniform '" + uniformId + "' has invalid format for default value: you can't assign a literal value to a " + type + " type. Got: '" + comment + "'.\nExample: uniform " + type + " " + uniformId + "; // = " + typeInfos[type].exampleValue
|
403 | }, extraPositionFromToken(uniformToken)));
|
404 | } else {
|
405 | return literalToJSValue(valueNode);
|
406 | }
|
407 | } else {
|
408 | errors.push(_extends({
|
409 | type: "error",
|
410 | code: "GLT_invalid_default_value",
|
411 | message: "uniform '" + uniformId + "' has invalid format for default value. Got: '" + comment + "'.\nExample: uniform " + type + " " + uniformId + "; // = " + typeInfos[type].exampleValue
|
412 | }, extraPositionFromToken(uniformToken)));
|
413 | }
|
414 | }
|
415 |
|
416 | for (var i = 0; i < tokens.length; i++) {
|
417 | var token = tokens[i];
|
418 | if (token.type === "keyword" && token.data === "uniform") {
|
419 | var _ret = function () {
|
420 | var uniformToken = token;
|
421 | var idents = [],
|
422 | ident = void 0,
|
423 | typeTokens = [],
|
424 | parsingType = true,
|
425 | commentsPerIdent = {},
|
426 | commentsAll = [];
|
427 |
|
428 | while (++i < tokens.length) {
|
429 | var _token = tokens[i];
|
430 | if (_token.type === "operator" && _token.data === ";") {
|
431 | break;
|
432 | }
|
433 | if (_token.type === "block-comment" || _token.type === "line-comment") {
|
434 | if (ident) {
|
435 | commentsPerIdent[ident] = (commentsPerIdent[ident] || []).concat([extractCommentNode(_token)]);
|
436 | }
|
437 | continue;
|
438 | }
|
439 | if (_token.type === "ident") {
|
440 | parsingType = false;
|
441 | ident = _token.data;
|
442 | idents.push(ident);
|
443 | continue;
|
444 | }
|
445 | if (parsingType && _token.type !== "whitespace") {
|
446 | typeTokens.push(_token);
|
447 | continue;
|
448 | }
|
449 | }
|
450 |
|
451 | for (var j = i + 1; j < tokens.length; j++) {
|
452 | var _token2 = tokens[j];
|
453 | if (_token2.type === "whitespace") {
|
454 | continue;
|
455 | }
|
456 | if (_token2.type === "block-comment" || _token2.type === "line-comment") {
|
457 | commentsAll.push(extractCommentNode(_token2));
|
458 | }
|
459 | break;
|
460 | }
|
461 |
|
462 | idents.forEach(function (ident) {
|
463 | var type = typeTokens.map(function (n) {
|
464 | return n.data;
|
465 | }).join("");
|
466 | if (typeof type !== "string" || !(type in typeInfos)) {
|
467 | errors.push(_extends({
|
468 | type: "error",
|
469 | code: "GLT_unsupported_param_value_type",
|
470 | message: "uniform '" + ident + "' type '" + String(type) + "' is not supported"
|
471 | }, extraPositionFromToken(uniformToken)));
|
472 | } else {
|
473 |
|
474 | var defaultParam = void 0;
|
475 |
|
476 | if (type === "sampler2D") {
|
477 |
|
478 | defaultParam = null;
|
479 | } else {
|
480 |
|
481 | var comments = (commentsPerIdent[ident] || []).concat(commentsAll);
|
482 | for (var _j = 0; _j < comments.length && defaultParam === undefined; _j++) {
|
483 | defaultParam = parseUniformCommentDefault(comments[_j], type, ident, uniformToken);
|
484 | }
|
485 |
|
486 | if (defaultParam === undefined) {
|
487 | errors.push(_extends({
|
488 | type: "warn",
|
489 | code: "GLT_no_default_param_value",
|
490 | message: "uniform '" + ident + "' has not declared any commented default value.\nExample: uniform " + type + " " + ident + "; // = " + typeInfos[type].exampleValue + ";"
|
491 | }, extraPositionFromToken(uniformToken)));
|
492 | defaultParam = typeInfos[type].defaultValue;
|
493 | }
|
494 | }
|
495 | data.defaultParams[ident] = defaultParam;
|
496 | data.paramsTypes[ident] = type;
|
497 | }
|
498 | });
|
499 | return "continue";
|
500 | }();
|
501 |
|
502 | if (_ret === "continue") continue;
|
503 | }
|
504 |
|
505 | if (token.type === "line-comment") {
|
506 |
|
507 | var com = token.data.slice(2);
|
508 | var _m = com.match(/^(.*):(.*)$/);
|
509 | if (_m && _m.length === 3) {
|
510 | var _m2 = _slicedToArray(_m, 3),
|
511 | _2 = _m2[0],
|
512 | key = _m2[1],
|
513 | value = _m2[2];
|
514 |
|
515 | key = key.trim().toLowerCase();
|
516 | value = value.trim();
|
517 | if (whitelistMeta.indexOf(key) !== -1) {
|
518 | data[key] = value;
|
519 | }
|
520 | }
|
521 | continue;
|
522 | }
|
523 | }
|
524 |
|
525 | whitelistMeta.forEach(function (key) {
|
526 | if (!data[key]) {
|
527 | errors.push({
|
528 | type: "error",
|
529 | code: "GLT_meta_missing",
|
530 | message: "'" + key + "' is missing. Please define it in a '// " + key + ": ...' comment"
|
531 | });
|
532 | }
|
533 | });
|
534 |
|
535 | if (data.license && !(data.license in _acceptedLicenses2.default)) {
|
536 | errors.push({
|
537 | type: "error",
|
538 | code: "GLT_unknown_license",
|
539 | message: "'" + data.license + "' not found in supported licenses: " + Object.keys(_acceptedLicenses2.default).join(", ")
|
540 | });
|
541 | }
|
542 |
|
543 | var m = filename.match(/^(.*).glsl$/);
|
544 | if (m) {
|
545 | var _name = m[1];
|
546 | data.name = _name;
|
547 | if (!_name) {
|
548 | errors.push({
|
549 | type: "error",
|
550 | code: "GLT_invalid_filename",
|
551 | message: "A transition filename is required!"
|
552 | });
|
553 | } else if (_name.length > 40) {
|
554 | errors.push({
|
555 | type: "error",
|
556 | code: "GLT_invalid_filename",
|
557 | message: "filename is too long"
|
558 | });
|
559 | } else if (!_name.match(/^[a-zA-Z0-9-_]+$/)) {
|
560 | errors.push({
|
561 | type: "error",
|
562 | code: "GLT_invalid_filename",
|
563 | message: "filename can only contains letters, numbers or - and _ characters. Got '" + filename + "'"
|
564 | });
|
565 | } else if (reservedTransitionNames.includes(_name)) {
|
566 | errors.push({
|
567 | type: "error",
|
568 | code: "GLT_invalid_filename",
|
569 | message: "filename cannot be called '" + _name + "'."
|
570 | });
|
571 | }
|
572 | } else {
|
573 | data.name = filename;
|
574 | errors.push({
|
575 | type: "error",
|
576 | code: "GLT_invalid_filename",
|
577 | message: "filename needs to ends with '.glsl'. Got '" + filename + "'"
|
578 | });
|
579 | }
|
580 |
|
581 | return {
|
582 | data: data,
|
583 | errors: errors
|
584 | };
|
585 | } |
\ | No newline at end of file |