/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.elasticsearch.painless.node; import org.elasticsearch.painless.Constant; import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import java.util.Set; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.WriterConstants; /** * Represents a regex constant. All regexes are constants. */ public final class ERegex extends AExpression { private final String pattern; private final int flags; private Constant constant; public ERegex(Location location, String pattern, String flagsString) { super(location); this.pattern = pattern; int flags = 0; for (int c = 0; c < flagsString.length(); c++) { flags |= flagForChar(flagsString.charAt(c)); } this.flags = flags; } @Override void extractVariables(Set<String> variables) { // Do nothing. } @Override void analyze(Locals locals) { if (!read) { throw createError(new IllegalArgumentException("Regex constant may only be read [" + pattern + "].")); } try { Pattern.compile(pattern, flags); } catch (PatternSyntaxException e) { throw new Location(location.getSourceName(), location.getOffset() + 1 + e.getIndex()).createError( new IllegalArgumentException("Error compiling regex: " + e.getDescription())); } constant = new Constant(location, Definition.PATTERN_TYPE.type, "regexAt$" + location.getOffset(), this::initializeConstant); actual = Definition.PATTERN_TYPE; } @Override void write(MethodWriter writer, Globals globals) { writer.writeDebugInfo(location); writer.getStatic(WriterConstants.CLASS_TYPE, constant.name, Definition.PATTERN_TYPE.type); globals.addConstantInitializer(constant); } private void initializeConstant(MethodWriter writer) { writer.push(pattern); writer.push(flags); writer.invokeStatic(Definition.PATTERN_TYPE.type, WriterConstants.PATTERN_COMPILE); } private int flagForChar(char c) { switch (c) { case 'c': return Pattern.CANON_EQ; case 'i': return Pattern.CASE_INSENSITIVE; case 'l': return Pattern.LITERAL; case 'm': return Pattern.MULTILINE; case 's': return Pattern.DOTALL; case 'U': return Pattern.UNICODE_CHARACTER_CLASS; case 'u': return Pattern.UNICODE_CASE; case 'x': return Pattern.COMMENTS; default: throw new IllegalArgumentException("Unknown flag [" + c + "]"); } } @Override public String toString() { StringBuilder f = new StringBuilder(); if ((flags & Pattern.CANON_EQ) != 0) f.append('c'); if ((flags & Pattern.CASE_INSENSITIVE) != 0) f.append('i'); if ((flags & Pattern.LITERAL) != 0) f.append('l'); if ((flags & Pattern.MULTILINE) != 0) f.append('m'); if ((flags & Pattern.DOTALL) != 0) f.append('s'); if ((flags & Pattern.UNICODE_CHARACTER_CLASS) != 0) f.append('U'); if ((flags & Pattern.UNICODE_CASE) != 0) f.append('u'); if ((flags & Pattern.COMMENTS) != 0) f.append('x'); String p = "/" + pattern + "/"; if (f.length() == 0) { return singleLineToString(p); } return singleLineToString(p, f); } }