Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / dom / canvas / WebGLValidateStrings.cpp
blob43b814e83598b560d93bb1a23571d4e2e417c2dc
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "WebGLValidateStrings.h"
8 #include <regex>
10 #include "WebGLTypes.h"
11 #include "nsPrintfCString.h"
13 namespace mozilla {
15 /* GLSL ES 3.00 p17:
16 - Comments are delimited by / * and * /, or by // and a newline.
18 - '//' style comments include the initial '//' marker and continue up to, but
19 not including, the terminating newline.
21 - '/ * ... * /' comments include both the start and end marker.
23 - The begin comment delimiters (/ * or //) are not recognized as comment
24 delimiters inside of a comment, hence comments cannot be nested.
26 - Comments are treated syntactically as a single space.
29 std::string CommentsToSpaces(const std::string& src) {
30 constexpr auto flags =
31 std::regex::ECMAScript | std::regex::nosubs | std::regex::optimize;
33 static const auto RE_COMMENT_BEGIN = std::regex("/[*/]", flags);
34 static const auto RE_LINE_COMMENT_END = std::regex(R"([^\\]\n)", flags);
35 static const auto RE_BLOCK_COMMENT_END = std::regex(R"(\*/)", flags);
37 std::string ret;
38 ret.reserve(src.size());
40 // Replace all comments with block comments with the right number of newlines.
41 // Line positions may be off, but line numbers will be accurate, which is more
42 // important.
44 auto itr = src.begin();
45 const auto end = src.end();
46 std::smatch match;
47 while (std::regex_search(itr, end, match, RE_COMMENT_BEGIN)) {
48 MOZ_ASSERT(match.length() == 2);
49 const auto commentBegin = itr + match.position();
50 ret.append(itr, commentBegin);
52 itr = commentBegin + match.length();
54 const bool isBlockComment = (*(commentBegin + 1) == '*');
55 const auto* endRegex = &RE_LINE_COMMENT_END;
56 if (isBlockComment) {
57 endRegex = &RE_BLOCK_COMMENT_END;
60 if (isBlockComment) {
61 ret += "/*";
64 auto commentEnd = end;
65 if (!isBlockComment && itr != end && *itr == '\n') {
66 commentEnd = itr + 1; // '//\n'
67 } else if (std::regex_search(itr, end, match, *endRegex)) {
68 commentEnd = itr + match.position() + match.length();
69 } else {
70 return ret;
73 for (; itr != commentEnd; ++itr) {
74 const auto cur = *itr;
75 if (cur == '\n') {
76 ret += cur;
79 if (isBlockComment) {
80 ret += "*/";
84 ret.append(itr, end);
85 return ret;
88 ////////////////////////////////////////////////////////////////////////////////
90 static constexpr bool IsValidGLSLChar(const char c) {
91 if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
92 ('0' <= c && c <= '9')) {
93 return true;
96 switch (c) {
97 case ' ':
98 case '\t':
99 case '\v':
100 case '\f':
101 case '\r':
102 case '\n':
103 case '_':
104 case '.':
105 case '+':
106 case '-':
107 case '/':
108 case '*':
109 case '%':
110 case '<':
111 case '>':
112 case '[':
113 case ']':
114 case '(':
115 case ')':
116 case '{':
117 case '}':
118 case '^':
119 case '|':
120 case '&':
121 case '~':
122 case '=':
123 case '!':
124 case ':':
125 case ';':
126 case ',':
127 case '?':
128 return true;
130 default:
131 return false;
135 static constexpr bool IsValidForPreprocOrGlsl(const char c) {
136 switch (c) {
137 case '#':
138 case '\\':
139 return true;
141 default:
142 return IsValidGLSLChar(c);
146 ////
148 static constexpr char INVALID_GLSL_CHAR = '$';
150 std::string CrushGlslToAscii(const std::string& u8) {
151 static_assert(!IsValidForPreprocOrGlsl(INVALID_GLSL_CHAR));
152 auto ascii = u8;
153 for (auto& c : ascii) {
154 if (MOZ_UNLIKELY(!IsValidForPreprocOrGlsl(c))) {
155 c = INVALID_GLSL_CHAR;
158 return ascii;
161 Maybe<webgl::ErrorInfo> CheckGLSLVariableName(const bool webgl2,
162 const std::string& name) {
163 if (name.empty()) return {};
165 const uint32_t maxSize = webgl2 ? 1024 : 256;
166 if (name.size() > maxSize) {
167 const auto info = nsPrintfCString(
168 "Identifier is %zu characters long, exceeds the"
169 " maximum allowed length of %u characters.",
170 name.size(), maxSize);
171 return Some(webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, info.BeginReading()});
174 for (const auto cur : name) {
175 if (!IsValidGLSLChar(cur)) {
176 const auto info =
177 nsPrintfCString("String contains the illegal character 0x%x'.", cur);
178 return Some(
179 webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, info.BeginReading()});
183 if (name.find("webgl_") == 0 || name.find("_webgl_") == 0) {
184 return Some(webgl::ErrorInfo{
185 LOCAL_GL_INVALID_OPERATION,
186 "String matches reserved GLSL prefix pattern /_?webgl_/."});
189 return {};
192 } // namespace mozilla