/******************************************************************************* * Copyright (c) 2009 xored software, Inc. * * 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: * xored software, Inc. - initial API and Implementation (Alex Panchenko) *******************************************************************************/ package org.eclipse.dltk.tcl.internal.structure; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.dltk.compiler.ISourceElementRequestor; import org.eclipse.dltk.compiler.SourceElementRequestorMode; import org.eclipse.dltk.compiler.env.IModuleSource; import org.eclipse.dltk.compiler.problem.IProblemReporter; import org.eclipse.dltk.compiler.problem.ProblemSeverity; import org.eclipse.dltk.core.ISourceElementParser; import org.eclipse.dltk.core.builder.ISourceLineTracker; import org.eclipse.dltk.tcl.ast.TclCommand; import org.eclipse.dltk.tcl.ast.TclModule; import org.eclipse.dltk.tcl.core.TclPlugin; import org.eclipse.dltk.tcl.internal.parser.NewTclSourceParser; import org.eclipse.dltk.tcl.internal.parser.TclSourceElementParser; import org.eclipse.dltk.tcl.parser.ITclErrorReporter; import org.eclipse.dltk.tcl.parser.TclErrorCollector; import org.eclipse.dltk.tcl.parser.TclParser; import org.eclipse.dltk.tcl.parser.TclParserUtils; import org.eclipse.dltk.tcl.parser.TclVisitor; import org.eclipse.dltk.tcl.parser.definitions.DefinitionManager; import org.eclipse.dltk.tcl.parser.definitions.NamespaceScopeProcessor; import org.eclipse.dltk.tcl.structure.ITclModelBuildContext; import org.eclipse.dltk.tcl.structure.ITclModelBuilder; import org.eclipse.dltk.tcl.structure.ITclModelBuilderDetector; import org.eclipse.dltk.tcl.structure.TclModelProblem; import org.eclipse.dltk.tcl.structure.TclProcessorUtil; public class TclSourceElementParser2 extends TclSourceElementParser implements ISourceElementParser { private class TclModelBuilderVisitor extends TclVisitor { private final TclModelBuildContext context; /** * @param context */ private TclModelBuilderVisitor(TclModelBuildContext context) { this.context = context; } @Override public boolean visit(TclCommand command) { final String commandName = TclProcessorUtil.asString(command .getName()); // context.resetAttributes(); for (ITclModelBuilderDetector detector : detectors) { final String builderId = detector.detect(commandName, command, context); if (builderId != null) { final ITclModelBuilder builder = getBuilder(builderId, true); if (builder != null) { try { return builder.process(command, context); } catch (TclModelProblem e) { // TODO Auto-generated catch block return false; } } return true; } } final ITclModelBuilder builder = getBuilder(commandName, false); if (builder != null) { try { return builder.process(command, context); } catch (TclModelProblem e) { // TODO Auto-generated catch block return false; } } return true; } @Override public void endVisit(TclCommand command) { context.leave(command); } } public static final boolean USE_NEW = true; @Override public void parseSourceModule(IModuleSource module) { final ISourceElementRequestor requestor = getRequestor(); if (USE_NEW && SourceElementRequestorMode.STRUCTURE.matches(requestor)) { initDetectors(); final IProblemReporter reporter = getProblemReporter(); // TODO load from disk cache // TODO load from memory cache TclErrorCollector collector = (reporter != null) ? new TclErrorCollector() : null; final String source = module.getSourceContents(); final TclModelBuildContext context = new TclModelBuildContext(this, requestor, collector); requestor.enterModule(); // final TclParser newParser = createParser(); final NamespaceScopeProcessor coreProcessor = DefinitionManager .getInstance().createProcessor(); TclModule tclModule = newParser.parseModule(source, context.getErrorReporter(), coreProcessor); traverse(tclModule.getStatements(), context); // requestor.exitModule(source.length()); if (collector != null) { final ISourceLineTracker tracker = NewTclSourceParser .createLineTracker(tclModule); collector.reportAll(reporter, tracker); } } else { super.parseSourceModule(module); } } public List<TclCommand> parse(String source, int offset) { initDetectors(); ITclModelBuildContext context = new TclModelBuildContext(this, getRequestor(), new ITclErrorReporter() { public void report(int code, String message, String[] extraMessage, int start, int end, ProblemSeverity kind) { // empty } }); final TclParser newParser = createParser(); newParser.setGlobalOffset(offset); final NamespaceScopeProcessor coreProcessor = DefinitionManager .getInstance().createProcessor(); List<TclCommand> commands = newParser.parse(source, context.getErrorReporter(), coreProcessor); traverse(commands, (TclModelBuildContext) context); return commands; } protected TclParser createParser() { return new TclParser(); } protected void traverse(List<TclCommand> commands, TclModelBuildContext context) { TclParserUtils.traverse(commands, new TclModelBuilderVisitor(context)); } private void initDetectors() { if (detectors == null) { detectors = ModelBuilderManager.getInstance().getDetectors(); } } protected ITclModelBuilderDetector[] detectors = null; private Map<String, ITclModelBuilder> builders = new HashMap<String, ITclModelBuilder>(); private static final ITclModelBuilder NULL_BUILDER = new ITclModelBuilder() { public boolean process(TclCommand command, ITclModelBuildContext context) { return true; } }; private static final Set<String> LOGGED_BUILDERS = Collections .synchronizedSet(new HashSet<String>()); protected ITclModelBuilder getBuilder(String id, boolean logMissingAsError) { ITclModelBuilder builder = builders.get(id); if (builder == null) { builder = ModelBuilderManager.getInstance().getModelBuilder(id); if (builder == null) { if (logMissingAsError && LOGGED_BUILDERS.add(id)) { TclPlugin.error("Tcl Model Builder '" + id + "' is not found"); } builder = NULL_BUILDER; } builders.put(id, builder); } return builder != NULL_BUILDER ? builder : null; } }