blob: 56d82b9830872c9c8ff18e7c701d179f0de4e15d [file] [log] [blame]
/*
*
* 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);
}
}