/** * Copyright 2012 Tobias Gierke <tobias.gierke@code-sourcery.de> * * Licensed 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 de.codesourcery.jasm16.ast; import org.apache.log4j.Logger; import de.codesourcery.jasm16.compiler.CompilationError; import de.codesourcery.jasm16.compiler.ISymbol; import de.codesourcery.jasm16.compiler.Label; import de.codesourcery.jasm16.exceptions.DuplicateSymbolException; import de.codesourcery.jasm16.exceptions.ParseException; import de.codesourcery.jasm16.lexer.IToken; import de.codesourcery.jasm16.lexer.TokenType; import de.codesourcery.jasm16.parser.IParseContext; import de.codesourcery.jasm16.parser.IParser.ParserOption; import de.codesourcery.jasm16.parser.Identifier; import de.codesourcery.jasm16.utils.ITextRegion; import de.codesourcery.jasm16.utils.TextRegion; /** * An AST node that represents a label definition. * * @author tobias.gierke@code-sourcery.de */ public class LabelNode extends ASTNode { @SuppressWarnings("unused") private static final Logger LOG = Logger.getLogger(LabelNode.class); private Identifier identifier; private ISymbol scope; private Label label; public LabelNode() { } public Identifier getIdentifier() { return identifier; } public ISymbol getScope() { return scope; } public Label getLabel() { return label; } public void setLabel(Label newLabel) { if (newLabel == null) { throw new IllegalArgumentException("newLabel must not be null"); } this.label = newLabel; this.identifier = newLabel.getName(); this.scope = newLabel.getScope(); } @Override protected ASTNode parseInternal(IParseContext context) throws ParseException { final boolean localLabelsAllowed = context.hasParserOption( ParserOption.LOCAL_LABELS_SUPPORTED ); final int startIndex = context.currentParseIndex(); ITextRegion range = null; boolean leadingCharacterFound = false; final IToken current = context.peek(); final boolean isLocalLabel; if ( current.hasType( TokenType.DOT ) ) { if ( ! localLabelsAllowed ) { context.addCompilationError("Local label not permitted here",this); } range = new TextRegion( context.read() ); leadingCharacterFound=true; isLocalLabel = true; } else if ( current.hasType( TokenType.COLON ) ) { range = new TextRegion( context.read() ); leadingCharacterFound=true; isLocalLabel = false; } else { isLocalLabel = false; } final int identifierStartIndex = context.currentParseIndex(); identifier = context.parseIdentifier( range , localLabelsAllowed ); if ( range == null ) { range = new TextRegion( startIndex , context.currentParseIndex() - startIndex ); } final ITextRegion symbolRange = new TextRegion(identifierStartIndex, identifier.getRawValue().length() ); final ISymbol scope; if ( isLocalLabel ) { scope = context.getPreviousGlobalSymbol(); if ( scope == null ) { throw new RuntimeException("Internal error, encountered local label "+identifier+" without any previous global label ?"); } } else { scope = null; } this.label = new Label( context.getCompilationUnit() , symbolRange , identifier , scope ); this.scope = scope; if ( ! leadingCharacterFound ) { if ( context.peek().hasType( TokenType.COLON ) ) { range.merge( context.read( TokenType.COLON ) ); mergeWithAllTokensTextRegion( range ); } else { mergeWithAllTokensTextRegion( range ); context.addCompilationError( "Label lacks trailing colon", this ); } } else { mergeWithAllTokensTextRegion( range ); } try { context.getSymbolTable().defineSymbol( this.label ); // only keep track of the previous global symbol if we need to if ( ! isLocalLabel ) { context.storePreviousGlobalSymbol( this.label ); } } catch(DuplicateSymbolException e) { final String message = "Duplicate symbol '"+identifier+"' found at "+range+" in "+context.getCompilationUnit()+" , " + "previous definition found in "+e.getExistingDefinition().getCompilationUnit(); addCompilationErrorAndAdvanceParser( new CompilationError(message,context.getCompilationUnit(),this,e) , context ); } return this; } @Override protected LabelNode copySingleNode() { final LabelNode result = new LabelNode(); result.label = label; result.identifier = identifier; return result; } @Override public boolean supportsChildNodes() { return false; } }