| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF 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.apache.royale.compiler.internal.parsing.as; |
| |
| import static org.apache.royale.compiler.common.ISourceLocation.UNKNOWN; |
| |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.royale.compiler.constants.IMetaAttributeConstants; |
| import com.google.common.collect.ImmutableMap; |
| |
| /** |
| * Tokenizes sequences of metadata attributes (e.g. [Event(name="click")]) in |
| * ActionScript. Uses RawMetadataTokenizer to get raw tokens. Does not attempt |
| * to identify keywords. |
| */ |
| public class MetadataTokenizer |
| { |
| /** |
| * Are we in an attribute list? |
| */ |
| protected boolean inAttrList; |
| |
| protected int adjust = 0; |
| |
| private boolean unknownKeyword; |
| |
| private RawASTokenizer tokenizer; |
| |
| private static final Map<String, Integer> keywordToTokenMap = new ImmutableMap.Builder<String, Integer>() |
| .put(IMetaAttributeConstants.ATTRIBUTE_BINDABLE, MetadataTokenTypes.TOKEN_BINDABLE_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_EVENT, MetadataTokenTypes.TOKEN_EVENT_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_EFFECT, MetadataTokenTypes.TOKEN_EFFECT_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_STYLE, MetadataTokenTypes.TOKEN_STYLE_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_ARRAYELEMENTTYPE, MetadataTokenTypes.TOKEN_ARRAYELEMENTTYPE_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_DEFAULTPROPERTY, MetadataTokenTypes.TOKEN_DEFAULTPROPERTY_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_INSPECTABLE, MetadataTokenTypes.TOKEN_INSPECTABLE_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_INSTANCETYPE, MetadataTokenTypes.TOKEN_INSTANCETYPE_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_NONCOMMITTING, MetadataTokenTypes.TOKEN_NONCOMMITTINGCHANGE_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_ACCESSIBIlITY_CLASS, MetadataTokenTypes.TOKEN_ACCESSIBILITY_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_STATES, MetadataTokenTypes.TOKEN_STATES_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_RESOURCEBUNDLE, MetadataTokenTypes.TOKEN_RESOURCEBUNDLE_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_HOST_COMPONENT, MetadataTokenTypes.TOKEN_HOST_COMPONENT_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_SKIN_CLASS, MetadataTokenTypes.TOKEN_SKINCLASS_KEYWORD) |
| .put(IMetaAttributeConstants.ATTRIBUTE_ALTERNATIVE, MetadataTokenTypes.TOKEN_ALTERNATIVE_KEYWORD) |
| .build(); |
| |
| private static final Map<String, Integer> attrToTokenMap = new ImmutableMap.Builder<String, Integer>() |
| .put(IMetaAttributeConstants.NAME_STYLE_NAME, MetadataTokenTypes.TOKEN_ATTR_NAME) |
| .put(IMetaAttributeConstants.NAME_STYLE_TYPE, MetadataTokenTypes.TOKEN_ATTR_TYPE) |
| .put(IMetaAttributeConstants.NAME_STYLE_ARRAYTYPE, MetadataTokenTypes.TOKEN_ATTR_ARRAY_TYPE) |
| .put(IMetaAttributeConstants.NAME_STYLE_FORMAT, MetadataTokenTypes.TOKEN_ATTR_FORMAT) |
| .put(IMetaAttributeConstants.NAME_STYLE_ENUMERATION, MetadataTokenTypes.TOKEN_ATTR_ENUM) |
| .put(IMetaAttributeConstants.NAME_STYLE_INHERIT, MetadataTokenTypes.TOKEN_ATTR_INHERITS) |
| .put(IMetaAttributeConstants.NAME_EFFECT_EVENT, MetadataTokenTypes.TOKEN_ATTR_EVENT) |
| .put(IMetaAttributeConstants.NAME_INSPECTABLE_ENVIRONMENT, MetadataTokenTypes.TOKEN_ATTR_ENV) |
| .put(IMetaAttributeConstants.NAME_INSPECTABLE_VERBOSE, MetadataTokenTypes.TOKEN_ATTR_VERBOSE) |
| .put(IMetaAttributeConstants.NAME_INSPECTABLE_CATEGORY, MetadataTokenTypes.TOKEN_ATTR_CATEGORY) |
| .put(IMetaAttributeConstants.NAME_INSPECTABLE_VARIABLE, MetadataTokenTypes.TOKEN_ATTR_VARIABLE) |
| .put(IMetaAttributeConstants.NAME_INSPECTABLE_DEFAULT_VALUE, MetadataTokenTypes.TOKEN_ATTR_DEFAULT_VALUE) |
| .put(IMetaAttributeConstants.VALUE_SKIN_PART_REQUIRED_TRUE, MetadataTokenTypes.TOKEN_STRING) |
| .put(IMetaAttributeConstants.VALUE_SKIN_PART_REQUIRED_FALSE, MetadataTokenTypes.TOKEN_STRING) |
| .put(IMetaAttributeConstants.NAME_STYLE_STATES, MetadataTokenTypes.TOKEN_ATTR_STATES) |
| .put(IMetaAttributeConstants.NAME_ALTERNATIVE_REPLACEMENT, MetadataTokenTypes.TOKEN_ATTR_TYPE) |
| .put(IMetaAttributeConstants.NAME_ACCESSIBILITY_IMPLEMENTATION, MetadataTokenTypes.TOKEN_ATTR_IMPLEMENTATION) |
| .build(); |
| |
| /** |
| * Constructor |
| */ |
| public MetadataTokenizer(Reader reader) |
| { |
| tokenizer = new RawASTokenizer(reader); |
| unknownKeyword = true; |
| inAttrList = false; |
| } |
| |
| public MetadataTokenizer() |
| { |
| unknownKeyword = true; |
| inAttrList = false; |
| } |
| |
| /** |
| * Sets the reader that will be used as the input for the data that will be |
| * tokenized. |
| * |
| * @param reader a Reader pointing to a source that will yield text |
| */ |
| public void setInput(Reader reader) throws IOException |
| { |
| if (tokenizer != null) |
| close(); |
| tokenizer = new RawASTokenizer(reader); |
| } |
| |
| public void setAdjust(int offset) |
| { |
| adjust = offset; |
| } |
| |
| public MetadataToken next() |
| { |
| ASToken token = null; |
| boolean needToken = true; |
| while (needToken) |
| { |
| try |
| { |
| token = tokenizer.nextToken(); |
| needToken = false; |
| } |
| catch (Exception e) |
| { |
| needToken = true; |
| } |
| if (token == null) |
| return null; |
| switch (token.getType()) |
| { |
| case ASTokenTypes.TOKEN_IDENTIFIER: |
| case ASTokenTypes.TOKEN_LITERAL_NUMBER: |
| case ASTokenTypes.TOKEN_LITERAL_STRING: |
| case ASTokenTypes.TOKEN_SQUARE_OPEN: |
| case ASTokenTypes.TOKEN_SQUARE_CLOSE: |
| case ASTokenTypes.TOKEN_PAREN_OPEN: |
| case ASTokenTypes.TOKEN_PAREN_CLOSE: |
| return transformToken(token); |
| case ASTokenTypes.TOKEN_COMMA: //skip comma |
| needToken = true; |
| break; |
| case ASTokenTypes.TOKEN_OPERATOR_ASSIGNMENT: |
| break; |
| default: |
| //TODO log errors here |
| break; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Closes the underlying reader |
| */ |
| public void close() throws IOException |
| { |
| if (tokenizer != null) |
| tokenizer.yyclose(); |
| } |
| |
| /** |
| * Parse the sequence of metadata attributes in input and return a list of |
| * MetadataTokens |
| * |
| * @return list of MetadataTokens |
| */ |
| public List<MetadataToken> parseTokens() |
| { |
| ArrayList<MetadataToken> tokenList = new ArrayList<MetadataToken>(100); |
| MetadataToken token = null; |
| do |
| { |
| token = next(); |
| if (token == null) |
| return tokenList; |
| tokenList.add(token); |
| } |
| while (true); |
| } |
| |
| /** |
| * transforms an ASToken to a MetaDataToken. Keeps state, should only be |
| * called during parsing or with a list of tokens |
| * |
| * @param token the token to transform |
| * @return a MetadataToken or null if the token, while valid, cannot be |
| * tranformed such as TOKEN_COMMA |
| */ |
| public final MetadataToken transformToken(ASToken token) |
| { |
| String tokenString = token.getText(); |
| String sourcePath = token.getSourcePath(); |
| int startOffset = token.getStart() + adjust; |
| int endOffset = token.getEnd() + adjust; |
| int line = token.getLine(); |
| int column = token.getColumn(); |
| |
| switch (token.getType()) |
| { |
| case ASTokenTypes.TOKEN_IDENTIFIER: |
| { |
| if (!inAttrList) |
| { |
| unknownKeyword = true; |
| Object object = keywordToTokenMap.get(token.getText()); |
| int num = MetadataTokenTypes.TOKEN_UNKNOWN_KEYWORD; |
| if (object != null) |
| { |
| num = ((Integer)object).intValue(); |
| unknownKeyword = false; |
| } |
| return new MetadataToken(num, sourcePath, startOffset, endOffset, |
| line, column, tokenString); |
| } |
| else |
| { |
| Object object = attrToTokenMap.get(token.getText()); |
| int num = MetadataTokenTypes.TOKEN_ATTR_UNKNOWN; |
| if (object != null && !unknownKeyword) |
| num = ((Integer)object).intValue(); |
| return new MetadataToken(num, sourcePath, startOffset, endOffset, |
| line, column, tokenString); |
| } |
| } |
| |
| case ASTokenTypes.TOKEN_LITERAL_NUMBER: |
| case ASTokenTypes.TOKEN_LITERAL_STRING: |
| { |
| if (tokenString.length() > 0 && |
| ((tokenString.charAt(0) == '"') || |
| (tokenString.charAt(0) == '\''))) |
| { |
| startOffset++; |
| tokenString = tokenString.substring(1); |
| } |
| |
| if (tokenString.length() > 0 && |
| ((tokenString.charAt(tokenString.length() - 1) == '"') || |
| tokenString.charAt(tokenString.length() - 1) == '\'')) |
| { |
| endOffset--; |
| tokenString = tokenString.substring(0, tokenString.length() - 1); |
| } |
| return new MetadataToken(MetadataTokenTypes.TOKEN_STRING, |
| sourcePath, startOffset, endOffset, |
| line, column, tokenString); |
| } |
| |
| case ASTokenTypes.TOKEN_SQUARE_OPEN: |
| { |
| return new MetadataToken(MetadataTokenTypes.TOKEN_OPEN_BRACE, |
| sourcePath, startOffset, endOffset, |
| line, column, tokenString); |
| } |
| |
| case ASTokenTypes.TOKEN_SQUARE_CLOSE: |
| { |
| return new MetadataToken(MetadataTokenTypes.TOKEN_CLOSE_BRACE, |
| sourcePath, startOffset, endOffset, |
| line, column, tokenString); |
| } |
| |
| case ASTokenTypes.TOKEN_PAREN_OPEN: |
| { |
| inAttrList = true; |
| return new MetadataToken(MetadataTokenTypes.TOKEN_OPEN_PAREN, |
| sourcePath, startOffset, endOffset, |
| line, column, tokenString); |
| } |
| |
| case ASTokenTypes.TOKEN_PAREN_CLOSE: |
| { |
| inAttrList = false; |
| return new MetadataToken(MetadataTokenTypes.TOKEN_CLOSE_PAREN, |
| sourcePath, startOffset, endOffset, |
| line, column, tokenString); |
| } |
| case ASTokenTypes.TOKEN_OPERATOR_ASSIGNMENT: |
| case ASTokenTypes.TOKEN_COMMA: |
| { |
| return null; |
| } |
| } |
| |
| return null; |
| } |
| |
| public static final MetadataToken buildNameToken(String name) |
| { |
| Object object = keywordToTokenMap.get(name); |
| int num = MetadataTokenTypes.TOKEN_UNKNOWN_KEYWORD; |
| if (object != null) |
| { |
| num = ((Integer)object).intValue(); |
| } |
| return new MetadataToken(num, null, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, name); |
| } |
| |
| public static final MetadataToken buildIdentifierToken(String identifier, int parentID) |
| { |
| Object object = attrToTokenMap.get(identifier); |
| int num = MetadataTokenTypes.TOKEN_ATTR_UNKNOWN; |
| if (object != null && parentID != MetadataTokenTypes.TOKEN_UNKNOWN_KEYWORD) |
| { |
| num = ((Integer)object).intValue(); |
| } |
| return new MetadataToken(num, null, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, identifier); |
| } |
| |
| public static final MetadataToken buildOpenBraceToken() |
| { |
| return new MetadataToken(MetadataTokenTypes.TOKEN_OPEN_BRACE, null, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, "["); |
| } |
| |
| public static final MetadataToken buildCloseBraceToken() |
| { |
| return new MetadataToken(MetadataTokenTypes.TOKEN_CLOSE_BRACE, null, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, "]"); |
| } |
| |
| public static final MetadataToken buildOpenParenToken() |
| { |
| return new MetadataToken(MetadataTokenTypes.TOKEN_OPEN_PAREN, null, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, "("); |
| } |
| |
| public static final MetadataToken buildCloseParenToken() |
| { |
| return new MetadataToken(MetadataTokenTypes.TOKEN_CLOSE_PAREN, null, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, ")"); |
| } |
| |
| public static final MetadataToken buildStringToken(String identifier) |
| { |
| return new MetadataToken(MetadataTokenTypes.TOKEN_STRING, null, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, identifier); |
| } |
| |
| public static final MetadataToken buildIdentifierToken(String identifier) |
| { |
| return new MetadataToken(MetadataTokenTypes.TOKEN_ID, null, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, identifier); |
| } |
| } |