PsyRegExp.java

package coneforest.psylla.core;

import coneforest.psylla.runtime.*;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
*	The representation of {@code regexp}.
*/
@Type("regexp")
public final class PsyRegExp
	implements PsyValue
{
	/**
	*	Context action of the {@code regexp} operator.
	*/
	@OperatorType("regexp")
	public static final ContextAction PSY_REGEXP
		=ContextAction.<PsyString>ofFunction(PsyRegExp::new);

	private final Pattern pattern;

	/**
	*	Constructs a new {@code regexp} from the character sequence.
	*
	*	@param cs the character sequence.
	*	@throws PsyInvalidRegExpException when a syntax error in a regular-expression pattern
	*	occured.
	*/
	public PsyRegExp(final CharSequence cs)
		throws PsyInvalidRegExpException
	{
		try
		{
			pattern=Pattern.compile(cs.toString());
		}
		catch(final PatternSyntaxException ex)
		{
			throw new PsyInvalidRegExpException(ex);
		}
	}

	/**
	*	Constructs a new {@code regexp} from the given {@code string}.
	*
	*	@param oName the given {@code string}.
	*	@throws PsyInvalidRegExpException when a syntax error in a regular-expression pattern
	*	occured.
	*/
	public PsyRegExp(final PsyString oName)
		throws PsyInvalidRegExpException
	{
		this(oName.stringValue());
	}

	/**
	*	{@return the pattern}
	*/
	public Pattern getPattern()
	{
		return pattern;
	}

	@Override
	public String toSyntaxString()
	{
		final var sb=new StringBuilder("~");
		final var patternImage=pattern.toString();
		for(int i=0; i<patternImage.length(); i++)
		{
			final char c=patternImage.charAt(i);
			sb.append(switch(c)
				{
					case '\u0000'->"\\0";
					case '\u0007'->"\\a";
					case '\t'->"\\t";
					case '\u000B'->"\\v";
					case '\n'->"\\n";
					case '\f'->"\\f";
					case '\r'->"\\r";
					case '\u001B'->"\\e";
					case '~'->"\\~";
					default->c;
				});
		}
		sb.append('~');
		return sb.toString();
	}

	/**
	*	{@return the {@code string} object obtained as a result of parsing the literal token image}
	*
	*	@param image the literal token image.
	*	@throws PsySyntaxErrorException when the literal image is syntactically incorrect.
	*/
	public static PsyRegExp parseLiteral(final String image)
		throws PsyInvalidRegExpException, PsySyntaxErrorException
	{
		final var sb=new StringBuilder();
		for(int i=1; i<image.length()-1; i++)
		{
			final var c=image.charAt(i);
			switch(c)
			{
				case '\\'->
					{
						i++;
						switch(image.charAt(i))
						{
							case '0'->sb.append('\u0000');
							case 'a'->sb.append('\u0007');
							case 'n'->sb.append('\n');
							case 'r'->sb.append('\r');
							case 't'->sb.append('\t');
							case 'v'->sb.append('\u000B');
							case 'f'->sb.append('\f');
							case 'e'->sb.append('\u001B');
							case '\n'->{}
							case 'u'->
								{
									sb.append(Character.toChars(
											Integer.valueOf(image.substring(i+1, i+5), 16)));
									i+=4;
								}
							case 'c'->
								{
									final var ch=image.charAt(++i);
									sb.append(Character.toChars(ch+(ch<64? 64: -64)));
								}
							case 'x'->
								{
									try
									{
										// TODO: if not found
										final var j=image.indexOf('}', i+2);
										sb.append(Character.toChars(
												Integer.valueOf(image.substring(i+2, j), 16)));
										i=j;
									}
									catch(final IllegalArgumentException ex)
									{
										throw new PsySyntaxErrorException(ex);
									}
								}
							case 'o'->
								{
									try
									{
										// TODO: if not found
										final var j=image.indexOf('}', i+2);
										sb.append(Character.toChars(
												Integer.valueOf(image.substring(i+2, j), 8)));
										i=j;
									}
									catch(final IllegalArgumentException ex)
									{
										throw new PsySyntaxErrorException(ex);
									}
								}
							case 'N'->
								{
									try
									{
										// TODO: if not found
										final var j=image.indexOf('}', i+2);
										final var cp=Character.codePointOf(image.substring(i+2, j));
										// TODO
										sb.append((char)cp);
										i=j;
									}
									catch(final IllegalArgumentException ex)
									{
										throw new PsySyntaxErrorException(ex);
									}
								}
							case '~'->sb.append('~');
							default->sb.append("\\"+image.charAt(i));
						}
					}
				default->sb.append(c);
			}
		}
		return new PsyRegExp(sb);
	}
}