/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * GemCodeSyntaxListener.java * Creation date: Oct 02, 2002 * By: Ken Wong */ package org.openquark.gems.client; import java.awt.Color; import java.util.Arrays; import org.openquark.cal.compiler.CodeAnalyser; import org.openquark.cal.compiler.ModuleName; import org.openquark.cal.compiler.QualifiedName; import org.openquark.cal.compiler.SourceIdentifier; import org.openquark.cal.services.GemEntity; import org.openquark.cal.services.Perspective; import org.openquark.gems.client.caleditor.CALSyntaxStyleListener; /** * This is a helper class that handles some of the syntax highlighting for CAL Code Editor. * In particular, it highlights CAL keywords, code arguments, local variables, and built-in and user defined * type classes, type constructors, and functional agents * * Any CALEditor objects can add this GemCodeSyntaxListener to allow for such highlighting, given that * a valid TypeChecker is passed in. It is important to update the typechecker in this highlighter * if the compiler was changed. * * Creation date: Oct 02, 2002 * * @author Ken Wong */ public class GemCodeSyntaxListener implements CALSyntaxStyleListener { /** Perspective used to look up tokens to figure out how they should be coloured. */ private final Perspective perspective; /** Names of known local variables definied in the code, sorted alphabetically */ private String[] localVariableNames = new String[0]; /** Names of known arguments to the code, sorted alphabetically */ private String[] argumentNames = new String[0]; /* * GUI members **************************************************************** */ private static final java.awt.Color USER_CLASS_COLOUR = new java.awt.Color(0,140,190); private static final java.awt.Color USER_CONS_COLOUR = new java.awt.Color(210,140,20); private static final java.awt.Color USER_TYPE_COLOUR = new java.awt.Color(0,150,90); private static final java.awt.Color USER_SC_COLOUR = new java.awt.Color(255,0,170); private static final java.awt.Color ARGUMENT_COLOUR = new java.awt.Color(58,154,154); private static final java.awt.Color LOCAL_VARIABLE_COLOUR = new java.awt.Color(110,110,150); /** * Default Contructor for GemCodeSyntaxListener; * @param perspective */ public GemCodeSyntaxListener(Perspective perspective) { this.perspective = perspective; } /** * Lookup the font for a given scanCode. * Creation date: (1/30/01 9:08:01 AM) * @return java.awt.Font the font to apply * @param scanCode int the scan code (token type) * @param image String the token image * @param suggestedFont java.awt.Font the suggested font (default or user set) or null */ public java.awt.Font fontLookup(int scanCode, java.lang.String image, java.awt.Font suggestedFont) { // Just accept whatever we were given return suggestedFont; } /** * Lookup the foreground colour for a given scanCode. * Creation date: (1/30/01 9:08:01 AM) * @return Style the font to apply * @param scanCode the scan code (token type) * @param image the token image * @param suggestedColour the suggested colour (default or user set) or null */ public Color foreColourLookup(int scanCode, String image, Color suggestedColour) { //todoBI foreColourLookup needs updating. The problem is that qualified names are not a lexical construct //and so something like M.x will result in 3 calls to this method: for "M" for "." and for "x". //if (true) // return suggestedColour; if (scanCode != org.openquark.cal.compiler.CALTokenTypes.VAR_ID && scanCode != org.openquark.cal.compiler.CALTokenTypes.CONS_ID) { // simply accept the colour we're given return suggestedColour; } // Modify the colour of identifiers depending on what they actually are GemEntity entity = null; int periodPos = image.indexOf('.'); if (periodPos == -1) { // This is an unqualified name. if (Arrays.binarySearch(argumentNames, image) > -1) { // This is an argument return ARGUMENT_COLOUR; } // See if this is a known type or class entity = perspective.resolveAmbiguousGemEntity(image); if (entity == null) { // Unqualified name is not a visible supercombinator or class method // Check if it is a type constructor, type class or local variable if (CodeAnalyser.getModulesContainingIdentifier(image, SourceIdentifier.Category.TYPE_CONSTRUCTOR, perspective.getWorkingModuleTypeInfo()).size() > 0) { // This is a type constructor, found in a module return USER_TYPE_COLOUR; } else if (CodeAnalyser.getModulesContainingIdentifier(image, SourceIdentifier.Category.TYPE_CLASS, perspective.getWorkingModuleTypeInfo()).size() > 0) { // This is a class, found in a module return USER_CLASS_COLOUR; } else if (Arrays.binarySearch(localVariableNames, image) > -1) { // This is a local variable return LOCAL_VARIABLE_COLOUR; } } } else if (QualifiedName.isValidCompoundName(image)) { QualifiedName rawImageName = QualifiedName.makeFromCompoundName(image); ModuleName resolvedModuleName = perspective.getWorkingModuleTypeInfo().getModuleNameResolver().resolve(rawImageName.getModuleName()).getResolvedModuleName(); QualifiedName imageName = QualifiedName.make(resolvedModuleName, rawImageName.getUnqualifiedName()); if (imageName.getModuleName().equals(perspective.getWorkingModuleName()) && (Arrays.binarySearch(argumentNames, image) > -1)) { // This is an argument return ARGUMENT_COLOUR; } entity = perspective.getVisibleGemEntity(imageName); if (entity == null) { // Qualified name is not a visible supercombinator or class method // Check if it is a type constructor, type class, or local variable if (CodeAnalyser.getVisibleModuleEntity(imageName, SourceIdentifier.Category.TYPE_CONSTRUCTOR, perspective.getWorkingModuleTypeInfo()) != null) { return USER_TYPE_COLOUR; } else if (CodeAnalyser.getVisibleModuleEntity(imageName, SourceIdentifier.Category.TYPE_CLASS, perspective.getWorkingModuleTypeInfo()) != null) { return USER_CLASS_COLOUR; } else if (imageName.getModuleName().equals(perspective.getWorkingModuleName()) && (Arrays.binarySearch(localVariableNames, image) > -1)) { return LOCAL_VARIABLE_COLOUR; } } } if (entity == null) { return suggestedColour; } // We have this in our environment; we should know what it is boolean cons = entity.isDataConstructor(); //check if constructor if (cons) { // It's a constructor //System.out.println ("Coloured user defined constructor."); return USER_CONS_COLOUR; } else { // It's a supercombinator //System.out.println ("Coloured user defined SC."); return USER_SC_COLOUR; } } /** * Lookup the style for a given scanCode. * Creation date: (1/30/01 9:08:01 AM) * @return javax.swing.text.Style the style to apply * @param scanCode the scan code (token type) * @param image the token image * @param suggestedStyle the suggested style (default or user set) or null */ public javax.swing.text.Style styleLookup(int scanCode, String image, javax.swing.text.Style suggestedStyle) { // Just accept whatever we were given return suggestedStyle; } /** * Set the names of known code arguments * @param argumentNames names of code arguments, sorted alphabetically */ public void setArgumentNames(String[] argumentNames) { this.argumentNames = argumentNames.clone(); } /** * Set the names of known local variables * @param localVariableNames names of local variables, sorted alphabetically */ public void setLocalVariableNames(String[] localVariableNames) { this.localVariableNames = localVariableNames.clone(); } }