/******************************************************************************* * Copyright (c) 2010, 2013 EclipseSource and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * EclipseSource - initial API and implementation ******************************************************************************/ package org.eclipse.rap.clientbuilder; import java.util.List; import org.mozilla.javascript.Token; import com.yahoo.platform.yui.compressor.JavaScriptToken; public class TokenList { private final List<JavaScriptToken> tokens; public TokenList( List<JavaScriptToken> tokens ) { this.tokens = tokens; } public int size() { return tokens.size(); } public JavaScriptToken getToken( int index ) { JavaScriptToken token = null; if( index >= 0 && index < tokens.size() ) { token = tokens.get( index ); } return token; } public void removeToken( int index ) { replaceToken( index, null ); } public void replaceToken( int index, JavaScriptToken[] replacement ) { replaceTokens( index, index, replacement ); } public void replaceTokens( int begin, int end, JavaScriptToken[] replacement ) { if( begin >= 0 && begin <= end && end < tokens.size() ) { for( int i = begin; i <= end; i++ ) { tokens.remove( begin ); } if( replacement != null ) { for( int i = 0; i < replacement.length; i++ ) { tokens.add( begin + i, replacement[ i ] ); } } } } public int readExpression( int offset ) { int result = -1; JavaScriptToken token = getToken( offset ); if( TokenMatcher.LEFT_BRACE.matches( token ) || TokenMatcher.LEFT_BRACKET.matches( token ) ) { result = findClosing( offset ); } int pos = offset; while( pos >= 0 && pos < size() && result == -1 ) { token = getToken( pos ); if( TokenMatcher.LEFT_BRACE.matches( token ) || TokenMatcher.LEFT_BRACKET.matches( token ) || TokenMatcher.LEFT_PAREN.matches( token ) ) { pos = findClosing( pos ) + 1; } else if( TokenMatcher.RIGHT_BRACE.matches( token ) || TokenMatcher.RIGHT_BRACKET.matches( token ) || TokenMatcher.RIGHT_PAREN.matches( token ) || TokenMatcher.COMMA.matches( token ) || TokenMatcher.SEMI.matches( token ) ) { result = pos - 1; } else { pos++; } } if( result == -1 ) { result = pos - 1; } return result; } public int findClosing( int offset ) { int result = -1; TokenMatcher leftMatcher; TokenMatcher rightMatcher; JavaScriptToken token = getToken( offset ); if( TokenMatcher.LEFT_BRACE.matches( token ) ) { leftMatcher = TokenMatcher.LEFT_BRACE; rightMatcher = TokenMatcher.RIGHT_BRACE; } else if( TokenMatcher.LEFT_BRACKET.matches( token ) ) { leftMatcher = TokenMatcher.LEFT_BRACKET; rightMatcher = TokenMatcher.RIGHT_BRACKET; } else if( TokenMatcher.LEFT_PAREN.matches( token ) ) { leftMatcher = TokenMatcher.LEFT_PAREN; rightMatcher = TokenMatcher.RIGHT_PAREN; } else { String message = "Not an opening brace, bracket or parenthesis at pos " + offset; throw new IllegalArgumentException( message ); } int level = 0; int pos = offset; while( pos < tokens.size() && result == -1 ) { token = getToken( pos ); if( leftMatcher.matches( token ) ) { level++; } else if( rightMatcher.matches( token ) ) { level--; if( level == 0 ) { result = pos; } } pos++; } return result; } public int findInObjectLiteral( String key, int offset ) { if( !TokenMatcher.LEFT_BRACE.matches( getToken( offset ) ) ) { throw new IllegalArgumentException( "Not an object literal at pos " + offset ); } int result = -1; int closingBrace = findClosing( offset ); if( closingBrace == -1 ) { throw new IllegalArgumentException( "No closing brace found for pos " + offset ); } int pos = offset + 1; TokenMatcher keyStringMatcher = TokenMatcher.string(); TokenMatcher keyNameMatcher = TokenMatcher.name(); while( pos < closingBrace - 2 ) { JavaScriptToken token = getToken( pos ); if( keyStringMatcher.matches( token ) || keyNameMatcher.matches( token ) ) { if( key.equals( keyStringMatcher.matchedValue ) || key.equals( keyNameMatcher.matchedValue ) || "default".equals( keyStringMatcher.matchedValue ) || "default".equals( keyNameMatcher.matchedValue ) ) { if( TokenMatcher.OBJECTLIT.matches( getToken( pos + 1 ) ) ) { result = pos + 2; } } } pos++; } return result; } public static class TokenPattern { private final TokenMatcher[] matchers; public TokenPattern( TokenMatcher[] matchers ) { this.matchers = matchers; } public int read( TokenList reader, int offset ) { boolean result = true; for( int i = 0; i < matchers.length && result; i++ ) { matchers[ i ].clear(); } int pos = offset; for( int i = 0; i < matchers.length && result; i++ ) { result &= matchers[ i ].matches( reader.getToken( pos ) ); pos++; } if( result ) { return pos - 1; } return -1; } } public static class TokenMatcher { public static final TokenMatcher DOT = TokenMatcher.literal( Token.DOT ); public static final TokenMatcher IF = TokenMatcher.literal( Token.IF ); public static final TokenMatcher ELSE = TokenMatcher.literal( Token.ELSE ); public static final TokenMatcher COMMA = TokenMatcher.literal( Token.COMMA ); public static final TokenMatcher SEMI = TokenMatcher.literal( Token.SEMI ); public static final TokenMatcher OBJECTLIT = TokenMatcher.literal( Token.OBJECTLIT ); public static final TokenMatcher LEFT_PAREN = TokenMatcher.literal( Token.LP ); public static final TokenMatcher RIGHT_PAREN = TokenMatcher.literal( Token.RP ); public static final TokenMatcher LEFT_BRACE = TokenMatcher.literal( Token.LC ); public static final TokenMatcher RIGHT_BRACE = TokenMatcher.literal( Token.RC ); public static final TokenMatcher LEFT_BRACKET = TokenMatcher.literal( Token.LB ); public static final TokenMatcher RIGHT_BRACKET = TokenMatcher.literal( Token.RB ); private final int expectedType; private final String expectedValue; public String matchedValue; public static TokenMatcher string() { return new TokenMatcher( Token.STRING, null ); } public static TokenMatcher name() { return new TokenMatcher( Token.NAME, null ); } public static TokenMatcher string( String string ) { return new TokenMatcher( Token.STRING, string ); } public static TokenMatcher name( String string ) { return new TokenMatcher( Token.NAME, string ); } public static TokenMatcher literal( int type ) { return new TokenMatcher( type, null ); } private TokenMatcher( int type, String value ) { this.expectedType = type; this.expectedValue = value; } public boolean matches( JavaScriptToken token ) { boolean result = false; matchedValue = null; if( token != null ) { result = token.getType() == expectedType; if( expectedValue != null ) { result &= expectedValue.equals( token.getValue() ); } else { matchedValue = token.getValue(); } } return result; } public String getMatchedValue() { return matchedValue; } public void clear() { matchedValue = null; } } }