@shaderfrog/glsl-parser
Version:
A GLSL ES 1.0 and 3.0 parser and preprocessor that can preserve whitespace and comments
1,378 lines (1,290 loc) • 477 kB
JavaScript
// Generated by Peggy 1.2.0.
//
// https://peggyjs.org/
import {
makeLocals,
collapse,
partial,
leftAssociate,
isDeclaredFunction,
isDeclaredType,
xnil,
builtIns
} from './grammar.js';
// Apparently peggy can't handle an open curly brace in a string, see
// https://github.com/pegjs/pegjs/issues/187
const OPEN_CURLY = String.fromCharCode(123);
function peg$subclass(child, parent) {
function C() { this.constructor = child; }
C.prototype = parent.prototype;
child.prototype = new C();
}
function peg$SyntaxError(message, expected, found, location) {
var self = Error.call(this, message);
if (Object.setPrototypeOf) {
Object.setPrototypeOf(self, peg$SyntaxError.prototype);
}
self.expected = expected;
self.found = found;
self.location = location;
self.name = "SyntaxError";
return self;
}
peg$subclass(peg$SyntaxError, Error);
function peg$padEnd(str, targetLength, padString) {
padString = padString || " ";
if (str.length > targetLength) { return str; }
targetLength -= str.length;
padString += padString.repeat(targetLength);
return str + padString.slice(0, targetLength);
}
peg$SyntaxError.prototype.format = function(sources) {
var str = "Error: " + this.message;
if (this.location) {
var src = null;
var k;
for (k = 0; k < sources.length; k++) {
if (sources[k].source === this.location.source) {
src = sources[k].text.split(/\r\n|\n|\r/g);
break;
}
}
var s = this.location.start;
var loc = this.location.source + ":" + s.line + ":" + s.column;
if (src) {
var e = this.location.end;
var filler = peg$padEnd("", s.line.toString().length);
var line = src[s.line - 1];
var last = s.line === e.line ? e.column : line.length + 1;
str += "\n --> " + loc + "\n"
+ filler + " |\n"
+ s.line + " | " + line + "\n"
+ filler + " | " + peg$padEnd("", s.column - 1)
+ peg$padEnd("", last - s.column, "^");
} else {
str += "\n at " + loc;
}
}
return str;
};
peg$SyntaxError.buildMessage = function(expected, found) {
var DESCRIBE_EXPECTATION_FNS = {
literal: function(expectation) {
return "\"" + literalEscape(expectation.text) + "\"";
},
class: function(expectation) {
var escapedParts = expectation.parts.map(function(part) {
return Array.isArray(part)
? classEscape(part[0]) + "-" + classEscape(part[1])
: classEscape(part);
});
return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]";
},
any: function() {
return "any character";
},
end: function() {
return "end of input";
},
other: function(expectation) {
return expectation.description;
}
};
function hex(ch) {
return ch.charCodeAt(0).toString(16).toUpperCase();
}
function literalEscape(s) {
return s
.replace(/\\/g, "\\\\")
.replace(/"/g, "\\\"")
.replace(/\0/g, "\\0")
.replace(/\t/g, "\\t")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
}
function classEscape(s) {
return s
.replace(/\\/g, "\\\\")
.replace(/\]/g, "\\]")
.replace(/\^/g, "\\^")
.replace(/-/g, "\\-")
.replace(/\0/g, "\\0")
.replace(/\t/g, "\\t")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
}
function describeExpectation(expectation) {
return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
}
function describeExpected(expected) {
var descriptions = expected.map(describeExpectation);
var i, j;
descriptions.sort();
if (descriptions.length > 0) {
for (i = 1, j = 1; i < descriptions.length; i++) {
if (descriptions[i - 1] !== descriptions[i]) {
descriptions[j] = descriptions[i];
j++;
}
}
descriptions.length = j;
}
switch (descriptions.length) {
case 1:
return descriptions[0];
case 2:
return descriptions[0] + " or " + descriptions[1];
default:
return descriptions.slice(0, -1).join(", ")
+ ", or "
+ descriptions[descriptions.length - 1];
}
}
function describeFound(found) {
return found ? "\"" + literalEscape(found) + "\"" : "end of input";
}
return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
};
function peg$parse(input, options) {
options = options !== undefined ? options : {};
var peg$FAILED = {};
var peg$source = options.grammarSource;
var peg$startRuleFunctions = { start: peg$parsestart };
var peg$startRuleFunction = peg$parsestart;
var peg$c0 = "attribute";
var peg$c1 = "varying";
var peg$c2 = "const";
var peg$c3 = "bool";
var peg$c4 = "float";
var peg$c5 = "double";
var peg$c6 = "int";
var peg$c7 = "uint";
var peg$c8 = "break";
var peg$c9 = "continue";
var peg$c10 = "do";
var peg$c11 = "else";
var peg$c12 = "for";
var peg$c13 = "if";
var peg$c14 = "discard";
var peg$c15 = "return";
var peg$c16 = "switch";
var peg$c17 = "case";
var peg$c18 = "default";
var peg$c19 = "subroutine";
var peg$c20 = "bvec2";
var peg$c21 = "bvec3";
var peg$c22 = "bvec4";
var peg$c23 = "ivec2";
var peg$c24 = "ivec3";
var peg$c25 = "ivec4";
var peg$c26 = "uvec2";
var peg$c27 = "uvec3";
var peg$c28 = "uvec4";
var peg$c29 = "vec2";
var peg$c30 = "vec3";
var peg$c31 = "vec4";
var peg$c32 = "mat2";
var peg$c33 = "mat3";
var peg$c34 = "mat4";
var peg$c35 = "centroid";
var peg$c36 = "in";
var peg$c37 = "out";
var peg$c38 = "inout";
var peg$c39 = "uniform";
var peg$c40 = "patch";
var peg$c41 = "sample";
var peg$c42 = "buffer";
var peg$c43 = "shared";
var peg$c44 = "coherent";
var peg$c45 = "volatile";
var peg$c46 = "restrict";
var peg$c47 = "readonly";
var peg$c48 = "writeonly";
var peg$c49 = "dvec2";
var peg$c50 = "dvec3";
var peg$c51 = "dvec4";
var peg$c52 = "dmat2";
var peg$c53 = "dmat3";
var peg$c54 = "dmat4";
var peg$c55 = "noperspective";
var peg$c56 = "flat";
var peg$c57 = "smooth";
var peg$c58 = "layout";
var peg$c59 = "mat2x2";
var peg$c60 = "mat2x3";
var peg$c61 = "mat2x4";
var peg$c62 = "mat3x2";
var peg$c63 = "mat3x3";
var peg$c64 = "mat3x4";
var peg$c65 = "mat4x2";
var peg$c66 = "mat4x3";
var peg$c67 = "mat4x4";
var peg$c68 = "dmat2x2";
var peg$c69 = "dmat2x3";
var peg$c70 = "dmat2x4";
var peg$c71 = "dmat3x2";
var peg$c72 = "dmat3x3";
var peg$c73 = "dmat3x4";
var peg$c74 = "dmat4x2";
var peg$c75 = "dmat4x3";
var peg$c76 = "dmat4x4";
var peg$c77 = "atomic_uint";
var peg$c78 = "sampler1D";
var peg$c79 = "sampler2D";
var peg$c80 = "sampler3D";
var peg$c81 = "samplerCube";
var peg$c82 = "sampler1DShadow";
var peg$c83 = "sampler2DShadow";
var peg$c84 = "samplerCubeShadow";
var peg$c85 = "sampler1DArray";
var peg$c86 = "sampler2DArray";
var peg$c87 = "sampler1DArrayShadow";
var peg$c88 = "sampler2DArrayShadow";
var peg$c89 = "isampler1D";
var peg$c90 = "isampler2D";
var peg$c91 = "isampler3D";
var peg$c92 = "isamplerCube";
var peg$c93 = "isampler1Darray";
var peg$c94 = "isampler2DArray";
var peg$c95 = "usampler1D";
var peg$c96 = "usampler2D";
var peg$c97 = "usampler3D";
var peg$c98 = "usamplerCube";
var peg$c99 = "usampler1DArray";
var peg$c100 = "usampler2DArray";
var peg$c101 = "sampler2DRect";
var peg$c102 = "sampler2DRectShadow";
var peg$c103 = "isampler2DRect";
var peg$c104 = "usampler2DRect";
var peg$c105 = "samplerBuffer";
var peg$c106 = "isamplerBuffer";
var peg$c107 = "usamplerBuffer";
var peg$c108 = "samplerCubeArray";
var peg$c109 = "samplerCubeArrayShadow";
var peg$c110 = "isamplerCubeArray";
var peg$c111 = "usamplerCubeArray";
var peg$c112 = "sampler2DMS";
var peg$c113 = "isampler2DMS";
var peg$c114 = "usampler2DMS";
var peg$c115 = "sampler2DMSArray";
var peg$c116 = "isampler2DMSArray";
var peg$c117 = "usampler2DMSArray";
var peg$c118 = "image1D";
var peg$c119 = "iimage1D";
var peg$c120 = "uimage1D";
var peg$c121 = "image2D";
var peg$c122 = "iimage2D";
var peg$c123 = "uimage2D";
var peg$c124 = "image3D";
var peg$c125 = "iimage3D";
var peg$c126 = "uimage3D";
var peg$c127 = "image2DRect";
var peg$c128 = "iimage2DRect";
var peg$c129 = "uimage2DRect";
var peg$c130 = "imageCube";
var peg$c131 = "iimageCube";
var peg$c132 = "uimageCube";
var peg$c133 = "imageBuffer";
var peg$c134 = "iimageBuffer";
var peg$c135 = "uimageBuffer";
var peg$c136 = "image1DArray";
var peg$c137 = "iimage1DArray";
var peg$c138 = "uimage1DArray";
var peg$c139 = "image2DArray";
var peg$c140 = "iimage2DArray";
var peg$c141 = "uimage2DArray";
var peg$c142 = "imageCubeArray";
var peg$c143 = "iimageCubeArray";
var peg$c144 = "uimageCubeArray";
var peg$c145 = "image2DMS";
var peg$c146 = "iimage2DMS";
var peg$c147 = "uimage2DMS";
var peg$c148 = "image2DMArray";
var peg$c149 = "iimage2DMSArray";
var peg$c150 = "uimage2DMSArray";
var peg$c151 = "struct";
var peg$c152 = "void";
var peg$c153 = "while";
var peg$c154 = "invariant";
var peg$c155 = "precise";
var peg$c156 = "highp";
var peg$c157 = "mediump";
var peg$c158 = "lowp";
var peg$c159 = "precision";
var peg$c160 = "true";
var peg$c161 = "false";
var peg$c162 = "<<";
var peg$c163 = ">>";
var peg$c164 = "++";
var peg$c165 = "--";
var peg$c166 = "<=";
var peg$c167 = ">=";
var peg$c168 = "==";
var peg$c169 = "!=";
var peg$c170 = "&&";
var peg$c171 = "||";
var peg$c172 = "^^";
var peg$c173 = "*=";
var peg$c174 = "/=";
var peg$c175 = "+=";
var peg$c176 = "%=";
var peg$c177 = "<<=";
var peg$c178 = ">>=";
var peg$c179 = "&=";
var peg$c180 = "^=";
var peg$c181 = "|=";
var peg$c182 = "-=";
var peg$c183 = "(";
var peg$c184 = ")";
var peg$c185 = "[";
var peg$c186 = "]";
var peg$c187 = "{";
var peg$c188 = "}";
var peg$c189 = ".";
var peg$c190 = ",";
var peg$c191 = ":";
var peg$c192 = "=";
var peg$c193 = ";";
var peg$c194 = "!";
var peg$c195 = "-";
var peg$c196 = "~";
var peg$c197 = "+";
var peg$c198 = "*";
var peg$c199 = "/";
var peg$c200 = "%";
var peg$c201 = "<";
var peg$c202 = ">";
var peg$c203 = "|";
var peg$c204 = "^";
var peg$c205 = "&";
var peg$c206 = "?";
var peg$c207 = "0";
var peg$c208 = "lf";
var peg$c209 = "LF";
var peg$c210 = "#";
var peg$c211 = "//";
var peg$c212 = "/*";
var peg$c213 = "*/";
var peg$r0 = /^[A-Za-z_]/;
var peg$r1 = /^[A-Za-z_0-9]/;
var peg$r2 = /^[uU]/;
var peg$r3 = /^[1-9]/;
var peg$r4 = /^[0-7]/;
var peg$r5 = /^[xX]/;
var peg$r6 = /^[0-9a-fA-F]/;
var peg$r7 = /^[0-9]/;
var peg$r8 = /^[eE]/;
var peg$r9 = /^[+\-]/;
var peg$r10 = /^[fF]/;
var peg$r11 = /^[^\n]/;
var peg$r12 = /^[ \t\n\r]/;
var peg$e0 = peg$literalExpectation("attribute", false);
var peg$e1 = peg$literalExpectation("varying", false);
var peg$e2 = peg$literalExpectation("const", false);
var peg$e3 = peg$literalExpectation("bool", false);
var peg$e4 = peg$literalExpectation("float", false);
var peg$e5 = peg$literalExpectation("double", false);
var peg$e6 = peg$literalExpectation("int", false);
var peg$e7 = peg$literalExpectation("uint", false);
var peg$e8 = peg$literalExpectation("break", false);
var peg$e9 = peg$literalExpectation("continue", false);
var peg$e10 = peg$literalExpectation("do", false);
var peg$e11 = peg$literalExpectation("else", false);
var peg$e12 = peg$literalExpectation("for", false);
var peg$e13 = peg$literalExpectation("if", false);
var peg$e14 = peg$literalExpectation("discard", false);
var peg$e15 = peg$literalExpectation("return", false);
var peg$e16 = peg$literalExpectation("switch", false);
var peg$e17 = peg$literalExpectation("case", false);
var peg$e18 = peg$literalExpectation("default", false);
var peg$e19 = peg$literalExpectation("subroutine", false);
var peg$e20 = peg$literalExpectation("bvec2", false);
var peg$e21 = peg$literalExpectation("bvec3", false);
var peg$e22 = peg$literalExpectation("bvec4", false);
var peg$e23 = peg$literalExpectation("ivec2", false);
var peg$e24 = peg$literalExpectation("ivec3", false);
var peg$e25 = peg$literalExpectation("ivec4", false);
var peg$e26 = peg$literalExpectation("uvec2", false);
var peg$e27 = peg$literalExpectation("uvec3", false);
var peg$e28 = peg$literalExpectation("uvec4", false);
var peg$e29 = peg$literalExpectation("vec2", false);
var peg$e30 = peg$literalExpectation("vec3", false);
var peg$e31 = peg$literalExpectation("vec4", false);
var peg$e32 = peg$literalExpectation("mat2", false);
var peg$e33 = peg$literalExpectation("mat3", false);
var peg$e34 = peg$literalExpectation("mat4", false);
var peg$e35 = peg$literalExpectation("centroid", false);
var peg$e36 = peg$literalExpectation("in", false);
var peg$e37 = peg$literalExpectation("out", false);
var peg$e38 = peg$literalExpectation("inout", false);
var peg$e39 = peg$literalExpectation("uniform", false);
var peg$e40 = peg$literalExpectation("patch", false);
var peg$e41 = peg$literalExpectation("sample", false);
var peg$e42 = peg$literalExpectation("buffer", false);
var peg$e43 = peg$literalExpectation("shared", false);
var peg$e44 = peg$literalExpectation("coherent", false);
var peg$e45 = peg$literalExpectation("volatile", false);
var peg$e46 = peg$literalExpectation("restrict", false);
var peg$e47 = peg$literalExpectation("readonly", false);
var peg$e48 = peg$literalExpectation("writeonly", false);
var peg$e49 = peg$literalExpectation("dvec2", false);
var peg$e50 = peg$literalExpectation("dvec3", false);
var peg$e51 = peg$literalExpectation("dvec4", false);
var peg$e52 = peg$literalExpectation("dmat2", false);
var peg$e53 = peg$literalExpectation("dmat3", false);
var peg$e54 = peg$literalExpectation("dmat4", false);
var peg$e55 = peg$literalExpectation("noperspective", false);
var peg$e56 = peg$literalExpectation("flat", false);
var peg$e57 = peg$literalExpectation("smooth", false);
var peg$e58 = peg$literalExpectation("layout", false);
var peg$e59 = peg$literalExpectation("mat2x2", false);
var peg$e60 = peg$literalExpectation("mat2x3", false);
var peg$e61 = peg$literalExpectation("mat2x4", false);
var peg$e62 = peg$literalExpectation("mat3x2", false);
var peg$e63 = peg$literalExpectation("mat3x3", false);
var peg$e64 = peg$literalExpectation("mat3x4", false);
var peg$e65 = peg$literalExpectation("mat4x2", false);
var peg$e66 = peg$literalExpectation("mat4x3", false);
var peg$e67 = peg$literalExpectation("mat4x4", false);
var peg$e68 = peg$literalExpectation("dmat2x2", false);
var peg$e69 = peg$literalExpectation("dmat2x3", false);
var peg$e70 = peg$literalExpectation("dmat2x4", false);
var peg$e71 = peg$literalExpectation("dmat3x2", false);
var peg$e72 = peg$literalExpectation("dmat3x3", false);
var peg$e73 = peg$literalExpectation("dmat3x4", false);
var peg$e74 = peg$literalExpectation("dmat4x2", false);
var peg$e75 = peg$literalExpectation("dmat4x3", false);
var peg$e76 = peg$literalExpectation("dmat4x4", false);
var peg$e77 = peg$literalExpectation("atomic_uint", false);
var peg$e78 = peg$literalExpectation("sampler1D", false);
var peg$e79 = peg$literalExpectation("sampler2D", false);
var peg$e80 = peg$literalExpectation("sampler3D", false);
var peg$e81 = peg$literalExpectation("samplerCube", false);
var peg$e82 = peg$literalExpectation("sampler1DShadow", false);
var peg$e83 = peg$literalExpectation("sampler2DShadow", false);
var peg$e84 = peg$literalExpectation("samplerCubeShadow", false);
var peg$e85 = peg$literalExpectation("sampler1DArray", false);
var peg$e86 = peg$literalExpectation("sampler2DArray", false);
var peg$e87 = peg$literalExpectation("sampler1DArrayShadow", false);
var peg$e88 = peg$literalExpectation("sampler2DArrayShadow", false);
var peg$e89 = peg$literalExpectation("isampler1D", false);
var peg$e90 = peg$literalExpectation("isampler2D", false);
var peg$e91 = peg$literalExpectation("isampler3D", false);
var peg$e92 = peg$literalExpectation("isamplerCube", false);
var peg$e93 = peg$literalExpectation("isampler1Darray", false);
var peg$e94 = peg$literalExpectation("isampler2DArray", false);
var peg$e95 = peg$literalExpectation("usampler1D", false);
var peg$e96 = peg$literalExpectation("usampler2D", false);
var peg$e97 = peg$literalExpectation("usampler3D", false);
var peg$e98 = peg$literalExpectation("usamplerCube", false);
var peg$e99 = peg$literalExpectation("usampler1DArray", false);
var peg$e100 = peg$literalExpectation("usampler2DArray", false);
var peg$e101 = peg$literalExpectation("sampler2DRect", false);
var peg$e102 = peg$literalExpectation("sampler2DRectShadow", false);
var peg$e103 = peg$literalExpectation("isampler2DRect", false);
var peg$e104 = peg$literalExpectation("usampler2DRect", false);
var peg$e105 = peg$literalExpectation("samplerBuffer", false);
var peg$e106 = peg$literalExpectation("isamplerBuffer", false);
var peg$e107 = peg$literalExpectation("usamplerBuffer", false);
var peg$e108 = peg$literalExpectation("samplerCubeArray", false);
var peg$e109 = peg$literalExpectation("samplerCubeArrayShadow", false);
var peg$e110 = peg$literalExpectation("isamplerCubeArray", false);
var peg$e111 = peg$literalExpectation("usamplerCubeArray", false);
var peg$e112 = peg$literalExpectation("sampler2DMS", false);
var peg$e113 = peg$literalExpectation("isampler2DMS", false);
var peg$e114 = peg$literalExpectation("usampler2DMS", false);
var peg$e115 = peg$literalExpectation("sampler2DMSArray", false);
var peg$e116 = peg$literalExpectation("isampler2DMSArray", false);
var peg$e117 = peg$literalExpectation("usampler2DMSArray", false);
var peg$e118 = peg$literalExpectation("image1D", false);
var peg$e119 = peg$literalExpectation("iimage1D", false);
var peg$e120 = peg$literalExpectation("uimage1D", false);
var peg$e121 = peg$literalExpectation("image2D", false);
var peg$e122 = peg$literalExpectation("iimage2D", false);
var peg$e123 = peg$literalExpectation("uimage2D", false);
var peg$e124 = peg$literalExpectation("image3D", false);
var peg$e125 = peg$literalExpectation("iimage3D", false);
var peg$e126 = peg$literalExpectation("uimage3D", false);
var peg$e127 = peg$literalExpectation("image2DRect", false);
var peg$e128 = peg$literalExpectation("iimage2DRect", false);
var peg$e129 = peg$literalExpectation("uimage2DRect", false);
var peg$e130 = peg$literalExpectation("imageCube", false);
var peg$e131 = peg$literalExpectation("iimageCube", false);
var peg$e132 = peg$literalExpectation("uimageCube", false);
var peg$e133 = peg$literalExpectation("imageBuffer", false);
var peg$e134 = peg$literalExpectation("iimageBuffer", false);
var peg$e135 = peg$literalExpectation("uimageBuffer", false);
var peg$e136 = peg$literalExpectation("image1DArray", false);
var peg$e137 = peg$literalExpectation("iimage1DArray", false);
var peg$e138 = peg$literalExpectation("uimage1DArray", false);
var peg$e139 = peg$literalExpectation("image2DArray", false);
var peg$e140 = peg$literalExpectation("iimage2DArray", false);
var peg$e141 = peg$literalExpectation("uimage2DArray", false);
var peg$e142 = peg$literalExpectation("imageCubeArray", false);
var peg$e143 = peg$literalExpectation("iimageCubeArray", false);
var peg$e144 = peg$literalExpectation("uimageCubeArray", false);
var peg$e145 = peg$literalExpectation("image2DMS", false);
var peg$e146 = peg$literalExpectation("iimage2DMS", false);
var peg$e147 = peg$literalExpectation("uimage2DMS", false);
var peg$e148 = peg$literalExpectation("image2DMArray", false);
var peg$e149 = peg$literalExpectation("iimage2DMSArray", false);
var peg$e150 = peg$literalExpectation("uimage2DMSArray", false);
var peg$e151 = peg$literalExpectation("struct", false);
var peg$e152 = peg$literalExpectation("void", false);
var peg$e153 = peg$literalExpectation("while", false);
var peg$e154 = peg$literalExpectation("invariant", false);
var peg$e155 = peg$literalExpectation("precise", false);
var peg$e156 = peg$literalExpectation("highp", false);
var peg$e157 = peg$literalExpectation("mediump", false);
var peg$e158 = peg$literalExpectation("lowp", false);
var peg$e159 = peg$literalExpectation("precision", false);
var peg$e160 = peg$literalExpectation("true", false);
var peg$e161 = peg$literalExpectation("false", false);
var peg$e162 = peg$otherExpectation("keyword");
var peg$e163 = peg$literalExpectation("<<", false);
var peg$e164 = peg$literalExpectation(">>", false);
var peg$e165 = peg$literalExpectation("++", false);
var peg$e166 = peg$literalExpectation("--", false);
var peg$e167 = peg$literalExpectation("<=", false);
var peg$e168 = peg$literalExpectation(">=", false);
var peg$e169 = peg$literalExpectation("==", false);
var peg$e170 = peg$literalExpectation("!=", false);
var peg$e171 = peg$literalExpectation("&&", false);
var peg$e172 = peg$literalExpectation("||", false);
var peg$e173 = peg$literalExpectation("^^", false);
var peg$e174 = peg$literalExpectation("*=", false);
var peg$e175 = peg$literalExpectation("/=", false);
var peg$e176 = peg$literalExpectation("+=", false);
var peg$e177 = peg$literalExpectation("%=", false);
var peg$e178 = peg$literalExpectation("<<=", false);
var peg$e179 = peg$literalExpectation(">>=", false);
var peg$e180 = peg$literalExpectation("&=", false);
var peg$e181 = peg$literalExpectation("^=", false);
var peg$e182 = peg$literalExpectation("|=", false);
var peg$e183 = peg$literalExpectation("-=", false);
var peg$e184 = peg$literalExpectation("(", false);
var peg$e185 = peg$literalExpectation(")", false);
var peg$e186 = peg$literalExpectation("[", false);
var peg$e187 = peg$literalExpectation("]", false);
var peg$e188 = peg$literalExpectation("{", false);
var peg$e189 = peg$literalExpectation("}", false);
var peg$e190 = peg$literalExpectation(".", false);
var peg$e191 = peg$literalExpectation(",", false);
var peg$e192 = peg$literalExpectation(":", false);
var peg$e193 = peg$literalExpectation("=", false);
var peg$e194 = peg$literalExpectation(";", false);
var peg$e195 = peg$literalExpectation("!", false);
var peg$e196 = peg$literalExpectation("-", false);
var peg$e197 = peg$literalExpectation("~", false);
var peg$e198 = peg$literalExpectation("+", false);
var peg$e199 = peg$literalExpectation("*", false);
var peg$e200 = peg$literalExpectation("/", false);
var peg$e201 = peg$literalExpectation("%", false);
var peg$e202 = peg$literalExpectation("<", false);
var peg$e203 = peg$literalExpectation(">", false);
var peg$e204 = peg$literalExpectation("|", false);
var peg$e205 = peg$literalExpectation("^", false);
var peg$e206 = peg$literalExpectation("&", false);
var peg$e207 = peg$literalExpectation("?", false);
var peg$e208 = peg$classExpectation([["A", "Z"], ["a", "z"], "_"], false, false);
var peg$e209 = peg$classExpectation([["A", "Z"], ["a", "z"], "_", ["0", "9"]], false, false);
var peg$e210 = peg$classExpectation(["u", "U"], false, false);
var peg$e211 = peg$classExpectation([["1", "9"]], false, false);
var peg$e212 = peg$literalExpectation("0", false);
var peg$e213 = peg$classExpectation([["0", "7"]], false, false);
var peg$e214 = peg$classExpectation(["x", "X"], false, false);
var peg$e215 = peg$classExpectation([["0", "9"], ["a", "f"], ["A", "F"]], false, false);
var peg$e216 = peg$classExpectation([["0", "9"]], false, false);
var peg$e217 = peg$otherExpectation("exponent");
var peg$e218 = peg$classExpectation(["e", "E"], false, false);
var peg$e219 = peg$classExpectation(["+", "-"], false, false);
var peg$e220 = peg$classExpectation(["f", "F"], false, false);
var peg$e221 = peg$literalExpectation("lf", false);
var peg$e222 = peg$literalExpectation("LF", false);
var peg$e223 = peg$otherExpectation("primary expression");
var peg$e224 = peg$otherExpectation("unary expression");
var peg$e225 = peg$otherExpectation("equality expression");
var peg$e226 = peg$otherExpectation("and expression");
var peg$e227 = peg$otherExpectation("asignment");
var peg$e228 = peg$otherExpectation("expression");
var peg$e229 = peg$otherExpectation("precision statement");
var peg$e230 = peg$otherExpectation("function prototype");
var peg$e231 = peg$otherExpectation("function header");
var peg$e232 = peg$otherExpectation("function prototype scope");
var peg$e233 = peg$otherExpectation("function header scope");
var peg$e234 = peg$otherExpectation("function parameters");
var peg$e235 = peg$otherExpectation("parameter declaration");
var peg$e236 = peg$otherExpectation("single type qualifier");
var peg$e237 = peg$otherExpectation("interpolation qualifier");
var peg$e238 = peg$otherExpectation("storage qualifier");
var peg$e239 = peg$otherExpectation("type specifier");
var peg$e240 = peg$otherExpectation("array specifier");
var peg$e241 = peg$otherExpectation("precision qualifier");
var peg$e242 = peg$otherExpectation("struct specifier");
var peg$e243 = peg$otherExpectation("iteration statement");
var peg$e244 = peg$otherExpectation("jump statement");
var peg$e245 = peg$otherExpectation("prepocessor");
var peg$e246 = peg$literalExpectation("#", false);
var peg$e247 = peg$classExpectation(["\n"], true, false);
var peg$e248 = peg$otherExpectation("whitespace");
var peg$e249 = peg$literalExpectation("//", false);
var peg$e250 = peg$literalExpectation("/*", false);
var peg$e251 = peg$literalExpectation("*/", false);
var peg$e252 = peg$anyExpectation();
var peg$e253 = peg$classExpectation([" ", "\t", "\n", "\r"], false, false);
var peg$f0 = function(wsStart, program) {
// Set the global scope end to the end of the program
setScopeEnd(context.scope, getLocation()?.end);
return node('program', { wsStart, program, scopes: context.scopes });
};
var peg$f1 = function(token, t) { return node('keyword', { token, whitespace: t }); };
var peg$f2 = function(token, _) { return node('float_constant', { token, whitespace: _ }); };
var peg$f3 = function(token, _) { return node('double_constant', { token, whitespace: _ }); };
var peg$f4 = function(token, _) { return node('int_constant', { token, whitespace: _ }); };
var peg$f5 = function(token, _) { return node('uint_constant', { token, whitespace: _ }); };
var peg$f6 = function(token, _) { return node('bool_constant', { token, whitespace:_ }); };
var peg$f7 = function(token, _) { return node('literal', { literal: token, whitespace: _ }); };
var peg$f8 = function(identifier, _) {
return node('identifier', { identifier, whitespace: _ });
};
var peg$f9 = function(identifier, _) {
return node('type_name', { identifier, whitespace: _ });
};
var peg$f10 = function(lp, expression, rp) {
return node('group', { lp, expression, rp });
};
var peg$f11 = function(ident) {
const { identifier } = ident;
addOrCreateBindingReference(context.scope, identifier, ident);
return ident;
};
var peg$f12 = function(body) {
// Postfix becomes a left associative tree
return body.flat().reduceRight((postfix, expression) =>
postfix ?
node('postfix', { expression, postfix }) :
expression
);
};
var peg$f13 = function(lb, expression, rb) {
return node('quantifier', { lb, expression, rb });
};
var peg$f14 = function(dot, selection) {
return node('field_selection', { dot, selection });
};
var peg$f15 = function(function_identifier, args, rp) {
const identifierPartial = function_identifier.partial;
const { identifier } = identifierPartial;
// Identify the function name, if present. Note: The inner postfix branch
// below probably means there's a discrepancy in how the postfix fn is
// identified, depending on the prefix.
let fnIdentifier =
identifier.type === 'postfix'
? identifier.expression.identifier
// Handles the case where the postfix is x().length()
? identifier.expression.identifier.specifier
// Handles the case where the postfix is x.length()
: identifier.expression.specifier
// Non-built-in-type (like "vec4") function call
: identifier.specifier;
let fnName = fnIdentifier.identifier;
const n = node('function_call', { ...identifierPartial, args: args || [], rp });
const isDeclaredFn = isDeclaredFunction(context.scope, fnName);
const isBuiltIn = builtIns.has(fnName);
const isType = isDeclaredType(context.scope, fnName);
// fnName will be undefined here if the identifier is a keyword
// constructor (like "vec4()"). We don't care about scope/renaming in
// these cases
if(fnName) {
/*
* This complexity is from the intentional choice of the parser to allow
* for undeclared structs and functions, combined with the fact that
* struct names can be used as function constructors. There are two
* cases where this matters:
* 1. "MyStruct()" when MyStruct isn't defined
* 2. "texture2D()" which is a built-in function call
* In the Khronos grammar, the first case is supposed to fail, because
* when it checks TYPE_NAME, it doesn't find it declared, and then it
* moves on to the second case, which is what texture2D does. In the
* Khronos grammar, POSTFIX then catches the IDENTIFIER in both cases. In
* this parser, TYPE_NAME catches it, because it's ambiguous if this is
* a type or an identifier, since we alllow undefined types. Fortunately
* this is the only place in the grammar where a TYPE_NAME and IDENTIFIER
* could be used in the same place, so we only have to handle this here.
*
* So once we define the function_call, we need to check if we really did
* hit a type name, or not, or a built in (like "texture2D()"), here
* we mutate the function header to be an identifier rather than a type.
*/
if(!isType && fnIdentifier.type === 'type_name' && (!isDeclaredFn || isBuiltIn)) {
fnIdentifier = node('identifier', {
identifier: fnIdentifier.identifier,
whitespace: fnIdentifier.whitespace
});
if(n.identifier.type === 'postfix') {
n.identifier.expression.identifier = fnIdentifier;
} else {
n.identifier = fnIdentifier;
}
}
// Now do the scope check
if(
// You can override built-in functions like "noise", so only add
// "noise" to scope usage if it's declared by the user
(isDeclaredFn || !isBuiltIn)
) {
// Struct constructors look like function calls. If this is a struct,
// treat it as a type.
if(isType) {
if(identifier.type === 'type_specifier') {
addTypeReference(
context.scope,
fnName,
identifier.specifier
);
} else {
throw new Error(`Unknown function call identifier type ${
identifier.type
}. Please file a bug against @shaderfrog/glsl-parser and incldue your source grammar.`)
}
} else {
addFunctionCallReference(context.scope, fnName, n);
}
}
}
return n;
};
var peg$f16 = function(v) {
return [v];
};
var peg$f17 = function(head, tail) {
// For convenience, we don't store commas as trees, but rather flatten
// into an array
return [head, ...tail.flat()];
};
var peg$f18 = function(head, suffix, lp) {
return partial({ head: [head, suffix], lp });
};
var peg$f19 = function(identifier) {
return partial({
lp: identifier.partial.lp,
identifier: [identifier.partial.head].flat().reduceRight((postfix, expression) =>
postfix ?
node('postfix', { expression, postfix }) :
expression
)
});
};
var peg$f20 = function(identifier, lp, args, rp) {
return node('function_call', { identifier, lp, args, rp });
};
var peg$f21 = function(operator, expression) {
return node('unary', { operator, expression });
};
var peg$f22 = function(head, tail) {
return leftAssociate(head, tail);
};
var peg$f23 = function(expression, question, left, colon, right) {
return { question, left, right, colon };
};
var peg$f24 = function(expression, suffix) {
// ? and : operators are right associative, which happens automatically
// in pegjs grammar
return suffix ?
node('ternary', { expression, ...suffix }) :
expression
};
var peg$f25 = function(left, operator, right) {
return node('assignment', { left, operator, right });
};
var peg$f26 = function(declaration) {
return node(
'declaration_statement',
{
declaration: declaration.partial.node,
semi: declaration.partial.semi,
}
);
};
var peg$f27 = function(qualifiers, head, tail, semi) {
return partial({
node: node(
'qualifier_declarator',
{
qualifiers,
// Head is optional, so remove falsey
declarations: xnil([head, ...tail.map(t => t[1])]),
commas: tail.map(t => t[0])
}
),
semi
});
};
var peg$f28 = function(qualifiers, interface_type, lp, declarations, rp, identifier, semi) {
const n = node(
'interface_declarator',
{ qualifiers, interface_type, lp, declarations, rp, identifier }
);
createBindings(context.scope, [interface_type.identifier, n]);
return partial({
node: n,
semi
});
};
var peg$f29 = function(prefix, qualifier, specifier, semi) {
return partial({
node: node('precision', { prefix, qualifier, specifier }),
semi
});
};
var peg$f30 = function(header, params, rp) {
// Add function parameters to current scope (which is the function scope
// created in function_header_new_scope) before we encounter the function
// body.
const bindings = (params?.parameters || [])
// Ignore any param without an identifier, aka main(void)
.filter(p => !!p.identifier)
.map(p => [p.identifier.identifier, p]);
createBindings(context.scope, ...bindings)
return node('function_prototype', { header, ...params, rp });
};
var peg$f31 = function(returnType, name, lp) {
const n = node(
'function_header',
{ returnType, name, lp }
);
context.scope = pushScope(makeScope(name.identifier, context.scope, lp.location));
return n;
};
var peg$f32 = function(header, params, rp) {
return node('function_prototype', { header, ...params, rp });
};
var peg$f33 = function(returnType, name, lp) {
return node(
'function_header',
{ returnType, name, lp }
);
};
var peg$f34 = function(head, tail) {
return {
parameters: [head, ...tail.map(t => t[1])],
commas: tail.map(t => t[0])
}
};
var peg$f35 = function(qualifier, specifier, declaration) {
return node(
'parameter_declaration',
{
qualifier,
specifier,
identifier: declaration?.[0],
quantifier: declaration?.[1]
}
);
};
var peg$f36 = function(head, tail, semi) {
const declarations = [
head.partial.declaration, ...tail.map(t => t[1])
].filter(decl => !!decl.identifier);
addTypeIfFound(context.scope, head.partial.specified_type);
// initial_declaration also adds bindings to support "int a = 1, b = a;"
createBindings(context.scope, ...tail.map(t => t[1]).map(decl => [decl.identifier.identifier, decl]));
return partial({
node: node(
'declarator_list',
{
specified_type: head.partial.specified_type,
declarations,
commas: tail.map(t => t[0])
}
),
semi
});
};
var peg$f37 = function(identifier, quantifier, suffix) {
const [equal, initializer] = suffix || [];
return node(
'declaration',
{ identifier, quantifier, equal, initializer }
);
};
var peg$f38 = function(specified_type, suffix) {
// No gaurantee of a suffix because fully_specified_type contains a
// type_specifier which includes structs and type_names
const [identifier, quantifier, suffix_tail] = suffix || [];
const [equal, initializer] = suffix_tail || [];
// This production is used as part of init_declarator_list, where we also
// add bindings, but I add bindings here to support "int a = 1, b = a;"
if(identifier) {
createBindings(context.scope, [identifier.identifier, identifier]);
}
// Break out the specified type so it can be grouped into the
// declarator_list
return partial({
declaration: node(
'declaration',
{ identifier, quantifier, equal, initializer }
),
specified_type
});
};
var peg$f39 = function(qualifiers, specifier) {
return node(
'fully_specified_type',
{ qualifiers, specifier }
);
};
var peg$f40 = function(layout, lp, head, tail) {
return partial({
qualifiers: [head, ...tail.map(t => t[1])],
commas: tail.map(t => t[0])
});
};
var peg$f41 = function(layout, lp, qualifiers, rp) {
return node(
'layout_qualifier',
{ layout, lp, ...(qualifiers.partial), rp }
);
};
var peg$f42 = function(identifier, tail) {
const [operator, expression] = tail || [];
return node('layout_qualifier_id', { identifier, operator, expression });
};
var peg$f43 = function(subroutine, lp, head, tail, rp) {
return partial({
lp,
type_names: [head, ...tail.map(t => t[1])],
commas: tail.map(t => t[0]),
rp,
});
};
var peg$f44 = function(subroutine, type_names) {
return node(
'subroutine_qualifier',
{
subroutine,
...(type_names?.partial),
}
);
};
var peg$f45 = function(specifier, quantifier) {
return node('type_specifier', { specifier, quantifier });
};
var peg$f46 = function(lb, expression, rb) {
return node('array_specifier', { lb, expression, rb });
};
var peg$f47 = function(specifiers) {
return specifiers;
};
var peg$f48 = function(struct, typeName, lb, declarations, rb) {
const n = node('struct', { lb, declarations, rb, struct, typeName });
// Anonymous structs don't get a type name
if(typeName) {
createType(context.scope, typeName.identifier, n.typeName);
}
return n;
};
var peg$f49 = function(declaration, semi) {
addTypeIfFound(context.scope, declaration.specified_type);
return node('struct_declaration', { declaration, semi });
};
var peg$f50 = function(specified_type, head, tail) {
if(specified_type)
return node(
'struct_declarator',
{
specified_type,
declarations: [head, ...tail.map(t => t[1])],
commas: tail.map(t => t[0])
}
);
};
var peg$f51 = function(identifier, quantifier) {
return node('quantified_identifier', { identifier, quantifier });
};
var peg$f52 = function(lb, head, tail, trailing, rb) {
// TODO: Scope
return node(
'initializer_list',
{
lb,
initializers: [head, ...tail.map(t => t[1])],
commas: xnil(tail.map(t => t[0]), trailing),
rb
}
);
};
var peg$f53 = function(sym) {
context.scope = pushScope(makeScope(OPEN_CURLY, context.scope));
return sym;
};
var peg$f54 = function(lb, statements, rb) {
// Use start of right bracket, so trailing whitespace is not counted towards
// scope range
setScopeEnd(context.scope, rb.location?.start);
context.scope = popScope(context.scope);
return node(
'compound_statement',
{ lb, statements: (statements || []).flat(), rb }
);
};
var peg$f55 = function(lb, statements, rb) {
return node(
'compound_statement',
{ lb, statements: (statements || []).flat(), rb }
);
};
var peg$f56 = function(expression, semi) {
return node('expression_statement', { expression, semi });
};
var peg$f57 = function(ifSymbol, lp, condition, rp, tail) {
const [body, elseBranch] = tail;
return node(
'if_statement',
{
'if': ifSymbol,
body,
lp,
condition,
rp,
...(elseBranch && { 'else': elseBranch.flat() }),
});
};
var peg$f58 = function(switchSymbol, lp, expression, rp, lb, statements, rb) {
// TODO: Scope?
return node(
'switch_statement',
{
switch: switchSymbol,
lp,
expression,
rp,
lb,
cases: groupCases(statements),
rb
}
);
};
var peg$f59 = function(caseSymbol, test, colon) {
return partial('case_label', { 'case': caseSymbol, test, colon });
};
var peg$f60 = function(defaultSymbol, colon) {
return partial('default_label', { default: defaultSymbol, colon });
};
var peg$f61 = function(sym) {
context.scope = pushScope(makeScope('while', context.scope));
return sym;
};
var peg$f62 = function(whileSymbol, lp, condition, rp, body) {
// use right bracket or fallback to location.end
const end = body.rb ? body.rb.location?.start : body.location?.end;
setScopeEnd(context.scope, end);
context.scope = popScope(context.scope);
return node(
'while_statement',
{
while: whileSymbol,
lp,
condition,
rp,
body
}
);
};
var peg$f63 = function(doSymbol, body, whileSymbol, lp, expression, rp, semi) {
return node(
'do_statement',
{
do: doSymbol,
body,
while: whileSymbol,
lp,
expression,
rp,
semi
}
);
};
var peg$f64 = function(sym) {
context.scope = pushScope(makeScope('for', context.scope));
return sym;
};
var peg$f65 = function(forSymbol, lp, init, condition, conditionSemi, operation, rp, body) {
const end = body.rb ? body.rb.location?.start : body.location?.end;
setScopeEnd(context.scope, end);
context.scope = popScope(context.scope);
return node(
'for_statement',
{
'for': forSymbol,
body,
lp,
init: init.expression || init.declaration,
initSemi: init.semi,
condition,
conditionSemi,
operation,
rp
}
);
};
var peg$f66 = function(specified_type, identifier, operator, initializer) {
const n = node(
'condition_expression',
{ specified_type, identifier, operator, initializer }
);
createBindings(context.scope, [identifier.identifier, n]);
return n;
};
var peg$f67 = function(jump, semi) {
return node('continue_statement', { continue: jump, semi });
};
var peg$f68 = function(jump, semi) {
return node('break_statement', { break: jump, semi });
};
var peg$f69 = function(jump, expression, semi) {
return node('return_statement', { return: jump, expression, semi });
};
var peg$f70 = function(jump, semi) { // Fragment shader only.
return node('discard_statement', { discard: jump, semi });
};
var peg$f71 = function(line, _) { return node('preprocessor', { line, _ }); };
var peg$f72 = function(declaration, semi) {
(declaration.parameters || []).forEach(p => addTypeIfFound(context.scope, p.specifier));
addTypeIfFound(context.scope, declaration.header.returnType);
createFunctionPrototype(context.scope, declaration.header.name.identifier, declaration);
const n = node(
'declaration_statement',
{
declaration,
semi,
}
);
return n;
};
var peg$f73 = function(prototype, body) {
const n = node('function', { prototype, body });
setScopeEnd(context.scope, body.rb.location?.start);
context.scope = popScope(context.scope);
// Check the return type and parameters for any customer type usage. This
// has to be done in the global scope, even though function parameters are
// bound to the function scope, becuase the *types* come from the global
// scope. In:
// void main(MyStruct x) { struct MyStruct {...} }
// MyStruct is global, and shouldn't match the inner shadowing MyStruct, so
// the check for types has to be done after we pop the scope
(prototype.parameters || []).forEach(p => addTypeIfFound(context.scope, p.specifier));
addTypeIfFound(context.scope, prototype.header.returnType);
createFunctionDefinition(context.scope, prototype.header.name.identifier, n, n);
return n;
};
var peg$f74 = function(w, rest) {
return collapse(w, rest);
};
var peg$f75 = function(a, x, cc) {
return xnil(x, cc);
};
var peg$f76 = function(a, d) { return xnil(a, d.flat()); };
var peg$f77 = function(i) { return i; };
var peg$f78 = function(_) { return _; };
var peg$currPos = 0;
var peg$savedPos = 0;
var peg$posDetailsCache = [{ line: 1, column: 1 }];
var peg$maxFailPos = 0;
var peg$maxFailExpected = [];
var peg$silentFails = 0;
var peg$resultsCache = {};
var peg$result;
if ("startRule" in options) {
if (!(options.startRule in peg$startRuleFunctions)) {
throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
}
peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
}
function text() {
return input.substring(peg$savedPos, peg$currPos);
}
function offset() {
return peg$savedPos;
}
function range() {
return {
source: peg$source,
start: peg$savedPos,
end: peg$currPos
};
}
function location() {
return peg$computeLocation(peg$savedPos, peg$currPos);
}
function expected(description, location) {
location = location !== undefined
? location
: peg$computeLocation(peg$savedPos, peg$currPos);
throw peg$buildStructuredError(
[peg$otherExpectation(description)],
input.substring(peg$savedPos, peg$currPos),
location
);
}
function error(message, location) {
location = location !== undefined
? location
: peg$computeLocation(peg$savedPos, peg$currPos);
throw peg$buildSimpleError(message, location);
}
function peg$literalExpectation(text, ignoreCase) {
return { type: "literal", text: text, ignoreCase: ignoreCase };
}
function peg$classExpectation(parts, inverted, ignoreCase) {
return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };
}
function peg$anyExpectation() {
return { type: "any" };
}
function peg$endExpectation() {
return { type: "end" };
}
function peg$otherExpectation(description) {
return { type: "other", description: description };
}
function peg$computePosDetails(pos) {
var details = peg$posDetailsCache[pos];
var p;
if (details) {
return details;
} else {
p = pos - 1;
while (!peg$posDetailsCache[p]) {
p--;
}
details = peg$posDetailsCache[p];
details = {
line: details.line,
column: details.column
};
while (p < pos) {
if (input.charCodeAt(p) === 10) {
details.line++;
details.column = 1;
} else {
details.column++;
}
p++;
}
peg$posDetailsCache[pos] = details;
return details;
}
}
function peg$computeLocation(startPos, endPos) {
var startPosDetails = peg$computePosDetails(startPos);
var endPosDetails = peg$computePosDetails(endPos);
return {
source: peg$source,
start: {
offset: startPos,
line: